Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Merge trunk into deltify-tkt-blobs branch. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | deltify-tkt-blobs |
| Files: | files | file ages | folders |
| SHA3-256: |
86916df5349cb79d4429390dc356c323 |
| User & Date: | stephan 2022-10-28 06:37:57.838 |
Context
|
2022-10-28
| ||
| 06:51 | Typo fix in changes.wiki. ... (check-in: 141793c4ab user: stephan tags: deltify-tkt-blobs) | |
| 06:37 | Merge trunk into deltify-tkt-blobs branch. ... (check-in: 86916df534 user: stephan tags: deltify-tkt-blobs) | |
| 00:18 | Fix a typo in a comment. ... (check-in: a2ed111979 user: george tags: deltify-tkt-blobs) | |
|
2022-10-27
| ||
| 17:56 | The check for whether to continue during sync due to outstanding "uvgimme" requests was being skipped in clone -u mode due to misordered tests at the end of the client side of the sync protocol. ... (check-in: 52648d0384 user: wyoung tags: trunk) | |
Changes
Name change from Dockerfile.in to Dockerfile.
|
| > | > > > < < < < < < < > > > > > > > > | | | > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > | > | | > | > | > | > > | | | > > | | | | > > > > > > > > > > | | | < < < | < < < < > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# See www/containers.md for documentation on how to use this file.
## ---------------------------------------------------------------------
## STAGE 1: Build static Fossil & BusyBox binaries atop Alpine Linux
## ---------------------------------------------------------------------
FROM alpine:latest AS builder
WORKDIR /tmp
### Bake the basic Alpine Linux into a base layer so we never have to
### repeat that step unless we change the package set. Although we're
### going to throw this layer away below, we still pass --no-cache
### because that cache is of no use in an immutable layer. Note that
### we allow the UPX step to fail: it isn't in the ARM distros. We'll
### check whether this optional piece exists before using it below.
RUN set -x \
&& apk update \
&& apk upgrade --no-cache \
&& apk add --no-cache \
gcc make moreutils \
linux-headers musl-dev \
openssl-dev openssl-libs-static \
zlib-dev zlib-static \
; apk add --no-cache upx
### Bake the custom BusyBox into another layer. The intent is that this
### changes only when we change BBXVER. That will force an update of
### the layers below, but this is a rare occurrence.
ARG BBXVER="1_35_0"
ENV BBXURL "https://github.com/mirror/busybox/tarball/${BBXVER}"
COPY containers/busybox-config /tmp/bbx/.config
ADD $BBXURL /tmp/bbx/src.tar.gz
RUN set -x \
&& tar --strip-components=1 -C bbx -xzf bbx/src.tar.gz \
&& ( cd bbx && yes "" | make oldconfig && make -j11 ) \
&& if [ -x /usr/bin/upx ] ; then upx -9q bbx/busybox ; fi
### The changeable Fossil layer is the only one in the first stage that
### changes often, so add it last, to make it independent of the others.
###
### $FSLSTB can be either a file or a directory due to a ADD's bizarre
### behavior: it unpacks tarballs when added from a local file but not
### from a URL! It matters because we default to a URL in case you're
### building outside a Fossil checkout, but when building via the
### container-image target, we can avoid a costly hit on the Fossil
### project's home site by pulling the data from the local repo via the
### "tarball" command. This is a DVCS, after all!
ARG FSLVER="trunk"
ARG FSLURL="https://fossil-scm.org/home/tarball/src?r=${FSLVER}"
ENV FSLSTB=/tmp/fsl/src.tar.gz
ADD $FSLURL $FSLSTB
RUN set -x \
&& if [ -d $FSLSTB ] ; then mv $FSLSTB/src fsl ; \
else tar -C fsl -xzf fsl/src.tar.gz ; fi \
&& m=fsl/src/src/main.mk \
&& grep -v '/skins/[a-ce-z]' $m | sponge $m \
&& fsl/src/configure --static CFLAGS='-Os -s' && make -j11 \
&& if [ -x /usr/bin/upx ] ; then upx -9q fossil ; fi
## ---------------------------------------------------------------------
## STAGE 2: Pare that back to the bare essentials.
## ---------------------------------------------------------------------
FROM scratch
WORKDIR /jail
ARG UID=499
ENV PATH "/bin:/jail/bin"
### Lay BusyBox down as the first base layer. Coupled with the host's
### kernel, this is the "OS."
COPY --from=builder /tmp/bbx/busybox /bin/
RUN [ "/bin/busybox", "--install", "/bin" ]
### Set up that base OS for our specific use without tying it to
### anything likely to change often. So long as the user leaves
### UID alone, this layer will be durable.
RUN set -x \
&& echo 'root:x:0:0:SysAdmin:/:/bin/nologin' > /etc/passwd \
&& echo 'root:x:0:root' > /etc/group \
&& addgroup -S -g ${UID} fossil \
&& adduser -S -h `pwd` -g 'Fossil User' -G fossil -u ${UID} fossil \
&& install -d -m 700 -o fossil -g fossil log museum \
&& install -d -m 755 -o fossil -g fossil dev \
&& mknod -m 666 dev/null c 1 3 \
&& mknod -m 444 dev/urandom c 1 9
### Do Fossil-specific things atop those base layers; this will change
### as often as the Fossil build-from-source layer above.
COPY --from=builder /tmp/fossil bin/
RUN set -x \
&& ln -s /jail/bin/fossil /bin/f \
&& echo -e '#!/bin/sh\nfossil sha1sum "$@"' > /bin/sha1sum \
&& echo -e '#!/bin/sh\nfossil sha3sum "$@"' > /bin/sha3sum \
&& echo -e '#!/bin/sh\nfossil sqlite3 --no-repository "$@"' > \
/bin/sqlite3 \
&& chmod +x /bin/sha?sum /bin/sqlite3
## ---------------------------------------------------------------------
## STAGE 3: Run!
## ---------------------------------------------------------------------
EXPOSE 8080/tcp
CMD [ \
"bin/fossil", "server", \
"--chroot", "/jail", \
"--create", \
"--jsmode", "bundled", \
|
| ︙ | ︙ |
Changes to Makefile.in.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 | # TCLSH = @TCLSH@ CFLAGS = @CFLAGS@ CFLAGS_INCLUDE = @CFLAGS_INCLUDE@ LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ BCCFLAGS = @CPPFLAGS@ $(CFLAGS) | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | # TCLSH = @TCLSH@ CFLAGS = @CFLAGS@ CFLAGS_INCLUDE = @CFLAGS_INCLUDE@ LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ BCCFLAGS = @CPPFLAGS@ $(CFLAGS) TCCFLAGS = @EXTRA_CFLAGS@ @CPPFLAGS@ $(CFLAGS) -DHAVE_AUTOCONFIG_H # # Fuzzing may be enable by appending -fsanitize=fuzzer -DFOSSIL_FUZZ # to the TCCFLAGS variable. # For more thorouth (but also slower) investigation # -fsanitize=fuzzer,undefined,address # might be more useful. |
| ︙ | ︙ | |||
116 117 118 119 120 121 122 | # of delegating to it with "$(MAKE) reconfig": having children running # around interfering makes this failure mode even worse. Makefile: @srcdir@/Makefile.in $(SRCDIR)/main.mk @AUTODEPS@ @AUTOREMAKE@ touch @builddir@/Makefile # Container stuff | > | > > | > > > > | | < < | > > > > > > > > > > | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | # of delegating to it with "$(MAKE) reconfig": having children running # around interfering makes this failure mode even worse. Makefile: @srcdir@/Makefile.in $(SRCDIR)/main.mk @AUTODEPS@ @AUTOREMAKE@ touch @builddir@/Makefile # Container stuff SRCTB := src-@FOSSIL_CI_PFX@.tar.gz container-image: $(APPNAME) tarball --name src @FOSSIL_CI_PFX@ $(SRCTB) docker build \ --tag fossil:@FOSSIL_CI_PFX@ \ --build-arg FSLURL=$(SRCTB) \ $(DBFLAGS) @srcdir@ rm -f $(SRCTB) container-run: container-image docker run \ --name fossil-@FOSSIL_CI_PFX@ \ --cap-drop AUDIT_WRITE \ --cap-drop CHOWN \ --cap-drop FSETID \ --cap-drop KILL \ --cap-drop MKNOD \ --cap-drop NET_BIND_SERVICE \ --cap-drop NET_RAW \ --cap-drop SETFCAP \ --cap-drop SETPCAP \ --detach --publish 8080:8080 \ $(DRFLAGS) fossil:@FOSSIL_CI_PFX@ docker container logs fossil-@FOSSIL_CI_PFX@ |
Changes to auto.def.
| ︙ | ︙ | |||
763 764 765 766 767 768 769 |
make-template tools/emcc.sh.in
catch {exec chmod u+x tools/emcc.sh}
} else {
define EMCC_WRAPPER ""
catch {exec rm -f tools/emcc.sh}
}
| | > > | > | < | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 |
make-template tools/emcc.sh.in
catch {exec chmod u+x tools/emcc.sh}
} else {
define EMCC_WRAPPER ""
catch {exec rm -f tools/emcc.sh}
}
# Tag container builds with a prefix of the checkin ID of the version
# of Fossil each one contains. This not only allows multiple images
# to coexist and multiple containers to be created unamgiguosly from
# them, it also changes the URL we fetch the source tarball from, so
# repeated builds of a given version generate and fetch the source
# tarball once only, keeping it in the local Docker/Podman cache.
set ci [readfile "$::autosetup(srcdir)/manifest.uuid"]
define FOSSIL_CI_PFX [string range $ci 0 11]
make-template Makefile.in
make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
|
Added containers/Dockerfile-nojail.patch.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
Index: Dockerfile
==================================================================
--- Dockerfile
+++ Dockerfile
@@ -61,13 +61,13 @@
## ---------------------------------------------------------------------
## STAGE 2: Pare that back to the bare essentials.
## ---------------------------------------------------------------------
FROM scratch
-WORKDIR /jail
+WORKDIR /
ARG UID=499
-ENV PATH "/bin:/jail/bin"
+ENV PATH "/bin"
### Lay BusyBox down as the first base layer. Coupled with the host's
### kernel, this is the "OS."
COPY --from=builder /tmp/bbx/busybox /bin/
RUN [ "/bin/busybox", "--install", "/bin" ]
@@ -78,20 +78,17 @@
RUN set -x \
&& echo 'root:x:0:0:SysAdmin:/:/bin/nologin' > /etc/passwd \
&& echo 'root:x:0:root' > /etc/group \
&& addgroup -S -g ${UID} fossil \
&& adduser -S -h `pwd` -g 'Fossil User' -G fossil -u ${UID} fossil \
- && install -d -m 700 -o fossil -g fossil log museum \
- && install -d -m 755 -o fossil -g fossil dev \
- && mknod -m 666 dev/null c 1 3 \
- && mknod -m 444 dev/urandom c 1 9
+ && install -d -m 700 -o fossil -g fossil log museum
### Do Fossil-specific things atop those base layers; this will change
### as often as the Fossil build-from-source layer above.
COPY --from=builder /tmp/fossil bin/
RUN set -x \
- && ln -s /jail/bin/fossil /bin/f \
+ && ln -s /bin/fossil /bin/f \
&& echo -e '#!/bin/sh\nfossil sha1sum "$@"' > /bin/sha1sum \
&& echo -e '#!/bin/sh\nfossil sha3sum "$@"' > /bin/sha3sum \
&& echo -e '#!/bin/sh\nfossil sqlite3 --no-repository "$@"' > \
/bin/sqlite3 \
&& chmod +x /bin/sha?sum /bin/sqlite3
@@ -100,12 +97,12 @@
## ---------------------------------------------------------------------
## STAGE 3: Run!
## ---------------------------------------------------------------------
EXPOSE 8080/tcp
+USER fossil
CMD [ \
"bin/fossil", "server", \
- "--chroot", "/jail", \
"--create", \
"--jsmode", "bundled", \
"--user", "admin", \
"museum/repo.fossil"]
|
Name change from tools/busybox-config to containers/busybox-config.
| ︙ | ︙ | |||
936 937 938 939 940 941 942 | # CONFIG_NSLOOKUP is not set # CONFIG_FEATURE_NSLOOKUP_BIG is not set # CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set # CONFIG_FEATURE_NTPD_CONF is not set # CONFIG_FEATURE_NTP_AUTH is not set | | | | | 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 | # CONFIG_NSLOOKUP is not set # CONFIG_FEATURE_NSLOOKUP_BIG is not set # CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set # CONFIG_FEATURE_NTPD_CONF is not set # CONFIG_FEATURE_NTP_AUTH is not set # CONFIG_PING is not set # CONFIG_PING6 is not set # CONFIG_FEATURE_FANCY_PING is not set # CONFIG_PSCAN is not set CONFIG_ROUTE=y # CONFIG_SLATTACH is not set CONFIG_SSL_CLIENT=y # CONFIG_TC is not set # CONFIG_FEATURE_TC_INGRESS is not set # CONFIG_TCPSVD is not set |
| ︙ | ︙ | |||
964 965 966 967 968 969 970 | # CONFIG_FEATURE_TFTP_HPA_COMPAT is not set # CONFIG_TFTPD is not set # CONFIG_FEATURE_TFTP_GET is not set # CONFIG_FEATURE_TFTP_PUT is not set # CONFIG_FEATURE_TFTP_BLOCKSIZE is not set # CONFIG_TFTP_DEBUG is not set CONFIG_TLS=y | | | | | | 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 | # CONFIG_FEATURE_TFTP_HPA_COMPAT is not set # CONFIG_TFTPD is not set # CONFIG_FEATURE_TFTP_GET is not set # CONFIG_FEATURE_TFTP_PUT is not set # CONFIG_FEATURE_TFTP_BLOCKSIZE is not set # CONFIG_TFTP_DEBUG is not set CONFIG_TLS=y # CONFIG_TRACEROUTE is not set # CONFIG_TRACEROUTE6 is not set # CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set # CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set # CONFIG_TUNCTL is not set # CONFIG_FEATURE_TUNCTL_UG is not set # CONFIG_VCONFIG is not set CONFIG_WGET=y CONFIG_FEATURE_WGET_LONG_OPTIONS=y CONFIG_FEATURE_WGET_STATUSBAR=y CONFIG_FEATURE_WGET_FTP=y |
| ︙ | ︙ |
Changes to extsrc/pikchr.c.
| ︙ | ︙ | |||
1254 1255 1256 1257 1258 1259 1260 1261 1262 | #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; #ifndef NDEBUG #include <stdio.h> | > < | 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 | #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; #include <assert.h> #ifndef NDEBUG #include <stdio.h> static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG /* ** Turn parser tracing on by giving a stream to which to write the trace |
| ︙ | ︙ | |||
2366 2367 2368 2369 2370 2371 2372 | YYACTIONTYPE yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ pik_parserARG_FETCH (void)yyLookahead; (void)yyLookaheadToken; yymsp = yypParser->yytos; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 |
YYACTIONTYPE yyact; /* The next action */
yyStackEntry *yymsp; /* The top of the parser's stack */
int yysize; /* Amount to pop the stack */
pik_parserARG_FETCH
(void)yyLookahead;
(void)yyLookaheadToken;
yymsp = yypParser->yytos;
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
** follows:
** case 0:
** #line <lineno> <grammarfile>
** { ... } // User supplied code
** #line <lineno> <thisfile>
** break;
*/
/********** Begin reduce actions **********************************************/
YYMINORTYPE yylhsminor;
case 0: /* document ::= statement_list */
#line 547 "pikchr.y"
{pik_render(p,yymsp[0].minor.yy227);}
#line 2413 "pikchr.c"
break;
case 1: /* statement_list ::= statement */
#line 550 "pikchr.y"
{ yylhsminor.yy227 = pik_elist_append(p,0,yymsp[0].minor.yy36); }
#line 2418 "pikchr.c"
yymsp[0].minor.yy227 = yylhsminor.yy227;
break;
case 2: /* statement_list ::= statement_list EOL statement */
#line 552 "pikchr.y"
{ yylhsminor.yy227 = pik_elist_append(p,yymsp[-2].minor.yy227,yymsp[0].minor.yy36); }
#line 2424 "pikchr.c"
yymsp[-2].minor.yy227 = yylhsminor.yy227;
break;
case 3: /* statement ::= */
#line 555 "pikchr.y"
{ yymsp[1].minor.yy36 = 0; }
#line 2430 "pikchr.c"
break;
case 4: /* statement ::= direction */
#line 556 "pikchr.y"
{ pik_set_direction(p,yymsp[0].minor.yy0.eCode); yylhsminor.yy36=0; }
#line 2435 "pikchr.c"
yymsp[0].minor.yy36 = yylhsminor.yy36;
break;
case 5: /* statement ::= lvalue ASSIGN rvalue */
#line 557 "pikchr.y"
{pik_set_var(p,&yymsp[-2].minor.yy0,yymsp[0].minor.yy153,&yymsp[-1].minor.yy0); yylhsminor.yy36=0;}
#line 2441 "pikchr.c"
yymsp[-2].minor.yy36 = yylhsminor.yy36;
break;
case 6: /* statement ::= PLACENAME COLON unnamed_statement */
#line 559 "pikchr.y"
{ yylhsminor.yy36 = yymsp[0].minor.yy36; pik_elem_setname(p,yymsp[0].minor.yy36,&yymsp[-2].minor.yy0); }
#line 2447 "pikchr.c"
yymsp[-2].minor.yy36 = yylhsminor.yy36;
break;
case 7: /* statement ::= PLACENAME COLON position */
#line 561 "pikchr.y"
{ yylhsminor.yy36 = pik_elem_new(p,0,0,0);
if(yylhsminor.yy36){ yylhsminor.yy36->ptAt = yymsp[0].minor.yy79; pik_elem_setname(p,yylhsminor.yy36,&yymsp[-2].minor.yy0); }}
#line 2454 "pikchr.c"
yymsp[-2].minor.yy36 = yylhsminor.yy36;
break;
case 8: /* statement ::= unnamed_statement */
#line 563 "pikchr.y"
{yylhsminor.yy36 = yymsp[0].minor.yy36;}
#line 2460 "pikchr.c"
yymsp[0].minor.yy36 = yylhsminor.yy36;
break;
case 9: /* statement ::= print prlist */
#line 564 "pikchr.y"
{pik_append(p,"<br>\n",5); yymsp[-1].minor.yy36=0;}
#line 2466 "pikchr.c"
break;
case 10: /* statement ::= ASSERT LP expr EQ expr RP */
#line 569 "pikchr.y"
{yymsp[-5].minor.yy36=pik_assert(p,yymsp[-3].minor.yy153,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy153);}
#line 2471 "pikchr.c"
break;
case 11: /* statement ::= ASSERT LP position EQ position RP */
#line 571 "pikchr.y"
{yymsp[-5].minor.yy36=pik_position_assert(p,&yymsp[-3].minor.yy79,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy79);}
#line 2476 "pikchr.c"
break;
case 12: /* statement ::= DEFINE ID CODEBLOCK */
#line 572 "pikchr.y"
{yymsp[-2].minor.yy36=0; pik_add_macro(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
#line 2481 "pikchr.c"
break;
case 13: /* rvalue ::= PLACENAME */
#line 583 "pikchr.y"
{yylhsminor.yy153 = pik_lookup_color(p,&yymsp[0].minor.yy0);}
#line 2486 "pikchr.c"
yymsp[0].minor.yy153 = yylhsminor.yy153;
break;
case 14: /* pritem ::= FILL */
case 15: /* pritem ::= COLOR */ yytestcase(yyruleno==15);
case 16: /* pritem ::= THICKNESS */ yytestcase(yyruleno==16);
#line 588 "pikchr.y"
{pik_append_num(p,"",pik_value(p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.n,0));}
#line 2494 "pikchr.c"
break;
case 17: /* pritem ::= rvalue */
#line 591 "pikchr.y"
{pik_append_num(p,"",yymsp[0].minor.yy153);}
#line 2499 "pikchr.c"
break;
case 18: /* pritem ::= STRING */
#line 592 "pikchr.y"
{pik_append_text(p,yymsp[0].minor.yy0.z+1,yymsp[0].minor.yy0.n-2,0);}
#line 2504 "pikchr.c"
break;
case 19: /* prsep ::= COMMA */
#line 593 "pikchr.y"
{pik_append(p, " ", 1);}
#line 2509 "pikchr.c"
break;
case 20: /* unnamed_statement ::= basetype attribute_list */
#line 596 "pikchr.y"
{yylhsminor.yy36 = yymsp[-1].minor.yy36; pik_after_adding_attributes(p,yylhsminor.yy36);}
#line 2514 "pikchr.c"
yymsp[-1].minor.yy36 = yylhsminor.yy36;
break;
case 21: /* basetype ::= CLASSNAME */
#line 598 "pikchr.y"
{yylhsminor.yy36 = pik_elem_new(p,&yymsp[0].minor.yy0,0,0); }
#line 2520 "pikchr.c"
yymsp[0].minor.yy36 = yylhsminor.yy36;
break;
case 22: /* basetype ::= STRING textposition */
#line 600 "pikchr.y"
{yymsp[-1].minor.yy0.eCode = yymsp[0].minor.yy164; yylhsminor.yy36 = pik_elem_new(p,0,&yymsp[-1].minor.yy0,0); }
#line 2526 "pikchr.c"
yymsp[-1].minor.yy36 = yylhsminor.yy36;
break;
case 23: /* basetype ::= LB savelist statement_list RB */
#line 602 "pikchr.y"
{ p->list = yymsp[-2].minor.yy227; yymsp[-3].minor.yy36 = pik_elem_new(p,0,0,yymsp[-1].minor.yy227); if(yymsp[-3].minor.yy36) yymsp[-3].minor.yy36->errTok = yymsp[0].minor.yy0; }
#line 2532 "pikchr.c"
break;
case 24: /* savelist ::= */
#line 607 "pikchr.y"
{yymsp[1].minor.yy227 = p->list; p->list = 0;}
#line 2537 "pikchr.c"
break;
case 25: /* relexpr ::= expr */
#line 614 "pikchr.y"
{yylhsminor.yy10.rAbs = yymsp[0].minor.yy153; yylhsminor.yy10.rRel = 0;}
#line 2542 "pikchr.c"
yymsp[0].minor.yy10 = yylhsminor.yy10;
break;
case 26: /* relexpr ::= expr PERCENT */
#line 615 "pikchr.y"
{yylhsminor.yy10.rAbs = 0; yylhsminor.yy10.rRel = yymsp[-1].minor.yy153/100;}
#line 2548 "pikchr.c"
yymsp[-1].minor.yy10 = yylhsminor.yy10;
break;
case 27: /* optrelexpr ::= */
#line 617 "pikchr.y"
{yymsp[1].minor.yy10.rAbs = 0; yymsp[1].minor.yy10.rRel = 1.0;}
#line 2554 "pikchr.c"
break;
case 28: /* attribute_list ::= relexpr alist */
#line 619 "pikchr.y"
{pik_add_direction(p,0,&yymsp[-1].minor.yy10);}
#line 2559 "pikchr.c"
break;
case 29: /* attribute ::= numproperty relexpr */
#line 623 "pikchr.y"
{ pik_set_numprop(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy10); }
#line 2564 "pikchr.c"
break;
case 30: /* attribute ::= dashproperty expr */
#line 624 "pikchr.y"
{ pik_set_dashed(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy153); }
#line 2569 "pikchr.c"
break;
case 31: /* attribute ::= dashproperty */
#line 625 "pikchr.y"
{ pik_set_dashed(p,&yymsp[0].minor.yy0,0); }
#line 2574 "pikchr.c"
break;
case 32: /* attribute ::= colorproperty rvalue */
#line 626 "pikchr.y"
{ pik_set_clrprop(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy153); }
#line 2579 "pikchr.c"
break;
case 33: /* attribute ::= go direction optrelexpr */
#line 627 "pikchr.y"
{ pik_add_direction(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy10);}
#line 2584 "pikchr.c"
break;
case 34: /* attribute ::= go direction even position */
#line 628 "pikchr.y"
{pik_evenwith(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy79);}
#line 2589 "pikchr.c"
break;
case 35: /* attribute ::= CLOSE */
#line 629 "pikchr.y"
{ pik_close_path(p,&yymsp[0].minor.yy0); }
#line 2594 "pikchr.c"
break;
case 36: /* attribute ::= CHOP */
#line 630 "pikchr.y"
{ p->cur->bChop = 1; }
#line 2599 "pikchr.c"
break;
case 37: /* attribute ::= FROM position */
#line 631 "pikchr.y"
{ pik_set_from(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy79); }
#line 2604 "pikchr.c"
break;
case 38: /* attribute ::= TO position */
#line 632 "pikchr.y"
{ pik_add_to(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy79); }
#line 2609 "pikchr.c"
break;
case 39: /* attribute ::= THEN */
#line 633 "pikchr.y"
{ pik_then(p, &yymsp[0].minor.yy0, p->cur); }
#line 2614 "pikchr.c"
break;
case 40: /* attribute ::= THEN optrelexpr HEADING expr */
case 42: /* attribute ::= GO optrelexpr HEADING expr */ yytestcase(yyruleno==42);
#line 635 "pikchr.y"
{pik_move_hdg(p,&yymsp[-2].minor.yy10,&yymsp[-1].minor.yy0,yymsp[0].minor.yy153,0,&yymsp[-3].minor.yy0);}
#line 2620 "pikchr.c"
break;
case 41: /* attribute ::= THEN optrelexpr EDGEPT */
case 43: /* attribute ::= GO optrelexpr EDGEPT */ yytestcase(yyruleno==43);
#line 636 "pikchr.y"
{pik_move_hdg(p,&yymsp[-1].minor.yy10,0,0,&yymsp[0].minor.yy0,&yymsp[-2].minor.yy0);}
#line 2626 "pikchr.c"
break;
case 44: /* attribute ::= AT position */
#line 641 "pikchr.y"
{ pik_set_at(p,0,&yymsp[0].minor.yy79,&yymsp[-1].minor.yy0); }
#line 2631 "pikchr.c"
break;
case 45: /* attribute ::= SAME */
#line 643 "pikchr.y"
{pik_same(p,0,&yymsp[0].minor.yy0);}
#line 2636 "pikchr.c"
break;
case 46: /* attribute ::= SAME AS object */
#line 644 "pikchr.y"
{pik_same(p,yymsp[0].minor.yy36,&yymsp[-2].minor.yy0);}
#line 2641 "pikchr.c"
break;
case 47: /* attribute ::= STRING textposition */
#line 645 "pikchr.y"
{pik_add_txt(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy164);}
#line 2646 "pikchr.c"
break;
case 48: /* attribute ::= FIT */
#line 646 "pikchr.y"
{pik_size_to_fit(p,&yymsp[0].minor.yy0,3); }
#line 2651 "pikchr.c"
break;
case 49: /* attribute ::= BEHIND object */
#line 647 "pikchr.y"
{pik_behind(p,yymsp[0].minor.yy36);}
#line 2656 "pikchr.c"
break;
case 50: /* withclause ::= DOT_E edge AT position */
case 51: /* withclause ::= edge AT position */ yytestcase(yyruleno==51);
#line 655 "pikchr.y"
{ pik_set_at(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy79,&yymsp[-1].minor.yy0); }
#line 2662 "pikchr.c"
break;
case 52: /* numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */
#line 659 "pikchr.y"
{yylhsminor.yy0 = yymsp[0].minor.yy0;}
#line 2667 "pikchr.c"
yymsp[0].minor.yy0 = yylhsminor.yy0;
break;
case 53: /* boolproperty ::= CW */
#line 670 "pikchr.y"
{p->cur->cw = 1;}
#line 2673 "pikchr.c"
break;
case 54: /* boolproperty ::= CCW */
#line 671 "pikchr.y"
{p->cur->cw = 0;}
#line 2678 "pikchr.c"
break;
case 55: /* boolproperty ::= LARROW */
#line 672 "pikchr.y"
{p->cur->larrow=1; p->cur->rarrow=0; }
#line 2683 "pikchr.c"
break;
case 56: /* boolproperty ::= RARROW */
#line 673 "pikchr.y"
{p->cur->larrow=0; p->cur->rarrow=1; }
#line 2688 "pikchr.c"
break;
case 57: /* boolproperty ::= LRARROW */
#line 674 "pikchr.y"
{p->cur->larrow=1; p->cur->rarrow=1; }
#line 2693 "pikchr.c"
break;
case 58: /* boolproperty ::= INVIS */
#line 675 "pikchr.y"
{p->cur->sw = 0.0;}
#line 2698 "pikchr.c"
break;
case 59: /* boolproperty ::= THICK */
#line 676 "pikchr.y"
{p->cur->sw *= 1.5;}
#line 2703 "pikchr.c"
break;
case 60: /* boolproperty ::= THIN */
#line 677 "pikchr.y"
{p->cur->sw *= 0.67;}
#line 2708 "pikchr.c"
break;
case 61: /* boolproperty ::= SOLID */
#line 678 "pikchr.y"
{p->cur->sw = pik_value(p,"thickness",9,0);
p->cur->dotted = p->cur->dashed = 0.0;}
#line 2714 "pikchr.c"
break;
case 62: /* textposition ::= */
#line 681 "pikchr.y"
{yymsp[1].minor.yy164 = 0;}
#line 2719 "pikchr.c"
break;
case 63: /* textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|ALIGNED|BIG|SMALL */
#line 684 "pikchr.y"
{yylhsminor.yy164 = (short int)pik_text_position(yymsp[-1].minor.yy164,&yymsp[0].minor.yy0);}
#line 2724 "pikchr.c"
yymsp[-1].minor.yy164 = yylhsminor.yy164;
break;
case 64: /* position ::= expr COMMA expr */
#line 687 "pikchr.y"
{yylhsminor.yy79.x=yymsp[-2].minor.yy153; yylhsminor.yy79.y=yymsp[0].minor.yy153;}
#line 2730 "pikchr.c"
yymsp[-2].minor.yy79 = yylhsminor.yy79;
break;
case 65: /* position ::= place PLUS expr COMMA expr */
#line 689 "pikchr.y"
{yylhsminor.yy79.x=yymsp[-4].minor.yy79.x+yymsp[-2].minor.yy153; yylhsminor.yy79.y=yymsp[-4].minor.yy79.y+yymsp[0].minor.yy153;}
#line 2736 "pikchr.c"
yymsp[-4].minor.yy79 = yylhsminor.yy79;
break;
case 66: /* position ::= place MINUS expr COMMA expr */
#line 690 "pikchr.y"
{yylhsminor.yy79.x=yymsp[-4].minor.yy79.x-yymsp[-2].minor.yy153; yylhsminor.yy79.y=yymsp[-4].minor.yy79.y-yymsp[0].minor.yy153;}
#line 2742 "pikchr.c"
yymsp[-4].minor.yy79 = yylhsminor.yy79;
break;
case 67: /* position ::= place PLUS LP expr COMMA expr RP */
#line 692 "pikchr.y"
{yylhsminor.yy79.x=yymsp[-6].minor.yy79.x+yymsp[-3].minor.yy153; yylhsminor.yy79.y=yymsp[-6].minor.yy79.y+yymsp[-1].minor.yy153;}
#line 2748 "pikchr.c"
yymsp[-6].minor.yy79 = yylhsminor.yy79;
break;
case 68: /* position ::= place MINUS LP expr COMMA expr RP */
#line 694 "pikchr.y"
{yylhsminor.yy79.x=yymsp[-6].minor.yy79.x-yymsp[-3].minor.yy153; yylhsminor.yy79.y=yymsp[-6].minor.yy79.y-yymsp[-1].minor.yy153;}
#line 2754 "pikchr.c"
yymsp[-6].minor.yy79 = yylhsminor.yy79;
break;
case 69: /* position ::= LP position COMMA position RP */
#line 695 "pikchr.y"
{yymsp[-4].minor.yy79.x=yymsp[-3].minor.yy79.x; yymsp[-4].minor.yy79.y=yymsp[-1].minor.yy79.y;}
#line 2760 "pikchr.c"
break;
case 70: /* position ::= LP position RP */
#line 696 "pikchr.y"
{yymsp[-2].minor.yy79=yymsp[-1].minor.yy79;}
#line 2765 "pikchr.c"
break;
case 71: /* position ::= expr between position AND position */
#line 698 "pikchr.y"
{yylhsminor.yy79 = pik_position_between(yymsp[-4].minor.yy153,yymsp[-2].minor.yy79,yymsp[0].minor.yy79);}
#line 2770 "pikchr.c"
yymsp[-4].minor.yy79 = yylhsminor.yy79;
break;
case 72: /* position ::= expr LT position COMMA position GT */
#line 700 "pikchr.y"
{yylhsminor.yy79 = pik_position_between(yymsp[-5].minor.yy153,yymsp[-3].minor.yy79,yymsp[-1].minor.yy79);}
#line 2776 "pikchr.c"
yymsp[-5].minor.yy79 = yylhsminor.yy79;
break;
case 73: /* position ::= expr ABOVE position */
#line 701 "pikchr.y"
{yylhsminor.yy79=yymsp[0].minor.yy79; yylhsminor.yy79.y += yymsp[-2].minor.yy153;}
#line 2782 "pikchr.c"
yymsp[-2].minor.yy79 = yylhsminor.yy79;
break;
case 74: /* position ::= expr BELOW position */
#line 702 "pikchr.y"
{yylhsminor.yy79=yymsp[0].minor.yy79; yylhsminor.yy79.y -= yymsp[-2].minor.yy153;}
#line 2788 "pikchr.c"
yymsp[-2].minor.yy79 = yylhsminor.yy79;
break;
case 75: /* position ::= expr LEFT OF position */
#line 703 "pikchr.y"
{yylhsminor.yy79=yymsp[0].minor.yy79; yylhsminor.yy79.x -= yymsp[-3].minor.yy153;}
#line 2794 "pikchr.c"
yymsp[-3].minor.yy79 = yylhsminor.yy79;
break;
case 76: /* position ::= expr RIGHT OF position */
#line 704 "pikchr.y"
{yylhsminor.yy79=yymsp[0].minor.yy79; yylhsminor.yy79.x += yymsp[-3].minor.yy153;}
#line 2800 "pikchr.c"
yymsp[-3].minor.yy79 = yylhsminor.yy79;
break;
case 77: /* position ::= expr ON HEADING EDGEPT OF position */
#line 706 "pikchr.y"
{yylhsminor.yy79 = pik_position_at_hdg(yymsp[-5].minor.yy153,&yymsp[-2].minor.yy0,yymsp[0].minor.yy79);}
#line 2806 "pikchr.c"
yymsp[-5].minor.yy79 = yylhsminor.yy79;
break;
case 78: /* position ::= expr HEADING EDGEPT OF position */
#line 708 "pikchr.y"
{yylhsminor.yy79 = pik_position_at_hdg(yymsp[-4].minor.yy153,&yymsp[-2].minor.yy0,yymsp[0].minor.yy79);}
#line 2812 "pikchr.c"
yymsp[-4].minor.yy79 = yylhsminor.yy79;
break;
case 79: /* position ::= expr EDGEPT OF position */
#line 710 "pikchr.y"
{yylhsminor.yy79 = pik_position_at_hdg(yymsp[-3].minor.yy153,&yymsp[-2].minor.yy0,yymsp[0].minor.yy79);}
#line 2818 "pikchr.c"
yymsp[-3].minor.yy79 = yylhsminor.yy79;
break;
case 80: /* position ::= expr ON HEADING expr FROM position */
#line 712 "pikchr.y"
{yylhsminor.yy79 = pik_position_at_angle(yymsp[-5].minor.yy153,yymsp[-2].minor.yy153,yymsp[0].minor.yy79);}
#line 2824 "pikchr.c"
yymsp[-5].minor.yy79 = yylhsminor.yy79;
break;
case 81: /* position ::= expr HEADING expr FROM position */
#line 714 "pikchr.y"
{yylhsminor.yy79 = pik_position_at_angle(yymsp[-4].minor.yy153,yymsp[-2].minor.yy153,yymsp[0].minor.yy79);}
#line 2830 "pikchr.c"
yymsp[-4].minor.yy79 = yylhsminor.yy79;
break;
case 82: /* place ::= edge OF object */
#line 726 "pikchr.y"
{yylhsminor.yy79 = pik_place_of_elem(p,yymsp[0].minor.yy36,&yymsp[-2].minor.yy0);}
#line 2836 "pikchr.c"
yymsp[-2].minor.yy79 = yylhsminor.yy79;
break;
case 83: /* place2 ::= object */
#line 727 "pikchr.y"
{yylhsminor.yy79 = pik_place_of_elem(p,yymsp[0].minor.yy36,0);}
#line 2842 "pikchr.c"
yymsp[0].minor.yy79 = yylhsminor.yy79;
break;
case 84: /* place2 ::= object DOT_E edge */
#line 728 "pikchr.y"
{yylhsminor.yy79 = pik_place_of_elem(p,yymsp[-2].minor.yy36,&yymsp[0].minor.yy0);}
#line 2848 "pikchr.c"
yymsp[-2].minor.yy79 = yylhsminor.yy79;
break;
case 85: /* place2 ::= NTH VERTEX OF object */
#line 729 "pikchr.y"
{yylhsminor.yy79 = pik_nth_vertex(p,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,yymsp[0].minor.yy36);}
#line 2854 "pikchr.c"
yymsp[-3].minor.yy79 = yylhsminor.yy79;
break;
case 86: /* object ::= nth */
#line 741 "pikchr.y"
{yylhsminor.yy36 = pik_find_nth(p,0,&yymsp[0].minor.yy0);}
#line 2860 "pikchr.c"
yymsp[0].minor.yy36 = yylhsminor.yy36;
break;
case 87: /* object ::= nth OF|IN object */
#line 742 "pikchr.y"
{yylhsminor.yy36 = pik_find_nth(p,yymsp[0].minor.yy36,&yymsp[-2].minor.yy0);}
#line 2866 "pikchr.c"
yymsp[-2].minor.yy36 = yylhsminor.yy36;
break;
case 88: /* objectname ::= THIS */
#line 744 "pikchr.y"
{yymsp[0].minor.yy36 = p->cur;}
#line 2872 "pikchr.c"
break;
case 89: /* objectname ::= PLACENAME */
#line 745 "pikchr.y"
{yylhsminor.yy36 = pik_find_byname(p,0,&yymsp[0].minor.yy0);}
#line 2877 "pikchr.c"
yymsp[0].minor.yy36 = yylhsminor.yy36;
break;
case 90: /* objectname ::= objectname DOT_U PLACENAME */
#line 747 "pikchr.y"
{yylhsminor.yy36 = pik_find_byname(p,yymsp[-2].minor.yy36,&yymsp[0].minor.yy0);}
#line 2883 "pikchr.c"
yymsp[-2].minor.yy36 = yylhsminor.yy36;
break;
case 91: /* nth ::= NTH CLASSNAME */
#line 749 "pikchr.y"
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-1].minor.yy0); }
#line 2889 "pikchr.c"
yymsp[-1].minor.yy0 = yylhsminor.yy0;
break;
case 92: /* nth ::= NTH LAST CLASSNAME */
#line 750 "pikchr.y"
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-2].minor.yy0); }
#line 2895 "pikchr.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0;
break;
case 93: /* nth ::= LAST CLASSNAME */
#line 751 "pikchr.y"
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.eCode = -1;}
#line 2901 "pikchr.c"
break;
case 94: /* nth ::= LAST */
#line 752 "pikchr.y"
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -1;}
#line 2906 "pikchr.c"
yymsp[0].minor.yy0 = yylhsminor.yy0;
break;
case 95: /* nth ::= NTH LB RB */
#line 753 "pikchr.y"
{yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-2].minor.yy0);}
#line 2912 "pikchr.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0;
break;
case 96: /* nth ::= NTH LAST LB RB */
#line 754 "pikchr.y"
{yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-3].minor.yy0);}
#line 2918 "pikchr.c"
yymsp[-3].minor.yy0 = yylhsminor.yy0;
break;
case 97: /* nth ::= LAST LB RB */
#line 755 "pikchr.y"
{yymsp[-2].minor.yy0=yymsp[-1].minor.yy0; yymsp[-2].minor.yy0.eCode = -1; }
#line 2924 "pikchr.c"
break;
case 98: /* expr ::= expr PLUS expr */
#line 757 "pikchr.y"
{yylhsminor.yy153=yymsp[-2].minor.yy153+yymsp[0].minor.yy153;}
#line 2929 "pikchr.c"
yymsp[-2].minor.yy153 = yylhsminor.yy153;
break;
case 99: /* expr ::= expr MINUS expr */
#line 758 "pikchr.y"
{yylhsminor.yy153=yymsp[-2].minor.yy153-yymsp[0].minor.yy153;}
#line 2935 "pikchr.c"
yymsp[-2].minor.yy153 = yylhsminor.yy153;
break;
case 100: /* expr ::= expr STAR expr */
#line 759 "pikchr.y"
{yylhsminor.yy153=yymsp[-2].minor.yy153*yymsp[0].minor.yy153;}
#line 2941 "pikchr.c"
yymsp[-2].minor.yy153 = yylhsminor.yy153;
break;
case 101: /* expr ::= expr SLASH expr */
#line 760 "pikchr.y"
{
if( yymsp[0].minor.yy153==0.0 ){ pik_error(p, &yymsp[-1].minor.yy0, "division by zero"); yylhsminor.yy153 = 0.0; }
else{ yylhsminor.yy153 = yymsp[-2].minor.yy153/yymsp[0].minor.yy153; }
}
#line 2950 "pikchr.c"
yymsp[-2].minor.yy153 = yylhsminor.yy153;
break;
case 102: /* expr ::= MINUS expr */
#line 764 "pikchr.y"
{yymsp[-1].minor.yy153=-yymsp[0].minor.yy153;}
#line 2956 "pikchr.c"
break;
case 103: /* expr ::= PLUS expr */
#line 765 "pikchr.y"
{yymsp[-1].minor.yy153=yymsp[0].minor.yy153;}
#line 2961 "pikchr.c"
break;
case 104: /* expr ::= LP expr RP */
#line 766 "pikchr.y"
{yymsp[-2].minor.yy153=yymsp[-1].minor.yy153;}
#line 2966 "pikchr.c"
break;
case 105: /* expr ::= LP FILL|COLOR|THICKNESS RP */
#line 767 "pikchr.y"
{yymsp[-2].minor.yy153=pik_get_var(p,&yymsp[-1].minor.yy0);}
#line 2971 "pikchr.c"
break;
case 106: /* expr ::= NUMBER */
#line 768 "pikchr.y"
{yylhsminor.yy153=pik_atof(&yymsp[0].minor.yy0);}
#line 2976 "pikchr.c"
yymsp[0].minor.yy153 = yylhsminor.yy153;
break;
case 107: /* expr ::= ID */
#line 769 "pikchr.y"
{yylhsminor.yy153=pik_get_var(p,&yymsp[0].minor.yy0);}
#line 2982 "pikchr.c"
yymsp[0].minor.yy153 = yylhsminor.yy153;
break;
case 108: /* expr ::= FUNC1 LP expr RP */
#line 770 "pikchr.y"
{yylhsminor.yy153 = pik_func(p,&yymsp[-3].minor.yy0,yymsp[-1].minor.yy153,0.0);}
#line 2988 "pikchr.c"
yymsp[-3].minor.yy153 = yylhsminor.yy153;
break;
case 109: /* expr ::= FUNC2 LP expr COMMA expr RP */
#line 771 "pikchr.y"
{yylhsminor.yy153 = pik_func(p,&yymsp[-5].minor.yy0,yymsp[-3].minor.yy153,yymsp[-1].minor.yy153);}
#line 2994 "pikchr.c"
yymsp[-5].minor.yy153 = yylhsminor.yy153;
break;
case 110: /* expr ::= DIST LP position COMMA position RP */
#line 772 "pikchr.y"
{yymsp[-5].minor.yy153 = pik_dist(&yymsp[-3].minor.yy79,&yymsp[-1].minor.yy79);}
#line 3000 "pikchr.c"
break;
case 111: /* expr ::= place2 DOT_XY X */
#line 773 "pikchr.y"
{yylhsminor.yy153 = yymsp[-2].minor.yy79.x;}
#line 3005 "pikchr.c"
yymsp[-2].minor.yy153 = yylhsminor.yy153;
break;
case 112: /* expr ::= place2 DOT_XY Y */
#line 774 "pikchr.y"
{yylhsminor.yy153 = yymsp[-2].minor.yy79.y;}
#line 3011 "pikchr.c"
yymsp[-2].minor.yy153 = yylhsminor.yy153;
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 775 "pikchr.y"
{yylhsminor.yy153=pik_property_of(yymsp[-2].minor.yy36,&yymsp[0].minor.yy0);}
#line 3019 "pikchr.c"
yymsp[-2].minor.yy153 = yylhsminor.yy153;
break;
default:
/* (116) lvalue ::= ID */ yytestcase(yyruleno==116);
/* (117) lvalue ::= FILL */ yytestcase(yyruleno==117);
/* (118) lvalue ::= COLOR */ yytestcase(yyruleno==118);
/* (119) lvalue ::= THICKNESS */ yytestcase(yyruleno==119);
|
| ︙ | ︙ | |||
3147 3148 3149 3150 3151 3152 3153 |
if( TOKEN.z && TOKEN.z[0] ){
pik_error(p, &TOKEN, "syntax error");
}else{
pik_error(p, 0, "syntax error");
}
UNUSED_PARAMETER(yymajor);
| | | 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 |
if( TOKEN.z && TOKEN.z[0] ){
pik_error(p, &TOKEN, "syntax error");
}else{
pik_error(p, 0, "syntax error");
}
UNUSED_PARAMETER(yymajor);
#line 3130 "pikchr.c"
/************ End %syntax_error code ******************************************/
pik_parserARG_STORE /* Suppress warning about unused %extra_argument variable */
pik_parserCTX_STORE
}
/*
** The following is executed when the parser accepts
|
| ︙ | ︙ | |||
3233 3234 3235 3236 3237 3238 3239 |
}else{
fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE);
}
}
#endif
| | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | | 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 |
}else{
fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE);
}
}
#endif
while(1){ /* Exit by "break" */
assert( yypParser->yytos>=yypParser->yystack );
assert( yyact==yypParser->yytos->stateno );
yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact);
if( yyact >= YY_MIN_REDUCE ){
unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */
#ifndef NDEBUG
assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) );
if( yyTraceFILE ){
int yysize = yyRuleInfoNRhs[yyruleno];
if( yysize ){
fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
yyTracePrompt,
yyruleno, yyRuleName[yyruleno],
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
yypParser->yytos[yysize].stateno);
}else{
fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
yyTracePrompt, yyruleno, yyRuleName[yyruleno],
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
}
}
#endif /* NDEBUG */
/* Check that the stack is large enough to grow by a single entry
** if the RHS of the rule is empty. This ensures that there is room
** enough on the stack to push the LHS value */
if( yyRuleInfoNRhs[yyruleno]==0 ){
#ifdef YYTRACKMAXSTACKDEPTH
if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
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
yypParser->yyerrcnt--;
#endif
break;
}else if( yyact==YY_ACCEPT_ACTION ){
|
| ︙ | ︙ | |||
3294 3295 3296 3297 3298 3299 3300 |
fprintf(yyTraceFILE,"%sDiscard input token %s\n",
yyTracePrompt,yyTokenName[yymajor]);
}
#endif
yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
yymajor = YYNOCODE;
}else{
| | | < | < > | | 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 |
fprintf(yyTraceFILE,"%sDiscard input token %s\n",
yyTracePrompt,yyTokenName[yymajor]);
}
#endif
yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
yymajor = YYNOCODE;
}else{
while( yypParser->yytos > yypParser->yystack ){
yyact = yy_find_reduce_action(yypParser->yytos->stateno,
YYERRORSYMBOL);
if( yyact<=YY_MAX_SHIFTREDUCE ) break;
yy_pop_parser_stack(yypParser);
}
if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
yy_parse_failed(yypParser);
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt = -1;
#endif
yymajor = YYNOCODE;
}else if( yymx!=YYERRORSYMBOL ){
|
| ︙ | ︙ | |||
3351 3352 3353 3354 3355 3356 3357 |
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt = -1;
#endif
}
break;
#endif
}
| < > | 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 |
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt = -1;
#endif
}
break;
#endif
}
}
#ifndef NDEBUG
if( yyTraceFILE ){
yyStackEntry *i;
char cDiv = '[';
fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
|
| ︙ | ︙ | |||
8127 8128 8129 8130 8131 8132 8133 | return TCL_OK; } #endif /* PIKCHR_TCL */ | | | 8121 8122 8123 8124 8125 8126 8127 8128 | return TCL_OK; } #endif /* PIKCHR_TCL */ #line 8153 "pikchr.c" |
Changes to extsrc/pikchr.js.
| ︙ | ︙ | |||
114 115 116 117 118 119 120 | var wasmMemory; var ABORT = false; var EXITSTATUS; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | | | | | | | | | | | | | | | | | | | | | < | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
var wasmMemory;
var ABORT = false;
var EXITSTATUS;
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) : "";
|
| ︙ | ︙ | |||
260 261 262 263 264 265 266 |
return outIdx - startIdx;
}
function stringToUTF8(str, outPtr, maxBytesToWrite) {
return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
}
| < < < < | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
return outIdx - startIdx;
}
function stringToUTF8(str, outPtr, maxBytesToWrite) {
return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
}
var buffer, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
function updateGlobalBufferAndViews(buf) {
buffer = buf;
Module["HEAP8"] = HEAP8 = new Int8Array(buf);
Module["HEAP16"] = HEAP16 = new Int16Array(buf);
Module["HEAP32"] = HEAP32 = new Int32Array(buf);
|
| ︙ | ︙ | |||
399 400 401 402 403 404 405 |
function getBinary(file) {
try {
if (file == wasmBinaryFile && wasmBinary) {
return new Uint8Array(wasmBinary);
}
if (readBinary) {
return readBinary(file);
| < < > | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
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)) {
|
| ︙ | ︙ | |||
486 487 488 489 490 491 492 493 494 495 |
instantiateAsync().catch(readyPromiseReject);
return {};
}
var tempDouble;
var tempI64;
function callRuntimeCallbacks(callbacks) {
while (callbacks.length > 0) {
| > > > > > > | < < < < < < < < < < < < < < | | > > > < < < < | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
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;
|
| ︙ | ︙ | |||
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
case "float":
HEAPF32[ptr >> 2] = value;
break;
case "double":
HEAPF64[ptr >> 3] = 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);
}
| > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
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 writeArrayToMemory(array, buffer) {
HEAP8.set(array, buffer);
}
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 ccall(ident, returnType, argTypes, args, opts) {
var toC = {
"string": str => {
var ret = 0;
if (str !== null && str !== undefined && str !== 0) {
var len = (str.length << 2) + 1;
ret = stackAlloc(len);
stringToUTF8(str, ret, len);
}
return ret;
},
"array": arr => {
var ret = stackAlloc(arr.length);
writeArrayToMemory(arr, ret);
return ret;
}
};
function convertReturnValue(ret) {
if (returnType === "string") {
return UTF8ToString(ret);
}
if (returnType === "boolean") return Boolean(ret);
return ret;
}
var func = getCFunc(ident);
var cArgs = [];
var stack = 0;
if (args) {
for (var i = 0; i < args.length; i++) {
var converter = toC[argTypes[i]];
if (converter) {
if (stack === 0) stack = stackSave();
cArgs[i] = converter(args[i]);
} else {
cArgs[i] = args[i];
}
}
}
var ret = func.apply(null, cArgs);
function onDone(ret) {
if (stack !== 0) stackRestore(stack);
return convertReturnValue(ret);
}
ret = onDone(ret);
return ret;
}
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 asmLibraryArg = {
"a": ___assert_fail,
"b": _emscripten_resize_heap,
"c": _exit
};
|
| ︙ | ︙ | |||
624 625 626 627 628 629 630 |
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);
};
| < < > > < < < < < < | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 |
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;
Module["cwrap"] = cwrap;
Module["setValue"] = setValue;
Module["getValue"] = getValue;
var calledRun;
dependenciesFulfilled = function runCaller() {
if (!calledRun) run();
if (!calledRun) dependenciesFulfilled = runCaller;
};
function run(args) {
args = args || arguments_;
|
| ︙ | ︙ | |||
679 680 681 682 683 684 685 |
doRun();
}, 1);
} else {
doRun();
}
}
| < < < < < < < < < < < < < < < < | 689 690 691 692 693 694 695 696 697 698 699 700 701 702 |
doRun();
}, 1);
} else {
doRun();
}
}
if (Module["preInit"]) {
if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ];
while (Module["preInit"].length > 0) {
Module["preInit"].pop()();
}
}
|
| ︙ | ︙ |
Changes to extsrc/pikchr.wasm.
cannot compute difference between binary files
Changes to extsrc/shell.c.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 61 62 63 64 | ** Determine if we are dealing with WinRT, which provides only a subset of ** the full Win32 API. */ #if !defined(SQLITE_OS_WINRT) # define SQLITE_OS_WINRT 0 #endif /* ** Warning pragmas copied from msvc.h in the core. */ #if defined(_MSC_VER) #pragma warning(disable : 4054) #pragma warning(disable : 4055) #pragma warning(disable : 4100) | > > > > > > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | ** Determine if we are dealing with WinRT, which provides only a subset of ** the full Win32 API. */ #if !defined(SQLITE_OS_WINRT) # define SQLITE_OS_WINRT 0 #endif /* ** If SQLITE_SHELL_FIDDLE is defined then the shell is modified ** somewhat for use as a WASM module in a web browser. This flag ** should only be used when building the "fiddle" web application, as ** the browser-mode build has much different user input requirements ** and this build mode rewires the user input subsystem to account for ** that. */ /* ** Warning pragmas copied from msvc.h in the core. */ #if defined(_MSC_VER) #pragma warning(disable : 4054) #pragma warning(disable : 4055) #pragma warning(disable : 4100) |
| ︙ | ︙ | |||
89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #ifndef SQLITE_DISABLE_LFS # define _LARGE_FILE 1 # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 # endif # define _LARGEFILE_SOURCE 1 #endif #include <stdlib.h> #include <string.h> #include <stdio.h> #include <assert.h> #include "sqlite3.h" typedef sqlite3_int64 i64; | > > > > > > > > | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | #ifndef SQLITE_DISABLE_LFS # define _LARGE_FILE 1 # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 # endif # define _LARGEFILE_SOURCE 1 #endif #if defined(SQLITE_SHELL_FIDDLE) && !defined(_POSIX_SOURCE) /* ** emcc requires _POSIX_SOURCE (or one of several similar defines) ** to expose strdup(). */ # define _POSIX_SOURCE #endif #include <stdlib.h> #include <string.h> #include <stdio.h> #include <assert.h> #include "sqlite3.h" typedef sqlite3_int64 i64; |
| ︙ | ︙ | |||
243 244 245 246 247 248 249 | _setmode(_fileno(file), _O_TEXT); } #else # define setBinaryMode(X,Y) # define setTextMode(X,Y) #endif | | | | | | | < < < | > | < | > > > > | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
_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;
/* A version of strcmp() that works with NULL values */
static int cli_strcmp(const char *a, const char *b){
if( a==0 ) a = "";
if( b==0 ) b = "";
return strcmp(a,b);
}
static int cli_strncmp(const char *a, const char *b, size_t n){
if( a==0 ) a = "";
if( b==0 ) b = "";
return strncmp(a,b,n);
}
/* Return the current wall-clock time */
static sqlite3_int64 timeOfDay(void){
static sqlite3_vfs *clockVfs = 0;
sqlite3_int64 t;
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
if( clockVfs==0 ) return 0; /* Never actually happens */
|
| ︙ | ︙ | |||
688 689 690 691 692 693 694 |
}
#if defined(_WIN32) || defined(WIN32)
/* For interactive input on Windows systems, translate the
** multi-byte characterset characters into UTF-8. */
if( stdin_is_interactive && in==stdin ){
char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
if( zTrans ){
| | | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 |
}
#if defined(_WIN32) || defined(WIN32)
/* For interactive input on Windows systems, translate the
** multi-byte characterset characters into UTF-8. */
if( stdin_is_interactive && in==stdin ){
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);
}
|
| ︙ | ︙ | |||
715 716 717 718 719 720 721 | ** If zPrior is not NULL then it is a buffer from a prior call to this ** routine that can be reused. ** ** The result is stored in space obtained from malloc() and must either ** be freed by the caller or else passed back into this routine via the ** zPrior argument for reuse. */ | | | | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 |
** If zPrior is not NULL then it is a buffer from a prior call to this
** routine that can be reused.
**
** The result is stored in space obtained from malloc() and must either
** be freed by the caller or else passed back into this routine via the
** zPrior argument for reuse.
*/
#ifndef SQLITE_SHELL_FIDDLE
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
char *zPrompt;
char *zResult;
if( in!=0 ){
zResult = local_getline(zPrior, in);
}else{
zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if SHELL_USE_LOCAL_GETLINE
printf("%s", zPrompt);
fflush(stdout);
zResult = local_getline(zPrior, stdin);
#else
free(zPrior);
zResult = shell_readline(zPrompt);
if( zResult && *zResult ) shell_add_history(zResult);
#endif
}
return zResult;
}
#endif /* !SQLITE_SHELL_FIDDLE */
/*
** Return the value of a hexadecimal digit. Return -1 if the input
** is not a hex digit.
*/
static int hexDigitValue(char c){
if( c>='0' && c<='9' ) return c - '0';
|
| ︙ | ︙ | |||
824 825 826 827 828 829 830 |
** added to zIn, and the result returned in memory obtained from malloc().
** zIn, if it was not NULL, is freed.
**
** If the third argument, quote, is not '\0', then it is used as a
** quote character for zAppend.
*/
static void appendText(ShellText *p, const char *zAppend, char quote){
| | | | | 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 |
** added to zIn, and the result returned in memory obtained from malloc().
** zIn, if it was not NULL, is freed.
**
** If the third argument, quote, is not '\0', then it is used as a
** quote character for zAppend.
*/
static void appendText(ShellText *p, const char *zAppend, char quote){
i64 len;
i64 i;
i64 nAppend = strlen30(zAppend);
len = nAppend+p->n+1;
if( quote ){
len += 2;
for(i=0; i<nAppend; i++){
if( zAppend[i]==quote ) len++;
}
|
| ︙ | ︙ | |||
985 986 987 988 989 990 991 | }; int i = 0; const char *zIn = (const char*)sqlite3_value_text(apVal[0]); const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); const char *zName = (const char*)sqlite3_value_text(apVal[2]); sqlite3 *db = sqlite3_context_db_handle(pCtx); UNUSED_PARAMETER(nVal); | | | | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 |
};
int i = 0;
const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
const char *zName = (const char*)sqlite3_value_text(apVal[2]);
sqlite3 *db = sqlite3_context_db_handle(pCtx);
UNUSED_PARAMETER(nVal);
if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){
for(i=0; i<ArraySize(aPrefix); i++){
int n = strlen30(aPrefix[i]);
if( cli_strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
char *z = 0;
char *zFake = 0;
if( zSchema ){
char cQuote = quoteChar(zSchema);
if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
}else{
|
| ︙ | ︙ | |||
3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 | */ #define re_match sqlite3re_match #define re_compile sqlite3re_compile #define re_free sqlite3re_free /* The end-of-input character */ #define RE_EOF 0 /* End of input */ /* The NFA is implemented as sequence of opcodes taken from the following ** set. Each opcode has a single integer argument. */ #define RE_OP_MATCH 1 /* Match the one character in the argument */ #define RE_OP_ANY 2 /* Match any one character. (Implements ".") */ #define RE_OP_ANYSTAR 3 /* Special optimized version of .* */ | > | 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 | */ #define re_match sqlite3re_match #define re_compile sqlite3re_compile #define re_free sqlite3re_free /* The end-of-input character */ #define RE_EOF 0 /* End of input */ #define RE_START 0xfffffff /* Start of input - larger than an UTF-8 */ /* The NFA is implemented as sequence of opcodes taken from the following ** set. Each opcode has a single integer argument. */ #define RE_OP_MATCH 1 /* Match the one character in the argument */ #define RE_OP_ANY 2 /* Match any one character. (Implements ".") */ #define RE_OP_ANYSTAR 3 /* Special optimized version of .* */ |
| ︙ | ︙ | |||
3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 | #define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */ #define RE_OP_NOTWORD 12 /* Not a perl word character */ #define RE_OP_DIGIT 13 /* digit: [0-9] */ #define RE_OP_NOTDIGIT 14 /* Not a digit */ #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ #define RE_OP_NOTSPACE 16 /* Not a digit */ #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ /* Each opcode is a "state" in the NFA */ typedef unsigned short ReStateNumber; /* Because this is an NFA and not a DFA, multiple states can be active at ** once. An instance of the following object records all active states in ** the NFA. The implementation is optimized for the common case where the | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 |
#define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */
#define RE_OP_NOTWORD 12 /* Not a perl word character */
#define RE_OP_DIGIT 13 /* digit: [0-9] */
#define RE_OP_NOTDIGIT 14 /* Not a digit */
#define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */
#define RE_OP_NOTSPACE 16 /* Not a digit */
#define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */
#define RE_OP_ATSTART 18 /* Currently at the start of the string */
#if defined(SQLITE_DEBUG)
/* Opcode names used for symbolic debugging */
static const char *ReOpName[] = {
"EOF",
"MATCH",
"ANY",
"ANYSTAR",
"FORK",
"GOTO",
"ACCEPT",
"CC_INC",
"CC_EXC",
"CC_VALUE",
"CC_RANGE",
"WORD",
"NOTWORD",
"DIGIT",
"NOTDIGIT",
"SPACE",
"NOTSPACE",
"BOUNDARY",
"ATSTART",
};
#endif /* SQLITE_DEBUG */
/* Each opcode is a "state" in the NFA */
typedef unsigned short ReStateNumber;
/* Because this is an NFA and not a DFA, multiple states can be active at
** once. An instance of the following object records all active states in
** the NFA. The implementation is optimized for the common case where the
|
| ︙ | ︙ | |||
3847 3848 3849 3850 3851 3852 3853 |
struct ReCompiled {
ReInput sIn; /* Regular expression text */
const char *zErr; /* Error message to return */
char *aOp; /* Operators for the virtual machine */
int *aArg; /* Arguments to each operator */
unsigned (*xNextChar)(ReInput*); /* Next character function */
unsigned char zInit[12]; /* Initial text to match */
| | | 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 |
struct ReCompiled {
ReInput sIn; /* Regular expression text */
const char *zErr; /* Error message to return */
char *aOp; /* Operators for the virtual machine */
int *aArg; /* Arguments to each operator */
unsigned (*xNextChar)(ReInput*); /* Next character function */
unsigned char zInit[12]; /* Initial text to match */
int nInit; /* Number of bytes in zInit */
unsigned nState; /* Number of entries in aOp[] and aArg[] */
unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
};
/* Add a state to the given state set if it is not already there */
static void re_add_state(ReStateSet *pSet, int newState){
unsigned i;
|
| ︙ | ︙ | |||
3920 3921 3922 3923 3924 3925 3926 |
*/
static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
ReStateSet aStateSet[2], *pThis, *pNext;
ReStateNumber aSpace[100];
ReStateNumber *pToFree;
unsigned int i = 0;
unsigned int iSwap = 0;
| | > | 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 |
*/
static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
ReStateSet aStateSet[2], *pThis, *pNext;
ReStateNumber aSpace[100];
ReStateNumber *pToFree;
unsigned int i = 0;
unsigned int iSwap = 0;
int c = RE_START;
int cPrev = 0;
int rc = 0;
ReInput in;
in.z = zIn;
in.i = 0;
in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn);
/* Look for the initial prefix match, if there is one. */
if( pRe->nInit ){
unsigned char x = pRe->zInit[0];
while( in.i+pRe->nInit<=in.mx
&& (zIn[in.i]!=x ||
strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
){
in.i++;
}
if( in.i+pRe->nInit>in.mx ) return 0;
c = RE_START-1;
}
if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
pToFree = 0;
aStateSet[0].aState = aSpace;
}else{
pToFree = sqlite3_malloc64( sizeof(ReStateNumber)*2*pRe->nState );
|
| ︙ | ︙ | |||
3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 |
pNext->nState = 0;
for(i=0; i<pThis->nState; i++){
int x = pThis->aState[i];
switch( pRe->aOp[x] ){
case RE_OP_MATCH: {
if( pRe->aArg[x]==c ) re_add_state(pNext, x+1);
break;
}
case RE_OP_ANY: {
if( c!=0 ) re_add_state(pNext, x+1);
break;
}
case RE_OP_WORD: {
if( re_word_char(c) ) re_add_state(pNext, x+1);
| > > > > | 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 |
pNext->nState = 0;
for(i=0; i<pThis->nState; i++){
int x = pThis->aState[i];
switch( pRe->aOp[x] ){
case RE_OP_MATCH: {
if( pRe->aArg[x]==c ) re_add_state(pNext, x+1);
break;
}
case RE_OP_ATSTART: {
if( cPrev==RE_START ) re_add_state(pThis, x+1);
break;
}
case RE_OP_ANY: {
if( c!=0 ) re_add_state(pNext, x+1);
break;
}
case RE_OP_WORD: {
if( re_word_char(c) ) re_add_state(pNext, x+1);
|
| ︙ | ︙ | |||
4048 4049 4050 4051 4052 4053 4054 |
if( hit ) re_add_state(pNext, x+n);
break;
}
}
}
}
for(i=0; i<pNext->nState; i++){
| > > | | 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 |
if( hit ) re_add_state(pNext, x+n);
break;
}
}
}
}
for(i=0; i<pNext->nState; i++){
int x = pNext->aState[i];
while( pRe->aOp[x]==RE_OP_GOTO ) x += pRe->aArg[x];
if( pRe->aOp[x]==RE_OP_ACCEPT ){ rc = 1; break; }
}
re_match_end:
sqlite3_free(pToFree);
return rc;
}
/* Resize the opcode and argument arrays for an RE under construction.
|
| ︙ | ︙ | |||
4203 4204 4205 4206 4207 4208 4209 |
int iStart;
unsigned c;
const char *zErr;
while( (c = p->xNextChar(&p->sIn))!=0 ){
iStart = p->nState;
switch( c ){
case '|':
| < | 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 |
int iStart;
unsigned c;
const char *zErr;
while( (c = p->xNextChar(&p->sIn))!=0 ){
iStart = p->nState;
switch( c ){
case '|':
case ')': {
p->sIn.i--;
return 0;
}
case '(': {
zErr = re_subcompile_re(p);
if( zErr ) return zErr;
|
| ︙ | ︙ | |||
4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 |
re_append(p, RE_OP_FORK, iPrev - p->nState);
break;
}
case '?': {
if( iPrev<0 ) return "'?' without operand";
re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1);
break;
}
case '{': {
int m = 0, n = 0;
int sz, j;
if( iPrev<0 ) return "'{m,n}' without operand";
while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; }
n = m;
if( c==',' ){
p->sIn.i++;
n = 0;
while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; }
}
if( c!='}' ) return "unmatched '{'";
if( n>0 && n<m ) return "n less than m in '{m,n}'";
p->sIn.i++;
sz = p->nState - iPrev;
if( m==0 ){
if( n==0 ) return "both m and n are zero in '{m,n}'";
re_insert(p, iPrev, RE_OP_FORK, sz+1);
n--;
}else{
for(j=1; j<m; j++) re_copy(p, iPrev, sz);
}
for(j=m; j<n; j++){
re_append(p, RE_OP_FORK, sz+1);
re_copy(p, iPrev, sz);
| > > > > > > > > > | 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 |
re_append(p, RE_OP_FORK, iPrev - p->nState);
break;
}
case '?': {
if( iPrev<0 ) return "'?' without operand";
re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1);
break;
}
case '$': {
re_append(p, RE_OP_MATCH, RE_EOF);
break;
}
case '^': {
re_append(p, RE_OP_ATSTART, 0);
break;
}
case '{': {
int m = 0, n = 0;
int sz, j;
if( iPrev<0 ) return "'{m,n}' without operand";
while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; }
n = m;
if( c==',' ){
p->sIn.i++;
n = 0;
while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; }
}
if( c!='}' ) return "unmatched '{'";
if( n>0 && n<m ) return "n less than m in '{m,n}'";
p->sIn.i++;
sz = p->nState - iPrev;
if( m==0 ){
if( n==0 ) return "both m and n are zero in '{m,n}'";
re_insert(p, iPrev, RE_OP_FORK, sz+1);
iPrev++;
n--;
}else{
for(j=1; j<m; j++) re_copy(p, iPrev, sz);
}
for(j=m; j<n; j++){
re_append(p, RE_OP_FORK, sz+1);
re_copy(p, iPrev, sz);
|
| ︙ | ︙ | |||
4376 4377 4378 4379 4380 4381 4382 |
pRe->sIn.i = 0;
pRe->sIn.mx = (int)strlen(zIn);
zErr = re_subcompile_re(pRe);
if( zErr ){
re_free(pRe);
return zErr;
}
| < < < < | | 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 |
pRe->sIn.i = 0;
pRe->sIn.mx = (int)strlen(zIn);
zErr = re_subcompile_re(pRe);
if( zErr ){
re_free(pRe);
return zErr;
}
if( pRe->sIn.i>=pRe->sIn.mx ){
re_append(pRe, RE_OP_ACCEPT, 0);
*ppRe = pRe;
}else{
re_free(pRe);
return "unrecognized character";
}
|
| ︙ | ︙ | |||
4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 |
if( zStr!=0 ){
sqlite3_result_int(context, re_match(pRe, zStr, -1));
}
if( setAux ){
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
}
}
/*
** Invoke this routine to register the regexp() function with the
** SQLite database connection.
*/
#ifdef _WIN32
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 |
if( zStr!=0 ){
sqlite3_result_int(context, re_match(pRe, zStr, -1));
}
if( setAux ){
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
}
}
#if defined(SQLITE_DEBUG)
/*
** This function is used for testing and debugging only. It is only available
** if the SQLITE_DEBUG compile-time option is used.
**
** Compile a regular expression and then convert the compiled expression into
** text and return that text.
*/
static void re_bytecode_func(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zPattern;
const char *zErr;
ReCompiled *pRe;
sqlite3_str *pStr;
int i;
int n;
char *z;
zPattern = (const char*)sqlite3_value_text(argv[0]);
if( zPattern==0 ) return;
zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0);
if( zErr ){
re_free(pRe);
sqlite3_result_error(context, zErr, -1);
return;
}
if( pRe==0 ){
sqlite3_result_error_nomem(context);
return;
}
pStr = sqlite3_str_new(0);
if( pStr==0 ) goto re_bytecode_func_err;
if( pRe->nInit>0 ){
sqlite3_str_appendf(pStr, "INIT ");
for(i=0; i<pRe->nInit; i++){
sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]);
}
sqlite3_str_appendf(pStr, "\n");
}
for(i=0; (unsigned)i<pRe->nState; i++){
sqlite3_str_appendf(pStr, "%-8s %4d\n",
ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]);
}
n = sqlite3_str_length(pStr);
z = sqlite3_str_finish(pStr);
if( n==0 ){
sqlite3_free(z);
}else{
sqlite3_result_text(context, z, n-1, sqlite3_free);
}
re_bytecode_func_err:
re_free(pRe);
}
#endif /* SQLITE_DEBUG */
/*
** Invoke this routine to register the regexp() function with the
** SQLite database connection.
*/
#ifdef _WIN32
|
| ︙ | ︙ | |||
4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 |
0, re_sql_func, 0, 0);
if( rc==SQLITE_OK ){
/* The regexpi(PATTERN,STRING) function is a case-insensitive version
** of regexp(PATTERN,STRING). */
rc = sqlite3_create_function(db, "regexpi", 2,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
(void*)db, re_sql_func, 0, 0);
}
return rc;
}
/************************* End ../ext/misc/regexp.c ********************/
| > > > > > > > | | 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 |
0, re_sql_func, 0, 0);
if( rc==SQLITE_OK ){
/* The regexpi(PATTERN,STRING) function is a case-insensitive version
** of regexp(PATTERN,STRING). */
rc = sqlite3_create_function(db, "regexpi", 2,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
(void*)db, re_sql_func, 0, 0);
#if defined(SQLITE_DEBUG)
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "regexp_bytecode", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
0, re_bytecode_func, 0, 0);
}
#endif /* SQLITE_DEBUG */
}
return rc;
}
/************************* End ../ext/misc/regexp.c ********************/
#ifndef SQLITE_SHELL_FIDDLE
/************************* Begin ../ext/misc/fileio.c ******************/
/*
** 2014-06-13
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
|
| ︙ | ︙ | |||
10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 |
/*
** Return true if zId must be quoted in order to use it as an SQL
** identifier, or false otherwise.
*/
static int idxIdentifierRequiresQuotes(const char *zId){
int i;
for(i=0; zId[i]; i++){
if( !(zId[i]=='_')
&& !(zId[i]>='0' && zId[i]<='9')
&& !(zId[i]>='a' && zId[i]<='z')
&& !(zId[i]>='A' && zId[i]<='Z')
){
return 1;
| > > > > | 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 |
/*
** Return true if zId must be quoted in order to use it as an SQL
** identifier, or false otherwise.
*/
static int idxIdentifierRequiresQuotes(const char *zId){
int i;
int nId = STRLEN(zId);
if( sqlite3_keyword_check(zId, nId) ) return 1;
for(i=0; zId[i]; i++){
if( !(zId[i]=='_')
&& !(zId[i]>='0' && zId[i]<='9')
&& !(zId[i]>='a' && zId[i]<='z')
&& !(zId[i]>='A' && zId[i]<='Z')
){
return 1;
|
| ︙ | ︙ | |||
12246 12247 12248 12249 12250 12251 12252 |
*pAuxDb; /* Currently active database connection */
int *aiIndent; /* Array of indents used in MODE_Explain */
int nIndent; /* Size of array aiIndent[] */
int iIndent; /* Index of current op in aiIndent[] */
char *zNonce; /* Nonce for temporary safe-mode excapes */
EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */
ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
| | > | | 12375 12376 12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 |
*pAuxDb; /* Currently active database connection */
int *aiIndent; /* Array of indents used in MODE_Explain */
int nIndent; /* Size of array aiIndent[] */
int iIndent; /* Index of current op in aiIndent[] */
char *zNonce; /* Nonce for temporary safe-mode excapes */
EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */
ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
#ifdef SQLITE_SHELL_FIDDLE
struct {
const char * zInput; /* Input string from wasm/JS proxy */
const char * zPos; /* Cursor pos into zInput */
const char * zDefaultDbName; /* Default name for db file */
} wasm;
#endif
};
#ifdef SQLITE_SHELL_FIDDLE
static ShellState shellState;
#endif
/* Allowed values for ShellState.autoEQP
*/
#define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */
|
| ︙ | ︙ | |||
12586 12587 12588 12589 12590 12591 12592 |
}
/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/
static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
int i;
| > | > > | | > > > > > > > > > | > | 12716 12717 12718 12719 12720 12721 12722 12723 12724 12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737 12738 12739 12740 12741 12742 12743 12744 12745 12746 |
}
/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/
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);
for(i=0; i<nBlob; i++){
static const char aHex[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
zStr[i*2] = aHex[ (aBlob[i] >> 4) ];
zStr[i*2+1] = aHex[ (aBlob[i] & 0x0F) ];
}
zStr[i*2] = '\0';
raw_printf(out,"X'%s'", zStr);
sqlite3_free(zStr);
}
/*
** Find a string that is not found anywhere in z[]. Return a pointer
** to that string.
**
** Try to use zA and zB first. If both of those are already found in z[]
|
| ︙ | ︙ | |||
12749 12750 12751 12752 12753 12754 12755 |
}
fputc('"', out);
}
/*
** Output the given string as a quoted according to JSON quoting rules.
*/
| | | | 12892 12893 12894 12895 12896 12897 12898 12899 12900 12901 12902 12903 12904 12905 12906 12907 12908 |
}
fputc('"', out);
}
/*
** Output the given string as a quoted according to JSON quoting rules.
*/
static void output_json_string(FILE *out, const char *z, i64 n){
unsigned int c;
if( n<0 ) n = strlen(z);
fputc('"', out);
while( n-- ){
c = *(z++);
if( c=='\\' || c=='"' ){
fputc('\\', out);
fputc(c, out);
}else if( c<=0x1f ){
|
| ︙ | ︙ | |||
12922 12923 12924 12925 12926 12927 12928 |
"zipfile_cds",
};
UNUSED_PARAMETER(zA2);
UNUSED_PARAMETER(zA3);
UNUSED_PARAMETER(zA4);
switch( op ){
case SQLITE_ATTACH: {
| | | 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 |
"zipfile_cds",
};
UNUSED_PARAMETER(zA2);
UNUSED_PARAMETER(zA3);
UNUSED_PARAMETER(zA4);
switch( op ){
case SQLITE_ATTACH: {
#ifndef SQLITE_SHELL_FIDDLE
/* In WASM builds the filesystem is a virtual sandbox, so
** there's no harm in using ATTACH. */
failIfSafeMode(p, "cannot run ATTACH in safe mode");
#endif
break;
}
case SQLITE_FUNCTION: {
|
| ︙ | ︙ | |||
12995 12996 12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 13008 13009 13010 13011 13012 13013 13014 13015 13016 13017 |
#endif
/*
** Print a schema statement. Part of MODE_Semi and MODE_Pretty output.
**
** This routine converts some CREATE TABLE statements for shadow tables
** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
*/
static void printSchemaLine(FILE *out, const char *z, const char *zTail){
if( z==0 ) return;
if( zTail==0 ) return;
if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
}else{
utf8_printf(out, "%s%s", z, zTail);
}
}
static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
char c = z[n];
z[n] = 0;
printSchemaLine(out, z, zTail);
z[n] = c;
}
| > > > > > > > > > > > > > > > > > > > > > > | 13138 13139 13140 13141 13142 13143 13144 13145 13146 13147 13148 13149 13150 13151 13152 13153 13154 13155 13156 13157 13158 13159 13160 13161 13162 13163 13164 13165 13166 13167 13168 13169 13170 13171 13172 13173 13174 13175 13176 13177 13178 13179 13180 13181 13182 |
#endif
/*
** Print a schema statement. Part of MODE_Semi and MODE_Pretty output.
**
** This routine converts some CREATE TABLE statements for shadow tables
** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
**
** 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(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;
static const char *azTerm[] = { "", "*/", "\n" };
int i;
for(i=0; i<ArraySize(azTerm); i++){
char *zNew = sqlite3_mprintf("%s%s;", zOrig, azTerm[i]);
if( sqlite3_complete(zNew) ){
size_t n = strlen(zNew);
zNew[n-1] = 0;
zToFree = zNew;
z = zNew;
break;
}
sqlite3_free(zNew);
}
}
if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
}else{
utf8_printf(out, "%s%s", z, zTail);
}
sqlite3_free(zToFree);
}
static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
char c = z[n];
z[n] = 0;
printSchemaLine(out, z, zTail);
z[n] = c;
}
|
| ︙ | ︙ | |||
13032 13033 13034 13035 13036 13037 13038 |
}
/*
** Add a new entry to the EXPLAIN QUERY PLAN data
*/
static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
EQPGraphRow *pNew;
| > > | | 13197 13198 13199 13200 13201 13202 13203 13204 13205 13206 13207 13208 13209 13210 13211 13212 13213 |
}
/*
** Add a new entry to the EXPLAIN QUERY PLAN data
*/
static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
EQPGraphRow *pNew;
i64 nText;
if( zText==0 ) return;
nText = strlen(zText);
if( p->autoEQPtest ){
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;
|
| ︙ | ︙ | |||
13077 13078 13079 13080 13081 13082 13083 |
}
/* Render a single level of the graph that has iEqpId as its parent. Called
** recursively to render sublevels.
*/
static void eqp_render_level(ShellState *p, int iEqpId){
EQPGraphRow *pRow, *pNext;
| | | | 13244 13245 13246 13247 13248 13249 13250 13251 13252 13253 13254 13255 13256 13257 13258 13259 13260 13261 13262 13263 13264 13265 |
}
/* Render a single level of the graph that has iEqpId as its parent. Called
** recursively to render sublevels.
*/
static void eqp_render_level(ShellState *p, int iEqpId){
EQPGraphRow *pRow, *pNext;
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;
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;
}
}
}
|
| ︙ | ︙ | |||
13800 13801 13802 13803 13804 13805 13806 |
{ "read_bytes: ", "Bytes read from storage:" },
{ "write_bytes: ", "Bytes written to storage:" },
{ "cancelled_write_bytes: ", "Cancelled write bytes:" },
};
int i;
for(i=0; i<ArraySize(aTrans); i++){
int n = strlen30(aTrans[i].zPattern);
| | | 13967 13968 13969 13970 13971 13972 13973 13974 13975 13976 13977 13978 13979 13980 13981 |
{ "read_bytes: ", "Bytes read from storage:" },
{ "write_bytes: ", "Bytes written to storage:" },
{ "cancelled_write_bytes: ", "Cancelled write bytes:" },
};
int i;
for(i=0; i<ArraySize(aTrans); i++){
int n = strlen30(aTrans[i].zPattern);
if( cli_strncmp(aTrans[i].zPattern, z, n)==0 ){
utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
break;
}
}
}
fclose(in);
}
|
| ︙ | ︙ | |||
14039 14040 14041 14042 14043 14044 14045 |
** points to a single nul-terminated string. Return non-zero if zStr
** is equal, according to strcmp(), to any of the strings in the array.
** Otherwise, return zero.
*/
static int str_in_array(const char *zStr, const char **azArray){
int i;
for(i=0; azArray[i]; i++){
| | | 14206 14207 14208 14209 14210 14211 14212 14213 14214 14215 14216 14217 14218 14219 14220 |
** points to a single nul-terminated string. Return non-zero if zStr
** is equal, according to strcmp(), to any of the strings in the array.
** Otherwise, return zero.
*/
static int str_in_array(const char *zStr, const char **azArray){
int i;
for(i=0; azArray[i]; i++){
if( 0==cli_strcmp(zStr, azArray[i]) ) return 1;
}
return 0;
}
/*
** If compiled statement pSql appears to be an EXPLAIN statement, allocate
** and populate the ShellState.aiIndent[] array with the number of
|
| ︙ | ︙ | |||
14114 14115 14116 14117 14118 14119 14120 |
if( iOp==0 ){
/* Do further verfication that this is explain output. Abort if
** it is not */
static const char *explainCols[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
int jj;
for(jj=0; jj<ArraySize(explainCols); jj++){
| | | 14281 14282 14283 14284 14285 14286 14287 14288 14289 14290 14291 14292 14293 14294 14295 |
if( iOp==0 ){
/* Do further verfication that this is explain output. Abort if
** it is not */
static const char *explainCols[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
int jj;
for(jj=0; jj<ArraySize(explainCols); jj++){
if( cli_strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
p->cMode = p->mode;
sqlite3_reset(pSql);
return;
}
}
}
nAlloc += 100;
|
| ︙ | ︙ | |||
14838 14839 14840 14841 14842 14843 14844 |
memset(&pState->expert, 0, sizeof(ExpertInfo));
for(i=1; rc==SQLITE_OK && i<nArg; i++){
char *z = azArg[i];
int n;
if( z[0]=='-' && z[1]=='-' ) z++;
n = strlen30(z);
| | | | 15005 15006 15007 15008 15009 15010 15011 15012 15013 15014 15015 15016 15017 15018 15019 15020 15021 15022 |
memset(&pState->expert, 0, sizeof(ExpertInfo));
for(i=1; rc==SQLITE_OK && i<nArg; i++){
char *z = azArg[i];
int n;
if( z[0]=='-' && z[1]=='-' ) z++;
n = strlen30(z);
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) ){
raw_printf(stderr, "option requires an argument: %s\n", z);
rc = SQLITE_ERROR;
}else{
iSample = (int)integerValue(azArg[++i]);
if( iSample<0 || iSample>100 ){
raw_printf(stderr, "value out of range: %s\n", azArg[i]);
|
| ︙ | ︙ | |||
15189 15190 15191 15192 15193 15194 15195 15196 15197 15198 | int noSys; UNUSED_PARAMETER(azNotUsed); if( nArg!=3 || azArg==0 ) return 0; zTable = azArg[0]; zType = azArg[1]; zSql = azArg[2]; dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0; noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0; | > > | | | | | 15356 15357 15358 15359 15360 15361 15362 15363 15364 15365 15366 15367 15368 15369 15370 15371 15372 15373 15374 15375 15376 15377 15378 15379 15380 15381 15382 15383 15384 15385 15386 15387 15388 15389 15390 15391 15392 15393 15394 15395 15396 15397 15398 15399 15400 15401 |
int noSys;
UNUSED_PARAMETER(azNotUsed);
if( nArg!=3 || azArg==0 ) return 0;
zTable = azArg[0];
zType = azArg[1];
zSql = azArg[2];
if( zTable==0 ) return 0;
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 ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
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 ){
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);
utf8_printf(p->out, "%s\n", zIns);
sqlite3_free(zIns);
return 0;
}else{
printSchemaLine(p->out, zSql, ";\n");
}
if( cli_strcmp(zType, "table")==0 ){
ShellText sSelect;
ShellText sTable;
char **azCol;
int i;
char *savedDestTable;
int savedMode;
|
| ︙ | ︙ | |||
15336 15337 15338 15339 15340 15341 15342 |
** with ".". Subsequent lines are supplemental information.
**
** There must be two or more spaces between the end of the command and the
** start of the description of what that command does.
*/
static const char *(azHelp[]) = {
#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) \
| | | 15505 15506 15507 15508 15509 15510 15511 15512 15513 15514 15515 15516 15517 15518 15519 |
** with ".". Subsequent lines are supplemental information.
**
** There must be two or more spaces between the end of the command and the
** start of the description of what that command does.
*/
static const char *(azHelp[]) = {
#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) \
&& !defined(SQLITE_SHELL_FIDDLE)
".archive ... Manage SQL archives",
" Each command must have exactly one of the following options:",
" -c, --create Create a new archive",
" -u, --update Add or update files with changed mtime",
" -i, --insert Like -u but always add even if unchanged",
" -r, --remove Remove files from archive",
" -t, --list List contents of archive",
|
| ︙ | ︙ | |||
15362 15363 15364 15365 15366 15367 15368 | " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE", " See also:", " http://sqlite.org/cli.html#sqlite_archive_support", #endif #ifndef SQLITE_OMIT_AUTHORIZATION ".auth ON|OFF Show authorizer callbacks", #endif | | | | | 15531 15532 15533 15534 15535 15536 15537 15538 15539 15540 15541 15542 15543 15544 15545 15546 15547 15548 15549 15550 15551 15552 15553 15554 15555 15556 15557 | " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE", " See also:", " http://sqlite.org/cli.html#sqlite_archive_support", #endif #ifndef SQLITE_OMIT_AUTHORIZATION ".auth ON|OFF Show authorizer callbacks", #endif #ifndef SQLITE_SHELL_FIDDLE ".backup ?DB? FILE Backup DB (default \"main\") to FILE", " Options:", " --append Use the appendvfs", " --async Write to FILE without journal and fsync()", #endif ".bail on|off Stop after hitting an error. Default OFF", ".binary on|off Turn binary output on or off. Default OFF", #ifndef SQLITE_SHELL_FIDDLE ".cd DIRECTORY Change the working directory to DIRECTORY", #endif ".changes on|off Show number of rows changed by SQL", #ifndef SQLITE_SHELL_FIDDLE ".check GLOB Fail if output since .testcase does not match", ".clone NEWDB Clone data into NEWDB from the existing database", #endif ".connection [close] [#] Open or close an auxiliary database connection", ".databases List names and files of attached databases", ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) |
| ︙ | ︙ | |||
15400 15401 15402 15403 15404 15405 15406 | ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN", " Other Modes:", #ifdef SQLITE_DEBUG " test Show raw EXPLAIN QUERY PLAN output", " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"", #endif " trigger Like \"full\" but also show trigger bytecode", | | | | | 15569 15570 15571 15572 15573 15574 15575 15576 15577 15578 15579 15580 15581 15582 15583 15584 15585 15586 15587 15588 15589 15590 15591 15592 15593 15594 15595 15596 15597 15598 | ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN", " Other Modes:", #ifdef SQLITE_DEBUG " test Show raw EXPLAIN QUERY PLAN output", " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"", #endif " trigger Like \"full\" but also show trigger bytecode", #ifndef SQLITE_SHELL_FIDDLE ".excel Display the output of next command in spreadsheet", " --bom Put a UTF8 byte-order mark on intermediate file", #endif #ifndef SQLITE_SHELL_FIDDLE ".exit ?CODE? Exit this program with return-code CODE", #endif ".expert EXPERIMENTAL. Suggest indexes for queries", ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto", ".filectrl CMD ... Run various sqlite3_file_control() operations", " --schema SCHEMA Use SCHEMA instead of \"main\"", " --help Show CMD details", ".fullschema ?--indent? Show schema and the content of sqlite_stat tables", ".headers on|off Turn display of headers on or off", ".help ?-all? ?PATTERN? Show help text for PATTERN", #ifndef SQLITE_SHELL_FIDDLE ".import FILE TABLE Import data from FILE into TABLE", " Options:", " --ascii Use \\037 and \\036 as column and row separators", " --csv Use , and \\n as column and row separators", " --skip N Skip the first N rows of input", " --schema S Target table to be S.TABLE", " -v \"Verbose\" - increase auxiliary output", |
| ︙ | ︙ | |||
15444 15445 15446 15447 15448 15449 15450 | #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.", " Options:", " fkey-indexes Find missing foreign key indexes", | | | | | | | 15613 15614 15615 15616 15617 15618 15619 15620 15621 15622 15623 15624 15625 15626 15627 15628 15629 15630 15631 15632 15633 15634 15635 15636 15637 15638 15639 15640 15641 15642 15643 15644 15645 15646 15647 15648 15649 15650 15651 15652 15653 15654 15655 15656 15657 15658 15659 15660 15661 | #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.", " Options:", " fkey-indexes Find missing foreign key indexes", #if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE) ".load FILE ?ENTRY? Load an extension library", #endif #ifndef SQLITE_SHELL_FIDDLE ".log FILE|off Turn logging on or off. FILE can be stderr/stdout", #endif ".mode MODE ?OPTIONS? Set output mode", " MODE is one of:", " ascii Columns/rows delimited by 0x1F and 0x1E", " box Tables using unicode box-drawing characters", " csv Comma-separated values", " column Output in columns. (See .width)", " html HTML <table> code", " insert SQL insert statements for TABLE", " json Results in a JSON array", " line One value per line", " list Values delimited by \"|\"", " markdown Markdown table format", " qbox Shorthand for \"box --wrap 60 --quote\"", " quote Escape answers as for SQL", " table ASCII-art table", " tabs Tab-separated values", " tcl TCL list elements", " OPTIONS: (for columnar modes or insert mode):", " --wrap N Wrap output lines to no longer than N characters", " --wordwrap B Wrap or not at word boundaries per B (on/off)", " --ww Shorthand for \"--wordwrap 1\"", " --quote Quote output text as SQL literals", " --noquote Do not quote output text", " TABLE The name of SQL table used for \"insert\" mode", #ifndef SQLITE_SHELL_FIDDLE ".nonce STRING Suspend safe mode for one command if nonce matches", #endif ".nullvalue STRING Use STRING in place of NULL values", #ifndef SQLITE_SHELL_FIDDLE ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE", " If FILE begins with '|' then open as a pipe", " --bom Put a UTF8 byte-order mark at the beginning", " -e Send output to the system text editor", " -x Send output as CSV to a spreadsheet (same as \".excel\")", /* Note that .open is (partially) available in WASM builds but is ** currently only intended to be used by the fiddle tool, not |
| ︙ | ︙ | |||
15500 15501 15502 15503 15504 15505 15506 | " --hexdb Load the output of \"dbtotxt\" as an in-memory db", " --maxsize N Maximum size for --hexdb or --deserialized database", #endif " --new Initialize FILE to an empty database", " --nofollow Do not follow symbolic links", " --readonly Open FILE readonly", " --zip FILE is a ZIP archive", | | | 15669 15670 15671 15672 15673 15674 15675 15676 15677 15678 15679 15680 15681 15682 15683 | " --hexdb Load the output of \"dbtotxt\" as an in-memory db", " --maxsize N Maximum size for --hexdb or --deserialized database", #endif " --new Initialize FILE to an empty database", " --nofollow Do not follow symbolic links", " --readonly Open FILE readonly", " --zip FILE is a ZIP archive", #ifndef SQLITE_SHELL_FIDDLE ".output ?FILE? Send output to FILE or stdout if FILE is omitted", " If FILE begins with '|' then open it as a pipe.", " Options:", " --bom Prefix output with a UTF8 byte-order mark", " -e Send output to the system text editor", " -x Send output as CSV to a spreadsheet", #endif |
| ︙ | ︙ | |||
15524 15525 15526 15527 15528 15529 15530 | ".progress N Invoke progress handler after every N opcodes", " --limit N Interrupt after N progress callbacks", " --once Do no more than one progress interrupt", " --quiet|-q No output except at interrupts", " --reset Reset the count for each input and interrupt", #endif ".prompt MAIN CONTINUE Replace the standard prompts", | | | | 15693 15694 15695 15696 15697 15698 15699 15700 15701 15702 15703 15704 15705 15706 15707 15708 15709 15710 15711 15712 15713 15714 15715 15716 15717 15718 15719 15720 | ".progress N Invoke progress handler after every N opcodes", " --limit N Interrupt after N progress callbacks", " --once Do no more than one progress interrupt", " --quiet|-q No output except at interrupts", " --reset Reset the count for each input and interrupt", #endif ".prompt MAIN CONTINUE Replace the standard prompts", #ifndef SQLITE_SHELL_FIDDLE ".quit Exit this program", ".read FILE Read input from FILE or command output", " If FILE begins with \"|\", it is a command that generates the input.", #endif #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) ".recover Recover as much data as possible from corrupt db.", " --freelist-corrupt Assume the freelist is corrupt", " --recovery-db NAME Store recovery metadata in database file NAME", " --lost-and-found TABLE Alternative name for the lost-and-found table", " --no-rowids Do not attempt to recover rowid values", " that are not also INTEGER PRIMARY KEYs", #endif #ifndef SQLITE_SHELL_FIDDLE ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE", ".save ?OPTIONS? FILE Write database to FILE (an alias for .backup ...)", #endif ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off", ".schema ?PATTERN? Show the CREATE statements matching PATTERN", " Options:", " --indent Try to pretty-print the schema", |
| ︙ | ︙ | |||
15574 15575 15576 15577 15578 15579 15580 | " Options:", " --schema Also hash the sqlite_schema table", " --sha3-224 Use the sha3-224 algorithm", " --sha3-256 Use the sha3-256 algorithm (default)", " --sha3-384 Use the sha3-384 algorithm", " --sha3-512 Use the sha3-512 algorithm", " Any other argument is a LIKE pattern for tables to hash", | | | | | 15743 15744 15745 15746 15747 15748 15749 15750 15751 15752 15753 15754 15755 15756 15757 15758 15759 15760 15761 15762 15763 15764 15765 15766 15767 15768 15769 15770 | " Options:", " --schema Also hash the sqlite_schema table", " --sha3-224 Use the sha3-224 algorithm", " --sha3-256 Use the sha3-256 algorithm (default)", " --sha3-384 Use the sha3-384 algorithm", " --sha3-512 Use the sha3-512 algorithm", " Any other argument is a LIKE pattern for tables to hash", #if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) ".shell CMD ARGS... Run CMD ARGS... in a system shell", #endif ".show Show the current values for various settings", ".stats ?ARG? Show stats or turn stats on or off", " off Turn off automatic stat display", " on Turn on automatic stat display", " stmt Show statement stats", " vmstep Show the virtual machine step count only", #if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) ".system CMD ARGS... Run CMD ARGS... in a system shell", #endif ".tables ?TABLE? List names of tables matching LIKE pattern TABLE", #ifndef SQLITE_SHELL_FIDDLE ".testcase NAME Begin redirecting output to 'testcase-out.txt'", #endif ".testctrl CMD ... Run various sqlite3_test_control() operations", " Run \".testctrl\" with no arguments for details", ".timeout MS Try opening locked tables for MS milliseconds", ".timer on|off Turn SQL timer on or off", #ifndef SQLITE_OMIT_TRACE |
| ︙ | ︙ | |||
15637 15638 15639 15640 15641 15642 15643 |
static int showHelp(FILE *out, const char *zPattern){
int i = 0;
int j = 0;
int n = 0;
char *zPat;
if( zPattern==0
|| zPattern[0]=='0'
| | | | | 15806 15807 15808 15809 15810 15811 15812 15813 15814 15815 15816 15817 15818 15819 15820 15821 15822 |
static int showHelp(FILE *out, const char *zPattern){
int i = 0;
int j = 0;
int n = 0;
char *zPat;
if( zPattern==0
|| zPattern[0]=='0'
|| cli_strcmp(zPattern,"-a")==0
|| cli_strcmp(zPattern,"-all")==0
|| cli_strcmp(zPattern,"--all")==0
){
/* Show all commands, but only one line per command */
if( zPattern==0 ) zPattern = "";
for(i=0; i<ArraySize(azHelp); i++){
if( azHelp[i][0]=='.' || zPattern[0] ){
utf8_printf(out, "%s\n", azHelp[i]);
n++;
|
| ︙ | ︙ | |||
15876 15877 15878 15879 15880 15881 15882 |
}
for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
rc = sscanf(zLine, "| page %d offset %d", &j, &k);
if( rc==2 ){
iOffset = k;
continue;
}
| | | 16045 16046 16047 16048 16049 16050 16051 16052 16053 16054 16055 16056 16057 16058 16059 |
}
for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
rc = sscanf(zLine, "| page %d offset %d", &j, &k);
if( rc==2 ){
iOffset = k;
continue;
}
if( cli_strncmp(zLine, "| end ", 6)==0 ){
break;
}
rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
&j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
&x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
if( rc==17 ){
k = iOffset+j;
|
| ︙ | ︙ | |||
15904 15905 15906 15907 15908 15909 15910 |
readHexDb_error:
if( in!=p->in ){
fclose(in);
}else{
while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
nLine++;
| | | 16073 16074 16075 16076 16077 16078 16079 16080 16081 16082 16083 16084 16085 16086 16087 |
readHexDb_error:
if( in!=p->in ){
fclose(in);
}else{
while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
nLine++;
if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
}
p->lineno = nLine;
}
sqlite3_free(a);
utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine);
return 0;
}
|
| ︙ | ︙ | |||
15996 15997 15998 15999 16000 16001 16002 |
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zText = (const char*)sqlite3_value_text(argv[0]);
UNUSED_PARAMETER(argc);
if( zText && zText[0]=='\'' ){
| | | | | | | | | 16165 16166 16167 16168 16169 16170 16171 16172 16173 16174 16175 16176 16177 16178 16179 16180 16181 16182 16183 16184 16185 16186 16187 16188 16189 16190 16191 16192 16193 16194 16195 16196 16197 16198 16199 16200 |
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zText = (const char*)sqlite3_value_text(argv[0]);
UNUSED_PARAMETER(argc);
if( zText && zText[0]=='\'' ){
i64 nText = sqlite3_value_bytes(argv[0]);
i64 i;
char zBuf1[20];
char zBuf2[20];
const char *zNL = 0;
const char *zCR = 0;
i64 nCR = 0;
i64 nNL = 0;
for(i=0; zText[i]; i++){
if( zNL==0 && zText[i]=='\n' ){
zNL = unused_string(zText, "\\n", "\\012", zBuf1);
nNL = strlen(zNL);
}
if( zCR==0 && zText[i]=='\r' ){
zCR = unused_string(zText, "\\r", "\\015", zBuf2);
nCR = strlen(zCR);
}
}
if( zNL || zCR ){
i64 iOut = 0;
i64 nMax = (nNL > nCR) ? nNL : nCR;
i64 nAlloc = nMax * nText + (nMax+64)*2;
char *zOut = (char*)sqlite3_malloc64(nAlloc);
if( zOut==0 ){
sqlite3_result_error_nomem(context);
return;
}
|
| ︙ | ︙ | |||
16140 16141 16142 16143 16144 16145 16146 |
#endif
sqlite3_shathree_init(p->db, 0, 0);
sqlite3_uint_init(p->db, 0, 0);
sqlite3_decimal_init(p->db, 0, 0);
sqlite3_regexp_init(p->db, 0, 0);
sqlite3_ieee_init(p->db, 0, 0);
sqlite3_series_init(p->db, 0, 0);
| | | 16309 16310 16311 16312 16313 16314 16315 16316 16317 16318 16319 16320 16321 16322 16323 |
#endif
sqlite3_shathree_init(p->db, 0, 0);
sqlite3_uint_init(p->db, 0, 0);
sqlite3_decimal_init(p->db, 0, 0);
sqlite3_regexp_init(p->db, 0, 0);
sqlite3_ieee_init(p->db, 0, 0);
sqlite3_series_init(p->db, 0, 0);
#ifndef SQLITE_SHELL_FIDDLE
sqlite3_fileio_init(p->db, 0, 0);
sqlite3_completion_init(p->db, 0, 0);
#endif
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
sqlite3_dbdata_init(p->db, 0, 0);
#endif
#ifdef SQLITE_HAVE_ZLIB
|
| ︙ | ︙ | |||
16258 16259 16260 16261 16262 16263 16264 |
}
#elif HAVE_LINENOISE
/*
** Linenoise completion callback
*/
static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
| | | | 16427 16428 16429 16430 16431 16432 16433 16434 16435 16436 16437 16438 16439 16440 16441 16442 |
}
#elif HAVE_LINENOISE
/*
** Linenoise completion callback
*/
static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
i64 nLine = strlen(zLine);
i64 i, iStart;
sqlite3_stmt *pStmt = 0;
char *zSql;
char zBuf[1000];
if( nLine>sizeof(zBuf)-30 ) return;
if( zLine[0]=='.' || zLine[0]=='#') return;
for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
|
| ︙ | ︙ | |||
16397 16398 16399 16400 16401 16402 16403 |
/*
** Try to open an output file. The names "stdout" and "stderr" are
** recognized and do the right thing. NULL is returned if the output
** filename is "off".
*/
static FILE *output_file_open(const char *zFile, int bTextMode){
FILE *f;
| | | | | 16566 16567 16568 16569 16570 16571 16572 16573 16574 16575 16576 16577 16578 16579 16580 16581 16582 16583 16584 |
/*
** Try to open an output file. The names "stdout" and "stderr" are
** recognized and do the right thing. NULL is returned if the output
** filename is "off".
*/
static FILE *output_file_open(const char *zFile, int bTextMode){
FILE *f;
if( cli_strcmp(zFile,"stdout")==0 ){
f = stdout;
}else if( cli_strcmp(zFile, "stderr")==0 ){
f = stderr;
}else if( cli_strcmp(zFile, "off")==0 ){
f = 0;
}else{
f = fopen(zFile, bTextMode ? "w" : "wb");
if( f==0 ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
}
}
|
| ︙ | ︙ | |||
16425 16426 16427 16428 16429 16430 16431 |
void *pArg, /* The ShellState pointer */
void *pP, /* Usually a pointer to sqlite_stmt */
void *pX /* Auxiliary output */
){
ShellState *p = (ShellState*)pArg;
sqlite3_stmt *pStmt;
const char *zSql;
| | | 16594 16595 16596 16597 16598 16599 16600 16601 16602 16603 16604 16605 16606 16607 16608 |
void *pArg, /* The ShellState pointer */
void *pP, /* Usually a pointer to sqlite_stmt */
void *pX /* Auxiliary output */
){
ShellState *p = (ShellState*)pArg;
sqlite3_stmt *pStmt;
const char *zSql;
i64 nSql;
if( p->traceOut==0 ) return 0;
if( mType==SQLITE_TRACE_CLOSE ){
utf8_printf(p->traceOut, "-- closing database connection\n");
return 0;
}
if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){
zSql = (const char*)pX;
|
| ︙ | ︙ | |||
16453 16454 16455 16456 16457 16458 16459 |
default: {
zSql = sqlite3_sql(pStmt);
break;
}
}
}
if( zSql==0 ) return 0;
| | > | | | 16622 16623 16624 16625 16626 16627 16628 16629 16630 16631 16632 16633 16634 16635 16636 16637 16638 16639 16640 16641 16642 16643 16644 16645 16646 16647 |
default: {
zSql = sqlite3_sql(pStmt);
break;
}
}
}
if( zSql==0 ) return 0;
nSql = strlen(zSql);
if( nSql>1000000000 ) nSql = 1000000000;
while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
switch( mType ){
case SQLITE_TRACE_ROW:
case SQLITE_TRACE_STMT: {
utf8_printf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
break;
}
case SQLITE_TRACE_PROFILE: {
sqlite3_int64 nNanosec = *(sqlite3_int64*)pX;
utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
break;
}
}
return 0;
}
#endif
|
| ︙ | ︙ | |||
17012 17013 17014 17015 17016 17017 17018 |
if( val==3 ) raw_printf(p->out, " (utf16be)");
}
}
raw_printf(p->out, "\n");
}
if( zDb==0 ){
zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
| | | 17182 17183 17184 17185 17186 17187 17188 17189 17190 17191 17192 17193 17194 17195 17196 |
if( val==3 ) raw_printf(p->out, " (utf16be)");
}
}
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");
}else{
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
}
for(i=0; i<ArraySize(aQuery); i++){
char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
int val = db_int(p->db, zSql);
|
| ︙ | ︙ | |||
17146 17147 17148 17149 17150 17151 17152 |
** Compare the string as a command-line option with either one or two
** initial "-" characters.
*/
static int optionMatch(const char *zStr, const char *zOpt){
if( zStr[0]!='-' ) return 0;
zStr++;
if( zStr[0]=='-' ) zStr++;
| | | 17316 17317 17318 17319 17320 17321 17322 17323 17324 17325 17326 17327 17328 17329 17330 |
** Compare the string as a command-line option with either one or two
** initial "-" characters.
*/
static int optionMatch(const char *zStr, const char *zOpt){
if( zStr[0]!='-' ) return 0;
zStr++;
if( zStr[0]=='-' ) zStr++;
return cli_strcmp(zStr, zOpt)==0;
}
/*
** Delete a file.
*/
int shellDeleteFile(const char *zFilename){
int rc;
|
| ︙ | ︙ | |||
19252 19253 19254 19255 19256 19257 19258 | */ if( nArg==0 ) return 0; /* no tokens, no error */ n = strlen30(azArg[0]); c = azArg[0][0]; clearTempFile(p); #ifndef SQLITE_OMIT_AUTHORIZATION | | | | | | | | | | 19422 19423 19424 19425 19426 19427 19428 19429 19430 19431 19432 19433 19434 19435 19436 19437 19438 19439 19440 19441 19442 19443 19444 19445 19446 19447 19448 19449 19450 19451 19452 19453 19454 19455 19456 19457 19458 19459 19460 19461 19462 19463 19464 19465 19466 19467 19468 19469 19470 19471 19472 19473 19474 19475 19476 19477 19478 19479 19480 19481 |
*/
if( nArg==0 ) return 0; /* no tokens, no error */
n = strlen30(azArg[0]);
c = azArg[0][0];
clearTempFile(p);
#ifndef SQLITE_OMIT_AUTHORIZATION
if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
if( nArg!=2 ){
raw_printf(stderr, "Usage: .auth ON|OFF\n");
rc = 1;
goto meta_command_exit;
}
open_db(p, 0);
if( booleanValue(azArg[1]) ){
sqlite3_set_authorizer(p->db, shellAuth, p);
}else if( p->bSafeModePersist ){
sqlite3_set_authorizer(p->db, safeModeAuth, p);
}else{
sqlite3_set_authorizer(p->db, 0, 0);
}
}else
#endif
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) \
&& !defined(SQLITE_SHELL_FIDDLE)
if( c=='a' && cli_strncmp(azArg[0], "archive", n)==0 ){
open_db(p, 0);
failIfSafeMode(p, "cannot run .archive in safe mode");
rc = arDotCommand(p, 0, azArg, nArg);
}else
#endif
#ifndef SQLITE_SHELL_FIDDLE
if( (c=='b' && n>=3 && cli_strncmp(azArg[0], "backup", n)==0)
|| (c=='s' && n>=3 && cli_strncmp(azArg[0], "save", n)==0)
){
const char *zDestFile = 0;
const char *zDb = 0;
sqlite3 *pDest;
sqlite3_backup *pBackup;
int j;
int bAsync = 0;
const char *zVfs = 0;
failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
for(j=1; j<nArg; j++){
const char *z = azArg[j];
if( z[0]=='-' ){
if( z[1]=='-' ) z++;
if( cli_strcmp(z, "-append")==0 ){
zVfs = "apndvfs";
}else
if( cli_strcmp(z, "-async")==0 ){
bAsync = 1;
}else
{
utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
return 1;
}
}else if( zDestFile==0 ){
|
| ︙ | ︙ | |||
19347 19348 19349 19350 19351 19352 19353 |
rc = 0;
}else{
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
rc = 1;
}
close_db(pDest);
}else
| | | | | | | | | | | | | | | | | 19517 19518 19519 19520 19521 19522 19523 19524 19525 19526 19527 19528 19529 19530 19531 19532 19533 19534 19535 19536 19537 19538 19539 19540 19541 19542 19543 19544 19545 19546 19547 19548 19549 19550 19551 19552 19553 19554 19555 19556 19557 19558 19559 19560 19561 19562 19563 19564 19565 19566 19567 19568 19569 19570 19571 19572 19573 19574 19575 19576 19577 19578 19579 19580 19581 19582 19583 19584 19585 19586 19587 19588 19589 19590 19591 19592 19593 19594 19595 19596 19597 19598 19599 19600 19601 19602 19603 19604 19605 19606 19607 19608 19609 19610 19611 19612 19613 19614 19615 19616 19617 19618 19619 19620 19621 19622 19623 19624 19625 19626 19627 19628 19629 19630 19631 19632 |
rc = 0;
}else{
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
rc = 1;
}
close_db(pDest);
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
if( c=='b' && n>=3 && cli_strncmp(azArg[0], "bail", n)==0 ){
if( nArg==2 ){
bail_on_error = booleanValue(azArg[1]);
}else{
raw_printf(stderr, "Usage: .bail on|off\n");
rc = 1;
}
}else
if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
if( nArg==2 ){
if( booleanValue(azArg[1]) ){
setBinaryMode(p->out, 1);
}else{
setTextMode(p->out, 1);
}
}else{
raw_printf(stderr, "Usage: .binary on|off\n");
rc = 1;
}
}else
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
if( c=='b' && n>=3 && cli_strncmp(azArg[0], "breakpoint", n)==0 ){
test_breakpoint();
}else
#ifndef SQLITE_SHELL_FIDDLE
if( c=='c' && cli_strcmp(azArg[0],"cd")==0 ){
failIfSafeMode(p, "cannot run .cd in safe mode");
if( nArg==2 ){
#if defined(_WIN32) || defined(WIN32)
wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
rc = !SetCurrentDirectoryW(z);
sqlite3_free(z);
#else
rc = chdir(azArg[1]);
#endif
if( rc ){
utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
rc = 1;
}
}else{
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{
raw_printf(stderr, "Usage: .changes on|off\n");
rc = 1;
}
}else
#ifndef SQLITE_SHELL_FIDDLE
/* Cancel output redirection, if it is currently set (by .testcase)
** Then read the content of the testcase-out.txt file and compare against
** azArg[1]. If there are differences, report an error and exit.
*/
if( c=='c' && n>=3 && cli_strncmp(azArg[0], "check", n)==0 ){
char *zRes = 0;
output_reset(p);
if( nArg!=2 ){
raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
rc = 2;
}else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
rc = 2;
}else if( testcase_glob(azArg[1],zRes)==0 ){
utf8_printf(stderr,
"testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
p->zTestcase, azArg[1], zRes);
rc = 1;
}else{
utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
p->nCheck++;
}
sqlite3_free(zRes);
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
#ifndef SQLITE_SHELL_FIDDLE
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{
raw_printf(stderr, "Usage: .clone FILENAME\n");
rc = 1;
}
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
if( c=='c' && cli_strncmp(azArg[0], "connection", n)==0 ){
if( nArg==1 ){
/* List available connections */
int i;
for(i=0; i<ArraySize(p->aAuxDb); i++){
const char *zFile = p->aAuxDb[i].zDbFilename;
if( p->aAuxDb[i].db==0 && p->pAuxDb!=&p->aAuxDb[i] ){
zFile = "(not open)";
|
| ︙ | ︙ | |||
19475 19476 19477 19478 19479 19480 19481 |
int i = azArg[1][0] - '0';
if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && i<ArraySize(p->aAuxDb) ){
p->pAuxDb->db = p->db;
p->pAuxDb = &p->aAuxDb[i];
globalDb = p->db = p->pAuxDb->db;
p->pAuxDb->db = 0;
}
| | | | 19645 19646 19647 19648 19649 19650 19651 19652 19653 19654 19655 19656 19657 19658 19659 19660 19661 19662 19663 19664 19665 19666 19667 19668 19669 19670 19671 19672 19673 19674 19675 19676 19677 19678 |
int i = azArg[1][0] - '0';
if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && i<ArraySize(p->aAuxDb) ){
p->pAuxDb->db = p->db;
p->pAuxDb = &p->aAuxDb[i];
globalDb = p->db = p->pAuxDb->db;
p->pAuxDb->db = 0;
}
}else if( nArg==3 && cli_strcmp(azArg[1], "close")==0
&& 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] ){
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{
raw_printf(stderr, "Usage: .connection [close] [CONNECTION-NUMBER]\n");
rc = 1;
}
}else
if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
char **azName = 0;
int nName = 0;
sqlite3_stmt *pStmt;
int i;
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ){
|
| ︙ | ︙ | |||
19533 19534 19535 19536 19537 19538 19539 |
eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
free(azName[i*2]);
free(azName[i*2+1]);
}
sqlite3_free(azName);
}else
| | | 19703 19704 19705 19706 19707 19708 19709 19710 19711 19712 19713 19714 19715 19716 19717 |
eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn");
free(azName[i*2]);
free(azName[i*2+1]);
}
sqlite3_free(azName);
}else
if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbconfig", n)==0 ){
static const struct DbConfigChoices {
const char *zName;
int op;
} aDbConfig[] = {
{ "defensive", SQLITE_DBCONFIG_DEFENSIVE },
{ "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
{ "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
|
| ︙ | ︙ | |||
19558 19559 19560 19561 19562 19563 19564 |
{ "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
{ "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA },
{ "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
};
int ii, v;
open_db(p, 0);
for(ii=0; ii<ArraySize(aDbConfig); ii++){
| | | | | | | | | | 19728 19729 19730 19731 19732 19733 19734 19735 19736 19737 19738 19739 19740 19741 19742 19743 19744 19745 19746 19747 19748 19749 19750 19751 19752 19753 19754 19755 19756 19757 19758 19759 19760 19761 19762 19763 19764 19765 19766 19767 19768 19769 19770 19771 19772 19773 19774 19775 19776 19777 19778 19779 19780 19781 19782 19783 19784 19785 19786 19787 19788 19789 19790 19791 19792 19793 19794 19795 19796 19797 |
{ "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
{ "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA },
{ "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
};
int ii, v;
open_db(p, 0);
for(ii=0; ii<ArraySize(aDbConfig); ii++){
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);
utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
if( nArg>1 ) break;
}
if( nArg>1 && ii==ArraySize(aDbConfig) ){
utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]);
utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n");
}
}else
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){
rc = shell_dbinfo_command(p, nArg, azArg);
}else
if( c=='r' && cli_strncmp(azArg[0], "recover", n)==0 ){
open_db(p, 0);
rc = recoverDatabaseCmd(p, nArg, azArg);
}else
#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){
char *zLike = 0;
char *zSql;
int i;
int savedShowHeader = p->showHeader;
int savedShellFlags = p->shellFlgs;
ShellClearFlag(p,
SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo
|SHFLG_DumpDataOnly|SHFLG_DumpNoSys);
for(i=1; i<nArg; i++){
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
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);
#endif
}else
if( cli_strcmp(z,"newlines")==0 ){
ShellSetFlag(p, SHFLG_Newlines);
}else
if( cli_strcmp(z,"data-only")==0 ){
ShellSetFlag(p, SHFLG_DumpDataOnly);
}else
if( cli_strcmp(z,"nosys")==0 ){
ShellSetFlag(p, SHFLG_DumpNoSys);
}else
{
raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
rc = 1;
sqlite3_free(zLike);
goto meta_command_exit;
|
| ︙ | ︙ | |||
19695 19696 19697 19698 19699 19700 19701 |
if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
}
p->showHeader = savedShowHeader;
p->shellFlgs = savedShellFlags;
}else
| | | | | | | | | | | | | | 19865 19866 19867 19868 19869 19870 19871 19872 19873 19874 19875 19876 19877 19878 19879 19880 19881 19882 19883 19884 19885 19886 19887 19888 19889 19890 19891 19892 19893 19894 19895 19896 19897 19898 19899 19900 19901 19902 19903 19904 19905 19906 19907 19908 19909 19910 19911 19912 19913 19914 19915 19916 19917 19918 19919 19920 19921 19922 19923 19924 19925 19926 19927 19928 19929 19930 19931 19932 19933 19934 19935 19936 19937 19938 19939 19940 19941 19942 19943 19944 19945 19946 19947 19948 19949 19950 19951 19952 19953 19954 19955 19956 19957 19958 19959 19960 19961 19962 19963 19964 |
if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){
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{
raw_printf(stderr, "Usage: .echo on|off\n");
rc = 1;
}
}else
if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
if( nArg==2 ){
p->autoEQPtest = 0;
if( p->autoEQPtrace ){
if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0);
p->autoEQPtrace = 0;
}
if( cli_strcmp(azArg[1],"full")==0 ){
p->autoEQP = AUTOEQP_full;
}else if( cli_strcmp(azArg[1],"trigger")==0 ){
p->autoEQP = AUTOEQP_trigger;
#ifdef SQLITE_DEBUG
}else if( cli_strcmp(azArg[1],"test")==0 ){
p->autoEQP = AUTOEQP_on;
p->autoEQPtest = 1;
}else if( cli_strcmp(azArg[1],"trace")==0 ){
p->autoEQP = AUTOEQP_full;
p->autoEQPtrace = 1;
open_db(p, 0);
sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0);
sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0);
#endif
}else{
p->autoEQP = (u8)booleanValue(azArg[1]);
}
}else{
raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n");
rc = 1;
}
}else
#ifndef SQLITE_SHELL_FIDDLE
if( c=='e' && cli_strncmp(azArg[0], "exit", n)==0 ){
if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
rc = 2;
}else
#endif
/* The ".explain" command is automatic now. It is largely pointless. It
** retained purely for backwards compatibility */
if( c=='e' && cli_strncmp(azArg[0], "explain", n)==0 ){
int val = 1;
if( nArg>=2 ){
if( cli_strcmp(azArg[1],"auto")==0 ){
val = 99;
}else{
val = booleanValue(azArg[1]);
}
}
if( val==1 && p->mode!=MODE_Explain ){
p->normalMode = p->mode;
p->mode = MODE_Explain;
p->autoExplain = 0;
}else if( val==0 ){
if( p->mode==MODE_Explain ) p->mode = p->normalMode;
p->autoExplain = 0;
}else if( val==99 ){
if( p->mode==MODE_Explain ) p->mode = p->normalMode;
p->autoExplain = 1;
}
}else
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){
if( p->bSafeMode ){
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);
}
}else
#endif
if( c=='f' && cli_strncmp(azArg[0], "filectrl", n)==0 ){
static const struct {
const char *zCtrlName; /* Name of a test-control option */
int ctrlCode; /* Integer code for that option */
const char *zUsage; /* Usage notes */
} aCtrl[] = {
{ "chunk_size", SQLITE_FCNTL_CHUNK_SIZE, "SIZE" },
{ "data_version", SQLITE_FCNTL_DATA_VERSION, "" },
|
| ︙ | ︙ | |||
19810 19811 19812 19813 19814 19815 19816 |
const char *zCmd = 0;
const char *zSchema = 0;
open_db(p, 0);
zCmd = nArg>=2 ? azArg[1] : "help";
if( zCmd[0]=='-'
| | | | | 19980 19981 19982 19983 19984 19985 19986 19987 19988 19989 19990 19991 19992 19993 19994 19995 19996 19997 19998 19999 20000 20001 20002 20003 20004 20005 20006 20007 20008 20009 20010 20011 20012 20013 20014 20015 20016 20017 20018 20019 20020 20021 20022 20023 20024 |
const char *zCmd = 0;
const char *zSchema = 0;
open_db(p, 0);
zCmd = nArg>=2 ? azArg[1] : "help";
if( zCmd[0]=='-'
&& (cli_strcmp(zCmd,"--schema")==0 || cli_strcmp(zCmd,"-schema")==0)
&& nArg>=4
){
zSchema = azArg[2];
for(i=3; i<nArg; i++) azArg[i-2] = azArg[i];
nArg -= 2;
zCmd = azArg[1];
}
/* The argument can optionally begin with "-" or "--" */
if( zCmd[0]=='-' && zCmd[1] ){
zCmd++;
if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
}
/* --help lists all file-controls */
if( cli_strcmp(zCmd,"help")==0 ){
utf8_printf(p->out, "Available file-controls:\n");
for(i=0; i<ArraySize(aCtrl); i++){
utf8_printf(p->out, " .filectrl %s %s\n",
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
rc = 1;
goto meta_command_exit;
}
/* convert filectrl text option to value. allow any unique prefix
** of the option name, or a numerical value. */
n2 = strlen30(zCmd);
for(i=0; i<ArraySize(aCtrl); i++){
if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
if( filectrl<0 ){
filectrl = aCtrl[i].ctrlCode;
iCtrl = i;
}else{
utf8_printf(stderr, "Error: ambiguous file-control: \"%s\"\n"
"Use \".filectrl --help\" for help\n", zCmd);
rc = 1;
|
| ︙ | ︙ | |||
19927 19928 19929 19930 19931 19932 19933 |
}else if( isOk==1 ){
char zBuf[100];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
raw_printf(p->out, "%s\n", zBuf);
}
}else
| | | 20097 20098 20099 20100 20101 20102 20103 20104 20105 20106 20107 20108 20109 20110 20111 |
}else if( isOk==1 ){
char zBuf[100];
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
raw_printf(p->out, "%s\n", zBuf);
}
}else
if( c=='f' && cli_strncmp(azArg[0], "fullschema", n)==0 ){
ShellState data;
int doStats = 0;
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.cMode = data.mode = MODE_Semi;
if( nArg==2 && optionMatch(azArg[1], "indent") ){
data.cMode = data.mode = MODE_Pretty;
|
| ︙ | ︙ | |||
19974 19975 19976 19977 19978 19979 19980 |
shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
data.zDestTable = "sqlite_stat4";
shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
raw_printf(p->out, "ANALYZE sqlite_schema;\n");
}
}else
| | | | | | 20144 20145 20146 20147 20148 20149 20150 20151 20152 20153 20154 20155 20156 20157 20158 20159 20160 20161 20162 20163 20164 20165 20166 20167 20168 20169 20170 20171 20172 20173 20174 20175 20176 20177 20178 20179 20180 |
shell_exec(&data, "SELECT * FROM sqlite_stat1", 0);
data.zDestTable = "sqlite_stat4";
shell_exec(&data, "SELECT * FROM sqlite_stat4", 0);
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{
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 ){
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; /* 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 */
int nByte; /* Number of bytes in an SQL string */
int i, j; /* Loop counters */
|
| ︙ | ︙ | |||
20036 20037 20038 20039 20040 20041 20042 |
}else if( zTable==0 ){
zTable = z;
}else{
utf8_printf(p->out, "ERROR: extra argument: \"%s\". Usage:\n", z);
showHelp(p->out, "import");
goto meta_command_exit;
}
| | | | | | | 20206 20207 20208 20209 20210 20211 20212 20213 20214 20215 20216 20217 20218 20219 20220 20221 20222 20223 20224 20225 20226 20227 20228 20229 20230 20231 |
}else if( zTable==0 ){
zTable = z;
}else{
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++;
}else if( cli_strcmp(z,"-schema")==0 && i<nArg-1 ){
zSchema = azArg[++i];
}else if( cli_strcmp(z,"-skip")==0 && i<nArg-1 ){
nSkip = integerValue(azArg[++i]);
}else if( cli_strcmp(z,"-ascii")==0 ){
sCtx.cColSep = SEP_Unit[0];
sCtx.cRowSep = SEP_Record[0];
xRead = ascii_read_one_field;
useOutputMode = 0;
}else if( cli_strcmp(z,"-csv")==0 ){
sCtx.cColSep = ',';
sCtx.cRowSep = '\n';
xRead = csv_read_one_field;
useOutputMode = 0;
}else{
utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
showHelp(p->out, "import");
|
| ︙ | ︙ | |||
20087 20088 20089 20090 20091 20092 20093 |
}
nSep = strlen30(p->rowSeparator);
if( nSep==0 ){
raw_printf(stderr,
"Error: non-null row separator required for import\n");
goto meta_command_exit;
}
| | > > | 20257 20258 20259 20260 20261 20262 20263 20264 20265 20266 20267 20268 20269 20270 20271 20272 20273 |
}
nSep = strlen30(p->rowSeparator);
if( nSep==0 ){
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
){
/* When importing CSV (only), if the row separator is set to the
** default output row separator, change it to the default input
** row separator. This avoids having to maintain different input
** and output row separators. */
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
nSep = strlen30(p->rowSeparator);
}
|
| ︙ | ︙ | |||
20286 20287 20288 20289 20290 20291 20292 |
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
if( eVerbose>0 ){
utf8_printf(p->out,
"Added %d rows with %d errors using %d lines of input\n",
sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
}
}else
| | | | 20458 20459 20460 20461 20462 20463 20464 20465 20466 20467 20468 20469 20470 20471 20472 20473 20474 20475 |
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
if( eVerbose>0 ){
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
if( c=='i' && cli_strncmp(azArg[0], "imposter", n)==0 ){
char *zSql;
char *zCollist = 0;
sqlite3_stmt *pStmt;
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;
|
| ︙ | ︙ | |||
20390 20391 20392 20393 20394 20395 20396 |
rc = 1;
}
sqlite3_free(zSql);
}else
#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
#ifdef SQLITE_ENABLE_IOTRACE
| | | | | 20562 20563 20564 20565 20566 20567 20568 20569 20570 20571 20572 20573 20574 20575 20576 20577 20578 20579 20580 20581 20582 20583 20584 20585 20586 20587 20588 20589 20590 20591 20592 20593 20594 20595 20596 20597 20598 |
rc = 1;
}
sqlite3_free(zSql);
}else
#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
#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;
if( nArg<2 ){
sqlite3IoTrace = 0;
}else if( cli_strcmp(azArg[1], "-")==0 ){
sqlite3IoTrace = iotracePrintf;
iotrace = stdout;
}else{
iotrace = fopen(azArg[1], "w");
if( iotrace==0 ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
sqlite3IoTrace = 0;
rc = 1;
}else{
sqlite3IoTrace = iotracePrintf;
}
}
}else
#endif
if( c=='l' && n>=5 && cli_strncmp(azArg[0], "limits", n)==0 ){
static const struct {
const char *zLimitName; /* Name of a limit */
int limitCode; /* Integer code for that limit */
} aLimit[] = {
{ "length", SQLITE_LIMIT_LENGTH },
{ "sql_length", SQLITE_LIMIT_SQL_LENGTH },
{ "column", SQLITE_LIMIT_COLUMN },
|
| ︙ | ︙ | |||
20471 20472 20473 20474 20475 20476 20477 |
(int)integerValue(azArg[2]));
}
printf("%20s %d\n", aLimit[iLimit].zLimitName,
sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
}
}else
| | | | | | | | | | 20643 20644 20645 20646 20647 20648 20649 20650 20651 20652 20653 20654 20655 20656 20657 20658 20659 20660 20661 20662 20663 20664 20665 20666 20667 20668 20669 20670 20671 20672 20673 20674 20675 20676 20677 20678 20679 20680 20681 20682 20683 20684 20685 20686 20687 20688 20689 20690 20691 20692 20693 20694 20695 20696 20697 20698 20699 20700 20701 20702 20703 20704 20705 20706 20707 20708 20709 20710 20711 20712 20713 20714 20715 20716 20717 20718 20719 20720 |
(int)integerValue(azArg[2]));
}
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);
lintDotCommand(p, azArg, nArg);
}else
#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE)
if( c=='l' && cli_strncmp(azArg[0], "load", n)==0 ){
const char *zFile, *zProc;
char *zErrMsg = 0;
failIfSafeMode(p, "cannot run .load in safe mode");
if( nArg<2 ){
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 ){
utf8_printf(stderr, "Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}
}else
#endif
#ifndef SQLITE_SHELL_FIDDLE
if( c=='l' && cli_strncmp(azArg[0], "log", n)==0 ){
failIfSafeMode(p, "cannot run .log in safe mode");
if( nArg!=2 ){
raw_printf(stderr, "Usage: .log FILENAME\n");
rc = 1;
}else{
const char *zFile = azArg[1];
output_file_close(p->pLog);
p->pLog = output_file_open(zFile, 0);
}
}else
#endif
if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
const char *zMode = 0;
const char *zTabname = 0;
int i, n2;
ColModeOpts cmOpts = ColModeOpts_default;
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( optionMatch(z,"wrap") && i+1<nArg ){
cmOpts.iWrap = integerValue(azArg[++i]);
}else if( optionMatch(z,"ww") ){
cmOpts.bWordWrap = 1;
}else if( optionMatch(z,"wordwrap") && i+1<nArg ){
cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
}else if( optionMatch(z,"quote") ){
cmOpts.bQuote = 1;
}else if( optionMatch(z,"noquote") ){
cmOpts.bQuote = 0;
}else if( zMode==0 ){
zMode = z;
/* Apply defaults for qbox pseudo-mode. If that
* overwrites already-set values, user was informed of this.
*/
if( cli_strcmp(z, "qbox")==0 ){
ColModeOpts cmo = ColModeOpts_default_qbox;
zMode = "box";
cmOpts = cmo;
}
}else if( zTabname==0 ){
zTabname = z;
}else if( z[0]=='-' ){
|
| ︙ | ︙ | |||
20573 20574 20575 20576 20577 20578 20579 |
p->cmOpts.bQuote ? "" : "no");
}else{
raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
}
zMode = modeDescr[p->mode];
}
n2 = strlen30(zMode);
| | | | | | | | | | | | | | | | | | | | | | | | | 20745 20746 20747 20748 20749 20750 20751 20752 20753 20754 20755 20756 20757 20758 20759 20760 20761 20762 20763 20764 20765 20766 20767 20768 20769 20770 20771 20772 20773 20774 20775 20776 20777 20778 20779 20780 20781 20782 20783 20784 20785 20786 20787 20788 20789 20790 20791 20792 20793 20794 20795 20796 20797 20798 20799 20800 20801 20802 20803 20804 20805 20806 20807 20808 20809 20810 20811 20812 20813 20814 20815 20816 20817 20818 20819 20820 20821 20822 20823 20824 20825 20826 20827 20828 20829 20830 20831 20832 20833 20834 20835 20836 20837 20838 20839 20840 20841 20842 20843 20844 20845 20846 20847 20848 20849 20850 20851 20852 20853 20854 20855 20856 20857 20858 |
p->cmOpts.bQuote ? "" : "no");
}else{
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 ){
p->mode = MODE_Line;
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( cli_strncmp(zMode,"columns",n2)==0 ){
p->mode = MODE_Column;
if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
p->showHeader = 1;
}
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
p->cmOpts = cmOpts;
}else if( cli_strncmp(zMode,"list",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( cli_strncmp(zMode,"html",n2)==0 ){
p->mode = MODE_Html;
}else if( cli_strncmp(zMode,"tcl",n2)==0 ){
p->mode = MODE_Tcl;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( cli_strncmp(zMode,"csv",n2)==0 ){
p->mode = MODE_Csv;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
}else if( cli_strncmp(zMode,"tabs",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
}else if( cli_strncmp(zMode,"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, zTabname ? zTabname : "table");
}else if( cli_strncmp(zMode,"quote",n2)==0 ){
p->mode = MODE_Quote;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( cli_strncmp(zMode,"ascii",n2)==0 ){
p->mode = MODE_Ascii;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
}else if( cli_strncmp(zMode,"markdown",n2)==0 ){
p->mode = MODE_Markdown;
p->cmOpts = cmOpts;
}else if( cli_strncmp(zMode,"table",n2)==0 ){
p->mode = MODE_Table;
p->cmOpts = cmOpts;
}else if( cli_strncmp(zMode,"box",n2)==0 ){
p->mode = MODE_Box;
p->cmOpts = cmOpts;
}else if( cli_strncmp(zMode,"count",n2)==0 ){
p->mode = MODE_Count;
}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{
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 ){
raw_printf(stderr, "Usage: .nonce NONCE\n");
rc = 1;
}else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
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 */
}
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
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{
raw_printf(stderr, "Usage: .nullvalue STRING\n");
rc = 1;
}
}else
if( c=='o' && cli_strncmp(azArg[0], "open", n)==0 && n>=2 ){
const char *zFN = 0; /* Pointer to constant filename */
char *zNewFilename = 0; /* Name of the database file to open */
int iName = 1; /* Index in azArg[] of the filename */
int newFlag = 0; /* True to delete file before opening */
int openMode = SHELL_OPEN_UNSPEC;
/* Check for command-line arguments */
for(iName=1; iName<nArg; iName++){
const char *z = azArg[iName];
#ifndef SQLITE_SHELL_FIDDLE
if( optionMatch(z,"new") ){
newFlag = 1;
#ifdef SQLITE_HAVE_ZLIB
}else if( optionMatch(z, "zip") ){
openMode = SHELL_OPEN_ZIPFILE;
#endif
}else if( optionMatch(z, "append") ){
|
| ︙ | ︙ | |||
20694 20695 20696 20697 20698 20699 20700 |
openMode = SHELL_OPEN_DESERIALIZE;
}else if( optionMatch(z, "hexdb") ){
openMode = SHELL_OPEN_HEXDB;
}else if( optionMatch(z, "maxsize") && iName+1<nArg ){
p->szMax = integerValue(azArg[++iName]);
#endif /* SQLITE_OMIT_DESERIALIZE */
}else
| | | 20866 20867 20868 20869 20870 20871 20872 20873 20874 20875 20876 20877 20878 20879 20880 |
openMode = SHELL_OPEN_DESERIALIZE;
}else if( optionMatch(z, "hexdb") ){
openMode = SHELL_OPEN_HEXDB;
}else if( optionMatch(z, "maxsize") && iName+1<nArg ){
p->szMax = integerValue(azArg[++iName]);
#endif /* SQLITE_OMIT_DESERIALIZE */
}else
#endif /* !SQLITE_SHELL_FIDDLE */
if( z[0]=='-' ){
utf8_printf(stderr, "unknown option: %s\n", z);
rc = 1;
goto meta_command_exit;
}else if( zFN ){
utf8_printf(stderr, "extra argument: \"%s\"\n", z);
rc = 1;
|
| ︙ | ︙ | |||
20722 20723 20724 20725 20726 20727 20728 |
p->openMode = openMode;
p->openFlags = 0;
p->szMax = 0;
/* If a filename is specified, try to open it first */
if( zFN || p->openMode==SHELL_OPEN_HEXDB ){
if( newFlag && zFN && !p->bSafeMode ) shellDeleteFile(zFN);
| | | | 20894 20895 20896 20897 20898 20899 20900 20901 20902 20903 20904 20905 20906 20907 20908 20909 20910 20911 20912 |
p->openMode = openMode;
p->openFlags = 0;
p->szMax = 0;
/* If a filename is specified, try to open it first */
if( zFN || p->openMode==SHELL_OPEN_HEXDB ){
if( newFlag && zFN && !p->bSafeMode ) shellDeleteFile(zFN);
#ifndef SQLITE_SHELL_FIDDLE
if( p->bSafeMode
&& p->openMode!=SHELL_OPEN_HEXDB
&& zFN
&& cli_strcmp(zFN,":memory:")!=0
){
failIfSafeMode(p, "cannot open disk-based database files in safe mode");
}
#else
/* WASM mode has its own sandboxed pseudo-filesystem. */
#endif
if( zFN ){
|
| ︙ | ︙ | |||
20755 20756 20757 20758 20759 20760 20761 |
if( p->db==0 ){
/* As a fall-back open a TEMP database */
p->pAuxDb->zDbFilename = 0;
open_db(p, 0);
}
}else
| | | > | | | | | | 20927 20928 20929 20930 20931 20932 20933 20934 20935 20936 20937 20938 20939 20940 20941 20942 20943 20944 20945 20946 20947 20948 20949 20950 20951 20952 20953 20954 20955 20956 20957 20958 20959 20960 20961 20962 20963 20964 20965 20966 20967 20968 20969 20970 20971 20972 20973 |
if( p->db==0 ){
/* As a fall-back open a TEMP database */
p->pAuxDb->zDbFilename = 0;
open_db(p, 0);
}
}else
#ifndef SQLITE_SHELL_FIDDLE
if( (c=='o'
&& (cli_strncmp(azArg[0], "output", n)==0
|| cli_strncmp(azArg[0], "once", n)==0))
|| (c=='e' && n==5 && cli_strcmp(azArg[0],"excel")==0)
){
char *zFile = 0;
int bTxtMode = 0;
int i;
int eMode = 0;
int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
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 ){
bOnce = 1;
}
for(i=1; i<nArg; i++){
char *z = azArg[i];
if( z[0]=='-' ){
if( z[1]=='-' ) z++;
if( cli_strcmp(z,"-bom")==0 ){
zBOM[0] = 0xef;
zBOM[1] = 0xbb;
zBOM[2] = 0xbf;
zBOM[3] = 0;
}else if( c!='e' && cli_strcmp(z,"-x")==0 ){
eMode = 'x'; /* spreadsheet */
}else if( c!='e' && cli_strcmp(z,"-e")==0 ){
eMode = 'e'; /* text editor */
}else{
utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n",
azArg[i]);
showHelp(p->out, azArg[0]);
rc = 1;
goto meta_command_exit;
|
| ︙ | ︙ | |||
20859 20860 20861 20862 20863 20864 20865 |
if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
#endif
}else{
p->out = output_file_open(zFile, bTxtMode);
if( p->out==0 ){
| | | | | | | 21032 21033 21034 21035 21036 21037 21038 21039 21040 21041 21042 21043 21044 21045 21046 21047 21048 21049 21050 21051 21052 21053 21054 21055 21056 21057 21058 21059 21060 21061 21062 21063 21064 21065 21066 21067 21068 21069 21070 21071 21072 21073 21074 21075 |
if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
#endif
}else{
p->out = output_file_open(zFile, bTxtMode);
if( p->out==0 ){
if( cli_strcmp(zFile,"off")!=0 ){
utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
}
p->out = stdout;
rc = 1;
} else {
if( zBOM[0] ) fwrite(zBOM, 1, 3, p->out);
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
}
sqlite3_free(zFile);
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
if( c=='p' && n>=3 && cli_strncmp(azArg[0], "parameter", n)==0 ){
open_db(p,0);
if( nArg<=1 ) goto parameter_syntax_error;
/* .parameter clear
** Clear all bind parameters by dropping the TEMP table that holds them.
*/
if( nArg==2 && cli_strcmp(azArg[1],"clear")==0 ){
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;",
0, 0, 0);
}else
/* .parameter list
** List all bind parameters.
*/
if( nArg==2 && cli_strcmp(azArg[1],"list")==0 ){
sqlite3_stmt *pStmt = 0;
int rx;
int len = 0;
rx = sqlite3_prepare_v2(p->db,
"SELECT max(length(key)) "
"FROM temp.sqlite_parameters;", -1, &pStmt, 0);
if( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
|
| ︙ | ︙ | |||
20917 20918 20919 20920 20921 20922 20923 |
}
}else
/* .parameter init
** Make sure the TEMP table used to hold bind parameters exists.
** Create it if necessary.
*/
| | | | 21090 21091 21092 21093 21094 21095 21096 21097 21098 21099 21100 21101 21102 21103 21104 21105 21106 21107 21108 21109 21110 21111 21112 21113 21114 |
}
}else
/* .parameter init
** Make sure the TEMP table used to hold bind parameters exists.
** Create it if necessary.
*/
if( nArg==2 && cli_strcmp(azArg[1],"init")==0 ){
bind_table_init(p);
}else
/* .parameter set NAME VALUE
** Set or reset a bind parameter. NAME should be the full parameter
** name exactly as it appears in the query. (ex: $abc, @def). The
** VALUE can be in either SQL literal notation, or if not it will be
** understood to be a text string.
*/
if( nArg==4 && cli_strcmp(azArg[1],"set")==0 ){
int rx;
char *zSql;
sqlite3_stmt *pStmt;
const char *zKey = azArg[2];
const char *zValue = azArg[3];
bind_table_init(p);
zSql = sqlite3_mprintf(
|
| ︙ | ︙ | |||
20965 20966 20967 20968 20969 20970 20971 |
sqlite3_finalize(pStmt);
}else
/* .parameter unset NAME
** Remove the NAME binding from the parameter binding table, if it
** exists.
*/
| | | | | | | | | 21138 21139 21140 21141 21142 21143 21144 21145 21146 21147 21148 21149 21150 21151 21152 21153 21154 21155 21156 21157 21158 21159 21160 21161 21162 21163 21164 21165 21166 21167 21168 21169 21170 21171 21172 21173 21174 21175 21176 21177 21178 21179 21180 21181 21182 21183 21184 21185 21186 21187 21188 21189 21190 21191 21192 21193 21194 21195 21196 21197 |
sqlite3_finalize(pStmt);
}else
/* .parameter unset NAME
** Remove the NAME binding from the parameter binding table, if it
** exists.
*/
if( nArg==3 && cli_strcmp(azArg[1],"unset")==0 ){
char *zSql = sqlite3_mprintf(
"DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]);
shell_check_oom(zSql);
sqlite3_exec(p->db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}else
/* If no command name matches, show a syntax error */
parameter_syntax_error:
showHelp(p->out, "parameter");
}else
if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){
int i;
for(i=1; i<nArg; i++){
if( i>1 ) raw_printf(p->out, " ");
utf8_printf(p->out, "%s", azArg[i]);
}
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;
int nn = 0;
p->flgProgress = 0;
p->mxProgress = 0;
p->nProgress = 0;
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( z[0]=='-' ){
z++;
if( z[0]=='-' ) z++;
if( cli_strcmp(z,"quiet")==0 || cli_strcmp(z,"q")==0 ){
p->flgProgress |= SHELL_PROGRESS_QUIET;
continue;
}
if( cli_strcmp(z,"reset")==0 ){
p->flgProgress |= SHELL_PROGRESS_RESET;
continue;
}
if( cli_strcmp(z,"once")==0 ){
p->flgProgress |= SHELL_PROGRESS_ONCE;
continue;
}
if( cli_strcmp(z,"limit")==0 ){
if( i+1>=nArg ){
utf8_printf(stderr, "Error: missing argument on --limit\n");
rc = 1;
goto meta_command_exit;
}else{
p->mxProgress = (int)integerValue(azArg[++i]);
}
|
| ︙ | ︙ | |||
21032 21033 21034 21035 21036 21037 21038 |
}
}
open_db(p, 0);
sqlite3_progress_handler(p->db, nn, progress_handler, p);
}else
#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
| | | | | | | 21205 21206 21207 21208 21209 21210 21211 21212 21213 21214 21215 21216 21217 21218 21219 21220 21221 21222 21223 21224 21225 21226 21227 21228 21229 21230 21231 21232 21233 21234 21235 |
}
}
open_db(p, 0);
sqlite3_progress_handler(p->db, nn, progress_handler, p);
}else
#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
if( c=='p' && cli_strncmp(azArg[0], "prompt", n)==0 ){
if( nArg >= 2) {
strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
}
if( nArg >= 3) {
strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
}
}else
#ifndef SQLITE_SHELL_FIDDLE
if( c=='q' && cli_strncmp(azArg[0], "quit", n)==0 ){
rc = 2;
}else
#endif
#ifndef SQLITE_SHELL_FIDDLE
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 ){
raw_printf(stderr, "Usage: .read FILE\n");
rc = 1;
goto meta_command_exit;
|
| ︙ | ︙ | |||
21082 21083 21084 21085 21086 21087 21088 |
}else{
rc = process_input(p);
fclose(p->in);
}
p->in = inSaved;
p->lineno = savedLineno;
}else
| | | | | 21255 21256 21257 21258 21259 21260 21261 21262 21263 21264 21265 21266 21267 21268 21269 21270 21271 21272 |
}else{
rc = process_input(p);
fclose(p->in);
}
p->in = inSaved;
p->lineno = savedLineno;
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
#ifndef SQLITE_SHELL_FIDDLE
if( c=='r' && n>=3 && cli_strncmp(azArg[0], "restore", n)==0 ){
const char *zSrcFile;
const char *zDb;
sqlite3 *pSrc;
sqlite3_backup *pBackup;
int nTimeout = 0;
failIfSafeMode(p, "cannot run .restore in safe mode");
|
| ︙ | ︙ | |||
21136 21137 21138 21139 21140 21141 21142 |
rc = 1;
}else{
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
rc = 1;
}
close_db(pSrc);
}else
| | | | | 21309 21310 21311 21312 21313 21314 21315 21316 21317 21318 21319 21320 21321 21322 21323 21324 21325 21326 21327 21328 21329 21330 21331 21332 21333 21334 21335 21336 21337 |
rc = 1;
}else{
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
rc = 1;
}
close_db(pSrc);
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
if( nArg==2 ){
p->scanstatsOn = (u8)booleanValue(azArg[1]);
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
#endif
}else{
raw_printf(stderr, "Usage: .scanstats on|off\n");
rc = 1;
}
}else
if( c=='s' && cli_strncmp(azArg[0], "schema", n)==0 ){
ShellText sSelect;
ShellState data;
char *zErrMsg = 0;
const char *zDiv = "(";
const char *zName = 0;
int iSchema = 0;
int bDebug = 0;
|
| ︙ | ︙ | |||
21293 21294 21295 21296 21297 21298 21299 |
raw_printf(stderr,"Error: querying schema information\n");
rc = 1;
}else{
rc = 0;
}
}else
| | | | | | | > > | 21466 21467 21468 21469 21470 21471 21472 21473 21474 21475 21476 21477 21478 21479 21480 21481 21482 21483 21484 21485 21486 21487 21488 21489 21490 21491 21492 21493 21494 21495 21496 21497 21498 21499 21500 21501 21502 21503 21504 21505 21506 21507 21508 21509 21510 21511 21512 21513 21514 21515 21516 21517 21518 21519 21520 21521 21522 21523 21524 21525 21526 21527 21528 21529 21530 21531 21532 21533 21534 21535 |
raw_printf(stderr,"Error: querying schema information\n");
rc = 1;
}else{
rc = 0;
}
}else
if( (c=='s' && n==11 && cli_strncmp(azArg[0], "selecttrace", n)==0)
|| (c=='t' && n==9 && cli_strncmp(azArg[0], "treetrace", n)==0)
){
unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x);
}else
#if defined(SQLITE_ENABLE_SESSION)
if( c=='s' && cli_strncmp(azArg[0],"session",n)==0 && n>=3 ){
struct AuxDb *pAuxDb = p->pAuxDb;
OpenSession *pSession = &pAuxDb->aSession[0];
char **azCmd = &azArg[1];
int iSes = 0;
int nCmd = nArg - 1;
int i;
if( nArg<=1 ) goto session_syntax_error;
open_db(p, 0);
if( nArg>=3 ){
for(iSes=0; iSes<pAuxDb->nSession; iSes++){
if( cli_strcmp(pAuxDb->aSession[iSes].zName, azArg[1])==0 ) break;
}
if( iSes<pAuxDb->nSession ){
pSession = &pAuxDb->aSession[iSes];
azCmd++;
nCmd--;
}else{
pSession = &pAuxDb->aSession[0];
iSes = 0;
}
}
/* .session attach TABLE
** Invoke the sqlite3session_attach() interface to attach a particular
** table so that it is never filtered.
*/
if( cli_strcmp(azCmd[0],"attach")==0 ){
if( nCmd!=2 ) goto session_syntax_error;
if( pSession->p==0 ){
session_not_open:
raw_printf(stderr, "ERROR: No sessions are open\n");
}else{
rc = sqlite3session_attach(pSession->p, azCmd[1]);
if( rc ){
raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc);
rc = 0;
}
}
}else
/* .session changeset FILE
** .session patchset FILE
** Write a changeset or patchset into a file. The file is overwritten.
*/
if( cli_strcmp(azCmd[0],"changeset")==0
|| cli_strcmp(azCmd[0],"patchset")==0
){
FILE *out = 0;
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 ){
utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n",
|
| ︙ | ︙ | |||
21380 21381 21382 21383 21384 21385 21386 |
fclose(out);
}
}else
/* .session close
** Close the identified session
*/
| | | | | 21555 21556 21557 21558 21559 21560 21561 21562 21563 21564 21565 21566 21567 21568 21569 21570 21571 21572 21573 21574 21575 21576 21577 21578 21579 21580 21581 21582 21583 21584 21585 21586 21587 21588 21589 21590 21591 21592 21593 21594 |
fclose(out);
}
}else
/* .session close
** Close the identified session
*/
if( cli_strcmp(azCmd[0], "close")==0 ){
if( nCmd!=1 ) goto session_syntax_error;
if( pAuxDb->nSession ){
session_close(pSession);
pAuxDb->aSession[iSes] = pAuxDb->aSession[--pAuxDb->nSession];
}
}else
/* .session enable ?BOOLEAN?
** Query or set the enable flag
*/
if( cli_strcmp(azCmd[0], "enable")==0 ){
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);
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.
*/
if( cli_strcmp(azCmd[0], "filter")==0 ){
int ii, nByte;
if( nCmd<2 ) goto session_syntax_error;
if( pAuxDb->nSession ){
for(ii=0; ii<pSession->nFilter; ii++){
sqlite3_free(pSession->azFilter[ii]);
}
sqlite3_free(pSession->azFilter);
|
| ︙ | ︙ | |||
21430 21431 21432 21433 21434 21435 21436 |
pSession->nFilter = ii-1;
}
}else
/* .session indirect ?BOOLEAN?
** Query or set the indirect flag
*/
| | | | | | | 21605 21606 21607 21608 21609 21610 21611 21612 21613 21614 21615 21616 21617 21618 21619 21620 21621 21622 21623 21624 21625 21626 21627 21628 21629 21630 21631 21632 21633 21634 21635 21636 21637 21638 21639 21640 21641 21642 21643 21644 21645 21646 21647 21648 21649 21650 21651 21652 21653 21654 21655 21656 21657 21658 21659 21660 21661 21662 |
pSession->nFilter = ii-1;
}
}else
/* .session indirect ?BOOLEAN?
** Query or set the indirect flag
*/
if( cli_strcmp(azCmd[0], "indirect")==0 ){
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);
utf8_printf(p->out, "session %s indirect flag = %d\n",
pSession->zName, ii);
}
}else
/* .session isempty
** Determine if the session is empty
*/
if( cli_strcmp(azCmd[0], "isempty")==0 ){
int ii;
if( nCmd!=1 ) goto session_syntax_error;
if( pAuxDb->nSession ){
ii = sqlite3session_isempty(pSession->p);
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; i<pAuxDb->nSession; i++){
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.
** DB is normally "main".
*/
if( cli_strcmp(azCmd[0],"open")==0 ){
char *zName;
if( nCmd!=3 ) goto session_syntax_error;
zName = azCmd[2];
if( zName[0]==0 ) goto session_syntax_error;
for(i=0; i<pAuxDb->nSession; i++){
if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
utf8_printf(stderr, "Session \"%s\" already exists\n", zName);
goto meta_command_exit;
}
}
if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){
raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession));
goto meta_command_exit;
|
| ︙ | ︙ | |||
21504 21505 21506 21507 21508 21509 21510 |
showHelp(p->out, "session");
}else
#endif
#ifdef SQLITE_DEBUG
/* Undocumented commands for internal testing. Subject to change
** without notice. */
| | | | | | | | 21679 21680 21681 21682 21683 21684 21685 21686 21687 21688 21689 21690 21691 21692 21693 21694 21695 21696 21697 21698 21699 21700 21701 21702 21703 21704 21705 21706 21707 21708 21709 21710 21711 21712 21713 21714 21715 21716 21717 21718 21719 21720 21721 21722 21723 21724 21725 21726 21727 21728 21729 21730 |
showHelp(p->out, "session");
}else
#endif
#ifdef SQLITE_DEBUG
/* Undocumented commands for internal testing. Subject to change
** without notice. */
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; i<nArg; i++){
v = booleanValue(azArg[i]);
utf8_printf(p->out, "%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; i<nArg; i++){
char zBuf[200];
v = integerValue(azArg[i]);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
utf8_printf(p->out, "%s", zBuf);
}
}
}else
#endif
if( c=='s' && n>=4 && cli_strncmp(azArg[0],"selftest",n)==0 ){
int bIsInit = 0; /* True to initialize the SELFTEST table */
int bVerbose = 0; /* Verbose output */
int bSelftestExists; /* True if SELFTEST already exists */
int i, k; /* Loop counters */
int nTest = 0; /* Number of tests runs */
int nErr = 0; /* Number of errors seen */
ShellText str; /* Answer for a query */
sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
open_db(p,0);
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( z[0]=='-' && z[1]=='-' ) z++;
if( cli_strcmp(z,"-init")==0 ){
bIsInit = 1;
}else
if( cli_strcmp(z,"-v")==0 ){
bVerbose++;
}else
{
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;
|
| ︙ | ︙ | |||
21594 21595 21596 21597 21598 21599 21600 |
if( zOp==0 ) continue;
if( zSql==0 ) continue;
if( zAns==0 ) continue;
k = 0;
if( bVerbose>0 ){
printf("%d: %s %s\n", tno, zOp, zSql);
}
| | | | | | | | | | | 21769 21770 21771 21772 21773 21774 21775 21776 21777 21778 21779 21780 21781 21782 21783 21784 21785 21786 21787 21788 21789 21790 21791 21792 21793 21794 21795 21796 21797 21798 21799 21800 21801 21802 21803 21804 21805 21806 21807 21808 21809 21810 21811 21812 21813 21814 21815 21816 21817 21818 21819 21820 21821 21822 21823 21824 21825 21826 21827 21828 21829 21830 21831 21832 21833 21834 21835 21836 21837 21838 21839 21840 21841 21842 21843 21844 21845 21846 21847 21848 21849 21850 21851 21852 21853 21854 21855 21856 21857 21858 21859 21860 21861 |
if( zOp==0 ) continue;
if( zSql==0 ) continue;
if( zAns==0 ) continue;
k = 0;
if( bVerbose>0 ){
printf("%d: %s %s\n", tno, zOp, zSql);
}
if( cli_strcmp(zOp,"memo")==0 ){
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 ){
utf8_printf(p->out, "Result: %s\n", str.z);
}
if( rc || zErrMsg ){
nErr++;
rc = 1;
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;
utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
}
}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);
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 ){
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]);
}
if( nArg>=3 ){
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
"%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
}
}else
if( c=='s' && n>=4 && cli_strncmp(azArg[0],"sha3sum",n)==0 ){
const char *zLike = 0; /* Which table to checksum. 0 means everything */
int i; /* Loop counter */
int bSchema = 0; /* Also hash the schema */
int bSeparate = 0; /* Hash each table separately */
int iSize = 224; /* Hash algorithm to use */
int bDebug = 0; /* Only show the query that would have run */
sqlite3_stmt *pStmt; /* For querying tables names */
char *zSql; /* SQL to be run */
char *zSep; /* Separator */
ShellText sSql; /* Complete SQL for the query to run the hash */
ShellText sQuery; /* Set of queries used to read all content */
open_db(p, 0);
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( z[0]=='-' ){
z++;
if( z[0]=='-' ) z++;
if( cli_strcmp(z,"schema")==0 ){
bSchema = 1;
}else
if( cli_strcmp(z,"sha3-224")==0 || cli_strcmp(z,"sha3-256")==0
|| cli_strcmp(z,"sha3-384")==0 || cli_strcmp(z,"sha3-512")==0
){
iSize = atoi(&z[5]);
}else
if( cli_strcmp(z,"debug")==0 ){
bDebug = 1;
}else
{
utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
azArg[i], azArg[0]);
showHelp(p->out, azArg[0]);
rc = 1;
|
| ︙ | ︙ | |||
21712 21713 21714 21715 21716 21717 21718 |
initText(&sSql);
appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
zSep = "VALUES(";
while( SQLITE_ROW==sqlite3_step(pStmt) ){
const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
if( zTab==0 ) continue;
if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
| | | | | | | 21887 21888 21889 21890 21891 21892 21893 21894 21895 21896 21897 21898 21899 21900 21901 21902 21903 21904 21905 21906 21907 21908 21909 21910 21911 21912 21913 21914 |
initText(&sSql);
appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
zSep = "VALUES(";
while( SQLITE_ROW==sqlite3_step(pStmt) ){
const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
if( zTab==0 ) continue;
if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
if( cli_strncmp(zTab, "sqlite_",7)!=0 ){
appendText(&sQuery,"SELECT * FROM ", 0);
appendText(&sQuery,zTab,'"');
appendText(&sQuery," NOT INDEXED;", 0);
}else if( cli_strcmp(zTab, "sqlite_schema")==0 ){
appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema"
" ORDER BY name;", 0);
}else if( cli_strcmp(zTab, "sqlite_sequence")==0 ){
appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
" ORDER BY name;", 0);
}else if( cli_strcmp(zTab, "sqlite_stat1")==0 ){
appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
" ORDER BY tbl,idx;", 0);
}else if( cli_strcmp(zTab, "sqlite_stat4")==0 ){
appendText(&sQuery, "SELECT * FROM ", 0);
appendText(&sQuery, zTab, 0);
appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
}
appendText(&sSql, zSep, 0);
appendText(&sSql, sQuery.z, '\'');
sQuery.n = 0;
|
| ︙ | ︙ | |||
21762 21763 21764 21765 21766 21767 21768 |
utf8_printf(p->out, "%s\n", zSql);
}else{
shell_exec(p, zSql, 0);
}
sqlite3_free(zSql);
}else
| | > | | | | 21937 21938 21939 21940 21941 21942 21943 21944 21945 21946 21947 21948 21949 21950 21951 21952 21953 21954 21955 21956 21957 21958 21959 21960 21961 21962 21963 21964 21965 21966 21967 21968 21969 21970 21971 21972 21973 21974 21975 |
utf8_printf(p->out, "%s\n", zSql);
}else{
shell_exec(p, zSql, 0);
}
sqlite3_free(zSql);
}else
#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
if( c=='s'
&& (cli_strncmp(azArg[0], "shell", n)==0
|| cli_strncmp(azArg[0],"system",n)==0)
){
char *zCmd;
int i, x;
failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
if( nArg<2 ){
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; i<nArg && zCmd!=0; i++){
zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
zCmd, azArg[i]);
}
x = zCmd!=0 ? system(zCmd) : 1;
sqlite3_free(zCmd);
if( x ) raw_printf(stderr, "System command returns %d\n", x);
}else
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
if( c=='s' && cli_strncmp(azArg[0], "show", n)==0 ){
static const char *azBool[] = { "off", "on", "trigger", "full"};
const char *zOut;
int i;
if( nArg!=1 ){
raw_printf(stderr, "Usage: .show\n");
rc = 1;
goto meta_command_exit;
|
| ︙ | ︙ | |||
21838 21839 21840 21841 21842 21843 21844 |
raw_printf(p->out, "%d ", p->colWidth[i]);
}
raw_printf(p->out, "\n");
utf8_printf(p->out, "%12.12s: %s\n", "filename",
p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
}else
| | | | | | | | 22014 22015 22016 22017 22018 22019 22020 22021 22022 22023 22024 22025 22026 22027 22028 22029 22030 22031 22032 22033 22034 22035 22036 22037 22038 22039 22040 22041 22042 22043 22044 22045 22046 22047 |
raw_printf(p->out, "%d ", p->colWidth[i]);
}
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 ){
p->statsOn = 2;
}else if( cli_strcmp(azArg[1],"vmstep")==0 ){
p->statsOn = 3;
}else{
p->statsOn = (u8)booleanValue(azArg[1]);
}
}else if( nArg==1 ){
display_stats(p->db, p, 0);
}else{
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)
|| (c=='i' && (cli_strncmp(azArg[0], "indices", n)==0
|| cli_strncmp(azArg[0], "indexes", n)==0) )
){
sqlite3_stmt *pStmt;
char **azResult;
int nRow, nAlloc;
int ii;
ShellText s;
initText(&s);
|
| ︙ | ︙ | |||
21963 21964 21965 21966 21967 21968 21969 |
}
}
for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
sqlite3_free(azResult);
}else
| | | | | | 22139 22140 22141 22142 22143 22144 22145 22146 22147 22148 22149 22150 22151 22152 22153 22154 22155 22156 22157 22158 22159 22160 22161 22162 22163 22164 22165 22166 22167 22168 22169 22170 |
}
}
for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
sqlite3_free(azResult);
}else
#ifndef SQLITE_SHELL_FIDDLE
/* Begin redirecting output to the file "testcase-out.txt" */
if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
output_reset(p);
p->out = output_file_open("testcase-out.txt", 0);
if( p->out==0 ){
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, "?");
}
}else
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
#ifndef SQLITE_UNTESTABLE
if( c=='t' && n>=8 && cli_strncmp(azArg[0], "testctrl", n)==0 ){
static const struct {
const char *zCtrlName; /* Name of a test-control option */
int ctrlCode; /* Integer code for that option */
int unSafe; /* Not valid for --safe mode */
const char *zUsage; /* Usage notes */
} aCtrl[] = {
{ "always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" },
|
| ︙ | ︙ | |||
22027 22028 22029 22030 22031 22032 22033 |
/* The argument can optionally begin with "-" or "--" */
if( zCmd[0]=='-' && zCmd[1] ){
zCmd++;
if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
}
/* --help lists all test-controls */
| | | | 22203 22204 22205 22206 22207 22208 22209 22210 22211 22212 22213 22214 22215 22216 22217 22218 22219 22220 22221 22222 22223 22224 22225 22226 22227 22228 22229 22230 22231 |
/* The argument can optionally begin with "-" or "--" */
if( zCmd[0]=='-' && zCmd[1] ){
zCmd++;
if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
}
/* --help lists all test-controls */
if( cli_strcmp(zCmd,"help")==0 ){
utf8_printf(p->out, "Available test-controls:\n");
for(i=0; i<ArraySize(aCtrl); i++){
utf8_printf(p->out, " .testctrl %s %s\n",
aCtrl[i].zCtrlName, aCtrl[i].zUsage);
}
rc = 1;
goto meta_command_exit;
}
/* convert testctrl text option to value. allow any unique prefix
** of the option name, or a numerical value. */
n2 = strlen30(zCmd);
for(i=0; i<ArraySize(aCtrl); i++){
if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
if( testctrl<0 ){
testctrl = aCtrl[i].ctrlCode;
iCtrl = i;
}else{
utf8_printf(stderr, "Error: ambiguous test-control: \"%s\"\n"
"Use \".testctrl --help\" for help\n", zCmd);
rc = 1;
|
| ︙ | ︙ | |||
22097 22098 22099 22100 22101 22102 22103 |
break;
/* sqlite3_test_control(int, int, sqlite3*) */
case SQLITE_TESTCTRL_PRNG_SEED:
if( nArg==3 || nArg==4 ){
int ii = (int)integerValue(azArg[2]);
sqlite3 *db;
| | | 22273 22274 22275 22276 22277 22278 22279 22280 22281 22282 22283 22284 22285 22286 22287 |
break;
/* sqlite3_test_control(int, int, sqlite3*) */
case SQLITE_TESTCTRL_PRNG_SEED:
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);
printf("-- random seed: %d\n", ii);
}
if( nArg==3 ){
db = 0;
}else{
db = p->db;
|
| ︙ | ︙ | |||
22213 22214 22215 22216 22217 22218 22219 |
raw_printf(p->out, "%d\n", rc2);
}else if( isOk==2 ){
raw_printf(p->out, "0x%08x\n", rc2);
}
}else
#endif /* !defined(SQLITE_UNTESTABLE) */
| | | | | 22389 22390 22391 22392 22393 22394 22395 22396 22397 22398 22399 22400 22401 22402 22403 22404 22405 22406 22407 22408 22409 22410 22411 22412 22413 22414 22415 22416 22417 22418 22419 22420 22421 22422 |
raw_printf(p->out, "%d\n", rc2);
}else if( isOk==2 ){
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 ){
open_db(p, 0);
sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
}else
if( c=='t' && n>=5 && cli_strncmp(azArg[0], "timer", n)==0 ){
if( nArg==2 ){
enableTimer = booleanValue(azArg[1]);
if( enableTimer && !HAS_TIMER ){
raw_printf(stderr, "Error: timer not available on this system.\n");
enableTimer = 0;
}
}else{
raw_printf(stderr, "Usage: .timer on|off\n");
rc = 1;
}
}else
#ifndef SQLITE_OMIT_TRACE
if( c=='t' && cli_strncmp(azArg[0], "trace", n)==0 ){
int mType = 0;
int jj;
open_db(p, 0);
for(jj=1; jj<nArg; jj++){
const char *z = azArg[jj];
if( z[0]=='-' ){
if( optionMatch(z, "expanded") ){
|
| ︙ | ︙ | |||
22282 22283 22284 22285 22286 22287 22288 |
if( mType==0 ) mType = SQLITE_TRACE_STMT;
sqlite3_trace_v2(p->db, mType, sql_trace_callback, p);
}
}else
#endif /* !defined(SQLITE_OMIT_TRACE) */
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE)
| | | | | | | | | | | | | | | 22458 22459 22460 22461 22462 22463 22464 22465 22466 22467 22468 22469 22470 22471 22472 22473 22474 22475 22476 22477 22478 22479 22480 22481 22482 22483 22484 22485 22486 22487 22488 22489 22490 22491 22492 22493 22494 22495 22496 22497 22498 22499 22500 22501 22502 22503 22504 22505 22506 22507 22508 22509 22510 22511 22512 22513 22514 22515 22516 22517 22518 22519 22520 22521 22522 22523 22524 22525 22526 22527 22528 22529 22530 22531 22532 22533 22534 22535 22536 22537 22538 22539 22540 22541 22542 22543 22544 22545 22546 22547 22548 22549 22550 22551 22552 22553 22554 22555 22556 22557 22558 22559 22560 22561 22562 22563 22564 22565 22566 22567 22568 22569 22570 22571 22572 22573 22574 22575 22576 22577 22578 22579 22580 22581 22582 22583 22584 22585 22586 22587 22588 22589 22590 22591 22592 22593 22594 22595 22596 22597 22598 22599 22600 22601 22602 22603 22604 22605 22606 22607 22608 22609 22610 22611 22612 22613 22614 22615 22616 22617 22618 22619 22620 22621 22622 22623 22624 22625 22626 22627 |
if( mType==0 ) mType = SQLITE_TRACE_STMT;
sqlite3_trace_v2(p->db, mType, sql_trace_callback, p);
}
}else
#endif /* !defined(SQLITE_OMIT_TRACE) */
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE)
if( c=='u' && cli_strncmp(azArg[0], "unmodule", n)==0 ){
int ii;
int lenOpt;
char *zOpt;
if( nArg<2 ){
raw_printf(stderr, "Usage: .unmodule [--allexcept] NAME ...\n");
rc = 1;
goto meta_command_exit;
}
open_db(p, 0);
zOpt = azArg[1];
if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++;
lenOpt = (int)strlen(zOpt);
if( lenOpt>=3 && cli_strncmp(zOpt, "-allexcept",lenOpt)==0 ){
assert( azArg[nArg]==0 );
sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0);
}else{
for(ii=1; ii<nArg; ii++){
sqlite3_create_module(p->db, azArg[ii], 0, 0);
}
}
}else
#endif
#if SQLITE_USER_AUTHENTICATION
if( c=='u' && cli_strncmp(azArg[0], "user", n)==0 ){
if( nArg<2 ){
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 ){
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 ){
utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
rc = 1;
}
}else if( cli_strcmp(azArg[1],"add")==0 ){
if( nArg!=5 ){
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 ){
raw_printf(stderr, "User-Add failed: %d\n", rc);
rc = 1;
}
}else if( cli_strcmp(azArg[1],"edit")==0 ){
if( nArg!=5 ){
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 ){
raw_printf(stderr, "User-Edit failed: %d\n", rc);
rc = 1;
}
}else if( cli_strcmp(azArg[1],"delete")==0 ){
if( nArg!=3 ){
raw_printf(stderr, "Usage: .user delete USER\n");
rc = 1;
goto meta_command_exit;
}
rc = sqlite3_user_delete(p->db, azArg[2]);
if( rc ){
raw_printf(stderr, "User-Delete failed: %d\n", rc);
rc = 1;
}
}else{
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 ){
utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
sqlite3_libversion(), sqlite3_sourceid());
#if SQLITE_HAVE_ZLIB
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__)
utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
CTIMEOPT_VAL(__clang_minor__) "."
CTIMEOPT_VAL(__clang_patchlevel__) "\n");
#elif defined(_MSC_VER)
utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n");
#elif defined(__GNUC__) && defined(__VERSION__)
utf8_printf(p->out, "gcc-" __VERSION__ "\n");
#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 ){
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 ){
sqlite3_vfs *pVfs;
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){
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 ){
raw_printf(p->out, "-----------------------------------\n");
}
}
}else
if( c=='v' && cli_strncmp(azArg[0], "vfsname", n)==0 ){
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 ){
utf8_printf(p->out, "%s\n", zVfsName);
sqlite3_free(zVfsName);
}
}
}else
if( c=='w' && cli_strncmp(azArg[0], "wheretrace", n)==0 ){
unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x);
}else
if( c=='w' && cli_strncmp(azArg[0], "width", n)==0 ){
int j;
assert( nArg<=ArraySize(azArg) );
p->nWidth = nArg-1;
p->colWidth = realloc(p->colWidth, (p->nWidth+1)*sizeof(int)*2);
if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory();
if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth];
for(j=1; j<nArg; j++){
|
| ︙ | ︙ | |||
22615 22616 22617 22618 22619 22620 22621 |
if( rc || zErrMsg ){
char zPrefix[100];
const char *zErrorTail;
const char *zErrorType;
if( zErrMsg==0 ){
zErrorType = "Error";
zErrorTail = sqlite3_errmsg(p->db);
| | | | 22791 22792 22793 22794 22795 22796 22797 22798 22799 22800 22801 22802 22803 22804 22805 22806 22807 22808 |
if( rc || zErrMsg ){
char zPrefix[100];
const char *zErrorTail;
const char *zErrorType;
if( zErrMsg==0 ){
zErrorType = "Error";
zErrorTail = sqlite3_errmsg(p->db);
}else if( cli_strncmp(zErrMsg, "in prepare, ",12)==0 ){
zErrorType = "Parse error";
zErrorTail = &zErrMsg[12];
}else if( cli_strncmp(zErrMsg, "stepping, ", 10)==0 ){
zErrorType = "Runtime error";
zErrorTail = &zErrMsg[10];
}else{
zErrorType = "Error";
zErrorTail = zErrMsg;
}
if( in!=0 || !stdin_is_interactive ){
|
| ︙ | ︙ | |||
22649 22650 22651 22652 22653 22654 22655 |
return 0;
}
static void echo_group_input(ShellState *p, const char *zDo){
if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo);
}
| | | | | | | | | | 22825 22826 22827 22828 22829 22830 22831 22832 22833 22834 22835 22836 22837 22838 22839 22840 22841 22842 22843 22844 22845 22846 22847 22848 22849 22850 22851 22852 22853 22854 22855 22856 22857 22858 22859 22860 22861 22862 22863 22864 22865 22866 22867 22868 22869 22870 22871 22872 22873 22874 22875 22876 22877 22878 22879 22880 22881 22882 22883 22884 22885 22886 22887 22888 22889 |
return 0;
}
static void echo_group_input(ShellState *p, const char *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 impl
** because we need the global shellState and cannot access it from that function
** without moving lots of code around (creating a larger/messier diff).
*/
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
/* Parse the next line from shellState.wasm.zInput. */
const char *zBegin = shellState.wasm.zPos;
const char *z = zBegin;
char *zLine = 0;
i64 nZ = 0;
UNUSED_PARAMETER(in);
UNUSED_PARAMETER(isContinuation);
if(!z || !*z){
return 0;
}
while(*z && isspace(*z)) ++z;
zBegin = z;
for(; *z && '\n'!=*z; ++nZ, ++z){}
if(nZ>0 && '\r'==zBegin[nZ-1]){
--nZ;
}
shellState.wasm.zPos = z;
zLine = realloc(zPrior, nZ+1);
shell_check_oom(zLine);
memcpy(zLine, zBegin, nZ);
zLine[nZ] = 0;
return zLine;
}
#endif /* SQLITE_SHELL_FIDDLE */
/*
** Read input from *in and process it. If *in==0 then input
** is interactive - the user is typing it it. Otherwise, input
** is coming from a file or device. A prompt is issued and history
** is saved only if input is interactive. An interrupt signal will
** cause this routine to exit immediately, unless input is interactive.
**
** Return the number of errors.
*/
static int process_input(ShellState *p){
char *zLine = 0; /* A single input line */
char *zSql = 0; /* Accumulated SQL text */
i64 nLine; /* Length of current line */
i64 nSql = 0; /* Bytes of zSql[] used */
i64 nAlloc = 0; /* Allocated zSql[] space */
int rc; /* Error code */
int errCnt = 0; /* Number of errors seen */
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. */
utf8_printf(stderr,"Input nesting limit (%d) reached at line %d."
" Check recursion.\n", MAX_INPUT_NESTING, p->lineno);
return 1;
|
| ︙ | ︙ | |||
22749 22750 22751 22752 22753 22754 22755 |
errCnt++;
}
}
qss = QSS_Start;
continue;
}
/* No single-line dispositions remain; accumulate line(s). */
| | | | 22925 22926 22927 22928 22929 22930 22931 22932 22933 22934 22935 22936 22937 22938 22939 22940 22941 22942 22943 22944 22945 22946 22947 |
errCnt++;
}
}
qss = QSS_Start;
continue;
}
/* No single-line dispositions remain; accumulate line(s). */
nLine = strlen(zLine);
if( nSql+nLine+2>=nAlloc ){
/* Grow buffer by half-again increments when big. */
nAlloc = nSql+(nSql>>1)+nLine+100;
zSql = realloc(zSql, nAlloc);
shell_check_oom(zSql);
}
if( nSql==0 ){
i64 i;
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
assert( nAlloc>0 && zSql!=0 );
memcpy(zSql, zLine+i, nLine+1-i);
startline = p->lineno;
nSql = nLine-i;
}else{
zSql[nSql++] = '\n';
|
| ︙ | ︙ | |||
22857 22858 22859 22860 22861 22862 22863 |
home_dir = "c:\\";
}
#endif
#endif /* !_WIN32_WCE */
if( home_dir ){
| | | 23033 23034 23035 23036 23037 23038 23039 23040 23041 23042 23043 23044 23045 23046 23047 |
home_dir = "c:\\";
}
#endif
#endif /* !_WIN32_WCE */
if( home_dir ){
i64 n = strlen(home_dir) + 1;
char *z = malloc( n );
if( z ) memcpy(z, home_dir, n);
home_dir = z;
}
return home_dir;
}
|
| ︙ | ︙ | |||
23063 23064 23065 23066 23067 23068 23069 | && (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__))) # define SQLITE_SHELL_IS_UTF8 (0) # else # define SQLITE_SHELL_IS_UTF8 (1) # endif #endif | | | | > | 23239 23240 23241 23242 23243 23244 23245 23246 23247 23248 23249 23250 23251 23252 23253 23254 23255 23256 23257 23258 23259 23260 23261 23262 23263 23264 23265 23266 23267 23268 23269 23270 23271 23272 23273 23274 23275 23276 23277 23278 23279 23280 23281 23282 23283 23284 23285 23286 23287 23288 23289 23290 |
&& (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
# define SQLITE_SHELL_IS_UTF8 (0)
# else
# define SQLITE_SHELL_IS_UTF8 (1)
# endif
#endif
#ifdef SQLITE_SHELL_FIDDLE
# define main fiddle_main
#endif
#if SQLITE_SHELL_IS_UTF8
int SQLITE_CDECL main(int argc, char **argv){
#else
int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
char **argv;
#endif
#ifdef SQLITE_DEBUG
sqlite3_int64 mem_main_enter = sqlite3_memory_used();
#endif
char *zErrMsg = 0;
#ifdef SQLITE_SHELL_FIDDLE
# define data shellState
#else
ShellState data;
#endif
const char *zInitFile = 0;
int i;
int rc = 0;
int warnInmemoryDb = 0;
int readStdin = 1;
int nCmd = 0;
char **azCmd = 0;
const char *zVfs = 0; /* Value of -vfs command-line option */
#if !SQLITE_SHELL_IS_UTF8
char **argvToFree = 0;
int argcToFree = 0;
#endif
setBinaryMode(stdin, 0);
setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
#ifdef SQLITE_SHELL_FIDDLE
stdin_is_interactive = 0;
stdout_is_console = 1;
data.wasm.zDefaultDbName = "/fiddle.sqlite3";
#else
stdin_is_interactive = isatty(0);
stdout_is_console = isatty(1);
#endif
#if !defined(_WIN32_WCE)
if( getenv("SQLITE_DEBUG_BREAK") ){
|
| ︙ | ︙ | |||
23127 23128 23129 23130 23131 23132 23133 |
raise(SIGTRAP);
#endif
}
}
#endif
#if USE_SYSTEM_SQLITE+0!=1
| | | 23304 23305 23306 23307 23308 23309 23310 23311 23312 23313 23314 23315 23316 23317 23318 |
raise(SIGTRAP);
#endif
}
}
#endif
#if USE_SYSTEM_SQLITE+0!=1
if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
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);
|
| ︙ | ︙ | |||
23149 23150 23151 23152 23153 23154 23155 |
sqlite3_initialize();
argvToFree = malloc(sizeof(argv[0])*argc*2);
shell_check_oom(argvToFree);
argcToFree = argc;
argv = argvToFree + argc;
for(i=0; i<argc; i++){
char *z = sqlite3_win32_unicode_to_utf8(wargv[i]);
| | | | 23326 23327 23328 23329 23330 23331 23332 23333 23334 23335 23336 23337 23338 23339 23340 23341 23342 |
sqlite3_initialize();
argvToFree = malloc(sizeof(argv[0])*argc*2);
shell_check_oom(argvToFree);
argcToFree = argc;
argv = argvToFree + argc;
for(i=0; i<argc; i++){
char *z = sqlite3_win32_unicode_to_utf8(wargv[i]);
i64 n;
shell_check_oom(z);
n = strlen(z);
argv[i] = malloc( n+1 );
shell_check_oom(argv[i]);
memcpy(argv[i], z, n+1);
argvToFree[i] = argv[i];
sqlite3_free(z);
}
sqlite3_shutdown();
|
| ︙ | ︙ | |||
23208 23209 23210 23211 23212 23213 23214 |
nCmd++;
azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
shell_check_oom(azCmd);
azCmd[nCmd-1] = z;
}
}
if( z[1]=='-' ) z++;
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 23385 23386 23387 23388 23389 23390 23391 23392 23393 23394 23395 23396 23397 23398 23399 23400 23401 23402 23403 23404 23405 23406 23407 23408 23409 23410 23411 23412 23413 23414 23415 23416 23417 23418 23419 23420 23421 23422 23423 23424 23425 23426 23427 23428 23429 23430 23431 23432 23433 23434 23435 23436 23437 23438 23439 23440 23441 23442 23443 23444 23445 23446 23447 23448 23449 23450 23451 23452 23453 23454 23455 23456 23457 23458 23459 23460 23461 23462 23463 23464 23465 23466 23467 23468 23469 23470 23471 23472 23473 23474 23475 23476 23477 23478 23479 23480 23481 23482 23483 23484 23485 23486 23487 23488 23489 23490 23491 23492 23493 23494 23495 23496 23497 23498 23499 23500 23501 23502 23503 23504 23505 23506 23507 23508 |
nCmd++;
azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
shell_check_oom(azCmd);
azCmd[nCmd-1] = z;
}
}
if( z[1]=='-' ) z++;
if( cli_strcmp(z,"-separator")==0
|| cli_strcmp(z,"-nullvalue")==0
|| cli_strcmp(z,"-newline")==0
|| cli_strcmp(z,"-cmd")==0
){
(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,"-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,"-heap")==0 ){
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
const char *zSize;
sqlite3_int64 szHeap;
zSize = cmdline_option_value(argc, argv, ++i);
szHeap = integerValue(zSize);
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
#else
(void)cmdline_option_value(argc, argv, ++i);
#endif
}else if( cli_strcmp(z,"-pagecache")==0 ){
sqlite3_int64 n, sz;
sz = integerValue(cmdline_option_value(argc,argv,++i));
if( sz>70000 ) sz = 70000;
if( sz<0 ) sz = 0;
n = integerValue(cmdline_option_value(argc,argv,++i));
if( sz>0 && n>0 && 0xffffffffffffLL/sz<n ){
n = 0xffffffffffffLL/sz;
}
sqlite3_config(SQLITE_CONFIG_PAGECACHE,
(n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
data.shellFlgs |= SHFLG_Pagecache;
}else if( cli_strcmp(z,"-lookaside")==0 ){
int n, sz;
sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
if( sz<0 ) sz = 0;
n = (int)integerValue(cmdline_option_value(argc,argv,++i));
if( n<0 ) n = 0;
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
}else if( cli_strcmp(z,"-threadsafe")==0 ){
int n;
n = (int)integerValue(cmdline_option_value(argc,argv,++i));
switch( n ){
case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break;
case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break;
default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break;
}
#ifdef SQLITE_ENABLE_VFSTRACE
}else if( cli_strcmp(z,"-vfstrace")==0 ){
extern int vfstrace_register(
const char *zTraceName,
const char *zOldVfsName,
int (*xOut)(const char*,void*),
void *pOutArg,
int makeDefault
);
vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( cli_strcmp(z,"-multiplex")==0 ){
extern int sqlite3_multiple_initialize(const char*,int);
sqlite3_multiplex_initialize(0, 1);
#endif
}else if( cli_strcmp(z,"-mmap")==0 ){
sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
}else if( cli_strcmp(z,"-sorterref")==0 ){
sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz);
#endif
}else if( cli_strcmp(z,"-vfs")==0 ){
zVfs = cmdline_option_value(argc, argv, ++i);
#ifdef SQLITE_HAVE_ZLIB
}else if( cli_strcmp(z,"-zip")==0 ){
data.openMode = SHELL_OPEN_ZIPFILE;
#endif
}else if( cli_strcmp(z,"-append")==0 ){
data.openMode = SHELL_OPEN_APPENDVFS;
#ifndef SQLITE_OMIT_DESERIALIZE
}else if( cli_strcmp(z,"-deserialize")==0 ){
data.openMode = SHELL_OPEN_DESERIALIZE;
}else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
data.szMax = integerValue(argv[++i]);
#endif
}else if( cli_strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
}else if( cli_strcmp(z,"-nofollow")==0 ){
data.openFlags = SQLITE_OPEN_NOFOLLOW;
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
}else if( cli_strncmp(z, "-A",2)==0 ){
/* All remaining command-line arguments are passed to the ".archive"
** command, so ignore them */
break;
#endif
}else if( cli_strcmp(z, "-memtrace")==0 ){
sqlite3MemTraceActivate(stderr);
}else if( cli_strcmp(z,"-bail")==0 ){
bail_on_error = 1;
}else if( cli_strcmp(z,"-nonce")==0 ){
free(data.zNonce);
data.zNonce = strdup(argv[++i]);
}else if( cli_strcmp(z,"-safe")==0 ){
/* no-op - catch this on the second pass */
}
}
verify_uninitialized();
#ifdef SQLITE_SHELL_INIT_PROC
|
| ︙ | ︙ | |||
23359 23360 23361 23362 23363 23364 23365 |
warnInmemoryDb = argc==1;
#else
utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
return 1;
#endif
}
data.out = stdout;
| | | 23536 23537 23538 23539 23540 23541 23542 23543 23544 23545 23546 23547 23548 23549 23550 |
warnInmemoryDb = argc==1;
#else
utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
return 1;
#endif
}
data.out = stdout;
#ifndef SQLITE_SHELL_FIDDLE
sqlite3_appendvfs_init(0,0,0);
#endif
/* Go ahead and open the database file if it already exists. If the
** file does not exist, delay opening it. This prevents empty database
** files from being created if a user mistypes the database name argument
** to the sqlite command-line tool.
|
| ︙ | ︙ | |||
23387 23388 23389 23390 23391 23392 23393 |
** file is processed so that the command-line arguments will override
** settings in the initialization file.
*/
for(i=1; i<argc; i++){
char *z = argv[i];
if( z[0]!='-' ) continue;
if( z[1]=='-' ){ z++; }
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 23564 23565 23566 23567 23568 23569 23570 23571 23572 23573 23574 23575 23576 23577 23578 23579 23580 23581 23582 23583 23584 23585 23586 23587 23588 23589 23590 23591 23592 23593 23594 23595 23596 23597 23598 23599 23600 23601 23602 23603 23604 23605 23606 23607 23608 23609 23610 23611 23612 23613 23614 23615 23616 23617 23618 23619 23620 23621 23622 23623 23624 23625 23626 23627 23628 23629 23630 23631 23632 23633 23634 23635 23636 23637 23638 23639 23640 23641 23642 23643 23644 23645 23646 23647 23648 23649 23650 23651 23652 23653 23654 23655 23656 23657 23658 23659 23660 23661 23662 23663 23664 23665 23666 23667 23668 23669 23670 23671 23672 23673 23674 23675 23676 23677 23678 23679 23680 23681 23682 23683 23684 23685 23686 23687 23688 23689 23690 23691 23692 23693 23694 23695 23696 23697 23698 |
** file is processed so that the command-line arguments will override
** settings in the initialization file.
*/
for(i=1; i<argc; i++){
char *z = argv[i];
if( z[0]!='-' ) continue;
if( z[1]=='-' ){ z++; }
if( cli_strcmp(z,"-init")==0 ){
i++;
}else if( cli_strcmp(z,"-html")==0 ){
data.mode = MODE_Html;
}else if( cli_strcmp(z,"-list")==0 ){
data.mode = MODE_List;
}else if( cli_strcmp(z,"-quote")==0 ){
data.mode = MODE_Quote;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
}else if( cli_strcmp(z,"-line")==0 ){
data.mode = MODE_Line;
}else if( cli_strcmp(z,"-column")==0 ){
data.mode = MODE_Column;
}else if( cli_strcmp(z,"-json")==0 ){
data.mode = MODE_Json;
}else if( cli_strcmp(z,"-markdown")==0 ){
data.mode = MODE_Markdown;
}else if( cli_strcmp(z,"-table")==0 ){
data.mode = MODE_Table;
}else if( cli_strcmp(z,"-box")==0 ){
data.mode = MODE_Box;
}else if( cli_strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);
#ifdef SQLITE_HAVE_ZLIB
}else if( cli_strcmp(z,"-zip")==0 ){
data.openMode = SHELL_OPEN_ZIPFILE;
#endif
}else if( cli_strcmp(z,"-append")==0 ){
data.openMode = SHELL_OPEN_APPENDVFS;
#ifndef SQLITE_OMIT_DESERIALIZE
}else if( cli_strcmp(z,"-deserialize")==0 ){
data.openMode = SHELL_OPEN_DESERIALIZE;
}else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
data.szMax = integerValue(argv[++i]);
#endif
}else if( cli_strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
}else if( cli_strcmp(z,"-nofollow")==0 ){
data.openFlags |= SQLITE_OPEN_NOFOLLOW;
}else if( cli_strcmp(z,"-ascii")==0 ){
data.mode = MODE_Ascii;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Unit);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Record);
}else if( cli_strcmp(z,"-tabs")==0 ){
data.mode = MODE_List;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Tab);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
}else if( cli_strcmp(z,"-separator")==0 ){
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
"%s",cmdline_option_value(argc,argv,++i));
}else if( cli_strcmp(z,"-newline")==0 ){
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
"%s",cmdline_option_value(argc,argv,++i));
}else if( cli_strcmp(z,"-nullvalue")==0 ){
sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
"%s",cmdline_option_value(argc,argv,++i));
}else if( cli_strcmp(z,"-header")==0 ){
data.showHeader = 1;
ShellSetFlag(&data, SHFLG_HeaderSet);
}else if( cli_strcmp(z,"-noheader")==0 ){
data.showHeader = 0;
ShellSetFlag(&data, SHFLG_HeaderSet);
}else if( cli_strcmp(z,"-echo")==0 ){
ShellSetFlag(&data, SHFLG_Echo);
}else if( cli_strcmp(z,"-eqp")==0 ){
data.autoEQP = AUTOEQP_on;
}else if( cli_strcmp(z,"-eqpfull")==0 ){
data.autoEQP = AUTOEQP_full;
}else if( cli_strcmp(z,"-stats")==0 ){
data.statsOn = 1;
}else if( cli_strcmp(z,"-scanstats")==0 ){
data.scanstatsOn = 1;
}else if( cli_strcmp(z,"-backslash")==0 ){
/* Undocumented command-line option: -backslash
** Causes C-style backslash escapes to be evaluated in SQL statements
** prior to sending the SQL into SQLite. Useful for injecting
** crazy bytes in the middle of SQL statements for testing and debugging.
*/
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 ){
printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
return 0;
}else if( cli_strcmp(z,"-interactive")==0 ){
stdin_is_interactive = 1;
}else if( cli_strcmp(z,"-batch")==0 ){
stdin_is_interactive = 0;
}else if( cli_strcmp(z,"-heap")==0 ){
i++;
}else if( cli_strcmp(z,"-pagecache")==0 ){
i+=2;
}else if( cli_strcmp(z,"-lookaside")==0 ){
i+=2;
}else if( cli_strcmp(z,"-threadsafe")==0 ){
i+=2;
}else if( cli_strcmp(z,"-nonce")==0 ){
i += 2;
}else if( cli_strcmp(z,"-mmap")==0 ){
i++;
}else if( cli_strcmp(z,"-memtrace")==0 ){
i++;
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
}else if( cli_strcmp(z,"-sorterref")==0 ){
i++;
#endif
}else if( cli_strcmp(z,"-vfs")==0 ){
i++;
#ifdef SQLITE_ENABLE_VFSTRACE
}else if( cli_strcmp(z,"-vfstrace")==0 ){
i++;
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
}else if( cli_strcmp(z,"-multiplex")==0 ){
i++;
#endif
}else if( cli_strcmp(z,"-help")==0 ){
usage(1);
}else if( cli_strcmp(z,"-cmd")==0 ){
/* Run commands that follow -cmd first and separately from commands
** that simply appear on the command-line. This seems goofy. It would
** be better if all commands ran in the order that they appear. But
** we retain the goofy behavior for historical compatibility. */
if( i==argc-1 ) break;
z = cmdline_option_value(argc,argv,++i);
if( z[0]=='.' ){
|
| ︙ | ︙ | |||
23529 23530 23531 23532 23533 23534 23535 |
if( bail_on_error ) return rc!=0 ? rc : 1;
}else if( rc!=0 ){
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)
| | | | 23706 23707 23708 23709 23710 23711 23712 23713 23714 23715 23716 23717 23718 23719 23720 23721 23722 23723 23724 23725 23726 23727 23728 23729 23730 23731 23732 23733 23734 23735 23736 |
if( bail_on_error ) return rc!=0 ? rc : 1;
}else if( rc!=0 ){
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 ){
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];
arDotCommand(&data, 1, argv+(i-1), argc-(i-1));
}else{
arDotCommand(&data, 1, argv+i, argc-i);
}
readStdin = 0;
break;
#endif
}else if( cli_strcmp(z,"-safe")==0 ){
data.bSafeMode = data.bSafeModePersist = 1;
}else{
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;
|
| ︙ | ︙ | |||
23627 23628 23629 23630 23631 23632 23633 |
free(zHistory);
}
}else{
data.in = stdin;
rc = process_input(&data);
}
}
| | | 23804 23805 23806 23807 23808 23809 23810 23811 23812 23813 23814 23815 23816 23817 23818 |
free(zHistory);
}
}else{
data.in = stdin;
rc = process_input(&data);
}
}
#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. */
free(azCmd);
set_table_name(&data, 0);
if( data.db ){
session_close_all(&data, -1);
close_db(data.db);
|
| ︙ | ︙ | |||
23662 23663 23664 23665 23666 23667 23668 |
memset(&data, 0, sizeof(data));
#ifdef SQLITE_DEBUG
if( sqlite3_memory_used()>mem_main_enter ){
utf8_printf(stderr, "Memory leaked: %u bytes\n",
(unsigned int)(sqlite3_memory_used()-mem_main_enter));
}
#endif
| | | | | | < | < | < > | < < < | < > > > > | < | < | > > > | > | < < | < > < | > | > > > | > > > > > > > > > > > | | | < < > > | | > > > > > > > > > > > > > < > > > > > > > | | < < < < | | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | 23839 23840 23841 23842 23843 23844 23845 23846 23847 23848 23849 23850 23851 23852 23853 23854 23855 23856 23857 23858 23859 23860 23861 23862 23863 23864 23865 23866 23867 23868 23869 23870 23871 23872 23873 23874 23875 23876 23877 23878 23879 23880 23881 23882 23883 23884 23885 23886 23887 23888 23889 23890 23891 23892 23893 23894 23895 23896 23897 23898 23899 23900 23901 23902 23903 23904 23905 23906 23907 23908 23909 23910 23911 23912 23913 23914 23915 23916 23917 23918 23919 23920 23921 23922 23923 23924 23925 23926 23927 23928 23929 23930 23931 23932 23933 23934 23935 23936 23937 23938 23939 23940 23941 23942 23943 23944 23945 23946 23947 23948 23949 23950 23951 23952 23953 23954 23955 23956 23957 23958 23959 23960 23961 23962 23963 23964 23965 23966 23967 23968 23969 23970 23971 23972 23973 |
memset(&data, 0, sizeof(data));
#ifdef SQLITE_DEBUG
if( 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;
}
#ifdef SQLITE_SHELL_FIDDLE
/* Only for emcc experimentation purposes. */
int fiddle_experiment(int a,int b){
return a + b;
}
/*
** Returns a pointer to the current DB handle.
*/
sqlite3 * fiddle_db_handle(){
return globalDb;
}
/*
** Returns a pointer to the given DB name's VFS. If zDbName is 0 then
** "main" is assumed. Returns 0 if no db with the given name is
** open.
*/
sqlite3_vfs * fiddle_db_vfs(const char *zDbName){
sqlite3_vfs * pVfs = 0;
if(globalDb){
sqlite3_file_control(globalDb, zDbName ? zDbName : "main",
SQLITE_FCNTL_VFS_POINTER, &pVfs);
}
return pVfs;
}
/* Only for emcc experimentation purposes. */
sqlite3 * fiddle_db_arg(sqlite3 *arg){
printf("fiddle_db_arg(%p)\n", (const void*)arg);
return arg;
}
/*
** Intended to be called via a SharedWorker() while a separate
** SharedWorker() (which manages the wasm module) is performing work
** which should be interrupted. Unfortunately, SharedWorker is not
** portable enough to make real use of.
*/
void fiddle_interrupt(void){
if( globalDb ) sqlite3_interrupt(globalDb);
}
/*
** Returns the filename of the given db name, assuming "main" if
** zDbName is NULL. Returns NULL if globalDb is not opened.
*/
const char * fiddle_db_filename(const char * zDbName){
return globalDb
? sqlite3_db_filename(globalDb, zDbName ? zDbName : "main")
: NULL;
}
/*
** Completely wipes out the contents of the currently-opened database
** but leaves its storage intact for reuse.
*/
void fiddle_reset_db(void){
if( globalDb ){
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);
}
}
/*
** Uses the current database's VFS xRead to stream the db file's
** contents out to the given callback. The callback gets a single
** chunk of size n (its 2nd argument) on each call and must return 0
** on success, non-0 on error. This function returns 0 on success,
** SQLITE_NOTFOUND if no db is open, or propagates any other non-0
** code from the callback. Note that this is not thread-friendly: it
** expects that it will be the only thread reading the db file and
** takes no measures to ensure that is the case.
*/
int fiddle_export_db( int (*xCallback)(unsigned const char *zOut, int n) ){
sqlite3_int64 nSize = 0;
sqlite3_int64 nPos = 0;
sqlite3_file * pFile = 0;
unsigned char buf[1024 * 8];
int nBuf = (int)sizeof(buf);
int rc = shellState.db
? sqlite3_file_control(shellState.db, "main",
SQLITE_FCNTL_FILE_POINTER, &pFile)
: SQLITE_NOTFOUND;
if( rc ) return rc;
rc = pFile->pMethods->xFileSize(pFile, &nSize);
if( rc ) return rc;
if(nSize % nBuf){
/* DB size is not an even multiple of the buffer size. Reduce
** buffer size so that we do not unduly inflate the db size when
** exporting. */
if(0 == nSize % 4096) nBuf = 4096;
else if(0 == nSize % 2048) nBuf = 2048;
else if(0 == nSize % 1024) nBuf = 1024;
else nBuf = 512;
}
for( ; 0==rc && nPos<nSize; nPos += nBuf ){
rc = pFile->pMethods->xRead(pFile, buf, nBuf, nPos);
if(SQLITE_IOERR_SHORT_READ == rc){
rc = (nPos + nBuf) < nSize ? rc : 0/*assume EOF*/;
}
if( 0==rc ) rc = xCallback(buf, nBuf);
}
return rc;
}
/*
** Trivial exportable function for emscripten. It processes zSql as if
** it were input to the sqlite3 shell and redirects all output to the
** wasm binding. fiddle_main() must have been called before this
** is called, or results are undefined.
*/
void fiddle_exec(const char * zSql){
if(zSql && *zSql){
if('.'==*zSql) puts(zSql);
shellState.wasm.zInput = zSql;
shellState.wasm.zPos = zSql;
process_input(&shellState);
shellState.wasm.zInput = shellState.wasm.zPos = 0;
}
}
#endif /* SQLITE_SHELL_FIDDLE */
|
Changes to extsrc/sqlite3.c.
1 2 | /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite | | | 1 2 3 4 5 6 7 8 9 10 | /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite ** version 3.40.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. ** ** This file is all you need to compile SQLite. To use SQLite in other |
| ︙ | ︙ | |||
448 449 450 451 452 453 454 | ** been edited in any way since it was last checked in, then the last ** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ | | | | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | ** been edited in any way since it was last checked in, then the last ** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.40.0" #define SQLITE_VERSION_NUMBER 3040000 #define SQLITE_SOURCE_ID "2022-10-26 11:11:31 3dfdfb3f12edb3f4267942598efd05d573e13b7c5d6cdbc3404373f41b8993dd" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ | |||
972 973 974 975 976 977 978 | #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods | | > > > > | | | | | | 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 | #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods ** of an [sqlite3_io_methods] object. These values are ordered from ** lest restrictive to most restrictive. ** ** The argument to xLock() is always SHARED or higher. The argument to ** xUnlock is either SHARED or NONE. */ #define SQLITE_LOCK_NONE 0 /* xUnlock() only */ #define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */ #define SQLITE_LOCK_RESERVED 2 /* xLock() only */ #define SQLITE_LOCK_PENDING 3 /* xLock() only */ #define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */ /* ** CAPI3REF: Synchronization Type Flags ** ** When SQLite invokes the xSync() method of an ** [sqlite3_io_methods] object it uses a combination of ** these integer values as the second argument. |
| ︙ | ︙ | |||
1056 1057 1058 1059 1060 1061 1062 | ** <ul> ** <li> [SQLITE_LOCK_NONE], ** <li> [SQLITE_LOCK_SHARED], ** <li> [SQLITE_LOCK_RESERVED], ** <li> [SQLITE_LOCK_PENDING], or ** <li> [SQLITE_LOCK_EXCLUSIVE]. ** </ul> | > > > > > > > | | 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 | ** <ul> ** <li> [SQLITE_LOCK_NONE], ** <li> [SQLITE_LOCK_SHARED], ** <li> [SQLITE_LOCK_RESERVED], ** <li> [SQLITE_LOCK_PENDING], or ** <li> [SQLITE_LOCK_EXCLUSIVE]. ** </ul> ** 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 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 ** 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. ** ** The xFileControl() method is a generic interface that allows custom ** VFS implementations to directly control an open file using the |
| ︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 | ** ** <ul> ** <li>[[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) | | | < | 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 | ** ** <ul> ** <li>[[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. ** This capability is only available if SQLite is compiled with [SQLITE_DEBUG]. ** ** <li>[[SQLITE_FCNTL_SIZE_HINT]] ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the ** current transaction. This hint is not guaranteed to be accurate but it ** is often close. The underlying VFS might choose to preallocate database ** file space based on this hint in order to help writes to the database |
| ︙ | ︙ | |||
3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 | ** (Mutexes will block any actual concurrency, but in this mode ** there is no harm in trying.) ** ** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt> ** <dd>The database is opened [shared cache] enabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** ** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt> ** <dd>The database is opened [shared cache] disabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** ** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt> ** <dd>The database connection comes up in "extended result code mode". ** In other words, the database behaves has if ** [sqlite3_extended_result_codes(db,1)] where called on the database ** connection as soon as the connection is created. In addition to setting ** the extended result code mode, this flag also causes [sqlite3_open_v2()] ** to return an extended result code.</dd> ** ** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt> | > > > | | 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 | ** (Mutexes will block any actual concurrency, but in this mode ** there is no harm in trying.) ** ** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt> ** <dd>The database is opened [shared cache] enabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** The [use of shared cache mode is discouraged] and hence shared cache ** capabilities may be omitted from many builds of SQLite. In such cases, ** this option is a no-op. ** ** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt> ** <dd>The database is opened [shared cache] disabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** ** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt> ** <dd>The database connection comes up in "extended result code mode". ** In other words, the database behaves has if ** [sqlite3_extended_result_codes(db,1)] where called on the database ** connection as soon as the connection is created. In addition to setting ** the extended result code mode, this flag also causes [sqlite3_open_v2()] ** to return an extended result code.</dd> ** ** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt> ** <dd>The database filename is not allowed to contain a symbolic link</dd> ** </dl>)^ ** ** If the 3rd parameter to sqlite3_open_v2() is not one of the ** required combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] ** then the behavior is undefined. Historic versions of SQLite ** have silently ignored surplus bits in the flags parameter to |
| ︙ | ︙ | |||
5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 | ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If ** such a conversion is possible without loss of information (in other ** words, if the value is a string that looks like a number) ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** ** ^Within the [xUpdate] method of a [virtual table], the ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation ** that the xUpdate method call was invoked to implement and if ** and the prior [xColumn] method call that was invoked to extracted ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column | > > > > > > > > > > | 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 | ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If ** such a conversion is possible without loss of information (in other ** words, if the value is a string that looks like a number) ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** ** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8], ** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current encoding ** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) ** returns something other than SQLITE_TEXT, then the return value from ** sqlite3_value_encoding(X) is meaningless. ^Calls to ** sqlite3_value_text(X), sqlite3_value_text16(X), sqlite3_value_text16be(X), ** sqlite3_value_text16le(X), sqlite3_value_bytes(X), or ** sqlite3_value_bytes16(X) might change the encoding of the value X and ** thus change the return from subsequent calls to sqlite3_value_encoding(X). ** ** ^Within the [xUpdate] method of a [virtual table], the ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation ** that the xUpdate method call was invoked to implement and if ** and the prior [xColumn] method call that was invoked to extracted ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column |
| ︙ | ︙ | |||
5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 | SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); SQLITE_API int sqlite3_value_bytes(sqlite3_value*); SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values ** METHOD: sqlite3_value ** ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype | > | 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 | SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); SQLITE_API int sqlite3_value_bytes(sqlite3_value*); SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); SQLITE_API int sqlite3_value_frombind(sqlite3_value*); SQLITE_API int sqlite3_value_encoding(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values ** METHOD: sqlite3_value ** ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype |
| ︙ | ︙ | |||
5927 5928 5929 5930 5931 5932 5933 | ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory | | | 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 | ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory ** allocation error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the ** value of N in any subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no |
| ︙ | ︙ | |||
6767 6768 6769 6770 6771 6772 6773 | ** CAPI3REF: Autovacuum Compaction Amount Callback ** METHOD: sqlite3 ** ** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback ** function C that is invoked prior to each autovacuum of the database ** file. ^The callback is passed a copy of the generic data pointer (P), ** the schema-name of the attached database that is being autovacuumed, | | | 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 | ** CAPI3REF: Autovacuum Compaction Amount Callback ** METHOD: sqlite3 ** ** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback ** function C that is invoked prior to each autovacuum of the database ** file. ^The callback is passed a copy of the generic data pointer (P), ** the schema-name of the attached database that is being autovacuumed, ** the size of the database file in pages, the number of free pages, ** and the number of bytes per page, respectively. The callback should ** return the number of free pages that should be removed by the ** autovacuum. ^If the callback returns zero, then no autovacuum happens. ** ^If the value returned is greater than or equal to the number of ** free pages, then a complete autovacuum happens. ** ** <p>^If there are multiple ATTACH-ed database files that are being |
| ︙ | ︙ | |||
6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 | /* ** CAPI3REF: Enable Or Disable Shared Pager Cache ** ** ^(This routine enables or disables the sharing of the database cache ** and schema data structures between [database connection | connections] ** to the same database. Sharing is enabled if the argument is true ** and disabled if the argument is false.)^ ** ** ^Cache sharing is enabled and disabled for an entire process. ** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). ** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent | > > > > > | 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 | /* ** CAPI3REF: Enable Or Disable Shared Pager Cache ** ** ^(This routine enables or disables the sharing of the database cache ** and schema data structures between [database connection | connections] ** to the same database. Sharing is enabled if the argument is true ** and disabled if the argument is false.)^ ** ** This interface is omitted if SQLite is compiled with ** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE] ** compile-time option is recommended because the ** [use of shared cache mode is discouraged]. ** ** ^Cache sharing is enabled and disabled for an entire process. ** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). ** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent |
| ︙ | ︙ | |||
6986 6987 6988 6989 6990 6991 6992 | ** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). ** ** ^Setting the heap limits to zero disables the heap limiter mechanism. ** ** ^The soft heap limit may not be greater than the hard heap limit. ** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) ** is invoked with a value of N that is greater than the hard heap limit, | | | 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 | ** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). ** ** ^Setting the heap limits to zero disables the heap limiter mechanism. ** ** ^The soft heap limit may not be greater than the hard heap limit. ** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) ** is invoked with a value of N that is greater than the hard heap limit, ** the soft heap limit is set to the value of the hard heap limit. ** ^The soft heap limit is automatically enabled whenever the hard heap ** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and ** the soft heap limit is outside the range of 1..N, then the soft heap ** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the ** hard heap limit is enabled makes the soft heap limit equal to the ** hard heap limit. ** |
| ︙ | ︙ | |||
9281 9282 9283 9284 9285 9286 9287 | ** However, the application must guarantee that the destination ** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] ** and so no error code is reported, but the operations may malfunction ** nevertheless. Use of the destination database connection while a | | | 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 | ** However, the application must guarantee that the destination ** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] ** and so no error code is reported, but the operations may malfunction ** nevertheless. Use of the destination database connection while a ** backup is in progress might also cause a mutex deadlock. ** ** If running in [shared cache mode], the application must ** guarantee that the shared cache used by the destination database ** is not accessed while the backup is running. In practice this means ** that the application must guarantee that the disk file being ** backed up to is not accessed by any connection within the process, ** not just the specific connection that was passed to sqlite3_backup_init(). |
| ︙ | ︙ | |||
9709 9710 9711 9712 9713 9714 9715 | ** These constants define all valid values for the "checkpoint mode" passed ** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ | | | 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 | ** These constants define all valid values for the "checkpoint mode" passed ** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ #define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */ #define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */ /* ** CAPI3REF: Virtual Table Interface Configuration ** ** This function may be called by either the [xConnect] or [xCreate] method ** of a [virtual table] implementation to configure |
| ︙ | ︙ | |||
13140 13141 13142 13143 13144 13145 13146 13147 13148 13149 13150 13151 | #endif /* _FTS5_H */ /******** End of fts5.h *********/ /************** End of sqlite3.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ #if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) | > > > > > | | 13169 13170 13171 13172 13173 13174 13175 13176 13177 13178 13179 13180 13181 13182 13183 13184 13185 13186 13187 13188 13189 13190 13191 13192 13193 | #endif /* _FTS5_H */ /******** End of fts5.h *********/ /************** End of sqlite3.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* ** Reuse the STATIC_LRU for mutex access to sqlite3_temp_directory. */ #define SQLITE_MUTEX_STATIC_TEMPDIR SQLITE_MUTEX_STATIC_VFS1 /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ #if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) #include "sqlite_cfg.h" #define SQLITECONFIG_H 1 #endif /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/ /************** Begin file sqliteLimit.h *************************************/ /* ** 2007 May 7 |
| ︙ | ︙ | |||
14628 14629 14630 14631 14632 14633 14634 14635 14636 14637 14638 14639 14640 14641 | typedef struct ExprList ExprList; typedef struct FKey FKey; typedef struct FuncDestructor FuncDestructor; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; typedef struct IdList IdList; typedef struct Index Index; typedef struct IndexSample IndexSample; typedef struct KeyClass KeyClass; typedef struct KeyInfo KeyInfo; typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; | > | 14662 14663 14664 14665 14666 14667 14668 14669 14670 14671 14672 14673 14674 14675 14676 | typedef struct ExprList ExprList; typedef struct FKey FKey; typedef struct FuncDestructor FuncDestructor; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; typedef struct IdList IdList; typedef struct Index Index; typedef struct IndexedExpr IndexedExpr; typedef struct IndexSample IndexSample; typedef struct KeyClass KeyClass; typedef struct KeyInfo KeyInfo; typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; |
| ︙ | ︙ | |||
14693 14694 14695 14696 14697 14698 14699 14700 14701 14702 14703 14704 14705 14706 14707 14708 14709 14710 14711 14712 14713 14714 14715 14716 14717 14718 14719 14720 | ** A bit in a Bitmask */ #define MASKBIT(n) (((Bitmask)1)<<(n)) #define MASKBIT64(n) (((u64)1)<<(n)) #define MASKBIT32(n) (((unsigned int)1)<<(n)) #define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0) #define ALLBITS ((Bitmask)-1) /* A VList object records a mapping between parameters/variables/wildcards ** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer ** variable number associated with that parameter. See the format description ** on the sqlite3VListAdd() routine for more information. A VList is really ** just an array of integers. */ typedef int VList; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque ** pointer types (i.e. FuncDef) defined above. */ /************** Include pager.h in the middle of sqliteInt.h *****************/ /************** Begin file pager.h *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 14728 14729 14730 14731 14732 14733 14734 14735 14736 14737 14738 14739 14740 14741 14742 14743 14744 14745 14746 14747 14748 14749 14750 14751 14752 14753 14754 14755 14756 14757 14758 14759 14760 14761 14762 14763 14764 14765 14766 14767 14768 14769 14770 14771 14772 14773 14774 14775 14776 14777 14778 14779 14780 14781 14782 14783 14784 14785 14786 14787 14788 14789 14790 14791 14792 14793 14794 14795 14796 14797 14798 14799 14800 14801 14802 14803 14804 14805 14806 14807 14808 14809 14810 14811 14812 14813 14814 14815 14816 14817 14818 14819 14820 14821 14822 14823 14824 14825 14826 14827 14828 14829 14830 14831 14832 14833 14834 14835 14836 14837 14838 14839 14840 14841 14842 14843 14844 14845 14846 14847 14848 14849 14850 14851 14852 14853 14854 14855 14856 14857 14858 14859 14860 14861 14862 14863 14864 14865 14866 14867 14868 14869 14870 14871 14872 14873 14874 14875 14876 14877 14878 14879 14880 14881 14882 14883 14884 14885 14886 14887 14888 14889 14890 14891 14892 14893 14894 14895 14896 14897 14898 14899 14900 14901 14902 14903 14904 14905 14906 14907 14908 14909 14910 14911 14912 14913 14914 14915 14916 14917 14918 14919 14920 14921 14922 14923 14924 14925 14926 14927 14928 14929 14930 14931 14932 14933 14934 14935 14936 14937 14938 14939 14940 14941 14942 14943 14944 14945 14946 14947 14948 14949 14950 14951 14952 14953 14954 14955 14956 14957 14958 14959 14960 14961 14962 14963 14964 14965 14966 14967 14968 14969 14970 14971 14972 14973 14974 14975 14976 14977 14978 14979 14980 14981 14982 14983 14984 14985 14986 14987 14988 14989 14990 14991 14992 14993 14994 14995 14996 14997 14998 14999 15000 15001 15002 15003 15004 15005 15006 15007 15008 15009 15010 15011 15012 15013 15014 15015 15016 15017 15018 15019 15020 15021 15022 15023 15024 15025 15026 15027 15028 15029 15030 15031 15032 15033 15034 15035 15036 15037 15038 15039 15040 15041 15042 15043 15044 15045 15046 15047 15048 15049 15050 15051 15052 15053 15054 15055 15056 15057 15058 15059 15060 15061 15062 15063 15064 15065 15066 15067 15068 15069 15070 15071 15072 15073 15074 15075 15076 15077 15078 15079 15080 15081 |
** A bit in a Bitmask
*/
#define MASKBIT(n) (((Bitmask)1)<<(n))
#define MASKBIT64(n) (((u64)1)<<(n))
#define MASKBIT32(n) (((unsigned int)1)<<(n))
#define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0)
#define ALLBITS ((Bitmask)-1)
#define TOPBIT (((Bitmask)1)<<(BMS-1))
/* A VList object records a mapping between parameters/variables/wildcards
** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
** variable number associated with that parameter. See the format description
** on the sqlite3VListAdd() routine for more information. A VList is really
** just an array of integers.
*/
typedef int VList;
/*
** Defer sourcing vdbe.h and btree.h until after the "u8" and
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
** pointer types (i.e. FuncDef) defined above.
*/
/************** Include os.h in the middle of sqliteInt.h ********************/
/************** Begin file os.h **********************************************/
/*
** 2001 September 16
**
** 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 header file (together with is companion C source-code file
** "os.c") attempt to abstract the underlying operating system so that
** the SQLite library will work on both POSIX and windows systems.
**
** This header file is #include-ed by sqliteInt.h and thus ends up
** being included by every source file.
*/
#ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_
/*
** Attempt to automatically detect the operating system and setup the
** necessary pre-processor macros for it.
*/
/************** Include os_setup.h in the middle of os.h *********************/
/************** Begin file os_setup.h ****************************************/
/*
** 2013 November 25
**
** 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 contains pre-processor directives related to operating system
** detection and/or setup.
*/
#ifndef SQLITE_OS_SETUP_H
#define SQLITE_OS_SETUP_H
/*
** Figure out if we are dealing with Unix, Windows, or some other operating
** system.
**
** After the following block of preprocess macros, all of
**
** SQLITE_OS_KV
** SQLITE_OS_OTHER
** SQLITE_OS_UNIX
** SQLITE_OS_WIN
**
** will defined to either 1 or 0. One of them will be 1. The others will be 0.
** If none of the macros are initially defined, then select either
** SQLITE_OS_UNIX or SQLITE_OS_WIN depending on the target platform.
**
** If SQLITE_OS_OTHER=1 is specified at compile-time, then the application
** must provide its own VFS implementation together with sqlite3_os_init()
** and sqlite3_os_end() routines.
*/
#if !defined(SQLITE_OS_KV) && !defined(SQLITE_OS_OTHER) && \
!defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_WIN)
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
defined(__MINGW32__) || defined(__BORLANDC__)
# define SQLITE_OS_WIN 1
# define SQLITE_OS_UNIX 0
# else
# define SQLITE_OS_WIN 0
# define SQLITE_OS_UNIX 1
# endif
#endif
#if SQLITE_OS_OTHER+1>1
# undef SQLITE_OS_KV
# define SQLITE_OS_KV 0
# undef SQLITE_OS_UNIX
# define SQLITE_OS_UNIX 0
# undef SQLITE_OS_WIN
# define SQLITE_OS_WIN 0
#endif
#if SQLITE_OS_KV+1>1
# undef SQLITE_OS_OTHER
# define SQLITE_OS_OTHER 0
# undef SQLITE_OS_UNIX
# define SQLITE_OS_UNIX 0
# undef SQLITE_OS_WIN
# define SQLITE_OS_WIN 0
# define SQLITE_OMIT_LOAD_EXTENSION 1
# define SQLITE_OMIT_WAL 1
# define SQLITE_OMIT_DEPRECATED 1
# undef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 3 /* Always use memory for temporary storage */
# define SQLITE_DQS 0
# define SQLITE_OMIT_SHARED_CACHE 1
# define SQLITE_OMIT_AUTOINIT 1
#endif
#if SQLITE_OS_UNIX+1>1
# undef SQLITE_OS_KV
# define SQLITE_OS_KV 0
# undef SQLITE_OS_OTHER
# define SQLITE_OS_OTHER 0
# undef SQLITE_OS_WIN
# define SQLITE_OS_WIN 0
#endif
#if SQLITE_OS_WIN+1>1
# undef SQLITE_OS_KV
# define SQLITE_OS_KV 0
# undef SQLITE_OS_OTHER
# define SQLITE_OS_OTHER 0
# undef SQLITE_OS_UNIX
# define SQLITE_OS_UNIX 0
#endif
#endif /* SQLITE_OS_SETUP_H */
/************** End of os_setup.h ********************************************/
/************** Continuing where we left off in os.h *************************/
/* If the SET_FULLSYNC macro is not defined above, then make it
** a no-op
*/
#ifndef SET_FULLSYNC
# define SET_FULLSYNC(x,y)
#endif
/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
*/
#ifndef SQLITE_MAX_PATHLEN
# define SQLITE_MAX_PATHLEN FILENAME_MAX
#endif
/* Maximum number of symlinks that will be resolved while trying to
** expand a filename in xFullPathname() in the VFS.
*/
#ifndef SQLITE_MAX_SYMLINK
# define SQLITE_MAX_SYMLINK 200
#endif
/*
** The default size of a disk sector
*/
#ifndef SQLITE_DEFAULT_SECTOR_SIZE
# define SQLITE_DEFAULT_SECTOR_SIZE 4096
#endif
/*
** Temporary files are named starting with this prefix followed by 16 random
** alphanumeric characters, and no file extension. They are stored in the
** OS's standard temporary file directory, and are deleted prior to exit.
** If sqlite is being embedded in another program, you may wish to change the
** prefix to reflect your program's name, so that if your program exits
** prematurely, old temporary files can be easily identified. This can be done
** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
**
** 2006-10-31: The default prefix used to be "sqlite_". But then
** Mcafee started using SQLite in their anti-virus product and it
** started putting files with the "sqlite" name in the c:/temp folder.
** This annoyed many windows users. Those users would then do a
** Google search for "sqlite", find the telephone numbers of the
** developers and call to wake them up at night and complain.
** For this reason, the default name prefix is changed to be "sqlite"
** spelled backwards. So the temp files are still identified, but
** anybody smart enough to figure out the code is also likely smart
** enough to know that calling the developer will not help get rid
** of the file.
*/
#ifndef SQLITE_TEMP_FILE_PREFIX
# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
#endif
/*
** The following values may be passed as the second argument to
** sqlite3OsLock(). The various locks exhibit the following semantics:
**
** SHARED: Any number of processes may hold a SHARED lock simultaneously.
** RESERVED: A single process may hold a RESERVED lock on a file at
** any time. Other processes may hold and obtain new SHARED locks.
** PENDING: A single process may hold a PENDING lock on a file at
** any one time. Existing SHARED locks may persist, but no new
** SHARED locks may be obtained by other processes.
** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
**
** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
** process that requests an EXCLUSIVE lock may actually obtain a PENDING
** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
** sqlite3OsLock().
*/
#define NO_LOCK 0
#define SHARED_LOCK 1
#define RESERVED_LOCK 2
#define PENDING_LOCK 3
#define EXCLUSIVE_LOCK 4
/*
** File Locking Notes: (Mostly about windows but also some info for Unix)
**
** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
** those functions are not available. So we use only LockFile() and
** UnlockFile().
**
** LockFile() prevents not just writing but also reading by other processes.
** A SHARED_LOCK is obtained by locking a single randomly-chosen
** byte out of a specific range of bytes. The lock byte is obtained at
** random so two separate readers can probably access the file at the
** same time, unless they are unlucky and choose the same lock byte.
** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
** There can only be one writer. A RESERVED_LOCK is obtained by locking
** a single byte of the file that is designated as the reserved lock byte.
** A PENDING_LOCK is obtained by locking a designated byte different from
** the RESERVED_LOCK byte.
**
** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
** which means we can use reader/writer locks. When reader/writer locks
** are used, the lock is placed on the same range of bytes that is used
** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
** will support two or more Win95 readers or two or more WinNT readers.
** But a single Win95 reader will lock out all WinNT readers and a single
** WinNT reader will lock out all other Win95 readers.
**
** The following #defines specify the range of bytes used for locking.
** SHARED_SIZE is the number of bytes available in the pool from which
** a random byte is selected for a shared lock. The pool of bytes for
** shared locks begins at SHARED_FIRST.
**
** The same locking strategy and
** byte ranges are used for Unix. This leaves open the possibility of having
** clients on win95, winNT, and unix all talking to the same shared file
** and all locking correctly. To do so would require that samba (or whatever
** tool is being used for file sharing) implements locks correctly between
** windows and unix. I'm guessing that isn't likely to happen, but by
** using the same locking range we are at least open to the possibility.
**
** Locking in windows is manditory. For this reason, we cannot store
** actual data in the bytes used for locking. The pager never allocates
** the pages involved in locking therefore. SHARED_SIZE is selected so
** that all locks will fit on a single page even at the minimum page size.
** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
** is set high so that we don't have to allocate an unused page except
** for very large databases. But one should test the page skipping logic
** by setting PENDING_BYTE low and running the entire regression suite.
**
** Changing the value of PENDING_BYTE results in a subtly incompatible
** file format. Depending on how it is changed, you might not notice
** the incompatibility right away, even running a full regression test.
** The default location of PENDING_BYTE is the first byte past the
** 1GB boundary.
**
*/
#ifdef SQLITE_OMIT_WSD
# define PENDING_BYTE (0x40000000)
#else
# define PENDING_BYTE sqlite3PendingByte
#endif
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
/*
** Wrapper around OS specific sqlite3_os_init() function.
*/
SQLITE_PRIVATE int sqlite3OsInit(void);
/*
** Functions for accessing sqlite3_file methods
*/
SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int);
SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int);
SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int);
SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut);
SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*);
SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
#ifndef SQLITE_OMIT_WAL
SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
#endif /* SQLITE_OMIT_WAL */
SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
/*
** Functions for accessing sqlite3_vfs methods
*/
SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
#ifndef SQLITE_OMIT_LOAD_EXTENSION
SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *);
SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);
SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
/*
** Convenience functions for opening and closing files using
** sqlite3_malloc() to obtain space for the file-handle structure.
*/
SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
#endif /* _SQLITE_OS_H_ */
/************** End of os.h **************************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include pager.h in the middle of sqliteInt.h *****************/
/************** Begin file pager.h *******************************************/
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
|
| ︙ | ︙ | |||
15551 15552 15553 15554 15555 15556 15557 | #define OP_AutoCommit 1 #define OP_Transaction 2 #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] */ | > | | | | | | | | | | < > | | | | | | | | | | | | | | | | | | | < | | | > | | | | < > | | | | | < | 15912 15913 15914 15915 15916 15917 15918 15919 15920 15921 15922 15923 15924 15925 15926 15927 15928 15929 15930 15931 15932 15933 15934 15935 15936 15937 15938 15939 15940 15941 15942 15943 15944 15945 15946 15947 15948 15949 15950 15951 15952 15953 15954 15955 15956 15957 15958 15959 15960 15961 15962 15963 15964 15965 15966 15967 15968 15969 15970 15971 15972 15973 15974 15975 15976 15977 15978 15979 15980 15981 15982 | #define OP_AutoCommit 1 #define OP_Transaction 2 #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 /* jump, synopsis: Start at P2 */ #define OP_Goto 9 /* jump */ #define OP_Gosub 10 /* jump */ #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 /* 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 /* jump, synopsis: intkey=r[P3] */ #define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */ #define OP_Last 32 /* jump */ #define OP_IfSmaller 33 /* jump */ #define OP_SorterSort 34 /* jump */ #define OP_Sort 35 /* jump */ #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] */ #define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */ #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 /* 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] */ #define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */ #define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */ #define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */ #define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */ #define OP_ElseEq 58 /* jump, same as TK_ESCAPE */ #define OP_IfPos 59 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ #define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ #define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */ #define OP_IncrVacuum 62 /* jump */ #define OP_VNext 63 /* jump */ #define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ #define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */ #define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */ #define OP_Return 67 #define OP_EndCoroutine 68 #define OP_HaltIfNull 69 /* synopsis: if r[P3]=null halt */ #define OP_Halt 70 #define OP_Integer 71 /* synopsis: r[P2]=P1 */ |
| ︙ | ︙ | |||
15743 15744 15745 15746 15747 15748 15749 |
#define OPFLG_IN1 0x02 /* in1: P1 is an input */
#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_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\
| | | | | | | | 16104 16105 16106 16107 16108 16109 16110 16111 16112 16113 16114 16115 16116 16117 16118 16119 16120 16121 16122 16123 16124 |
#define OPFLG_IN1 0x02 /* in1: P1 is an input */
#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_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\
/* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\
/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x09, 0x09, 0x09,\
/* 24 */ 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
/* 32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
/* 40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x01, 0x23, 0x0b,\
/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x01,\
/* 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, 0x00, 0x00,\
/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x26, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
/* 112 */ 0x00, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00,\
|
| ︙ | ︙ | |||
15841 15842 15843 15844 15845 15846 15847 15848 15849 15850 15851 15852 15853 15854 15855 15856 15857 15858 15859 15860 15861 15862 15863 15864 15865 15866 15867 15868 | #endif SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16); SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3); SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5); SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr); SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr); SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask, int); #else # define sqlite3VdbeReleaseRegisters(P,A,N,M,F) #endif SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type); SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*); SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*); SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int); | > > | 16202 16203 16204 16205 16206 16207 16208 16209 16210 16211 16212 16213 16214 16215 16216 16217 16218 16219 16220 16221 16222 16223 16224 16225 16226 16227 16228 16229 16230 16231 | #endif SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16); SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3); SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5); SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe*, int); SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr); SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr); SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask, int); #else # define sqlite3VdbeReleaseRegisters(P,A,N,M,F) #endif SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type); SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*); SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*); SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int); |
| ︙ | ︙ | |||
16203 16204 16205 16206 16207 16208 16209 | SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache); #endif #endif /* _PCACHE_H_ */ /************** End of pcache.h **********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 16566 16567 16568 16569 16570 16571 16572 16573 16574 16575 16576 16577 16578 16579 | SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache); #endif #endif /* _PCACHE_H_ */ /************** End of pcache.h **********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include mutex.h in the middle of sqliteInt.h *****************/ /************** Begin file mutex.h *******************************************/ /* ** 2007 August 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: |
| ︙ | ︙ | |||
16739 16740 16741 16742 16743 16744 16745 16746 16747 16748 16749 16750 16751 16752 |
LookasideSlot *pSmallInit; /* List of small buffers not prediously used */
LookasideSlot *pSmallFree; /* List of available small buffers */
void *pMiddle; /* First byte past end of full-size buffers and
** the first byte of LOOKASIDE_SMALL buffers */
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
};
struct LookasideSlot {
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
};
#define DisableLookaside db->lookaside.bDisable++;db->lookaside.sz=0
#define EnableLookaside db->lookaside.bDisable--;\
| > | 16811 16812 16813 16814 16815 16816 16817 16818 16819 16820 16821 16822 16823 16824 16825 |
LookasideSlot *pSmallInit; /* List of small buffers not prediously used */
LookasideSlot *pSmallFree; /* List of available small buffers */
void *pMiddle; /* First byte past end of full-size buffers and
** the first byte of LOOKASIDE_SMALL buffers */
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
void *pTrueEnd; /* True value of pEnd, when db->pnBytesFreed!=0 */
};
struct LookasideSlot {
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
};
#define DisableLookaside db->lookaside.bDisable++;db->lookaside.sz=0
#define EnableLookaside db->lookaside.bDisable--;\
|
| ︙ | ︙ | |||
17083 17084 17085 17086 17087 17088 17089 17090 17091 17092 17093 17094 17095 17096 | /* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */ #define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */ #define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */ #define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */ #define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */ #define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) #define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) | > | 17156 17157 17158 17159 17160 17161 17162 17163 17164 17165 17166 17167 17168 17169 17170 | /* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */ #define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */ #define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */ #define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */ #define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */ #define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */ /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */ #define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */ #define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) #define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) |
| ︙ | ︙ | |||
17655 17656 17657 17658 17659 17660 17661 | ** Test to see whether or not a table is a virtual table. This is ** done as a macro so that it will be optimized out when virtual ** table support is omitted from the build. */ #ifndef SQLITE_OMIT_VIRTUALTABLE # define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB) # define ExprIsVtab(X) \ | | | 17729 17730 17731 17732 17733 17734 17735 17736 17737 17738 17739 17740 17741 17742 17743 | ** Test to see whether or not a table is a virtual table. This is ** done as a macro so that it will be optimized out when virtual ** table support is omitted from the build. */ #ifndef SQLITE_OMIT_VIRTUALTABLE # define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB) # define ExprIsVtab(X) \ ((X)->op==TK_COLUMN && (X)->y.pTab->eTabType==TABTYP_VTAB) #else # define IsVirtual(X) 0 # define ExprIsVtab(X) 0 #endif /* ** Macros to determine if a column is hidden. IsOrdinaryHiddenColumn() |
| ︙ | ︙ | |||
17872 17873 17874 17875 17876 17877 17878 | ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. ** The second column to be indexed (c1) has an index of 0 in ** Ex1.aCol[], hence Ex2.aiColumn[1]==0. ** ** The Index.onError field determines whether or not the indexed columns ** must be unique and what to do if they are not. When Index.onError=OE_None, ** it means this is not a unique index. Otherwise it is a unique index | | | > > > > > > > > > > > > | 17946 17947 17948 17949 17950 17951 17952 17953 17954 17955 17956 17957 17958 17959 17960 17961 17962 17963 17964 17965 17966 17967 17968 17969 17970 17971 17972 17973 17974 | ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. ** The second column to be indexed (c1) has an index of 0 in ** Ex1.aCol[], hence Ex2.aiColumn[1]==0. ** ** The Index.onError field determines whether or not the indexed columns ** must be unique and what to do if they are not. When Index.onError=OE_None, ** it means this is not a unique index. Otherwise it is a unique index ** and the value of Index.onError indicates which conflict resolution ** algorithm to employ when an attempt is made to insert a non-unique ** element. ** ** The colNotIdxed bitmask is used in combination with SrcItem.colUsed ** for a fast test to see if an index can serve as a covering index. ** colNotIdxed has a 1 bit for every column of the original table that ** is *not* available in the index. Thus the expression ** "colUsed & colNotIdxed" will be non-zero if the index is not a ** covering index. The most significant bit of of colNotIdxed will always ** be true (note-20221022-a). If a column beyond the 63rd column of the ** table is used, the "colUsed & colNotIdxed" test will always be non-zero ** and we have to assume either that the index is not covering, or use ** an alternative (slower) algorithm to determine whether or not ** the index is covering. ** ** While parsing a CREATE TABLE or CREATE INDEX statement in order to ** generate VDBE code (as opposed to parsing one read from an sqlite_schema ** table as part of parsing an existing database schema), transient instances ** of this structure may be created. In this case the Index.tnum variable is ** used to store the address of a VDBE instruction, not a database page ** number (it cannot - the database page is not allocated until the VDBE |
| ︙ | ︙ | |||
17911 17912 17913 17914 17915 17916 17917 17918 17919 17920 17921 17922 17923 17924 17925 | 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 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 */ #ifdef SQLITE_ENABLE_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ #endif | > > | | 17997 17998 17999 18000 18001 18002 18003 18004 18005 18006 18007 18008 18009 18010 18011 18012 18013 18014 18015 18016 18017 18018 18019 18020 18021 |
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 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 */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
#endif
Bitmask colNotIdxed; /* Unindexed columns in pTab */
};
/*
** Allowed values for Index.idxType
*/
#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */
#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */
|
| ︙ | ︙ | |||
18187 18188 18189 18190 18191 18192 18193 | #define EP_Commuted 0x000400 /* Comparison operator has been commuted */ #define EP_IntValue 0x000800 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x001000 /* x.pSelect is valid (otherwise x.pList is) */ #define EP_Skip 0x002000 /* Operator does not contribute to affinity */ #define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_Win 0x008000 /* Contains window functions */ #define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ | | | 18275 18276 18277 18278 18279 18280 18281 18282 18283 18284 18285 18286 18287 18288 18289 |
#define EP_Commuted 0x000400 /* Comparison operator has been commuted */
#define EP_IntValue 0x000800 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x001000 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Skip 0x002000 /* Operator does not contribute to affinity */
#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_Win 0x008000 /* Contains window functions */
#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
/* 0x020000 // Available for reuse */
#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */
#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
#define EP_CanBeNull 0x200000 /* Can be null despite NOT NULL constraint */
#define EP_Subquery 0x400000 /* Tree contains a TK_SELECT operator */
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
|
| ︙ | ︙ | |||
18372 18373 18374 18375 18376 18377 18378 18379 18380 18381 18382 18383 18384 18385 | #define EU4_IDX 1 /* Uses IdList.a.u4.idx */ #define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */ /* ** The SrcItem object represents a single term in the FROM clause of a query. ** The SrcList object is mostly an array of SrcItems. ** ** Union member validity: ** ** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc ** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy ** u2.pIBIndex fg.isIndexedBy && !fg.isCte ** u2.pCteUse fg.isCte && !fg.isIndexedBy */ | > > > > > > > > | 18460 18461 18462 18463 18464 18465 18466 18467 18468 18469 18470 18471 18472 18473 18474 18475 18476 18477 18478 18479 18480 18481 | #define EU4_IDX 1 /* Uses IdList.a.u4.idx */ #define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */ /* ** The SrcItem object represents a single term in the FROM clause of a query. ** The SrcList object is mostly an array of SrcItems. ** ** The jointype starts out showing the join type between the current table ** and the next table on the list. The parser builds the list this way. ** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each ** jointype expresses the join between the table and the previous table. ** ** 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 ** u2.pIBIndex fg.isIndexedBy && !fg.isCte ** u2.pCteUse fg.isCte && !fg.isIndexedBy */ |
| ︙ | ︙ | |||
18411 18412 18413 18414 18415 18416 18417 |
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
union {
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
} u3;
| | | > > | < < < < < | < < < < < < < < < | 18507 18508 18509 18510 18511 18512 18513 18514 18515 18516 18517 18518 18519 18520 18521 18522 18523 18524 18525 18526 18527 18528 18529 18530 18531 18532 18533 18534 18535 18536 18537 18538 18539 18540 18541 18542 18543 18544 18545 18546 |
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
union {
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
} u3;
Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
ExprList *pFuncArg; /* Arguments to table-valued-function */
} u1;
union {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
} u2;
};
/*
** The OnOrUsing object represents either an ON clause or a USING clause.
** It can never be both at the same time, but it can be neither.
*/
struct OnOrUsing {
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
};
/*
** This object represents one or more tables that are the source of
** content for an SQL statement. For example, a single SrcList object
** is used to hold the FROM clause of a SELECT statement. SrcList also
** represents the target tables for DELETE, INSERT, and UPDATE statements.
**
*/
struct SrcList {
int nSrc; /* Number of tables or subqueries in the FROM clause */
u32 nAlloc; /* Number of entries allocated in a[] below */
SrcItem a[1]; /* One entry for each identifier on the list */
};
|
| ︙ | ︙ | |||
18858 18859 18860 18861 18862 18863 18864 18865 18866 18867 18868 18869 18870 18871 |
# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0)
# define DbMaskZero(M) (M)=0
# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I))
# define DbMaskAllZero(M) (M)==0
# define DbMaskNonZero(M) (M)!=0
#endif
/*
** An instance of the ParseCleanup object specifies an operation that
** should be performed after parsing to deallocation resources obtained
** during the parse and which are no longer needed.
*/
struct ParseCleanup {
ParseCleanup *pNext; /* Next cleanup task */
| > > > > > > > > > > > > > > > > > > > > > > | 18942 18943 18944 18945 18946 18947 18948 18949 18950 18951 18952 18953 18954 18955 18956 18957 18958 18959 18960 18961 18962 18963 18964 18965 18966 18967 18968 18969 18970 18971 18972 18973 18974 18975 18976 18977 |
# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0)
# define DbMaskZero(M) (M)=0
# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I))
# define DbMaskAllZero(M) (M)==0
# define DbMaskNonZero(M) (M)!=0
#endif
/*
** For each index X that has as one of its arguments either an expression
** or the name of a virtual generated column, and if X is in scope such that
** the value of the expression can simply be read from the index, then
** there is an instance of this object on the Parse.pIdxExpr list.
**
** During code generation, while generating code to evaluate expressions,
** this list is consulted and if a matching expression is found, the value
** is read from the index rather than being recomputed.
*/
struct IndexedExpr {
Expr *pExpr; /* The expression contained in the index */
int iDataCur; /* The data cursor associated with the index */
int iIdxCur; /* The index cursor */
int iIdxCol; /* The index column that contains value of pExpr */
u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */
IndexedExpr *pIENext; /* Next in a list of all indexed expressions */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
const char *zIdxName; /* Name of index, used only for bytecode comments */
#endif
};
/*
** An instance of the ParseCleanup object specifies an operation that
** should be performed after parsing to deallocation resources obtained
** during the parse and which are no longer needed.
*/
struct ParseCleanup {
ParseCleanup *pNext; /* Next cleanup task */
|
| ︙ | ︙ | |||
18899 18900 18901 18902 18903 18904 18905 | u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ | | > | 19005 19006 19007 19008 19009 19010 19011 19012 19013 19014 19015 19016 19017 19018 19019 19020 19021 19022 19023 19024 19025 19026 19027 19028 19029 19030 19031 19032 19033 19034 19035 19036 |
u8 nested; /* Number of nested calls to the parser/code generator */
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
u8 mayAbort; /* True if statement may throw an ABORT exception */
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 */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
#endif
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
int iSelfTab; /* Table associated with an index on expr, or negative
** of the base register during check-constraint eval */
int nLabel; /* The *negative* of the number of labels used */
int nLabelAlloc; /* Number of slots in aLabel */
int *aLabel; /* Space to hold the labels */
ExprList *pConstExpr;/* Constant expressions */
IndexedExpr *pIdxExpr;/* List of expressions used by active indexes */
Token constraintName;/* Name of the constraint currently being parsed */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
|
| ︙ | ︙ | |||
19351 19352 19353 19354 19355 19356 19357 |
int n; /* A counter */
int iCur; /* A cursor number */
SrcList *pSrcList; /* FROM clause */
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */
int *aiCol; /* array of column indexes */
struct IdxCover *pIdxCover; /* Check for index coverage */
| < > | | 19458 19459 19460 19461 19462 19463 19464 19465 19466 19467 19468 19469 19470 19471 19472 19473 19474 19475 19476 19477 19478 19479 19480 |
int n; /* A counter */
int iCur; /* A cursor number */
SrcList *pSrcList; /* FROM clause */
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */
int *aiCol; /* array of column indexes */
struct IdxCover *pIdxCover; /* Check for index coverage */
ExprList *pGroupBy; /* GROUP BY clause */
Select *pSelect; /* HAVING to WHERE clause ctx */
struct WindowRewrite *pRewrite; /* Window rewrite context */
struct WhereConst *pConst; /* WHERE clause constants */
struct RenameCtx *pRename; /* RENAME COLUMN context */
struct Table *pTab; /* Table of generated column */
struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
SrcItem *pSrcItem; /* A single FROM clause item */
DbFixer *pFix; /* See sqlite3FixSelect() */
} u;
};
/*
** The following structure contains information used by the sqliteFix...
** routines as they walk the parse tree to make database references
** explicit.
|
| ︙ | ︙ | |||
19665 19666 19667 19668 19669 19670 19671 19672 19673 19674 19675 19676 19677 19678 19679 19680 19681 19682 19683 19684 19685 19686 19687 19688 19689 19690 19691 19692 19693 19694 19695 19696 19697 19698 19699 19700 19701 19702 19703 19704 | SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64); SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*); SQLITE_PRIVATE void *sqlite3Realloc(void*, u64); SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64); SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*); SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*); SQLITE_PRIVATE int sqlite3MallocSize(const void*); SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, const void*); SQLITE_PRIVATE void *sqlite3PageMalloc(int); SQLITE_PRIVATE void sqlite3PageFree(void*); SQLITE_PRIVATE void sqlite3MemSetDefault(void); #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); #endif SQLITE_PRIVATE int sqlite3HeapNearlyFull(void); /* ** On systems with ample stack space and that support alloca(), make ** use of alloca() to obtain space for large automatic objects. By default, ** obtain space from malloc(). ** ** The alloca() routine never returns NULL. This will cause code paths ** that deal with sqlite3StackAlloc() failures to be unreachable. */ #ifdef SQLITE_USE_ALLOCA # define sqlite3StackAllocRaw(D,N) alloca(N) # define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N) # define sqlite3StackFree(D,P) #else # define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) # define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N) # define sqlite3StackFree(D,P) sqlite3DbFree(D,P) #endif /* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they ** are, disable MEMSYS3 */ #ifdef SQLITE_ENABLE_MEMSYS5 SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); | > > > > > | 19772 19773 19774 19775 19776 19777 19778 19779 19780 19781 19782 19783 19784 19785 19786 19787 19788 19789 19790 19791 19792 19793 19794 19795 19796 19797 19798 19799 19800 19801 19802 19803 19804 19805 19806 19807 19808 19809 19810 19811 19812 19813 19814 19815 19816 | SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64); SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*); SQLITE_PRIVATE void *sqlite3Realloc(void*, u64); SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64); SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*); SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*); SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3*, void*); SQLITE_PRIVATE int sqlite3MallocSize(const void*); SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, const void*); SQLITE_PRIVATE void *sqlite3PageMalloc(int); SQLITE_PRIVATE void sqlite3PageFree(void*); SQLITE_PRIVATE void sqlite3MemSetDefault(void); #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); #endif SQLITE_PRIVATE int sqlite3HeapNearlyFull(void); /* ** On systems with ample stack space and that support alloca(), make ** use of alloca() to obtain space for large automatic objects. By default, ** obtain space from malloc(). ** ** The alloca() routine never returns NULL. This will cause code paths ** that deal with sqlite3StackAlloc() failures to be unreachable. */ #ifdef SQLITE_USE_ALLOCA # define sqlite3StackAllocRaw(D,N) alloca(N) # define sqlite3StackAllocRawNN(D,N) alloca(N) # define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N) # define sqlite3StackFree(D,P) # define sqlite3StackFreeNN(D,P) #else # define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) # define sqlite3StackAllocRawNN(D,N) sqlite3DbMallocRawNN(D,N) # define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N) # define sqlite3StackFree(D,P) sqlite3DbFree(D,P) # define sqlite3StackFreeNN(D,P) sqlite3DbFreeNN(D,P) #endif /* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they ** are, disable MEMSYS3 */ #ifdef SQLITE_ENABLE_MEMSYS5 SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); |
| ︙ | ︙ | |||
20189 20190 20191 20192 20193 20194 20195 20196 20197 20198 20199 20200 20201 20202 | SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*); SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*); SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64); SQLITE_PRIVATE void sqlite3Int64ToText(i64,char*); SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*); SQLITE_PRIVATE int sqlite3Atoi(const char*); #ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); | > | 20301 20302 20303 20304 20305 20306 20307 20308 20309 20310 20311 20312 20313 20314 20315 | SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*); SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*); SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64); SQLITE_PRIVATE i64 sqlite3RealToI64(double); SQLITE_PRIVATE void sqlite3Int64ToText(i64,char*); SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*); SQLITE_PRIVATE int sqlite3Atoi(const char*); #ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); |
| ︙ | ︙ | |||
20305 20306 20307 20308 20309 20310 20311 | SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, const Expr *, u8, u8, sqlite3_value **); SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[]; SQLITE_PRIVATE const char sqlite3StrBINARY[]; SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[]; SQLITE_PRIVATE const char sqlite3StdTypeAffinity[]; | < | 20418 20419 20420 20421 20422 20423 20424 20425 20426 20427 20428 20429 20430 20431 | SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, const Expr *, u8, u8, sqlite3_value **); SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[]; SQLITE_PRIVATE const char sqlite3StrBINARY[]; SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[]; SQLITE_PRIVATE const char sqlite3StdTypeAffinity[]; SQLITE_PRIVATE const char *sqlite3StdType[]; SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[]; SQLITE_PRIVATE const unsigned char *sqlite3aLTb; SQLITE_PRIVATE const unsigned char *sqlite3aEQb; SQLITE_PRIVATE const unsigned char *sqlite3aGTb; SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[]; SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config; |
| ︙ | ︙ | |||
20748 20749 20750 20751 20752 20753 20754 20755 20756 20757 20758 20759 20760 20761 | SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int); SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int); SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt); #endif #endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ /************** Begin file os_common.h ***************************************/ /* ** 2004 May 22 | > > > > | 20860 20861 20862 20863 20864 20865 20866 20867 20868 20869 20870 20871 20872 20873 20874 20875 20876 20877 | SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int); SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int); SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt); #endif #if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) SQLITE_PRIVATE int sqlite3KvvfsInit(void); #endif #endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ /************** Begin file os_common.h ***************************************/ /* ** 2004 May 22 |
| ︙ | ︙ | |||
20980 20981 20982 20983 20984 20985 20986 | #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ #if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) | | | 21096 21097 21098 21099 21100 21101 21102 21103 21104 21105 21106 21107 21108 21109 21110 | #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ #if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) /* #include "sqlite_cfg.h" */ #define SQLITECONFIG_H 1 #endif /* These macros are provided to "stringify" the value of the define ** for those options in which the value is meaningful. */ #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) |
| ︙ | ︙ | |||
21145 21146 21147 21148 21149 21150 21151 21152 21153 21154 21155 21156 21157 21158 | #endif #ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS "DISABLE_PAGECACHE_OVERFLOW_STATS", #endif #ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT "DISABLE_SKIPAHEAD_DISTINCT", #endif #ifdef SQLITE_ENABLE_8_3_NAMES "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), #endif #ifdef SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE | > > > | 21261 21262 21263 21264 21265 21266 21267 21268 21269 21270 21271 21272 21273 21274 21275 21276 21277 | #endif #ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS "DISABLE_PAGECACHE_OVERFLOW_STATS", #endif #ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT "DISABLE_SKIPAHEAD_DISTINCT", #endif #ifdef SQLITE_DQS "DQS=" CTIMEOPT_VAL(SQLITE_DQS), #endif #ifdef SQLITE_ENABLE_8_3_NAMES "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), #endif #ifdef SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE |
| ︙ | ︙ | |||
21635 21636 21637 21638 21639 21640 21641 | #endif #ifdef SQLITE_OMIT_WSD "OMIT_WSD", #endif #ifdef SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif | < < < | 21754 21755 21756 21757 21758 21759 21760 21761 21762 21763 21764 21765 21766 21767 | #endif #ifdef SQLITE_OMIT_WSD "OMIT_WSD", #endif #ifdef SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif #ifdef SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif #ifdef SQLITE_POWERSAFE_OVERWRITE # if SQLITE_POWERSAFE_OVERWRITE != 1 "POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE), # endif |
| ︙ | ︙ | |||
22117 22118 22119 22120 22121 22122 22123 | ** sqlite3StdType[] The actual names of the datatypes. ** ** sqlite3StdTypeLen[] The length (in bytes) of each entry ** in sqlite3StdType[]. ** ** sqlite3StdTypeAffinity[] The affinity associated with each entry ** in sqlite3StdType[]. | < < < < < < < < < < < < | 22233 22234 22235 22236 22237 22238 22239 22240 22241 22242 22243 22244 22245 22246 22247 22248 22249 22250 22251 22252 22253 22254 22255 22256 |
** sqlite3StdType[] The actual names of the datatypes.
**
** sqlite3StdTypeLen[] The length (in bytes) of each entry
** in sqlite3StdType[].
**
** sqlite3StdTypeAffinity[] The affinity associated with each entry
** in sqlite3StdType[].
*/
SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 };
SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = {
SQLITE_AFF_NUMERIC,
SQLITE_AFF_BLOB,
SQLITE_AFF_INTEGER,
SQLITE_AFF_INTEGER,
SQLITE_AFF_REAL,
SQLITE_AFF_TEXT
};
SQLITE_PRIVATE const char *sqlite3StdType[] = {
"ANY",
"BLOB",
"INT",
"INTEGER",
"REAL",
"TEXT"
|
| ︙ | ︙ | |||
22590 22591 22592 22593 22594 22595 22596 |
** state of the virtual machine.
**
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
** is really a pointer to an instance of this structure.
*/
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
| | | 22694 22695 22696 22697 22698 22699 22700 22701 22702 22703 22704 22705 22706 22707 22708 |
** state of the virtual machine.
**
** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare()
** is really a pointer to an instance of this structure.
*/
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
Vdbe **ppVPrev,*pVNext; /* Linked list of VDBEs with the same Vdbe.db */
Parse *pParse; /* Parsing context used to create this Vdbe */
ynVar nVar; /* Number of entries in aVar[] */
int nMem; /* Number of memory locations currently allocated */
int nCursor; /* Number of slots in apCsr[] */
u32 cacheCtr; /* VdbeCursor row cache generation counter */
int pc; /* The program counter */
int rc; /* Value to return */
|
| ︙ | ︙ | |||
23148 23149 23150 23151 23152 23153 23154 23155 23156 23157 23158 23159 23160 23161 |
*/
case SQLITE_DBSTATUS_SCHEMA_USED: {
int i; /* Used to iterate through schemas */
int nByte = 0; /* Used to accumulate return value */
sqlite3BtreeEnterAll(db);
db->pnBytesFreed = &nByte;
for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema;
if( ALWAYS(pSchema!=0) ){
HashElem *p;
nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
pSchema->tblHash.count
| > > | 23252 23253 23254 23255 23256 23257 23258 23259 23260 23261 23262 23263 23264 23265 23266 23267 |
*/
case SQLITE_DBSTATUS_SCHEMA_USED: {
int i; /* Used to iterate through schemas */
int nByte = 0; /* Used to accumulate return value */
sqlite3BtreeEnterAll(db);
db->pnBytesFreed = &nByte;
assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
db->lookaside.pEnd = db->lookaside.pStart;
for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema;
if( ALWAYS(pSchema!=0) ){
HashElem *p;
nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
pSchema->tblHash.count
|
| ︙ | ︙ | |||
23173 23174 23175 23176 23177 23178 23179 23180 23181 23182 23183 23184 23185 23186 23187 23188 23189 23190 23191 23192 23193 23194 23195 23196 |
}
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
}
}
}
db->pnBytesFreed = 0;
sqlite3BtreeLeaveAll(db);
*pHighwater = 0;
*pCurrent = nByte;
break;
}
/*
** *pCurrent gets an accurate estimate of the amount of memory used
** to store all prepared statements.
** *pHighwater is set to zero.
*/
case SQLITE_DBSTATUS_STMT_USED: {
struct Vdbe *pVdbe; /* Used to iterate through VMs */
int nByte = 0; /* Used to accumulate return value */
db->pnBytesFreed = &nByte;
| > > > | > | 23279 23280 23281 23282 23283 23284 23285 23286 23287 23288 23289 23290 23291 23292 23293 23294 23295 23296 23297 23298 23299 23300 23301 23302 23303 23304 23305 23306 23307 23308 23309 23310 23311 23312 23313 23314 23315 23316 |
}
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
}
}
}
db->pnBytesFreed = 0;
db->lookaside.pEnd = db->lookaside.pTrueEnd;
sqlite3BtreeLeaveAll(db);
*pHighwater = 0;
*pCurrent = nByte;
break;
}
/*
** *pCurrent gets an accurate estimate of the amount of memory used
** to store all prepared statements.
** *pHighwater is set to zero.
*/
case SQLITE_DBSTATUS_STMT_USED: {
struct Vdbe *pVdbe; /* Used to iterate through VMs */
int nByte = 0; /* Used to accumulate return value */
db->pnBytesFreed = &nByte;
assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
db->lookaside.pEnd = db->lookaside.pStart;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pVNext){
sqlite3VdbeDelete(pVdbe);
}
db->lookaside.pEnd = db->lookaside.pTrueEnd;
db->pnBytesFreed = 0;
*pHighwater = 0; /* IMP: R-64479-57858 */
*pCurrent = nByte;
break;
}
|
| ︙ | ︙ | |||
23528 23529 23530 23531 23532 23533 23534 |
A = Y/100;
B = 2 - A + (A/4);
X1 = 36525*(Y+4716)/100;
X2 = 306001*(M+1)/10000;
p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
p->validJD = 1;
if( p->validHMS ){
| | | 23638 23639 23640 23641 23642 23643 23644 23645 23646 23647 23648 23649 23650 23651 23652 |
A = Y/100;
B = 2 - A + (A/4);
X1 = 36525*(Y+4716)/100;
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->validTZ ){
p->iJD -= p->tz*60000;
p->validYMD = 0;
p->validHMS = 0;
p->validTZ = 0;
}
}
|
| ︙ | ︙ | |||
24037 24038 24039 24040 24041 24042 24043 |
**
** Move the date to the same time on the next occurrence of
** weekday N where 0==Sunday, 1==Monday, and so forth. If the
** date is already on the appropriate weekday, this is a no-op.
*/
if( sqlite3_strnicmp(z, "weekday ", 8)==0
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
| | | 24147 24148 24149 24150 24151 24152 24153 24154 24155 24156 24157 24158 24159 24160 24161 |
**
** Move the date to the same time on the next occurrence of
** weekday N where 0==Sunday, 1==Monday, and so forth. If the
** date is already on the appropriate weekday, this is a no-op.
*/
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->validTZ = 0;
p->validJD = 0;
computeJD(p);
Z = ((p->iJD + 129600000)/86400000) % 7;
if( Z>n ) Z -= 7;
|
| ︙ | ︙ | |||
24718 24719 24720 24721 24722 24723 24724 24725 24726 24727 24728 24729 24730 24731 24732 24733 24734 |
}
SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
DO_OS_MALLOC_TEST(id);
return id->pMethods->xFileSize(id, pSize);
}
SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){
DO_OS_MALLOC_TEST(id);
return id->pMethods->xLock(id, lockType);
}
SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){
return id->pMethods->xUnlock(id, lockType);
}
SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
DO_OS_MALLOC_TEST(id);
return id->pMethods->xCheckReservedLock(id, pResOut);
}
| > > | 24828 24829 24830 24831 24832 24833 24834 24835 24836 24837 24838 24839 24840 24841 24842 24843 24844 24845 24846 |
}
SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
DO_OS_MALLOC_TEST(id);
return id->pMethods->xFileSize(id, pSize);
}
SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){
DO_OS_MALLOC_TEST(id);
assert( lockType>=SQLITE_LOCK_SHARED && lockType<=SQLITE_LOCK_EXCLUSIVE );
return id->pMethods->xLock(id, lockType);
}
SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){
assert( lockType==SQLITE_LOCK_NONE || lockType==SQLITE_LOCK_SHARED );
return id->pMethods->xUnlock(id, lockType);
}
SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
DO_OS_MALLOC_TEST(id);
return id->pMethods->xCheckReservedLock(id, pResOut);
}
|
| ︙ | ︙ | |||
24835 24836 24837 24838 24839 24840 24841 24842 24843 24844 24845 24846 24847 24848 |
){
int rc;
DO_OS_MALLOC_TEST(0);
/* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
}
SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
DO_OS_MALLOC_TEST(0);
assert( dirSync==0 || dirSync==1 );
| > | 24947 24948 24949 24950 24951 24952 24953 24954 24955 24956 24957 24958 24959 24960 24961 |
){
int rc;
DO_OS_MALLOC_TEST(0);
/* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
assert( zPath || (flags & SQLITE_OPEN_EXCLUSIVE) );
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
}
SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
DO_OS_MALLOC_TEST(0);
assert( dirSync==0 || dirSync==1 );
|
| ︙ | ︙ | |||
29053 29054 29055 29056 29057 29058 29059 29060 29061 29062 29063 29064 29065 |
nFull = sqlite3MallocSize(p);
sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull);
sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
}
*pp = p;
}
/*
** Allocate memory. This routine is like sqlite3_malloc() except that it
** assumes the memory subsystem has already been initialized.
*/
SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
void *p;
| > > > > > > > > > > > > > > > > > > > > > | < < < < < | 29166 29167 29168 29169 29170 29171 29172 29173 29174 29175 29176 29177 29178 29179 29180 29181 29182 29183 29184 29185 29186 29187 29188 29189 29190 29191 29192 29193 29194 29195 29196 29197 29198 29199 29200 29201 29202 29203 29204 29205 29206 29207 |
nFull = sqlite3MallocSize(p);
sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull);
sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
}
*pp = p;
}
/*
** Maximum size of any single memory allocation.
**
** This is not a limit on the total amount of memory used. This is
** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc().
**
** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391
** This provides a 256-byte safety margin for defense against 32-bit
** signed integer overflow bugs when computing memory allocation sizes.
** Parnoid applications might want to reduce the maximum allocation size
** further for an even larger safety margin. 0x3fffffff or 0x0fffffff
** or even smaller would be reasonable upper bounds on the size of a memory
** allocations for most applications.
*/
#ifndef SQLITE_MAX_ALLOCATION_SIZE
# define SQLITE_MAX_ALLOCATION_SIZE 2147483391
#endif
#if SQLITE_MAX_ALLOCATION_SIZE>2147483391
# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391
#endif
/*
** Allocate memory. This routine is like sqlite3_malloc() except that it
** assumes the memory subsystem has already been initialized.
*/
SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
void *p;
if( n==0 || n>SQLITE_MAX_ALLOCATION_SIZE ){
p = 0;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
mallocWithAlarm((int)n, &p);
sqlite3_mutex_leave(mem0.mutex);
}else{
p = sqlite3GlobalConfig.m.xMalloc((int)n);
|
| ︙ | ︙ | |||
29100 29101 29102 29103 29104 29105 29106 |
}
/*
** TRUE if p is a lookaside memory allocation from db
*/
#ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, const void *p){
| | | 29229 29230 29231 29232 29233 29234 29235 29236 29237 29238 29239 29240 29241 29242 29243 |
}
/*
** TRUE if p is a lookaside memory allocation from db
*/
#ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, const void *p){
return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pTrueEnd);
}
#else
#define isLookaside(A,B) 0
#endif
/*
** Return the size of a memory allocation previously obtained from
|
| ︙ | ︙ | |||
29124 29125 29126 29127 29128 29129 29130 |
#else
return db->lookaside.szTrue;
#endif
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, const void *p){
assert( p!=0 );
#ifdef SQLITE_DEBUG
| < | | | | | | < | | 29253 29254 29255 29256 29257 29258 29259 29260 29261 29262 29263 29264 29265 29266 29267 29268 29269 29270 29271 29272 29273 29274 29275 29276 |
#else
return db->lookaside.szTrue;
#endif
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, const void *p){
assert( p!=0 );
#ifdef SQLITE_DEBUG
if( db==0 ){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
}else if( !isLookaside(db,p) ){
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
}
#endif
if( db ){
if( ((uptr)p)<(uptr)(db->lookaside.pTrueEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
assert( sqlite3_mutex_held(db->mutex) );
return LOOKASIDE_SMALL;
}
#endif
if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
|
| ︙ | ︙ | |||
29191 29192 29193 29194 29195 29196 29197 |
** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op.
** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL.
*/
SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
assert( p!=0 );
if( db ){
| < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 29318 29319 29320 29321 29322 29323 29324 29325 29326 29327 29328 29329 29330 29331 29332 29333 29334 29335 29336 29337 29338 29339 29340 29341 29342 29343 29344 29345 29346 29347 29348 29349 29350 29351 29352 29353 29354 29355 29356 29357 29358 29359 29360 29361 29362 29363 29364 29365 29366 29367 29368 29369 29370 29371 29372 29373 29374 29375 29376 29377 29378 29379 29380 29381 29382 29383 29384 29385 29386 29387 29388 29389 29390 29391 29392 29393 29394 29395 29396 29397 29398 29399 29400 29401 29402 |
** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op.
** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL.
*/
SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
assert( p!=0 );
if( db ){
if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
#endif
pBuf->pNext = db->lookaside.pSmallFree;
db->lookaside.pSmallFree = pBuf;
return;
}
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
#endif
pBuf->pNext = db->lookaside.pFree;
db->lookaside.pFree = pBuf;
return;
}
}
if( db->pnBytesFreed ){
measureAllocationSize(db, p);
return;
}
}
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
}
SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3 *db, void *p){
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
assert( p!=0 );
if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
#endif
pBuf->pNext = db->lookaside.pSmallFree;
db->lookaside.pSmallFree = pBuf;
return;
}
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
#endif
pBuf->pNext = db->lookaside.pFree;
db->lookaside.pFree = pBuf;
return;
}
}
if( db->pnBytesFreed ){
measureAllocationSize(db, p);
return;
}
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
}
SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( p ) sqlite3DbFreeNN(db, p);
}
/*
|
| ︙ | ︙ | |||
29559 29560 29561 29562 29563 29564 29565 29566 29567 29568 29569 29570 29571 29572 29573 29574 |
if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
db->mallocFailed = 1;
if( db->nVdbeExec>0 ){
AtomicStore(&db->u1.isInterrupted, 1);
}
DisableLookaside;
if( db->pParse ){
sqlite3ErrorMsg(db->pParse, "out of memory");
db->pParse->rc = SQLITE_NOMEM_BKPT;
}
}
return 0;
}
/*
** This routine reactivates the memory allocator and clears the
| > > > > > | 29725 29726 29727 29728 29729 29730 29731 29732 29733 29734 29735 29736 29737 29738 29739 29740 29741 29742 29743 29744 29745 |
if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
db->mallocFailed = 1;
if( db->nVdbeExec>0 ){
AtomicStore(&db->u1.isInterrupted, 1);
}
DisableLookaside;
if( db->pParse ){
Parse *pParse;
sqlite3ErrorMsg(db->pParse, "out of memory");
db->pParse->rc = SQLITE_NOMEM_BKPT;
for(pParse=db->pParse->pOuterParse; pParse; pParse = pParse->pOuterParse){
pParse->nErr++;
pParse->rc = SQLITE_NOMEM;
}
}
}
return 0;
}
/*
** This routine reactivates the memory allocator and clears the
|
| ︙ | ︙ | |||
32330 32331 32332 32333 32334 32335 32336 |
/* #include "sqliteInt.h" */
/* All threads share a single random number generator.
** This structure is the current state of the generator.
*/
static SQLITE_WSD struct sqlite3PrngType {
| | | | > > > > > > > > > > > > > > > > > > > > > > > > > > < | 32501 32502 32503 32504 32505 32506 32507 32508 32509 32510 32511 32512 32513 32514 32515 32516 32517 32518 32519 32520 32521 32522 32523 32524 32525 32526 32527 32528 32529 32530 32531 32532 32533 32534 32535 32536 32537 32538 32539 32540 32541 32542 32543 32544 32545 32546 32547 32548 32549 |
/* #include "sqliteInt.h" */
/* All threads share a single random number generator.
** This structure is the current state of the generator.
*/
static SQLITE_WSD struct sqlite3PrngType {
u32 s[16]; /* 64 bytes of chacha20 state */
u8 out[64]; /* Output bytes */
u8 n; /* Output bytes remaining */
} sqlite3Prng;
/* The RFC-7539 ChaCha20 block function
*/
#define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
#define QR(a, b, c, d) ( \
a += b, d ^= a, d = ROTL(d,16), \
c += d, b ^= c, b = ROTL(b,12), \
a += b, d ^= a, d = ROTL(d, 8), \
c += d, b ^= c, b = ROTL(b, 7))
static void chacha_block(u32 *out, const u32 *in){
int i;
u32 x[16];
memcpy(x, in, 64);
for(i=0; i<10; i++){
QR(x[0], x[4], x[ 8], x[12]);
QR(x[1], x[5], x[ 9], x[13]);
QR(x[2], x[6], x[10], x[14]);
QR(x[3], x[7], x[11], x[15]);
QR(x[0], x[5], x[10], x[15]);
QR(x[1], x[6], x[11], x[12]);
QR(x[2], x[7], x[ 8], x[13]);
QR(x[3], x[4], x[ 9], x[14]);
}
for(i=0; i<16; i++) out[i] = x[i]+in[i];
}
/*
** Return N random bytes.
*/
SQLITE_API void sqlite3_randomness(int N, void *pBuf){
unsigned char *zBuf = pBuf;
/* The "wsdPrng" macro will resolve to the pseudo-random number generator
** state vector. If writable static data is unsupported on the target,
** we have to locate the state vector at run-time. In the more common
** case where writable static data is supported, wsdPrng can refer directly
** to the "sqlite3Prng" state vector declared above.
|
| ︙ | ︙ | |||
32369 32370 32371 32372 32373 32374 32375 |
#if SQLITE_THREADSAFE
mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
#endif
sqlite3_mutex_enter(mutex);
if( N<=0 || pBuf==0 ){
| | | < < < < < < | < | > > | < | | < < < < < | < | < | < > > > | > > | > | | > | | | < > | 32565 32566 32567 32568 32569 32570 32571 32572 32573 32574 32575 32576 32577 32578 32579 32580 32581 32582 32583 32584 32585 32586 32587 32588 32589 32590 32591 32592 32593 32594 32595 32596 32597 32598 32599 32600 32601 32602 32603 32604 32605 32606 32607 32608 32609 32610 32611 32612 32613 32614 32615 32616 32617 32618 |
#if SQLITE_THREADSAFE
mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
#endif
sqlite3_mutex_enter(mutex);
if( N<=0 || pBuf==0 ){
wsdPrng.s[0] = 0;
sqlite3_mutex_leave(mutex);
return;
}
/* Initialize the state of the random number generator once,
** the first time this routine is called.
*/
if( wsdPrng.s[0]==0 ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
static const u32 chacha20_init[] = {
0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
};
memcpy(&wsdPrng.s[0], chacha20_init, 16);
if( NEVER(pVfs==0) ){
memset(&wsdPrng.s[4], 0, 44);
}else{
sqlite3OsRandomness(pVfs, 44, (char*)&wsdPrng.s[4]);
}
wsdPrng.s[15] = wsdPrng.s[12];
wsdPrng.s[12] = 0;
wsdPrng.n = 0;
}
assert( N>0 );
while( 1 /* exit by break */ ){
if( N<=wsdPrng.n ){
memcpy(zBuf, &wsdPrng.out[wsdPrng.n-N], N);
wsdPrng.n -= N;
break;
}
if( wsdPrng.n>0 ){
memcpy(zBuf, wsdPrng.out, wsdPrng.n);
N -= wsdPrng.n;
zBuf += wsdPrng.n;
}
wsdPrng.s[12]++;
chacha_block((u32*)wsdPrng.out, wsdPrng.s);
wsdPrng.n = 64;
}
sqlite3_mutex_leave(mutex);
}
#ifndef SQLITE_UNTESTABLE
/*
** For testing purposes, we sometimes want to preserve the state of
** PRNG and restore the PRNG to its saved state at a later time, or
|
| ︙ | ︙ | |||
33455 33456 33457 33458 33459 33460 33461 |
** during statement execution (sqlite3_step() etc.).
*/
SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
char *zMsg;
va_list ap;
sqlite3 *db = pParse->db;
assert( db!=0 );
| | | 33644 33645 33646 33647 33648 33649 33650 33651 33652 33653 33654 33655 33656 33657 33658 |
** during statement execution (sqlite3_step() etc.).
*/
SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
char *zMsg;
va_list ap;
sqlite3 *db = pParse->db;
assert( db!=0 );
assert( db->pParse==pParse || db->pParse->pToplevel==pParse );
db->errByteOffset = -2;
va_start(ap, zFormat);
zMsg = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
if( db->errByteOffset<-1 ) db->errByteOffset = -1;
if( db->suppressErr ){
sqlite3DbFree(db, zMsg);
|
| ︙ | ︙ | |||
35273 35274 35275 35276 35277 35278 35279 |
/* 1 */ "AutoCommit" OpHelp(""),
/* 2 */ "Transaction" OpHelp(""),
/* 3 */ "Checkpoint" OpHelp(""),
/* 4 */ "JournalMode" OpHelp(""),
/* 5 */ "Vacuum" OpHelp(""),
/* 6 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
/* 7 */ "VUpdate" OpHelp("data=r[P3@P2]"),
| > | | | | | | | | | | < > | | | | | | | | | | | | | | | | | | | | | | < > | | | | < > | | | | | < | 35462 35463 35464 35465 35466 35467 35468 35469 35470 35471 35472 35473 35474 35475 35476 35477 35478 35479 35480 35481 35482 35483 35484 35485 35486 35487 35488 35489 35490 35491 35492 35493 35494 35495 35496 35497 35498 35499 35500 35501 35502 35503 35504 35505 35506 35507 35508 35509 35510 35511 35512 35513 35514 35515 35516 35517 35518 35519 35520 35521 35522 35523 35524 35525 35526 35527 35528 35529 35530 35531 35532 |
/* 1 */ "AutoCommit" OpHelp(""),
/* 2 */ "Transaction" OpHelp(""),
/* 3 */ "Checkpoint" OpHelp(""),
/* 4 */ "JournalMode" OpHelp(""),
/* 5 */ "Vacuum" OpHelp(""),
/* 6 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
/* 7 */ "VUpdate" OpHelp("data=r[P3@P2]"),
/* 8 */ "Init" OpHelp("Start at P2"),
/* 9 */ "Goto" OpHelp(""),
/* 10 */ "Gosub" OpHelp(""),
/* 11 */ "InitCoroutine" OpHelp(""),
/* 12 */ "Yield" OpHelp(""),
/* 13 */ "MustBeInt" OpHelp(""),
/* 14 */ "Jump" OpHelp(""),
/* 15 */ "Once" OpHelp(""),
/* 16 */ "If" OpHelp(""),
/* 17 */ "IfNot" OpHelp(""),
/* 18 */ "IsType" OpHelp("if typeof(P1.P3) in P5 goto P2"),
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
/* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
/* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"),
/* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"),
/* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"),
/* 24 */ "SeekGT" OpHelp("key=r[P3@P4]"),
/* 25 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
/* 26 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
/* 27 */ "NoConflict" OpHelp("key=r[P3@P4]"),
/* 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 */ "IfSmaller" OpHelp(""),
/* 34 */ "SorterSort" OpHelp(""),
/* 35 */ "Sort" OpHelp(""),
/* 36 */ "Rewind" OpHelp(""),
/* 37 */ "SorterNext" OpHelp(""),
/* 38 */ "Prev" OpHelp(""),
/* 39 */ "Next" OpHelp(""),
/* 40 */ "IdxLE" OpHelp("key=r[P3@P4]"),
/* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"),
/* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"),
/* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
/* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
/* 45 */ "IdxGE" OpHelp("key=r[P3@P4]"),
/* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
/* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
/* 48 */ "Program" OpHelp(""),
/* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
/* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
/* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
/* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
/* 53 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
/* 54 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
/* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
/* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
/* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
/* 58 */ "ElseEq" OpHelp(""),
/* 59 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
/* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
/* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
/* 62 */ "IncrVacuum" OpHelp(""),
/* 63 */ "VNext" OpHelp(""),
/* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"),
/* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"),
/* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"),
/* 67 */ "Return" OpHelp(""),
/* 68 */ "EndCoroutine" OpHelp(""),
/* 69 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
/* 70 */ "Halt" OpHelp(""),
/* 71 */ "Integer" OpHelp("r[P2]=P1"),
|
| ︙ | ︙ | |||
35458 35459 35460 35461 35462 35463 35464 35465 35466 35467 35468 35469 35470 35471 |
/* 186 */ "Abortable" OpHelp(""),
};
return azName[i];
}
#endif
/************** End of opcodes.c *********************************************/
/************** Begin file os_unix.c *****************************************/
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 35647 35648 35649 35650 35651 35652 35653 35654 35655 35656 35657 35658 35659 35660 35661 35662 35663 35664 35665 35666 35667 35668 35669 35670 35671 35672 35673 35674 35675 35676 35677 35678 35679 35680 35681 35682 35683 35684 35685 35686 35687 35688 35689 35690 35691 35692 35693 35694 35695 35696 35697 35698 35699 35700 35701 35702 35703 35704 35705 35706 35707 35708 35709 35710 35711 35712 35713 35714 35715 35716 35717 35718 35719 35720 35721 35722 35723 35724 35725 35726 35727 35728 35729 35730 35731 35732 35733 35734 35735 35736 35737 35738 35739 35740 35741 35742 35743 35744 35745 35746 35747 35748 35749 35750 35751 35752 35753 35754 35755 35756 35757 35758 35759 35760 35761 35762 35763 35764 35765 35766 35767 35768 35769 35770 35771 35772 35773 35774 35775 35776 35777 35778 35779 35780 35781 35782 35783 35784 35785 35786 35787 35788 35789 35790 35791 35792 35793 35794 35795 35796 35797 35798 35799 35800 35801 35802 35803 35804 35805 35806 35807 35808 35809 35810 35811 35812 35813 35814 35815 35816 35817 35818 35819 35820 35821 35822 35823 35824 35825 35826 35827 35828 35829 35830 35831 35832 35833 35834 35835 35836 35837 35838 35839 35840 35841 35842 35843 35844 35845 35846 35847 35848 35849 35850 35851 35852 35853 35854 35855 35856 35857 35858 35859 35860 35861 35862 35863 35864 35865 35866 35867 35868 35869 35870 35871 35872 35873 35874 35875 35876 35877 35878 35879 35880 35881 35882 35883 35884 35885 35886 35887 35888 35889 35890 35891 35892 35893 35894 35895 35896 35897 35898 35899 35900 35901 35902 35903 35904 35905 35906 35907 35908 35909 35910 35911 35912 35913 35914 35915 35916 35917 35918 35919 35920 35921 35922 35923 35924 35925 35926 35927 35928 35929 35930 35931 35932 35933 35934 35935 35936 35937 35938 35939 35940 35941 35942 35943 35944 35945 35946 35947 35948 35949 35950 35951 35952 35953 35954 35955 35956 35957 35958 35959 35960 35961 35962 35963 35964 35965 35966 35967 35968 35969 35970 35971 35972 35973 35974 35975 35976 35977 35978 35979 35980 35981 35982 35983 35984 35985 35986 35987 35988 35989 35990 35991 35992 35993 35994 35995 35996 35997 35998 35999 36000 36001 36002 36003 36004 36005 36006 36007 36008 36009 36010 36011 36012 36013 36014 36015 36016 36017 36018 36019 36020 36021 36022 36023 36024 36025 36026 36027 36028 36029 36030 36031 36032 36033 36034 36035 36036 36037 36038 36039 36040 36041 36042 36043 36044 36045 36046 36047 36048 36049 36050 36051 36052 36053 36054 36055 36056 36057 36058 36059 36060 36061 36062 36063 36064 36065 36066 36067 36068 36069 36070 36071 36072 36073 36074 36075 36076 36077 36078 36079 36080 36081 36082 36083 36084 36085 36086 36087 36088 36089 36090 36091 36092 36093 36094 36095 36096 36097 36098 36099 36100 36101 36102 36103 36104 36105 36106 36107 36108 36109 36110 36111 36112 36113 36114 36115 36116 36117 36118 36119 36120 36121 36122 36123 36124 36125 36126 36127 36128 36129 36130 36131 36132 36133 36134 36135 36136 36137 36138 36139 36140 36141 36142 36143 36144 36145 36146 36147 36148 36149 36150 36151 36152 36153 36154 36155 36156 36157 36158 36159 36160 36161 36162 36163 36164 36165 36166 36167 36168 36169 36170 36171 36172 36173 36174 36175 36176 36177 36178 36179 36180 36181 36182 36183 36184 36185 36186 36187 36188 36189 36190 36191 36192 36193 36194 36195 36196 36197 36198 36199 36200 36201 36202 36203 36204 36205 36206 36207 36208 36209 36210 36211 36212 36213 36214 36215 36216 36217 36218 36219 36220 36221 36222 36223 36224 36225 36226 36227 36228 36229 36230 36231 36232 36233 36234 36235 36236 36237 36238 36239 36240 36241 36242 36243 36244 36245 36246 36247 36248 36249 36250 36251 36252 36253 36254 36255 36256 36257 36258 36259 36260 36261 36262 36263 36264 36265 36266 36267 36268 36269 36270 36271 36272 36273 36274 36275 36276 36277 36278 36279 36280 36281 36282 36283 36284 36285 36286 36287 36288 36289 36290 36291 36292 36293 36294 36295 36296 36297 36298 36299 36300 36301 36302 36303 36304 36305 36306 36307 36308 36309 36310 36311 36312 36313 36314 36315 36316 36317 36318 36319 36320 36321 36322 36323 36324 36325 36326 36327 36328 36329 36330 36331 36332 36333 36334 36335 36336 36337 36338 36339 36340 36341 36342 36343 36344 36345 36346 36347 36348 36349 36350 36351 36352 36353 36354 36355 36356 36357 36358 36359 36360 36361 36362 36363 36364 36365 36366 36367 36368 36369 36370 36371 36372 36373 36374 36375 36376 36377 36378 36379 36380 36381 36382 36383 36384 36385 36386 36387 36388 36389 36390 36391 36392 36393 36394 36395 36396 36397 36398 36399 36400 36401 36402 36403 36404 36405 36406 36407 36408 36409 36410 36411 36412 36413 36414 36415 36416 36417 36418 36419 36420 36421 36422 36423 36424 36425 36426 36427 36428 36429 36430 36431 36432 36433 36434 36435 36436 36437 36438 36439 36440 36441 36442 36443 36444 36445 36446 36447 36448 36449 36450 36451 36452 36453 36454 36455 36456 36457 36458 36459 36460 36461 36462 36463 36464 36465 36466 36467 36468 36469 36470 36471 36472 36473 36474 36475 36476 36477 36478 36479 36480 36481 36482 36483 36484 36485 36486 36487 36488 36489 36490 36491 36492 36493 36494 36495 36496 36497 36498 36499 36500 36501 36502 36503 36504 36505 36506 36507 36508 36509 36510 36511 36512 36513 36514 36515 36516 36517 36518 36519 36520 36521 36522 36523 36524 36525 36526 36527 36528 36529 36530 36531 36532 36533 36534 36535 36536 36537 36538 36539 36540 36541 36542 36543 36544 36545 36546 36547 36548 36549 36550 36551 36552 36553 36554 36555 36556 36557 36558 36559 36560 36561 36562 36563 36564 36565 36566 36567 36568 36569 36570 36571 36572 36573 36574 36575 36576 36577 36578 36579 36580 36581 36582 36583 36584 36585 36586 36587 36588 36589 36590 36591 36592 36593 36594 36595 36596 36597 36598 36599 36600 36601 36602 36603 36604 36605 36606 36607 36608 36609 36610 36611 36612 36613 36614 36615 36616 36617 36618 36619 36620 36621 36622 36623 36624 36625 36626 36627 36628 36629 36630 36631 36632 |
/* 186 */ "Abortable" OpHelp(""),
};
return azName[i];
}
#endif
/************** End of opcodes.c *********************************************/
/************** Begin file os_kv.c *******************************************/
/*
** 2022-09-06
**
** 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 contains an experimental VFS layer that operates on a
** Key/Value storage engine where both keys and values must be pure
** text.
*/
/* #include <sqliteInt.h> */
#if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
/*****************************************************************************
** Debugging logic
*/
/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
#if 0
#define SQLITE_KV_TRACE(X) printf X
#else
#define SQLITE_KV_TRACE(X)
#endif
/* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
#if 0
#define SQLITE_KV_LOG(X) printf X
#else
#define SQLITE_KV_LOG(X)
#endif
/*
** Forward declaration of objects used by this VFS implementation
*/
typedef struct KVVfsFile KVVfsFile;
/* A single open file. There are only two files represented by this
** VFS - the database and the rollback journal.
*/
struct KVVfsFile {
sqlite3_file base; /* IO methods */
const char *zClass; /* Storage class */
int isJournal; /* True if this is a journal file */
unsigned int nJrnl; /* Space allocated for aJrnl[] */
char *aJrnl; /* Journal content */
int szPage; /* Last known page size */
sqlite3_int64 szDb; /* Database file size. -1 means unknown */
};
/*
** Methods for KVVfsFile
*/
static int kvvfsClose(sqlite3_file*);
static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size);
static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size);
static int kvvfsSyncDb(sqlite3_file*, int flags);
static int kvvfsSyncJrnl(sqlite3_file*, int flags);
static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize);
static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize);
static int kvvfsLock(sqlite3_file*, int);
static int kvvfsUnlock(sqlite3_file*, int);
static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut);
static int kvvfsFileControlDb(sqlite3_file*, int op, void *pArg);
static int kvvfsFileControlJrnl(sqlite3_file*, int op, void *pArg);
static int kvvfsSectorSize(sqlite3_file*);
static int kvvfsDeviceCharacteristics(sqlite3_file*);
/*
** Methods for sqlite3_vfs
*/
static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename);
static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int kvvfsSleep(sqlite3_vfs*, int microseconds);
static int kvvfsCurrentTime(sqlite3_vfs*, double*);
static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static sqlite3_vfs sqlite3OsKvvfsObject = {
1, /* iVersion */
sizeof(KVVfsFile), /* szOsFile */
1024, /* mxPathname */
0, /* pNext */
"kvvfs", /* zName */
0, /* pAppData */
kvvfsOpen, /* xOpen */
kvvfsDelete, /* xDelete */
kvvfsAccess, /* xAccess */
kvvfsFullPathname, /* xFullPathname */
kvvfsDlOpen, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
kvvfsRandomness, /* xRandomness */
kvvfsSleep, /* xSleep */
kvvfsCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
};
/* Methods for sqlite3_file objects referencing a database file
*/
static sqlite3_io_methods kvvfs_db_io_methods = {
1, /* iVersion */
kvvfsClose, /* xClose */
kvvfsReadDb, /* xRead */
kvvfsWriteDb, /* xWrite */
kvvfsTruncateDb, /* xTruncate */
kvvfsSyncDb, /* xSync */
kvvfsFileSizeDb, /* xFileSize */
kvvfsLock, /* xLock */
kvvfsUnlock, /* xUnlock */
kvvfsCheckReservedLock, /* xCheckReservedLock */
kvvfsFileControlDb, /* xFileControl */
kvvfsSectorSize, /* xSectorSize */
kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0, /* xShmUnmap */
0, /* xFetch */
0 /* xUnfetch */
};
/* Methods for sqlite3_file objects referencing a rollback journal
*/
static sqlite3_io_methods kvvfs_jrnl_io_methods = {
1, /* iVersion */
kvvfsClose, /* xClose */
kvvfsReadJrnl, /* xRead */
kvvfsWriteJrnl, /* xWrite */
kvvfsTruncateJrnl, /* xTruncate */
kvvfsSyncJrnl, /* xSync */
kvvfsFileSizeJrnl, /* xFileSize */
kvvfsLock, /* xLock */
kvvfsUnlock, /* xUnlock */
kvvfsCheckReservedLock, /* xCheckReservedLock */
kvvfsFileControlJrnl, /* xFileControl */
kvvfsSectorSize, /* xSectorSize */
kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0, /* xShmUnmap */
0, /* xFetch */
0 /* xUnfetch */
};
/****** Storage subsystem **************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* Forward declarations for the low-level storage engine
*/
static int kvstorageWrite(const char*, const char *zKey, const char *zData);
static int kvstorageDelete(const char*, const char *zKey);
static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
#define KVSTORAGE_KEY_SZ 32
/* Expand the key name with an appropriate prefix and put the result
** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least
** KVSTORAGE_KEY_SZ bytes.
*/
static void kvstorageMakeKey(
const char *zClass,
const char *zKeyIn,
char *zKeyOut
){
sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
}
/* Write content into a key. zClass is the particular namespace of the
** underlying key/value store to use - either "local" or "session".
**
** Both zKey and zData are zero-terminated pure text strings.
**
** Return the number of errors.
*/
static int kvstorageWrite(
const char *zClass,
const char *zKey,
const char *zData
){
FILE *fd;
char zXKey[KVSTORAGE_KEY_SZ];
kvstorageMakeKey(zClass, zKey, zXKey);
fd = fopen(zXKey, "wb");
if( fd ){
SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey,
(int)strlen(zData), zData,
strlen(zData)>50 ? "..." : ""));
fputs(zData, fd);
fclose(fd);
return 0;
}else{
return 1;
}
}
/* Delete a key (with its corresponding data) from the key/value
** namespace given by zClass. If the key does not previously exist,
** this routine is a no-op.
*/
static int kvstorageDelete(const char *zClass, const char *zKey){
char zXKey[KVSTORAGE_KEY_SZ];
kvstorageMakeKey(zClass, zKey, zXKey);
unlink(zXKey);
SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
return 0;
}
/* Read the value associated with a zKey from the key/value namespace given
** by zClass and put the text data associated with that key in the first
** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large
** enough to hold it all. The value put into zBuf must always be zero
** terminated, even if it gets truncated because nBuf is not large enough.
**
** Return the total number of bytes in the data, without truncation, and
** not counting the final zero terminator. Return -1 if the key does
** not exist.
**
** If nBuf<=0 then this routine simply returns the size of the data without
** actually reading it.
*/
static int kvstorageRead(
const char *zClass,
const char *zKey,
char *zBuf,
int nBuf
){
FILE *fd;
struct stat buf;
char zXKey[KVSTORAGE_KEY_SZ];
kvstorageMakeKey(zClass, zKey, zXKey);
if( access(zXKey, R_OK)!=0
|| stat(zXKey, &buf)!=0
|| !S_ISREG(buf.st_mode)
){
SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
return -1;
}
if( nBuf<=0 ){
return (int)buf.st_size;
}else if( nBuf==1 ){
zBuf[0] = 0;
SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey,
(int)buf.st_size));
return (int)buf.st_size;
}
if( nBuf > buf.st_size + 1 ){
nBuf = buf.st_size + 1;
}
fd = fopen(zXKey, "rb");
if( fd==0 ){
SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
return -1;
}else{
sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
fclose(fd);
zBuf[n] = 0;
SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey,
n, zBuf, n>50 ? "..." : ""));
return (int)n;
}
}
/*
** An internal level of indirection which enables us to replace the
** kvvfs i/o methods with JavaScript implementations in WASM builds.
** Maintenance reminder: if this struct changes in any way, the JSON
** rendering of its structure must be updated in
** sqlite3_wasm_enum_json(). There are no binary compatibility
** concerns, so it does not need an iVersion member. This file is
** necessarily always compiled together with sqlite3_wasm_enum_json(),
** and JS code dynamically creates the mapping of members based on
** that JSON description.
*/
typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods;
struct sqlite3_kvvfs_methods {
int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf);
int (*xWrite)(const char *zClass, const char *zKey, const char *zData);
int (*xDelete)(const char *zClass, const char *zKey);
const int nKeySize;
};
/*
** This object holds the kvvfs I/O methods which may be swapped out
** for JavaScript-side implementations in WASM builds. In such builds
** it cannot be const, but in native builds it should be so that
** the compiler can hopefully optimize this level of indirection out.
** That said, kvvfs is intended primarily for use in WASM builds.
**
** Note that this is not explicitly flagged as static because the
** amalgamation build will tag it with SQLITE_PRIVATE.
*/
#ifndef SQLITE_WASM
const
#endif
SQLITE_PRIVATE sqlite3_kvvfs_methods sqlite3KvvfsMethods = {
kvstorageRead,
kvstorageWrite,
kvstorageDelete,
KVSTORAGE_KEY_SZ
};
/****** Utility subroutines ************************************************/
/*
** Encode binary into the text encoded used to persist on disk.
** The output text is stored in aOut[], which must be at least
** nData+1 bytes in length.
**
** Return the actual length of the encoded text, not counting the
** zero terminator at the end.
**
** Encoding format
** ---------------
**
** * Non-zero bytes are encoded as upper-case hexadecimal
**
** * A sequence of one or more zero-bytes that are not at the
** beginning of the buffer are encoded as a little-endian
** base-26 number using a..z. "a" means 0. "b" means 1,
** "z" means 25. "ab" means 26. "ac" means 52. And so forth.
**
** * Because there is no overlap between the encoding characters
** of hexadecimal and base-26 numbers, it is always clear where
** one stops and the next begins.
*/
static int kvvfsEncode(const char *aData, int nData, char *aOut){
int i, j;
const unsigned char *a = (const unsigned char*)aData;
for(i=j=0; i<nData; i++){
unsigned char c = a[i];
if( c!=0 ){
aOut[j++] = "0123456789ABCDEF"[c>>4];
aOut[j++] = "0123456789ABCDEF"[c&0xf];
}else{
/* A sequence of 1 or more zeros is stored as a little-endian
** base-26 number using a..z as the digits. So one zero is "b".
** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
** and so forth.
*/
int k;
for(k=1; i+k<nData && a[i+k]==0; k++){}
i += k-1;
while( k>0 ){
aOut[j++] = 'a'+(k%26);
k /= 26;
}
}
}
aOut[j] = 0;
return j;
}
static const signed char kvvfsHexValue[256] = {
-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,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -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, -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, -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, -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
};
/*
** Decode the text encoding back to binary. The binary content is
** written into pOut, which must be at least nOut bytes in length.
**
** The return value is the number of bytes actually written into aOut[].
*/
static int kvvfsDecode(const char *a, char *aOut, int nOut){
int i, j;
int c;
const unsigned char *aIn = (const unsigned char*)a;
i = 0;
j = 0;
while( 1 ){
c = kvvfsHexValue[aIn[i]];
if( c<0 ){
int n = 0;
int mult = 1;
c = aIn[i];
if( c==0 ) break;
while( c>='a' && c<='z' ){
n += (c - 'a')*mult;
mult *= 26;
c = aIn[++i];
}
if( j+n>nOut ) return -1;
memset(&aOut[j], 0, n);
j += n;
c = aIn[i];
if( c==0 ) break;
}else{
aOut[j] = c<<4;
c = kvvfsHexValue[aIn[++i]];
if( c<0 ) break;
aOut[j++] += c;
i++;
}
}
return j;
}
/*
** Decode a complete journal file. Allocate space in pFile->aJrnl
** and store the decoding there. Or leave pFile->aJrnl set to NULL
** if an error is encountered.
**
** The first few characters of the text encoding will be a little-endian
** base-26 number (digits a..z) that is the total number of bytes
** in the decoded journal file image. This base-26 number is followed
** by a single space, then the encoding of the journal. The space
** separator is required to act as a terminator for the base-26 number.
*/
static void kvvfsDecodeJournal(
KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */
const char *zTxt, /* Text encoding. Zero-terminated */
int nTxt /* Bytes in zTxt, excluding zero terminator */
){
unsigned int n = 0;
int c, i, mult;
i = 0;
mult = 1;
while( (c = zTxt[i++])>='a' && c<='z' ){
n += (zTxt[i] - 'a')*mult;
mult *= 26;
}
sqlite3_free(pFile->aJrnl);
pFile->aJrnl = sqlite3_malloc64( n );
if( pFile->aJrnl==0 ){
pFile->nJrnl = 0;
return;
}
pFile->nJrnl = n;
n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl);
if( n<pFile->nJrnl ){
sqlite3_free(pFile->aJrnl);
pFile->aJrnl = 0;
pFile->nJrnl = 0;
}
}
/*
** Read or write the "sz" element, containing the database file size.
*/
static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
char zData[50];
zData[0] = 0;
sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
return strtoll(zData, 0, 0);
}
static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
char zData[50];
sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData);
}
/****** sqlite3_io_methods methods ******************************************/
/*
** Close an kvvfs-file.
*/
static int kvvfsClose(sqlite3_file *pProtoFile){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
pFile->isJournal ? "journal" : "db"));
sqlite3_free(pFile->aJrnl);
return SQLITE_OK;
}
/*
** Read from the -journal file.
*/
static int kvvfsReadJrnl(
sqlite3_file *pProtoFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
assert( pFile->isJournal );
SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
if( pFile->aJrnl==0 ){
int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
char *aTxt;
if( szTxt<=4 ){
return SQLITE_IOERR;
}
aTxt = sqlite3_malloc64( szTxt+1 );
if( aTxt==0 ) return SQLITE_NOMEM;
kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
kvvfsDecodeJournal(pFile, aTxt, szTxt);
sqlite3_free(aTxt);
if( pFile->aJrnl==0 ) return SQLITE_IOERR;
}
if( iOfst+iAmt>pFile->nJrnl ){
return SQLITE_IOERR_SHORT_READ;
}
memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
return SQLITE_OK;
}
/*
** Read from the database file.
*/
static int kvvfsReadDb(
sqlite3_file *pProtoFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
unsigned int pgno;
int got, n;
char zKey[30];
char aData[133073];
assert( iOfst>=0 );
assert( iAmt>=0 );
SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
if( iOfst+iAmt>=512 ){
if( (iOfst % iAmt)!=0 ){
return SQLITE_IOERR_READ;
}
if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){
return SQLITE_IOERR_READ;
}
pFile->szPage = iAmt;
pgno = 1 + iOfst/iAmt;
}else{
pgno = 1;
}
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, aData, sizeof(aData)-1);
if( got<0 ){
n = 0;
}else{
aData[got] = 0;
if( iOfst+iAmt<512 ){
int k = iOfst+iAmt;
aData[k*2] = 0;
n = kvvfsDecode(aData, &aData[2000], sizeof(aData)-2000);
if( n>=iOfst+iAmt ){
memcpy(zBuf, &aData[2000+iOfst], iAmt);
n = iAmt;
}else{
n = 0;
}
}else{
n = kvvfsDecode(aData, zBuf, iAmt);
}
}
if( n<iAmt ){
memset(zBuf+n, 0, iAmt-n);
return SQLITE_IOERR_SHORT_READ;
}
return SQLITE_OK;
}
/*
** Write into the -journal file.
*/
static int kvvfsWriteJrnl(
sqlite3_file *pProtoFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
sqlite3_int64 iEnd = iOfst+iAmt;
SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
if( iEnd>=0x10000000 ) return SQLITE_FULL;
if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd);
if( aNew==0 ){
return SQLITE_IOERR_NOMEM;
}
pFile->aJrnl = aNew;
if( pFile->nJrnl<iOfst ){
memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl);
}
pFile->nJrnl = iEnd;
}
memcpy(pFile->aJrnl+iOfst, zBuf, iAmt);
return SQLITE_OK;
}
/*
** Write into the database file.
*/
static int kvvfsWriteDb(
sqlite3_file *pProtoFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
unsigned int pgno;
char zKey[30];
char aData[131073];
SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
assert( iAmt>=512 && iAmt<=65536 );
assert( (iAmt & (iAmt-1))==0 );
pgno = 1 + iOfst/iAmt;
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
kvvfsEncode(zBuf, iAmt, aData);
if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){
return SQLITE_IOERR;
}
if( iOfst+iAmt > pFile->szDb ){
pFile->szDb = iOfst + iAmt;
}
return SQLITE_OK;
}
/*
** Truncate an kvvfs-file.
*/
static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
assert( size==0 );
sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl");
sqlite3_free(pFile->aJrnl);
pFile->aJrnl = 0;
pFile->nJrnl = 0;
return SQLITE_OK;
}
static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
if( pFile->szDb>size
&& pFile->szPage>0
&& (size % pFile->szPage)==0
){
char zKey[50];
unsigned int pgno, pgnoMax;
SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
pgno = 1 + size/pFile->szPage;
pgnoMax = 2 + pFile->szDb/pFile->szPage;
while( pgno<=pgnoMax ){
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey);
pgno++;
}
pFile->szDb = size;
return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK;
}
return SQLITE_IOERR;
}
/*
** Sync an kvvfs-file.
*/
static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){
int i, n;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
char *zOut;
SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass));
if( pFile->nJrnl<=0 ){
return kvvfsTruncateJrnl(pProtoFile, 0);
}
zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 );
if( zOut==0 ){
return SQLITE_IOERR_NOMEM;
}
n = pFile->nJrnl;
i = 0;
do{
zOut[i++] = 'a' + (n%26);
n /= 26;
}while( n>0 );
zOut[i++] = ' ';
kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut);
sqlite3_free(zOut);
return i ? SQLITE_IOERR : SQLITE_OK;
}
static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){
return SQLITE_OK;
}
/*
** Return the current file-size of an kvvfs-file.
*/
static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
*pSize = pFile->nJrnl;
return SQLITE_OK;
}
static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass));
if( pFile->szDb>=0 ){
*pSize = pFile->szDb;
}else{
*pSize = kvvfsReadFileSize(pFile);
}
return SQLITE_OK;
}
/*
** Lock an kvvfs-file.
*/
static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
assert( !pFile->isJournal );
SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
if( eLock!=SQLITE_LOCK_NONE ){
pFile->szDb = kvvfsReadFileSize(pFile);
}
return SQLITE_OK;
}
/*
** Unlock an kvvfs-file.
*/
static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
assert( !pFile->isJournal );
SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
if( eLock==SQLITE_LOCK_NONE ){
pFile->szDb = -1;
}
return SQLITE_OK;
}
/*
** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
*/
static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){
SQLITE_KV_LOG(("xCheckReservedLock\n"));
*pResOut = 0;
return SQLITE_OK;
}
/*
** File control method. For custom operations on an kvvfs-file.
*/
static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){
SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op));
return SQLITE_NOTFOUND;
}
static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){
SQLITE_KV_LOG(("xFileControl(%d) on database\n", op));
if( op==SQLITE_FCNTL_SYNC ){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
int rc = SQLITE_OK;
SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass));
if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){
rc = SQLITE_IOERR;
}
return rc;
}
return SQLITE_NOTFOUND;
}
/*
** Return the sector-size in bytes for an kvvfs-file.
*/
static int kvvfsSectorSize(sqlite3_file *pFile){
return 512;
}
/*
** Return the device characteristic flags supported by an kvvfs-file.
*/
static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){
return 0;
}
/****** sqlite3_vfs methods *************************************************/
/*
** Open an kvvfs file handle.
*/
static int kvvfsOpen(
sqlite3_vfs *pProtoVfs,
const char *zName,
sqlite3_file *pProtoFile,
int flags,
int *pOutFlags
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
if( strcmp(zName, "local")==0
|| strcmp(zName, "session")==0
){
pFile->isJournal = 0;
pFile->base.pMethods = &kvvfs_db_io_methods;
}else
if( strcmp(zName, "local-journal")==0
|| strcmp(zName, "session-journal")==0
){
pFile->isJournal = 1;
pFile->base.pMethods = &kvvfs_jrnl_io_methods;
}else{
return SQLITE_CANTOPEN;
}
if( zName[0]=='s' ){
pFile->zClass = "session";
}else{
pFile->zClass = "local";
}
pFile->aJrnl = 0;
pFile->nJrnl = 0;
pFile->szPage = -1;
pFile->szDb = -1;
return SQLITE_OK;
}
/*
** Delete the file located at zPath. If the dirSync argument is true,
** ensure the file-system modifications are synced to disk before
** returning.
*/
static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
if( strcmp(zPath, "local-journal")==0 ){
sqlite3KvvfsMethods.xDelete("local", "jrnl");
}else
if( strcmp(zPath, "session-journal")==0 ){
sqlite3KvvfsMethods.xDelete("session", "jrnl");
}
return SQLITE_OK;
}
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int kvvfsAccess(
sqlite3_vfs *pProtoVfs,
const char *zPath,
int flags,
int *pResOut
){
SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
if( strcmp(zPath, "local-journal")==0 ){
*pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0;
}else
if( strcmp(zPath, "session-journal")==0 ){
*pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0;
}else
if( strcmp(zPath, "local")==0 ){
*pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0;
}else
if( strcmp(zPath, "session")==0 ){
*pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0;
}else
{
*pResOut = 0;
}
SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
return SQLITE_OK;
}
/*
** Populate buffer zOut with the full canonical pathname corresponding
** to the pathname in zPath. zOut is guaranteed to point to a buffer
** of at least (INST_MAX_PATHNAME+1) bytes.
*/
static int kvvfsFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nOut,
char *zOut
){
size_t nPath;
#ifdef SQLITE_OS_KV_ALWAYS_LOCAL
zPath = "local";
#endif
nPath = strlen(zPath);
SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath));
if( nOut<nPath+1 ) nPath = nOut - 1;
memcpy(zOut, zPath, nPath);
zOut[nPath] = 0;
return SQLITE_OK;
}
/*
** Open the dynamic library located at zPath and return a handle.
*/
static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return 0;
}
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
memset(zBufOut, 0, nByte);
return nByte;
}
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
return SQLITE_OK;
}
/*
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
sqlite3_int64 i = 0;
int rc;
rc = kvvfsCurrentTimeInt64(0, &i);
*pTimeOut = i/86400000.0;
return rc;
}
#include <sys/time.h>
static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
struct timeval sNow;
(void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
*pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
return SQLITE_OK;
}
#endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
#if SQLITE_OS_KV
/*
** This routine is called initialize the KV-vfs as the default VFS.
*/
SQLITE_API int sqlite3_os_init(void){
return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1);
}
SQLITE_API int sqlite3_os_end(void){
return SQLITE_OK;
}
#endif /* SQLITE_OS_KV */
#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
SQLITE_PRIVATE int sqlite3KvvfsInit(void){
return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0);
}
#endif
/************** End of os_kv.c ***********************************************/
/************** Begin file os_unix.c *****************************************/
/*
** 2004 May 22
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
|
| ︙ | ︙ | |||
35548 35549 35550 35551 35552 35553 35554 | # undef USE_PREAD64 # define USE_PREAD 1 #endif /* ** standard include files. */ | | | | | | 36709 36710 36711 36712 36713 36714 36715 36716 36717 36718 36719 36720 36721 36722 36723 36724 36725 36726 36727 36728 36729 | # undef USE_PREAD64 # define USE_PREAD 1 #endif /* ** standard include files. */ #include <sys/types.h> /* amalgamator: keep */ #include <sys/stat.h> /* amalgamator: keep */ #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> /* amalgamator: keep */ /* #include <time.h> */ #include <sys/time.h> /* amalgamator: keep */ #include <errno.h> #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 # include <sys/mman.h> #endif #if SQLITE_ENABLE_LOCKING_STYLE /* # include <sys/ioctl.h> */ |
| ︙ | ︙ | |||
41316 41317 41318 41319 41320 41321 41322 41323 41324 41325 41326 41327 41328 41329 41330 41331 |
** Create a temporary file name in zBuf. zBuf must be allocated
** by the calling process and must be big enough to hold at least
** pVfs->mxPathname bytes.
*/
static int unixGetTempname(int nBuf, char *zBuf){
const char *zDir;
int iLimit = 0;
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
** function failing.
*/
zBuf[0] = 0;
SimulateIOError( return SQLITE_IOERR );
zDir = unixTempFileDir();
| > > > | > | | | | | | | | > > > | > > | | 42477 42478 42479 42480 42481 42482 42483 42484 42485 42486 42487 42488 42489 42490 42491 42492 42493 42494 42495 42496 42497 42498 42499 42500 42501 42502 42503 42504 42505 42506 42507 42508 42509 42510 42511 42512 42513 42514 42515 42516 42517 42518 42519 |
** Create a temporary file name in zBuf. zBuf must be allocated
** by the calling process and must be big enough to hold at least
** pVfs->mxPathname bytes.
*/
static int unixGetTempname(int nBuf, char *zBuf){
const char *zDir;
int iLimit = 0;
int rc = SQLITE_OK;
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
** function failing.
*/
zBuf[0] = 0;
SimulateIOError( return SQLITE_IOERR );
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
zDir = unixTempFileDir();
if( zDir==0 ){
rc = SQLITE_IOERR_GETTEMPPATH;
}else{
do{
u64 r;
sqlite3_randomness(sizeof(r), &r);
assert( nBuf>2 );
zBuf[nBuf-2] = 0;
sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
zDir, r, 0);
if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ){
rc = SQLITE_ERROR;
break;
}
}while( osAccess(zBuf,0)==0 );
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
return rc;
}
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
/*
** Routine to transform a unixFile into a proxy-locking unixFile.
** Implementation in the proxy-lock division, but used by unixOpen()
** if SQLITE_PREFER_PROXY_LOCKING is defined.
|
| ︙ | ︙ | |||
43510 43511 43512 43513 43514 43515 43516 43517 43518 43519 43520 43521 43522 43523 43524 43525 |
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==29 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
sqlite3_vfs_register(&aVfs[i], i==0);
}
unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#ifndef SQLITE_OMIT_WAL
/* Validate lock assumptions */
assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */
assert( UNIX_SHM_BASE==120 ); /* Start of locking area */
/* Locks:
| > > > > > > > > | 44680 44681 44682 44683 44684 44685 44686 44687 44688 44689 44690 44691 44692 44693 44694 44695 44696 44697 44698 44699 44700 44701 44702 44703 |
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==29 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
#ifdef SQLITE_DEFAULT_UNIX_VFS
sqlite3_vfs_register(&aVfs[i],
0==strcmp(aVfs[i].zName,SQLITE_DEFAULT_UNIX_VFS));
#else
sqlite3_vfs_register(&aVfs[i], i==0);
#endif
}
#ifdef SQLITE_OS_KV_OPTIONAL
sqlite3KvvfsInit();
#endif
unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#ifndef SQLITE_OMIT_WAL
/* Validate lock assumptions */
assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */
assert( UNIX_SHM_BASE==120 ); /* Start of locking area */
/* Locks:
|
| ︙ | ︙ | |||
45474 45475 45476 45477 45478 45479 45480 45481 |
** it accepts a UTF-8 string.
*/
SQLITE_API int sqlite3_win32_set_directory8(
unsigned long type, /* Identifier for directory being set or reset */
const char *zValue /* New value for directory being set or reset */
){
char **ppDirectory = 0;
#ifndef SQLITE_OMIT_AUTOINIT
| > | > | > | > > > > | | 46652 46653 46654 46655 46656 46657 46658 46659 46660 46661 46662 46663 46664 46665 46666 46667 46668 46669 46670 46671 46672 46673 46674 46675 46676 46677 46678 46679 46680 46681 46682 46683 46684 46685 46686 46687 46688 46689 46690 46691 46692 46693 46694 46695 46696 46697 46698 |
** it accepts a UTF-8 string.
*/
SQLITE_API int sqlite3_win32_set_directory8(
unsigned long type, /* Identifier for directory being set or reset */
const char *zValue /* New value for directory being set or reset */
){
char **ppDirectory = 0;
int rc;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
if( rc ) return rc;
#endif
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){
ppDirectory = &sqlite3_data_directory;
}else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){
ppDirectory = &sqlite3_temp_directory;
}
assert( !ppDirectory || type==SQLITE_WIN32_DATA_DIRECTORY_TYPE
|| type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE
);
assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) );
if( ppDirectory ){
char *zCopy = 0;
if( zValue && zValue[0] ){
zCopy = sqlite3_mprintf("%s", zValue);
if ( zCopy==0 ){
rc = SQLITE_NOMEM_BKPT;
goto set_directory8_done;
}
}
sqlite3_free(*ppDirectory);
*ppDirectory = zCopy;
rc = SQLITE_OK;
}else{
rc = SQLITE_ERROR;
}
set_directory8_done:
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
return rc;
}
/*
** This function is the same as sqlite3_win32_set_directory (below); however,
** it accepts a UTF-16 string.
*/
SQLITE_API int sqlite3_win32_set_directory16(
|
| ︙ | ︙ | |||
48272 48273 48274 48275 48276 48277 48278 48279 48280 48281 48282 48283 48284 48285 |
zBuf[nLen+1] = '\0';
return 1;
}
}
}
return 0;
}
/*
** Create a temporary file name and store the resulting pointer into pzBuf.
** The pointer returned in pzBuf must be freed via sqlite3_free().
*/
static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
static char zChars[] =
| > > > > > > > > > > > > | 49457 49458 49459 49460 49461 49462 49463 49464 49465 49466 49467 49468 49469 49470 49471 49472 49473 49474 49475 49476 49477 49478 49479 49480 49481 49482 |
zBuf[nLen+1] = '\0';
return 1;
}
}
}
return 0;
}
/*
** If sqlite3_temp_directory is not, take the mutex and return true.
**
** If sqlite3_temp_directory is NULL, omit the mutex and return false.
*/
static int winTempDirDefined(void){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( sqlite3_temp_directory!=0 ) return 1;
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
return 0;
}
/*
** Create a temporary file name and store the resulting pointer into pzBuf.
** The pointer returned in pzBuf must be freed via sqlite3_free().
*/
static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
static char zChars[] =
|
| ︙ | ︙ | |||
48309 48310 48311 48312 48313 48314 48315 | /* Figure out the effective temporary directory. First, check if one ** has been explicitly set by the application; otherwise, use the one ** configured by the operating system. */ nDir = nMax - (nPre + 15); assert( nDir>0 ); | | > > > | 49506 49507 49508 49509 49510 49511 49512 49513 49514 49515 49516 49517 49518 49519 49520 49521 49522 49523 49524 49525 49526 49527 49528 49529 49530 49531 49532 49533 49534 49535 49536 |
/* Figure out the effective temporary directory. First, check if one
** has been explicitly set by the application; otherwise, use the one
** configured by the operating system.
*/
nDir = nMax - (nPre + 15);
assert( nDir>0 );
if( winTempDirDefined() ){
int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);
if( nDirLen>0 ){
if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){
nDirLen++;
}
if( nDirLen>nDir ){
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);
}
sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
}
#if defined(__CYGWIN__)
else{
static const char *azDirs[] = {
0, /* getenv("SQLITE_TMPDIR") */
0, /* getenv("TMPDIR") */
0, /* getenv("TMP") */
0, /* getenv("TEMP") */
|
| ︙ | ︙ | |||
49111 49112 49113 49114 49115 49116 49117 | } /* ** Turn a relative pathname into a full pathname. Write the full ** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname ** bytes in size. */ | | | 50311 50312 50313 50314 50315 50316 50317 50318 50319 50320 50321 50322 50323 50324 50325 |
}
/*
** Turn a relative pathname into a full pathname. Write the full
** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
** bytes in size.
*/
static int winFullPathnameNoMutex(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
DWORD nByte;
|
| ︙ | ︙ | |||
49289 49290 49291 49292 49293 49294 49295 49296 49297 49298 49299 49300 49301 49302 |
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
sqlite3_free(zOut);
return SQLITE_OK;
}else{
return SQLITE_IOERR_NOMEM_BKPT;
}
#endif
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
| > > > > > > > > > > > > > > | 50489 50490 50491 50492 50493 50494 50495 50496 50497 50498 50499 50500 50501 50502 50503 50504 50505 50506 50507 50508 50509 50510 50511 50512 50513 50514 50515 50516 |
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
sqlite3_free(zOut);
return SQLITE_OK;
}else{
return SQLITE_IOERR_NOMEM_BKPT;
}
#endif
}
static int winFullPathname(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
int rc;
MUTEX_LOGIC( sqlite3_mutex *pMutex; )
MUTEX_LOGIC( pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR); )
sqlite3_mutex_enter(pMutex);
rc = winFullPathnameNoMutex(pVfs, zRelative, nFull, zFull);
sqlite3_mutex_leave(pMutex);
return rc;
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
|
| ︙ | ︙ | |||
51078 51079 51080 51081 51082 51083 51084 |
** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
** is displayed for many operations, resulting in a lot of output.
*/
#if defined(SQLITE_DEBUG) && 0
int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
| > > > > > > > > > > | | < < | < < < < | | > > > > > > > > > > > > > > > | > > > > | > | 52292 52293 52294 52295 52296 52297 52298 52299 52300 52301 52302 52303 52304 52305 52306 52307 52308 52309 52310 52311 52312 52313 52314 52315 52316 52317 52318 52319 52320 52321 52322 52323 52324 52325 52326 52327 52328 52329 52330 52331 52332 52333 52334 52335 52336 52337 52338 52339 52340 52341 52342 52343 52344 52345 52346 52347 52348 52349 52350 52351 52352 52353 52354 52355 52356 52357 52358 52359 52360 52361 52362 52363 52364 52365 52366 52367 52368 52369 52370 52371 52372 52373 52374 52375 52376 52377 52378 |
** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
** is displayed for many operations, resulting in a lot of output.
*/
#if defined(SQLITE_DEBUG) && 0
int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
static void pcachePageTrace(int i, sqlite3_pcache_page *pLower){
PgHdr *pPg;
unsigned char *a;
int j;
pPg = (PgHdr*)pLower->pExtra;
printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
a = (unsigned char *)pLower->pBuf;
for(j=0; j<12; j++) printf("%02x", a[j]);
printf(" ptr %p\n", pPg);
}
static void pcacheDump(PCache *pCache){
int N;
int i;
sqlite3_pcache_page *pLower;
if( sqlite3PcacheTrace<2 ) return;
if( pCache->pCache==0 ) return;
N = sqlite3PcachePagecount(pCache);
if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
for(i=1; i<=N; i++){
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
if( pLower==0 ) continue;
pcachePageTrace(i, pLower);
if( ((PgHdr*)pLower)->pPage==0 ){
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
}
#else
# define pcacheTrace(X)
# define pcachePageTrace(PGNO, X)
# define pcacheDump(X)
#endif
/*
** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
** This routine runs inside of assert() statements only.
*/
#ifdef SQLITE_DEBUG
static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
PgHdr *p;
for(p=pCache->pDirty; p; p=p->pDirtyNext){
if( p==pPg ) return 1;
}
return 0;
}
#endif
/*
** Check invariants on a PgHdr entry. Return true if everything is OK.
** Return false if any invariant is violated.
**
** This routine is for use inside of assert() statements only. For
** example:
**
** assert( sqlite3PcachePageSanity(pPg) );
*/
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
PCache *pCache;
assert( pPg!=0 );
assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */
pCache = pPg->pCache;
assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){
assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
}else{
assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
assert( pPg->pDirtyPrev==0 || pPg->pDirtyPrev->pDirtyNext==pPg );
assert( pPg->pDirtyPrev!=0 || pCache->pDirty==pPg );
assert( pageOnDirtyList(pCache, pPg) );
}
/* WRITEABLE pages must also be DIRTY */
if( pPg->flags & PGHDR_WRITEABLE ){
assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */
}
/* NEED_SYNC can be set independently of WRITEABLE. This can happen,
** for example, when using the sqlite3PagerDontWrite() optimization:
|
| ︙ | ︙ | |||
51400 51401 51402 51403 51404 51405 51406 | ** (createFlag==1 AND !(bPurgeable AND pDirty) */ eCreate = createFlag & pCache->eCreate; assert( eCreate==0 || eCreate==1 || eCreate==2 ); assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); | | > | 52638 52639 52640 52641 52642 52643 52644 52645 52646 52647 52648 52649 52650 52651 52652 52653 52654 |
** (createFlag==1 AND !(bPurgeable AND pDirty)
*/
eCreate = createFlag & pCache->eCreate;
assert( eCreate==0 || eCreate==1 || eCreate==2 );
assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno,
createFlag?" create":"",pRes));
pcachePageTrace(pgno, pRes);
return pRes;
}
/*
** If the sqlite3PcacheFetch() routine is unable to allocate a new
** page because no clean pages are available for reuse and the cache
** size limit has been reached, then this routine can be invoked to
|
| ︙ | ︙ | |||
51529 51530 51531 51532 51533 51534 51535 51536 51537 51538 51539 51540 51541 51542 |
assert( p->nRef>0 );
p->pCache->nRefSum--;
if( (--p->nRef)==0 ){
if( p->flags&PGHDR_CLEAN ){
pcacheUnpin(p);
}else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
}
/*
** Increase the reference count of a supplied page by 1.
*/
| > | 52768 52769 52770 52771 52772 52773 52774 52775 52776 52777 52778 52779 52780 52781 52782 |
assert( p->nRef>0 );
p->pCache->nRefSum--;
if( (--p->nRef)==0 ){
if( p->flags&PGHDR_CLEAN ){
pcacheUnpin(p);
}else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
assert( sqlite3PcachePageSanity(p) );
}
}
}
/*
** Increase the reference count of a supplied page by 1.
*/
|
| ︙ | ︙ | |||
51572 51573 51574 51575 51576 51577 51578 51579 51580 51581 51582 51583 51584 51585 |
if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/
p->flags &= ~PGHDR_DONT_WRITE;
if( p->flags & PGHDR_CLEAN ){
p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
}
assert( sqlite3PcachePageSanity(p) );
}
}
/*
** Make sure the page is marked as clean. If it isn't clean already,
| > | 52812 52813 52814 52815 52816 52817 52818 52819 52820 52821 52822 52823 52824 52825 52826 |
if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/
p->flags &= ~PGHDR_DONT_WRITE;
if( p->flags & PGHDR_CLEAN ){
p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
assert( sqlite3PcachePageSanity(p) );
}
assert( sqlite3PcachePageSanity(p) );
}
}
/*
** Make sure the page is marked as clean. If it isn't clean already,
|
| ︙ | ︙ | |||
51634 51635 51636 51637 51638 51639 51640 51641 51642 51643 51644 51645 51646 51647 51648 51649 51650 51651 51652 51653 51654 51655 |
}
/*
** Change the page number of page p to newPgno.
*/
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
assert( p->nRef>0 );
assert( newPgno>0 );
assert( sqlite3PcachePageSanity(p) );
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
/*
** Drop every cache entry whose page number is greater than "pgno". The
** caller must ensure that there are no outstanding references to any pages
** other than page 1 with a page number greater than pgno.
| > > > > > > > > > > | 52875 52876 52877 52878 52879 52880 52881 52882 52883 52884 52885 52886 52887 52888 52889 52890 52891 52892 52893 52894 52895 52896 52897 52898 52899 52900 52901 52902 52903 52904 52905 52906 |
}
/*
** Change the page number of page p to newPgno.
*/
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
sqlite3_pcache_page *pOther;
assert( p->nRef>0 );
assert( newPgno>0 );
assert( sqlite3PcachePageSanity(p) );
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
pOther = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, newPgno, 0);
if( pOther ){
PgHdr *pXPage = (PgHdr*)pOther->pExtra;
assert( pXPage->nRef==0 );
pXPage->nRef++;
pCache->nRefSum++;
sqlite3PcacheDrop(pXPage);
}
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
assert( sqlite3PcachePageSanity(p) );
}
}
/*
** Drop every cache entry whose page number is greater than "pgno". The
** caller must ensure that there are no outstanding references to any pages
** other than page 1 with a page number greater than pgno.
|
| ︙ | ︙ | |||
51939 51940 51941 51942 51943 51944 51945 | ** ** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at ** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The ** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this ** size can vary according to architecture, compile-time options, and ** SQLite library version number. ** | | > | < | > > | < | 53190 53191 53192 53193 53194 53195 53196 53197 53198 53199 53200 53201 53202 53203 53204 53205 53206 53207 53208 53209 53210 | ** ** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at ** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The ** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this ** size can vary according to architecture, compile-time options, and ** SQLite library version number. ** ** Historical note: It used to be that if the SQLITE_PCACHE_SEPARATE_HEADER ** was defined, then the page content would be held in a separate memory ** allocation from the PgHdr1. This was intended to avoid clownshoe memory ** allocations. However, the btree layer needs a small (16-byte) overrun ** area after the page content buffer. The header serves as that overrun ** area. Therefore SQLITE_PCACHE_SEPARATE_HEADER was discontinued to avoid ** any possibility of a memory error. ** ** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates ** with this module. Information is passed back and forth as PgHdr1 pointers. ** ** The pcache.c and pager.c modules deal pointers to PgHdr objects. ** The btree.c module deals with pointers to MemPage objects. ** |
| ︙ | ︙ | |||
51989 51990 51991 51992 51993 51994 51995 | typedef struct PCache1 PCache1; typedef struct PgHdr1 PgHdr1; typedef struct PgFreeslot PgFreeslot; typedef struct PGroup PGroup; /* ** Each cache entry is represented by an instance of the following | | | | > > > > > | | | > > > > > | | | | | | | | | | 53241 53242 53243 53244 53245 53246 53247 53248 53249 53250 53251 53252 53253 53254 53255 53256 53257 53258 53259 53260 53261 53262 53263 53264 53265 53266 53267 53268 53269 53270 53271 53272 53273 53274 53275 53276 53277 53278 53279 53280 53281 53282 53283 53284 53285 53286 53287 53288 |
typedef struct PCache1 PCache1;
typedef struct PgHdr1 PgHdr1;
typedef struct PgFreeslot PgFreeslot;
typedef struct PGroup PGroup;
/*
** Each cache entry is represented by an instance of the following
** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
** directly before this structure and is used to cache the page content.
**
** When reading a corrupt database file, it is possible that SQLite might
** read a few bytes (no more than 16 bytes) past the end of the page buffer.
** It will only read past the end of the page buffer, never write. This
** object is positioned immediately after the page buffer to serve as an
** overrun area, so that overreads are harmless.
**
** Variables isBulkLocal and isAnchor were once type "u8". That works,
** but causes a 2-byte gap in the structure for most architectures (since
** pointers must be either 4 or 8-byte aligned). As this structure is located
** in memory directly after the associated page data, if the database is
** corrupt, code at the b-tree layer may overread the page buffer and
** read part of this structure before the corruption is detected. This
** can cause a valgrind error if the unitialized gap is accessed. Using u16
** ensures there is no such gap, and therefore no bytes of uninitialized
** memory in the structure.
**
** The pLruNext and pLruPrev pointers form a double-linked circular list
** of all pages that are unpinned. The PGroup.lru element (which should be
** the only element on the list with PgHdr1.isAnchor set to 1) forms the
** beginning and the end of the list.
*/
struct PgHdr1 {
sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
unsigned int iKey; /* Key value (page number) */
u16 isBulkLocal; /* This page from bulk local storage */
u16 isAnchor; /* This is the PGroup.lru element */
PgHdr1 *pNext; /* Next in hash table chain */
PCache1 *pCache; /* Cache that currently owns this page */
PgHdr1 *pLruNext; /* Next in circular LRU list of unpinned pages */
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
/* NB: pLruPrev is only valid if pLruNext!=0 */
};
/*
** A page is pinned if it is not on the LRU list. To be "pinned" means
** that the page is in active use and must not be deallocated.
*/
#define PAGE_IS_PINNED(p) ((p)->pLruNext==0)
|
| ︙ | ︙ | |||
52338 52339 52340 52341 52342 52343 52344 |
** is because it might call sqlite3_release_memory(), which assumes that
** this mutex is not held. */
assert( pcache1.separateCache==0 );
assert( pCache->pGroup==&pcache1.grp );
pcache1LeaveMutex(pCache->pGroup);
#endif
if( benignMalloc ){ sqlite3BeginBenignMalloc(); }
| < < < < < < < < < < < < | 53600 53601 53602 53603 53604 53605 53606 53607 53608 53609 53610 53611 53612 53613 53614 53615 53616 53617 53618 53619 53620 |
** is because it might call sqlite3_release_memory(), which assumes that
** this mutex is not held. */
assert( pcache1.separateCache==0 );
assert( pCache->pGroup==&pcache1.grp );
pcache1LeaveMutex(pCache->pGroup);
#endif
if( benignMalloc ){ sqlite3BeginBenignMalloc(); }
pPg = pcache1Alloc(pCache->szAlloc);
if( benignMalloc ){ sqlite3EndBenignMalloc(); }
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
pcache1EnterMutex(pCache->pGroup);
#endif
if( pPg==0 ) return 0;
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
p->page.pBuf = pPg;
p->page.pExtra = &p[1];
p->isBulkLocal = 0;
p->isAnchor = 0;
p->pLruPrev = 0; /* Initializing this saves a valgrind error */
}
(*pCache->pnPurgeable)++;
|
| ︙ | ︙ | |||
52380 52381 52382 52383 52384 52385 52386 |
pCache = p->pCache;
assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
if( p->isBulkLocal ){
p->pNext = pCache->pFree;
pCache->pFree = p;
}else{
pcache1Free(p->page.pBuf);
| < < < | 53630 53631 53632 53633 53634 53635 53636 53637 53638 53639 53640 53641 53642 53643 |
pCache = p->pCache;
assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
if( p->isBulkLocal ){
p->pNext = pCache->pFree;
pCache->pFree = p;
}else{
pcache1Free(p->page.pBuf);
}
(*pCache->pnPurgeable)--;
}
/*
** Malloc function used by SQLite to obtain space from the buffer configured
** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer
|
| ︙ | ︙ | |||
53023 53024 53025 53026 53027 53028 53029 |
sqlite3_pcache_page *pPg,
unsigned int iOld,
unsigned int iNew
){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = (PgHdr1 *)pPg;
PgHdr1 **pp;
| | > > | | > | | | | 54270 54271 54272 54273 54274 54275 54276 54277 54278 54279 54280 54281 54282 54283 54284 54285 54286 54287 54288 54289 54290 54291 54292 54293 54294 54295 54296 54297 54298 54299 54300 54301 54302 54303 |
sqlite3_pcache_page *pPg,
unsigned int iOld,
unsigned int iNew
){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = (PgHdr1 *)pPg;
PgHdr1 **pp;
unsigned int hOld, hNew;
assert( pPage->iKey==iOld );
assert( pPage->pCache==pCache );
assert( iOld!=iNew ); /* The page number really is changing */
pcache1EnterMutex(pCache->pGroup);
assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */
hOld = iOld%pCache->nHash;
pp = &pCache->apHash[hOld];
while( (*pp)!=pPage ){
pp = &(*pp)->pNext;
}
*pp = pPage->pNext;
assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not in cache */
hNew = iNew%pCache->nHash;
pPage->iKey = iNew;
pPage->pNext = pCache->apHash[hNew];
pCache->apHash[hNew] = pPage;
if( iNew>pCache->iMaxKey ){
pCache->iMaxKey = iNew;
}
pcache1LeaveMutex(pCache->pGroup);
}
|
| ︙ | ︙ | |||
53146 53147 53148 53149 53150 53151 53152 |
PgHdr1 *p;
pcache1EnterMutex(&pcache1.grp);
while( (nReq<0 || nFree<nReq)
&& (p=pcache1.grp.lru.pLruPrev)!=0
&& p->isAnchor==0
){
nFree += pcache1MemSize(p->page.pBuf);
| < < < | 54396 54397 54398 54399 54400 54401 54402 54403 54404 54405 54406 54407 54408 54409 |
PgHdr1 *p;
pcache1EnterMutex(&pcache1.grp);
while( (nReq<0 || nFree<nReq)
&& (p=pcache1.grp.lru.pLruPrev)!=0
&& p->isAnchor==0
){
nFree += pcache1MemSize(p->page.pBuf);
assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
}
pcache1LeaveMutex(&pcache1.grp);
}
return nFree;
|
| ︙ | ︙ | |||
59637 59638 59639 59640 59641 59642 59643 59644 59645 59646 59647 59648 59649 59650 |
sqlite3MemJournalOpen(pPager->jfd);
}else{
int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
int nSpill;
if( pPager->tempFile ){
flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
nSpill = sqlite3Config.nStmtSpill;
}else{
flags |= SQLITE_OPEN_MAIN_JOURNAL;
nSpill = jrnlBufferSize(pPager);
}
/* Verify that the database still has the same name as it did when
| > | 60884 60885 60886 60887 60888 60889 60890 60891 60892 60893 60894 60895 60896 60897 60898 |
sqlite3MemJournalOpen(pPager->jfd);
}else{
int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
int nSpill;
if( pPager->tempFile ){
flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
flags |= SQLITE_OPEN_EXCLUSIVE;
nSpill = sqlite3Config.nStmtSpill;
}else{
flags |= SQLITE_OPEN_MAIN_JOURNAL;
nSpill = jrnlBufferSize(pPager);
}
/* Verify that the database still has the same name as it did when
|
| ︙ | ︙ | |||
59672 59673 59674 59675 59676 59677 59678 59679 59680 59681 59682 59683 59684 59685 |
rc = writeJournalHdr(pPager);
}
}
if( rc!=SQLITE_OK ){
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
}else{
assert( pPager->eState==PAGER_WRITER_LOCKED );
pPager->eState = PAGER_WRITER_CACHEMOD;
}
return rc;
}
| > | 60920 60921 60922 60923 60924 60925 60926 60927 60928 60929 60930 60931 60932 60933 60934 |
rc = writeJournalHdr(pPager);
}
}
if( rc!=SQLITE_OK ){
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
pPager->journalOff = 0;
}else{
assert( pPager->eState==PAGER_WRITER_LOCKED );
pPager->eState = PAGER_WRITER_CACHEMOD;
}
return rc;
}
|
| ︙ | ︙ | |||
66735 66736 66737 66738 66739 66740 66741 66742 66743 66744 66745 66746 66747 66748 |
**
** If pSchema is not NULL, then iDb is computed from pSchema and
** db using sqlite3SchemaToIndex().
*/
SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
Btree *p;
assert( db!=0 );
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
assert( iDb>=0 && iDb<db->nDb );
if( !sqlite3_mutex_held(db->mutex) ) return 0;
if( iDb==1 ) return 1;
p = db->aDb[iDb].pBt;
assert( p!=0 );
return p->sharable==0 || p->locked==1;
| > | 67984 67985 67986 67987 67988 67989 67990 67991 67992 67993 67994 67995 67996 67997 67998 |
**
** If pSchema is not NULL, then iDb is computed from pSchema and
** db using sqlite3SchemaToIndex().
*/
SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
Btree *p;
assert( db!=0 );
if( db->pVfs==0 && db->nDb==0 ) return 1;
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
assert( iDb>=0 && iDb<db->nDb );
if( !sqlite3_mutex_held(db->mutex) ) return 0;
if( iDb==1 ) return 1;
p = db->aDb[iDb].pBt;
assert( p!=0 );
return p->sharable==0 || p->locked==1;
|
| ︙ | ︙ | |||
68307 68308 68309 68310 68311 68312 68313 | int iCellStart; /* First cell offset in input */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt!=0 ); assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); assert( pPage->nOverflow==0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); | < | | 69557 69558 69559 69560 69561 69562 69563 69564 69565 69566 69567 69568 69569 69570 69571 | int iCellStart; /* First cell offset in input */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt!=0 ); assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE ); assert( pPage->nOverflow==0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); data = pPage->aData; hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; assert( nCell==get2byte(&data[hdr+3]) || CORRUPT_DB ); iCellFirst = cellOffset + 2*nCell; usableSize = pPage->pBt->usableSize; |
| ︙ | ︙ | |||
68342 68343 68344 68345 68346 68347 68348 |
}
if( iFree2 ){
if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage);
sz2 = get2byte(&data[iFree2+2]);
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
| | > > > > | | | | | | | | | | | | | | | | | | | | | | < < < | < < | | 69591 69592 69593 69594 69595 69596 69597 69598 69599 69600 69601 69602 69603 69604 69605 69606 69607 69608 69609 69610 69611 69612 69613 69614 69615 69616 69617 69618 69619 69620 69621 69622 69623 69624 69625 69626 69627 69628 69629 69630 69631 69632 69633 69634 69635 69636 69637 69638 69639 69640 69641 69642 69643 69644 69645 69646 69647 69648 69649 69650 69651 69652 69653 69654 69655 69656 |
}
if( iFree2 ){
if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage);
sz2 = get2byte(&data[iFree2+2]);
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
}else if( iFree+sz>usableSize ){
return SQLITE_CORRUPT_PAGE(pPage);
}
cbrk = top+sz;
assert( cbrk+(iFree-top) <= usableSize );
memmove(&data[cbrk], &data[top], iFree-top);
for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){
pc = get2byte(pAddr);
if( pc<iFree ){ put2byte(pAddr, pc+sz); }
else if( pc<iFree2 ){ put2byte(pAddr, pc+sz2); }
}
goto defragment_out;
}
}
}
cbrk = usableSize;
iCellLast = usableSize - 4;
iCellStart = get2byte(&data[hdr+5]);
if( nCell>0 ){
temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
src = temp;
for(i=0; i<nCell; i++){
u8 *pAddr; /* The i-th cell pointer */
pAddr = &data[cellOffset + i*2];
pc = get2byte(pAddr);
testcase( pc==iCellFirst );
testcase( pc==iCellLast );
/* These conditions have already been verified in btreeInitPage()
** if PRAGMA cell_size_check=ON.
*/
if( pc<iCellStart || pc>iCellLast ){
return SQLITE_CORRUPT_PAGE(pPage);
}
assert( pc>=iCellStart && pc<=iCellLast );
size = pPage->xCellSize(pPage, &src[pc]);
cbrk -= size;
if( cbrk<iCellStart || pc+size>usableSize ){
return SQLITE_CORRUPT_PAGE(pPage);
}
assert( cbrk+size<=usableSize && cbrk>=iCellStart );
testcase( cbrk+size==usableSize );
testcase( pc+size==usableSize );
put2byte(pAddr, cbrk);
memcpy(&data[cbrk], &src[pc], size);
}
}
data[hdr+7] = 0;
defragment_out:
assert( pPage->nFree>=0 );
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
return SQLITE_CORRUPT_PAGE(pPage);
}
assert( cbrk>=iCellFirst );
put2byte(&data[hdr+5], cbrk);
data[hdr+1] = 0;
|
| ︙ | ︙ | |||
68467 68468 68469 68470 68471 68472 68473 |
put2byte(&aData[pc+2], x);
}
return &aData[pc + x];
}
iAddr = pc;
pTmp = &aData[pc];
pc = get2byte(pTmp);
| | | | 69715 69716 69717 69718 69719 69720 69721 69722 69723 69724 69725 69726 69727 69728 69729 69730 69731 |
put2byte(&aData[pc+2], x);
}
return &aData[pc + x];
}
iAddr = pc;
pTmp = &aData[pc];
pc = get2byte(pTmp);
if( pc<=iAddr ){
if( pc ){
/* The next slot in the chain comes before the current slot */
*pRc = SQLITE_CORRUPT_PAGE(pPg);
}
return 0;
}
}
if( pc>maxPC+nByte-4 ){
/* The free slot chain extends off the end of the page */
|
| ︙ | ︙ | |||
68621 68622 68623 68624 68625 68626 68627 |
*/
hdr = pPage->hdrOffset;
iPtr = hdr + 1;
if( data[iPtr+1]==0 && data[iPtr]==0 ){
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
| | | 69869 69870 69871 69872 69873 69874 69875 69876 69877 69878 69879 69880 69881 69882 69883 |
*/
hdr = pPage->hdrOffset;
iPtr = hdr + 1;
if( data[iPtr+1]==0 && data[iPtr]==0 ){
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
if( iFreeBlk<=iPtr ){
if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
return SQLITE_CORRUPT_PAGE(pPage);
}
iPtr = iFreeBlk;
}
if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
return SQLITE_CORRUPT_PAGE(pPage);
|
| ︙ | ︙ | |||
69103 69104 69105 69106 69107 69108 69109 |
releasePage(*ppPage);
getAndInitPage_error1:
if( pCur ){
pCur->iPage--;
pCur->pPage = pCur->apPage[pCur->iPage];
}
testcase( pgno==0 );
| | < < | 70351 70352 70353 70354 70355 70356 70357 70358 70359 70360 70361 70362 70363 70364 70365 |
releasePage(*ppPage);
getAndInitPage_error1:
if( pCur ){
pCur->iPage--;
pCur->pPage = pCur->apPage[pCur->iPage];
}
testcase( pgno==0 );
assert( pgno!=0 || rc!=SQLITE_OK );
return rc;
}
/*
** Release a MemPage. This should be called once for each prior
** call to btreeGetPage.
**
|
| ︙ | ︙ | |||
70541 70542 70543 70544 70545 70546 70547 70548 70549 70550 70551 70552 70553 70554 |
}
if( iFrom==get4byte(pCell+info.nSize-4) ){
put4byte(pCell+info.nSize-4, iTo);
break;
}
}
}else{
if( get4byte(pCell)==iFrom ){
put4byte(pCell, iTo);
break;
}
}
}
| > > > | 71787 71788 71789 71790 71791 71792 71793 71794 71795 71796 71797 71798 71799 71800 71801 71802 71803 |
}
if( iFrom==get4byte(pCell+info.nSize-4) ){
put4byte(pCell+info.nSize-4, iTo);
break;
}
}
}else{
if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){
return SQLITE_CORRUPT_PAGE(pPage);
}
if( get4byte(pCell)==iFrom ){
put4byte(pCell, iTo);
break;
}
}
}
|
| ︙ | ︙ | |||
72047 72048 72049 72050 72051 72052 72053 |
**
** This function returns SQLITE_CORRUPT if the page-header flags field of
** the new child page does not match the flags field of the parent (i.e.
** if an intkey page appears to be the parent of a non-intkey page, or
** vice-versa).
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
| < < | > | 73296 73297 73298 73299 73300 73301 73302 73303 73304 73305 73306 73307 73308 73309 73310 73311 73312 73313 73314 73315 73316 73317 73318 73319 73320 73321 73322 73323 73324 |
**
** This function returns SQLITE_CORRUPT if the page-header flags field of
** the new child page does not match the flags field of the parent (i.e.
** if an intkey page appears to be the parent of a non-intkey page, or
** vice-versa).
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->iPage>=0 );
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT;
}
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
pCur->aiIdx[pCur->iPage] = pCur->ix;
pCur->apPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
pCur->iPage++;
return getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur,
pCur->curPagerFlags);
}
#ifdef SQLITE_DEBUG
/*
** Page pParent is an internal (non-leaf) tree page. This function
** asserts that page number iChild is the left-child if the iIdx'th
** cell in page pParent. Or, if iIdx is equal to the total number of
|
| ︙ | ︙ | |||
72168 72169 72170 72171 72172 72173 72174 |
if( pCur->eState>=CURSOR_REQUIRESEEK ){
if( pCur->eState==CURSOR_FAULT ){
assert( pCur->skipNext!=SQLITE_OK );
return pCur->skipNext;
}
sqlite3BtreeClearCursor(pCur);
}
| | | 73416 73417 73418 73419 73420 73421 73422 73423 73424 73425 73426 73427 73428 73429 73430 |
if( pCur->eState>=CURSOR_REQUIRESEEK ){
if( pCur->eState==CURSOR_FAULT ){
assert( pCur->skipNext!=SQLITE_OK );
return pCur->skipNext;
}
sqlite3BtreeClearCursor(pCur);
}
rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage,
0, pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
}
pCur->iPage = 0;
pCur->curIntKey = pCur->pPage->intKey;
|
| ︙ | ︙ | |||
72876 72877 72878 72879 72880 72881 72882 |
pCur->eState = CURSOR_VALID;
if( pCur->skipNext>0 ) return SQLITE_OK;
}
}
pPage = pCur->pPage;
idx = ++pCur->ix;
| | < < < < < < < | 74124 74125 74126 74127 74128 74129 74130 74131 74132 74133 74134 74135 74136 74137 74138 |
pCur->eState = CURSOR_VALID;
if( pCur->skipNext>0 ) return SQLITE_OK;
}
}
pPage = pCur->pPage;
idx = ++pCur->ix;
if( NEVER(!pPage->isInit) || sqlite3FaultSim(412) ){
return SQLITE_CORRUPT_BKPT;
}
if( idx>=pPage->nCell ){
if( !pPage->leaf ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
if( rc ) return rc;
|
| ︙ | ︙ | |||
73809 73810 73811 73812 73813 73814 73815 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->nFree>=0 ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; assert( pPage->pBt->usableSize > (u32)(ptr-data) ); pc = get2byte(ptr); hdr = pPage->hdrOffset; | < < < < < < | 75050 75051 75052 75053 75054 75055 75056 75057 75058 75059 75060 75061 75062 75063 |
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( pPage->nFree>=0 );
data = pPage->aData;
ptr = &pPage->aCellIdx[2*idx];
assert( pPage->pBt->usableSize > (u32)(ptr-data) );
pc = get2byte(ptr);
hdr = pPage->hdrOffset;
testcase( pc==(u32)get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
if( pc+sz > pPage->pBt->usableSize ){
*pRC = SQLITE_CORRUPT_BKPT;
return;
}
rc = freeSpace(pPage, pc, sz);
|
| ︙ | ︙ | |||
74698 74699 74700 74701 74702 74703 74704 | int cntNew[NB+2]; /* Index in b.paCell[] of cell after i-th page */ int cntOld[NB+2]; /* Old index in b.apCell[] */ int szNew[NB+2]; /* Combined size of cells placed on i-th page */ u8 *aSpace1; /* Space for copies of dividers cells */ Pgno pgno; /* Temp var to store a page number in */ u8 abDone[NB+2]; /* True after i'th new page is populated */ Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ | < < | 75933 75934 75935 75936 75937 75938 75939 75940 75941 75942 75943 75944 75945 75946 | int cntNew[NB+2]; /* Index in b.paCell[] of cell after i-th page */ int cntOld[NB+2]; /* Old index in b.apCell[] */ int szNew[NB+2]; /* Combined size of cells placed on i-th page */ u8 *aSpace1; /* Space for copies of dividers cells */ Pgno pgno; /* Temp var to store a page number in */ u8 abDone[NB+2]; /* True after i'th new page is populated */ Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ CellArray b; /* Parsed information on cells being balanced */ memset(abDone, 0, sizeof(abDone)); memset(&b, 0, sizeof(b)); pBt = pParent->pBt; assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); |
| ︙ | ︙ | |||
75123 75124 75125 75126 75127 75128 75129 | /* ** Reassign page numbers so that the new pages are in ascending order. ** This helps to keep entries in the disk file in order so that a scan ** of the table is closer to a linear scan through the file. That in turn ** helps the operating system to deliver pages from the disk more rapidly. ** | | | | | < < < < < < < < | < < | < < | | | | | > > > | > | > | > > > > | < | | > | 76356 76357 76358 76359 76360 76361 76362 76363 76364 76365 76366 76367 76368 76369 76370 76371 76372 76373 76374 76375 76376 76377 76378 76379 76380 76381 76382 76383 76384 76385 76386 76387 76388 76389 76390 76391 76392 76393 76394 76395 76396 76397 76398 76399 76400 76401 76402 |
/*
** Reassign page numbers so that the new pages are in ascending order.
** This helps to keep entries in the disk file in order so that a scan
** of the table is closer to a linear scan through the file. That in turn
** helps the operating system to deliver pages from the disk more rapidly.
**
** An O(N*N) sort algorithm is used, but since N is never more than NB+2
** (5), that is not a performance concern.
**
** When NB==3, this one optimization makes the database about 25% faster
** for large insertions and deletions.
*/
for(i=0; i<nNew; i++){
aPgno[i] = apNew[i]->pgno;
assert( apNew[i]->pDbPage->flags & PGHDR_WRITEABLE );
assert( apNew[i]->pDbPage->flags & PGHDR_DIRTY );
}
for(i=0; i<nNew-1; i++){
int iB = i;
for(j=i+1; j<nNew; j++){
if( apNew[j]->pgno < apNew[iB]->pgno ) iB = j;
}
/* If apNew[i] has a page number that is bigger than any of the
** subsequence apNew[i] entries, then swap apNew[i] with the subsequent
** entry that has the smallest page number (which we know to be
** entry apNew[iB]).
*/
if( iB!=i ){
Pgno pgnoA = apNew[i]->pgno;
Pgno pgnoB = apNew[iB]->pgno;
Pgno pgnoTemp = (PENDING_BYTE/pBt->pageSize)+1;
u16 fgA = apNew[i]->pDbPage->flags;
u16 fgB = apNew[iB]->pDbPage->flags;
sqlite3PagerRekey(apNew[i]->pDbPage, pgnoTemp, fgB);
sqlite3PagerRekey(apNew[iB]->pDbPage, pgnoA, fgA);
sqlite3PagerRekey(apNew[i]->pDbPage, pgnoB, fgB);
apNew[i]->pgno = pgnoB;
apNew[iB]->pgno = pgnoA;
}
}
TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) "
"%d(%d nc=%d) %d(%d nc=%d)\n",
apNew[0]->pgno, szNew[0], cntNew[0],
nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0,
|
| ︙ | ︙ | |||
75584 75585 75586 75587 75588 75589 75590 75591 75592 75593 75594 75595 75596 75597 |
pCur->apPage[0] = pPage;
pCur->pPage = pCur->apPage[1];
assert( pCur->pPage->nOverflow );
}
}else{
break;
}
}else{
MemPage * const pParent = pCur->apPage[iPage-1];
int const iIdx = pCur->aiIdx[iPage-1];
rc = sqlite3PagerWrite(pParent->pDbPage);
if( rc==SQLITE_OK && pParent->nFree<0 ){
rc = btreeComputeFreeSpace(pParent);
| > > > > > | 76814 76815 76816 76817 76818 76819 76820 76821 76822 76823 76824 76825 76826 76827 76828 76829 76830 76831 76832 |
pCur->apPage[0] = pPage;
pCur->pPage = pCur->apPage[1];
assert( pCur->pPage->nOverflow );
}
}else{
break;
}
}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_BKPT;
}else{
MemPage * const pParent = pCur->apPage[iPage-1];
int const iIdx = pCur->aiIdx[iPage-1];
rc = sqlite3PagerWrite(pParent->pDbPage);
if( rc==SQLITE_OK && pParent->nFree<0 ){
rc = btreeComputeFreeSpace(pParent);
|
| ︙ | ︙ | |||
79426 79427 79428 79429 79430 79431 79432 79433 79434 79435 79436 79437 79438 79439 |
*/
SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
double r2 = (double)i;
return r1==0.0
|| (memcmp(&r1, &r2, sizeof(r1))==0
&& i >= -2251799813685248LL && i < 2251799813685248LL);
}
/*
** Convert pMem so that it has type MEM_Real or MEM_Int.
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number. Convert
| > > > > > > > > > > | 80661 80662 80663 80664 80665 80666 80667 80668 80669 80670 80671 80672 80673 80674 80675 80676 80677 80678 80679 80680 80681 80682 80683 80684 |
*/
SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
double r2 = (double)i;
return r1==0.0
|| (memcmp(&r1, &r2, sizeof(r1))==0
&& i >= -2251799813685248LL && i < 2251799813685248LL);
}
/* Convert a floating point value to its closest integer. Do so in
** a way that avoids 'outside the range of representable values' warnings
** from UBSAN.
*/
SQLITE_PRIVATE i64 sqlite3RealToI64(double r){
if( r<=(double)SMALLEST_INT64 ) return SMALLEST_INT64;
if( r>=(double)LARGEST_INT64) return LARGEST_INT64;
return (i64)r;
}
/*
** Convert pMem so that it has type MEM_Real or MEM_Int.
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number. Convert
|
| ︙ | ︙ | |||
79448 79449 79450 79451 79452 79453 79454 |
if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){
int rc;
sqlite3_int64 ix;
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
| | | 80693 80694 80695 80696 80697 80698 80699 80700 80701 80702 80703 80704 80705 80706 80707 |
if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){
int rc;
sqlite3_int64 ix;
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
|| sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r)))
){
pMem->u.i = ix;
MemSetTypeFlag(pMem, MEM_Int);
}else{
MemSetTypeFlag(pMem, MEM_Real);
}
}
|
| ︙ | ︙ | |||
79500 79501 79502 79503 79504 79505 79506 79507 79508 79509 79510 79511 79512 79513 |
default: {
assert( aff==SQLITE_AFF_TEXT );
assert( MEM_Str==(MEM_Blob>>3) );
pMem->flags |= (pMem->flags&MEM_Blob)>>3;
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
return sqlite3VdbeChangeEncoding(pMem, encoding);
}
}
return SQLITE_OK;
}
/*
| > | 80745 80746 80747 80748 80749 80750 80751 80752 80753 80754 80755 80756 80757 80758 80759 |
default: {
assert( aff==SQLITE_AFF_TEXT );
assert( MEM_Str==(MEM_Blob>>3) );
pMem->flags |= (pMem->flags&MEM_Blob)>>3;
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1;
return sqlite3VdbeChangeEncoding(pMem, encoding);
}
}
return SQLITE_OK;
}
/*
|
| ︙ | ︙ | |||
80634 80635 80636 80637 80638 80639 80640 80641 80642 80643 80644 80645 80646 80647 |
return valueToText(pVal, enc)!=0 ? pVal->n : 0;
}
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
Mem *p = (Mem*)pVal;
assert( (p->flags & MEM_Null)==0 || (p->flags & (MEM_Str|MEM_Blob))==0 );
if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){
return p->n;
}
if( (p->flags & MEM_Blob)!=0 ){
if( p->flags & MEM_Zero ){
return p->n + p->u.nZero;
}else{
return p->n;
}
| > > > | 81880 81881 81882 81883 81884 81885 81886 81887 81888 81889 81890 81891 81892 81893 81894 81895 81896 |
return valueToText(pVal, enc)!=0 ? pVal->n : 0;
}
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
Mem *p = (Mem*)pVal;
assert( (p->flags & MEM_Null)==0 || (p->flags & (MEM_Str|MEM_Blob))==0 );
if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){
return p->n;
}
if( (p->flags & MEM_Str)!=0 && enc!=SQLITE_UTF8 && pVal->enc!=SQLITE_UTF8 ){
return p->n;
}
if( (p->flags & MEM_Blob)!=0 ){
if( p->flags & MEM_Zero ){
return p->n + p->u.nZero;
}else{
return p->n;
}
|
| ︙ | ︙ | |||
80680 80681 80682 80683 80684 80685 80686 |
sqlite3 *db = pParse->db;
Vdbe *p;
p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) );
if( p==0 ) return 0;
memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp));
p->db = db;
if( db->pVdbe ){
| | | | | 81929 81930 81931 81932 81933 81934 81935 81936 81937 81938 81939 81940 81941 81942 81943 81944 81945 81946 |
sqlite3 *db = pParse->db;
Vdbe *p;
p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) );
if( p==0 ) return 0;
memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp));
p->db = db;
if( db->pVdbe ){
db->pVdbe->ppVPrev = &p->pVNext;
}
p->pVNext = db->pVdbe;
p->ppVPrev = &db->pVdbe;
db->pVdbe = p;
assert( p->eVdbeState==VDBE_INIT_STATE );
p->pParse = pParse;
pParse->pVdbe = p;
assert( pParse->aLabel==0 );
assert( pParse->nLabel==0 );
assert( p->nOpAlloc==0 );
|
| ︙ | ︙ | |||
80765 80766 80767 80768 80769 80770 80771 |
if( strcmp(zId, pStr->z)==0 ) return 1;
}
return 0;
}
#endif
/*
| | > > > > > > > | | | | | | | | 82014 82015 82016 82017 82018 82019 82020 82021 82022 82023 82024 82025 82026 82027 82028 82029 82030 82031 82032 82033 82034 82035 82036 82037 82038 82039 82040 82041 82042 82043 82044 82045 82046 82047 82048 82049 |
if( strcmp(zId, pStr->z)==0 ) return 1;
}
return 0;
}
#endif
/*
** Swap byte-code between two VDBE structures.
**
** This happens after pB was previously run and returned
** SQLITE_SCHEMA. The statement was then reprepared in pA.
** This routine transfers the new bytecode in pA over to pB
** so that pB can be run again. The old pB byte code is
** moved back to pA so that it will be cleaned up when pA is
** finalized.
*/
SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
Vdbe tmp, *pTmp, **ppTmp;
char *zTmp;
assert( pA->db==pB->db );
tmp = *pA;
*pA = *pB;
*pB = tmp;
pTmp = pA->pVNext;
pA->pVNext = pB->pVNext;
pB->pVNext = pTmp;
ppTmp = pA->ppVPrev;
pA->ppVPrev = pB->ppVPrev;
pB->ppVPrev = ppTmp;
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
#ifdef SQLITE_ENABLE_NORMALIZE
zTmp = pA->zNormSql;
pA->zNormSql = pB->zNormSql;
pB->zNormSql = zTmp;
|
| ︙ | ︙ | |||
81031 81032 81033 81034 81035 81036 81037 81038 81039 81040 81041 81042 81043 81044 |
pCtx->pVdbe = 0;
pCtx->isError = 0;
pCtx->argc = nArg;
pCtx->iOp = sqlite3VdbeCurrentAddr(v);
addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef);
return addr;
}
/*
** Add an opcode that includes the p4 value with a P4_INT64 or
** P4_REAL type.
*/
| > | 82287 82288 82289 82290 82291 82292 82293 82294 82295 82296 82297 82298 82299 82300 82301 |
pCtx->pVdbe = 0;
pCtx->isError = 0;
pCtx->argc = nArg;
pCtx->iOp = sqlite3VdbeCurrentAddr(v);
addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef);
sqlite3MayAbort(pParse);
return addr;
}
/*
** Add an opcode that includes the p4 value with a P4_INT64 or
** P4_REAL type.
*/
|
| ︙ | ︙ | |||
81099 81100 81101 81102 81103 81104 81105 |
va_start(ap, zFmt);
zMsg = sqlite3VMPrintf(pParse->db, zFmt, ap);
va_end(ap);
v = pParse->pVdbe;
iThis = v->nOp;
sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
zMsg, P4_DYNAMIC);
| | | 82356 82357 82358 82359 82360 82361 82362 82363 82364 82365 82366 82367 82368 82369 82370 |
va_start(ap, zFmt);
zMsg = sqlite3VMPrintf(pParse->db, zFmt, ap);
va_end(ap);
v = pParse->pVdbe;
iThis = v->nOp;
sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
zMsg, P4_DYNAMIC);
sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetLastOp(v)->p4.z);
if( bPush){
pParse->addrExplain = iThis;
}
}
}
/*
|
| ︙ | ︙ | |||
81366 81367 81368 81369 81370 81371 81372 81373 81374 81375 81376 81377 81378 81379 |
while( (pOp = opIterNext(&sIter))!=0 ){
int opcode = pOp->opcode;
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|| opcode==OP_VDestroy
|| opcode==OP_VCreate
|| opcode==OP_ParseSchema
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
){
hasAbort = 1;
break;
}
if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
| > | 82623 82624 82625 82626 82627 82628 82629 82630 82631 82632 82633 82634 82635 82636 82637 |
while( (pOp = opIterNext(&sIter))!=0 ){
int opcode = pOp->opcode;
if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|| opcode==OP_VDestroy
|| opcode==OP_VCreate
|| opcode==OP_ParseSchema
|| opcode==OP_Function || opcode==OP_PureFunc
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
){
hasAbort = 1;
break;
}
if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
|
| ︙ | ︙ | |||
81456 81457 81458 81459 81460 81461 81462 | int nMaxArgs = *pMaxFuncArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; p->readOnly = 1; p->bIsReader = 0; pOp = &p->aOp[p->nOp-1]; | | | | 82714 82715 82716 82717 82718 82719 82720 82721 82722 82723 82724 82725 82726 82727 82728 82729 |
int nMaxArgs = *pMaxFuncArgs;
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
p->readOnly = 1;
p->bIsReader = 0;
pOp = &p->aOp[p->nOp-1];
assert( p->aOp[0].opcode==OP_Init );
while( 1 /* Loop termates when it reaches the OP_Init opcode */ ){
/* Only JUMP opcodes and the short list of special opcodes in the switch
** below need to be considered. The mkopcodeh.tcl generator script groups
** all these opcodes together near the front of the opcode list. Skip
** any opcode that does not need processing by virtual of the fact that
** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization.
*/
if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){
|
| ︙ | ︙ | |||
81486 81487 81488 81489 81490 81491 81492 81493 81494 81495 81496 81497 81498 81499 |
#endif
case OP_Vacuum:
case OP_JournalMode: {
p->readOnly = 0;
p->bIsReader = 1;
break;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
break;
}
case OP_VFilter: {
int n;
| > > > > | 82744 82745 82746 82747 82748 82749 82750 82751 82752 82753 82754 82755 82756 82757 82758 82759 82760 82761 |
#endif
case OP_Vacuum:
case OP_JournalMode: {
p->readOnly = 0;
p->bIsReader = 1;
break;
}
case OP_Init: {
assert( pOp->p2>=0 );
goto resolve_p2_values_loop_exit;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
break;
}
case OP_VFilter: {
int n;
|
| ︙ | ︙ | |||
81518 81519 81520 81521 81522 81523 81524 |
}
}
/* The mkopcodeh.tcl script has so arranged things that the only
** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
** have non-negative values for P2. */
assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
}
| | > | | 82780 82781 82782 82783 82784 82785 82786 82787 82788 82789 82790 82791 82792 82793 82794 82795 82796 82797 82798 82799 |
}
}
/* The mkopcodeh.tcl script has so arranged things that the only
** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
** have non-negative values for P2. */
assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
}
assert( pOp>p->aOp );
pOp--;
}
resolve_p2_values_loop_exit:
if( aLabel ){
sqlite3DbNNFreeNN(p->db, pParse->aLabel);
pParse->aLabel = 0;
}
pParse->nLabel = 0;
*pMaxFuncArgs = nMaxArgs;
assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
}
|
| ︙ | ︙ | |||
81771 81772 81773 81774 81775 81776 81777 81778 81779 81780 81781 81782 81783 81784 81785 81786 81787 81788 81789 81790 81791 81792 81793 81794 81795 81796 81797 81798 81799 |
/*
** Change the value of the opcode, or P1, P2, P3, or P5 operands
** for a specific instruction.
*/
SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){
sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
sqlite3VdbeGetOp(p,addr)->p1 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
sqlite3VdbeGetOp(p,addr)->p2 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
sqlite3VdbeGetOp(p,addr)->p3 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
assert( p->nOp>0 || p->db->mallocFailed );
if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5;
}
/*
** Change the P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
sqlite3VdbeChangeP2(p, addr, p->nOp);
| > > > > > > > > > > > > > > > > | 83034 83035 83036 83037 83038 83039 83040 83041 83042 83043 83044 83045 83046 83047 83048 83049 83050 83051 83052 83053 83054 83055 83056 83057 83058 83059 83060 83061 83062 83063 83064 83065 83066 83067 83068 83069 83070 83071 83072 83073 83074 83075 83076 83077 83078 |
/*
** Change the value of the opcode, or P1, P2, P3, or P5 operands
** for a specific instruction.
*/
SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){
assert( addr>=0 );
sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
assert( addr>=0 );
sqlite3VdbeGetOp(p,addr)->p1 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
assert( addr>=0 || p->db->mallocFailed );
sqlite3VdbeGetOp(p,addr)->p2 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
assert( addr>=0 );
sqlite3VdbeGetOp(p,addr)->p3 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
assert( p->nOp>0 || p->db->mallocFailed );
if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5;
}
/*
** If the previous opcode is an OP_Column that delivers results
** into register iDest, then add the OPFLAG_TYPEOFARG flag to that
** opcode.
*/
SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){
VdbeOp *pOp = sqlite3VdbeGetLastOp(p);
if( pOp->p3==iDest && pOp->opcode==OP_Column ){
pOp->p5 |= OPFLAG_TYPEOFARG;
}
}
/*
** Change the P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
sqlite3VdbeChangeP2(p, addr, p->nOp);
|
| ︙ | ︙ | |||
81815 81816 81817 81818 81819 81820 81821 |
SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
if( addr==p->nOp-1 ){
assert( p->aOp[addr].opcode==OP_Once
|| p->aOp[addr].opcode==OP_If
|| p->aOp[addr].opcode==OP_FkIfZero );
assert( p->aOp[addr].p4type==0 );
#ifdef SQLITE_VDBE_COVERAGE
| | > | | > | | | 83094 83095 83096 83097 83098 83099 83100 83101 83102 83103 83104 83105 83106 83107 83108 83109 83110 83111 83112 83113 83114 83115 83116 83117 83118 83119 83120 83121 83122 83123 83124 83125 83126 83127 83128 83129 83130 83131 83132 83133 83134 83135 83136 83137 83138 83139 83140 83141 83142 83143 83144 83145 83146 83147 83148 83149 83150 83151 |
SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
if( addr==p->nOp-1 ){
assert( p->aOp[addr].opcode==OP_Once
|| p->aOp[addr].opcode==OP_If
|| p->aOp[addr].opcode==OP_FkIfZero );
assert( p->aOp[addr].p4type==0 );
#ifdef SQLITE_VDBE_COVERAGE
sqlite3VdbeGetLastOp(p)->iSrcLine = 0; /* Erase VdbeCoverage() macros */
#endif
p->nOp--;
}else{
sqlite3VdbeChangeP2(p, addr, p->nOp);
}
}
/*
** If the input FuncDef structure is ephemeral, then free it. If
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
assert( db!=0 );
if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
sqlite3DbNNFreeNN(db, pDef);
}
}
/*
** Delete a P4 value if necessary.
*/
static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
sqlite3DbNNFreeNN(db, p);
}
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
assert( db!=0 );
freeEphemeralFunction(db, p->pFunc);
sqlite3DbNNFreeNN(db, p);
}
static void freeP4(sqlite3 *db, int p4type, void *p4){
assert( db );
switch( p4type ){
case P4_FUNCCTX: {
freeP4FuncCtx(db, (sqlite3_context*)p4);
break;
}
case P4_REAL:
case P4_INT64:
case P4_DYNAMIC:
case P4_INTARRAY: {
if( p4 ) sqlite3DbNNFreeNN(db, p4);
break;
}
case P4_KEYINFO: {
if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
break;
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
| ︙ | ︙ | |||
81895 81896 81897 81898 81899 81900 81901 81902 81903 81904 81905 81906 81907 81908 81909 81910 81911 |
/*
** Free the space allocated for aOp and any p4 values allocated for the
** opcodes contained within. If aOp is not NULL it is assumed to contain
** nOp entries.
*/
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
assert( nOp>=0 );
if( aOp ){
Op *pOp = &aOp[nOp-1];
while(1){ /* Exit via break */
if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
sqlite3DbFree(db, pOp->zComment);
#endif
if( pOp==aOp ) break;
pOp--;
}
| > | | 83176 83177 83178 83179 83180 83181 83182 83183 83184 83185 83186 83187 83188 83189 83190 83191 83192 83193 83194 83195 83196 83197 83198 83199 83200 83201 |
/*
** Free the space allocated for aOp and any p4 values allocated for the
** opcodes contained within. If aOp is not NULL it is assumed to contain
** nOp entries.
*/
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
assert( nOp>=0 );
assert( db!=0 );
if( aOp ){
Op *pOp = &aOp[nOp-1];
while(1){ /* Exit via break */
if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
sqlite3DbFree(db, pOp->zComment);
#endif
if( pOp==aOp ) break;
pOp--;
}
sqlite3DbNNFreeNN(db, aOp);
}
}
/*
** Link the SubProgram object passed as the second argument into the linked
** list at Vdbe.pSubProgram. This list is used to delete all sub-program
** objects when the VM is no longer required.
|
| ︙ | ︙ | |||
82136 82137 82138 82139 82140 82141 82142 |
#endif /* NDEBUG */
#ifdef SQLITE_VDBE_COVERAGE
/*
** Set the value if the iSrcLine field for the previously coded instruction.
*/
SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
| | | | < < < > > > > > > | 83418 83419 83420 83421 83422 83423 83424 83425 83426 83427 83428 83429 83430 83431 83432 83433 83434 83435 83436 83437 83438 83439 83440 83441 83442 83443 83444 83445 83446 83447 83448 83449 83450 83451 83452 83453 83454 83455 83456 83457 83458 83459 83460 83461 83462 83463 83464 83465 83466 |
#endif /* NDEBUG */
#ifdef SQLITE_VDBE_COVERAGE
/*
** Set the value if the iSrcLine field for the previously coded instruction.
*/
SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
sqlite3VdbeGetLastOp(v)->iSrcLine = iLine;
}
#endif /* SQLITE_VDBE_COVERAGE */
/*
** Return the opcode for a given address. The address must be non-negative.
** See sqlite3VdbeGetLastOp() to get the most recently added opcode.
**
** If a memory allocation error has occurred prior to the calling of this
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
** is readable but not writable, though it is cast to a writable value.
** The return of a dummy opcode allows the call to continue functioning
** after an OOM fault without having to check to see if the return from
** this routine is a valid pointer. But because the dummy.opcode is 0,
** dummy will never be written to. This is verified by code inspection and
** by running with Valgrind.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
/* C89 specifies that the constant "dummy" will be initialized to all
** zeros, which is correct. MSVC generates a warning, nevertheless. */
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
assert( p->eVdbeState==VDBE_INIT_STATE );
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
if( p->db->mallocFailed ){
return (VdbeOp*)&dummy;
}else{
return &p->aOp[addr];
}
}
/* Return the most recently added opcode
*/
VdbeOp * sqlite3VdbeGetLastOp(Vdbe *p){
return sqlite3VdbeGetOp(p, p->nOp - 1);
}
#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
/*
** Return an integer value for one of the parameters to the opcode pOp
** determined by character c.
*/
static int translateP(char c, const Op *pOp){
|
| ︙ | ︙ | |||
82656 82657 82658 82659 82660 82661 82662 |
testcase( p->flags & MEM_Agg );
testcase( p->flags & MEM_Dyn );
if( p->flags&(MEM_Agg|MEM_Dyn) ){
testcase( (p->flags & MEM_Dyn)!=0 && p->xDel==sqlite3VdbeFrameMemDel );
sqlite3VdbeMemRelease(p);
p->flags = MEM_Undefined;
}else if( p->szMalloc ){
| | | 83941 83942 83943 83944 83945 83946 83947 83948 83949 83950 83951 83952 83953 83954 83955 |
testcase( p->flags & MEM_Agg );
testcase( p->flags & MEM_Dyn );
if( p->flags&(MEM_Agg|MEM_Dyn) ){
testcase( (p->flags & MEM_Dyn)!=0 && p->xDel==sqlite3VdbeFrameMemDel );
sqlite3VdbeMemRelease(p);
p->flags = MEM_Undefined;
}else if( p->szMalloc ){
sqlite3DbNNFreeNN(db, p->zMalloc);
p->szMalloc = 0;
p->flags = MEM_Undefined;
}
#ifdef SQLITE_DEBUG
else{
p->flags = MEM_Undefined;
}
|
| ︙ | ︙ | |||
83648 83649 83650 83651 83652 83653 83654 |
p = db->pVdbe;
while( p ){
if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){
cnt++;
if( p->readOnly==0 ) nWrite++;
if( p->bIsReader ) nRead++;
}
| | | 84933 84934 84935 84936 84937 84938 84939 84940 84941 84942 84943 84944 84945 84946 84947 |
p = db->pVdbe;
while( p ){
if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){
cnt++;
if( p->readOnly==0 ) nWrite++;
if( p->bIsReader ) nRead++;
}
p = p->pVNext;
}
assert( cnt==db->nVdbeActive );
assert( nWrite==db->nVdbeWrite );
assert( nRead==db->nVdbeRead );
}
#else
#define checkActiveVdbeCnt(x)
|
| ︙ | ︙ | |||
84177 84178 84179 84180 84181 84182 84183 84184 84185 84186 |
**
** The difference between this function and sqlite3VdbeDelete() is that
** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
** the database connection and frees the object itself.
*/
static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
assert( p->db==0 || p->db==db );
if( p->aColName ){
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
| > | | | | | 85462 85463 85464 85465 85466 85467 85468 85469 85470 85471 85472 85473 85474 85475 85476 85477 85478 85479 85480 85481 85482 85483 85484 85485 85486 85487 85488 85489 85490 85491 85492 85493 |
**
** The difference between this function and sqlite3VdbeDelete() is that
** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
** the database connection and frees the object itself.
*/
static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
assert( db!=0 );
assert( p->db==0 || p->db==db );
if( p->aColName ){
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqlite3DbNNFreeNN(db, p->aColName);
}
for(pSub=p->pProgram; pSub; pSub=pNext){
pNext = pSub->pNext;
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
sqlite3DbFree(db, pSub);
}
if( p->eVdbeState!=VDBE_INIT_STATE ){
releaseMemArray(p->aVar, p->nVar);
if( p->pVList ) sqlite3DbNNFreeNN(db, p->pVList);
if( p->pFree ) sqlite3DbNNFreeNN(db, p->pFree);
}
vdbeFreeOpArray(db, p->aOp, p->nOp);
if( p->zSql ) sqlite3DbNNFreeNN(db, p->zSql);
#ifdef SQLITE_ENABLE_NORMALIZE
sqlite3DbFree(db, p->zNormSql);
{
DblquoteStr *pThis, *pNext;
for(pThis=p->pDblStr; pThis; pThis=pNext){
pNext = pThis->pNextStr;
sqlite3DbFree(db, pThis);
|
| ︙ | ︙ | |||
84223 84224 84225 84226 84227 84228 84229 84230 84231 84232 |
** Delete an entire VDBE.
*/
SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
sqlite3 *db;
assert( p!=0 );
db = p->db;
assert( sqlite3_mutex_held(db->mutex) );
sqlite3VdbeClearObject(db, p);
if( db->pnBytesFreed==0 ){
| > < < < | | < | | | | 85509 85510 85511 85512 85513 85514 85515 85516 85517 85518 85519 85520 85521 85522 85523 85524 85525 85526 85527 85528 85529 85530 85531 85532 85533 |
** Delete an entire VDBE.
*/
SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
sqlite3 *db;
assert( p!=0 );
db = p->db;
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
sqlite3VdbeClearObject(db, p);
if( db->pnBytesFreed==0 ){
assert( p->ppVPrev!=0 );
*p->ppVPrev = p->pVNext;
if( p->pVNext ){
p->pVNext->ppVPrev = p->ppVPrev;
}
}
sqlite3DbNNFreeNN(db, p);
}
/*
** The cursor "p" has a pending seek operation that has not yet been
** carried out. Seek the cursor now. If an error occurs, return
** the appropriate error code.
*/
|
| ︙ | ︙ | |||
85201 85202 85203 85204 85205 85206 85207 |
/* RHS is an integer */
if( pRhs->flags & (MEM_Int|MEM_IntReal) ){
testcase( pRhs->flags & MEM_Int );
testcase( pRhs->flags & MEM_IntReal );
serial_type = aKey1[idx1];
testcase( serial_type==12 );
if( serial_type>=10 ){
| | | 86484 86485 86486 86487 86488 86489 86490 86491 86492 86493 86494 86495 86496 86497 86498 |
/* RHS is an integer */
if( pRhs->flags & (MEM_Int|MEM_IntReal) ){
testcase( pRhs->flags & MEM_Int );
testcase( pRhs->flags & MEM_IntReal );
serial_type = aKey1[idx1];
testcase( serial_type==12 );
if( serial_type>=10 ){
rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else if( serial_type==7 ){
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
}else{
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
|
| ︙ | ︙ | |||
85226 85227 85228 85229 85230 85231 85232 |
else if( pRhs->flags & MEM_Real ){
serial_type = aKey1[idx1];
if( serial_type>=10 ){
/* Serial types 12 or greater are strings and blobs (greater than
** numbers). Types 10 and 11 are currently "reserved for future
** use", so it doesn't really matter what the results of comparing
** them to numberic values are. */
| | | 86509 86510 86511 86512 86513 86514 86515 86516 86517 86518 86519 86520 86521 86522 86523 |
else if( pRhs->flags & MEM_Real ){
serial_type = aKey1[idx1];
if( serial_type>=10 ){
/* Serial types 12 or greater are strings and blobs (greater than
** numbers). Types 10 and 11 are currently "reserved for future
** use", so it doesn't really matter what the results of comparing
** them to numberic values are. */
rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else{
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
if( serial_type==7 ){
if( mem1.u.r<pRhs->u.r ){
rc = -1;
|
| ︙ | ︙ | |||
85307 85308 85309 85310 85311 85312 85313 |
}
}
}
/* RHS is null */
else{
serial_type = aKey1[idx1];
| | | 86590 86591 86592 86593 86594 86595 86596 86597 86598 86599 86600 86601 86602 86603 86604 |
}
}
}
/* RHS is null */
else{
serial_type = aKey1[idx1];
rc = (serial_type!=0 && serial_type!=10);
}
if( rc!=0 ){
int sortFlags = pPKey2->pKeyInfo->aSortFlags[i];
if( sortFlags ){
if( (sortFlags & KEYINFO_ORDER_BIGNULL)==0
|| ((sortFlags & KEYINFO_ORDER_DESC)
|
| ︙ | ︙ | |||
85731 85732 85733 85734 85735 85736 85737 |
**
** Internally, this function just sets the Vdbe.expired flag on all
** prepared statements. The flag is set to 1 for an immediate expiration
** and set to 2 for an advisory expiration.
*/
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){
Vdbe *p;
| | | 87014 87015 87016 87017 87018 87019 87020 87021 87022 87023 87024 87025 87026 87027 87028 |
**
** Internally, this function just sets the Vdbe.expired flag on all
** prepared statements. The flag is set to 1 for an immediate expiration
** and set to 2 for an advisory expiration.
*/
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){
Vdbe *p;
for(p = db->pVdbe; p; p=p->pVNext){
p->expired = iCode+1;
}
}
/*
** Return the database associated with the Vdbe.
*/
|
| ︙ | ︙ | |||
85852 85853 85854 85855 85856 85857 85858 85859 85860 85861 85862 85863 85864 |
** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord
** structure itself, using sqlite3DbFree().
**
** This function is used to free UnpackedRecord structures allocated by
** the vdbeUnpackRecord() function found in vdbeapi.c.
*/
static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
if( p ){
int i;
for(i=0; i<nField; i++){
Mem *pMem = &p->aMem[i];
if( pMem->zMalloc ) sqlite3VdbeMemReleaseMalloc(pMem);
}
| > | | 87135 87136 87137 87138 87139 87140 87141 87142 87143 87144 87145 87146 87147 87148 87149 87150 87151 87152 87153 87154 87155 87156 |
** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord
** structure itself, using sqlite3DbFree().
**
** This function is used to free UnpackedRecord structures allocated by
** the vdbeUnpackRecord() function found in vdbeapi.c.
*/
static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
assert( db!=0 );
if( p ){
int i;
for(i=0; i<nField; i++){
Mem *pMem = &p->aMem[i];
if( pMem->zMalloc ) sqlite3VdbeMemReleaseMalloc(pMem);
}
sqlite3DbNNFreeNN(db, p);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
/*
** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call,
|
| ︙ | ︙ | |||
85929 85930 85931 85932 85933 85934 85935 |
vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
if( preupdate.aNew ){
int i;
for(i=0; i<pCsr->nField; i++){
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
}
| | | 87213 87214 87215 87216 87217 87218 87219 87220 87221 87222 87223 87224 87225 87226 87227 |
vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
if( preupdate.aNew ){
int i;
for(i=0; i<pCsr->nField; i++){
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
}
sqlite3DbNNFreeNN(db, preupdate.aNew);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
/************** End of vdbeaux.c *********************************************/
/************** Begin file vdbeapi.c *****************************************/
/*
|
| ︙ | ︙ | |||
86046 86047 86048 86049 86050 86051 86052 |
rc = SQLITE_OK;
}else{
Vdbe *v = (Vdbe*)pStmt;
sqlite3 *db = v->db;
if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
sqlite3_mutex_enter(db->mutex);
checkProfileCallback(db, v);
| > | > | 87330 87331 87332 87333 87334 87335 87336 87337 87338 87339 87340 87341 87342 87343 87344 87345 87346 |
rc = SQLITE_OK;
}else{
Vdbe *v = (Vdbe*)pStmt;
sqlite3 *db = v->db;
if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
sqlite3_mutex_enter(db->mutex);
checkProfileCallback(db, v);
assert( v->eVdbeState>=VDBE_READY_STATE );
rc = sqlite3VdbeReset(v);
sqlite3VdbeDelete(v);
rc = sqlite3ApiExit(db, rc);
sqlite3LeaveMutexAndCloseZombie(db);
}
return rc;
}
/*
|
| ︙ | ︙ | |||
86253 86254 86255 86256 86257 86258 86259 86260 86261 86262 86263 86264 86265 86266 |
}else if( pVal->flags & MEM_Str ){
eType = SQLITE_TEXT;
}
assert( eType == aType[pVal->flags&MEM_AffMask] );
}
#endif
return aType[pVal->flags&MEM_AffMask];
}
/* Return true if a parameter to xUpdate represents an unchanged column */
SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){
return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero);
}
| > > > | 87539 87540 87541 87542 87543 87544 87545 87546 87547 87548 87549 87550 87551 87552 87553 87554 87555 |
}else if( pVal->flags & MEM_Str ){
eType = SQLITE_TEXT;
}
assert( eType == aType[pVal->flags&MEM_AffMask] );
}
#endif
return aType[pVal->flags&MEM_AffMask];
}
SQLITE_API int sqlite3_value_encoding(sqlite3_value *pVal){
return pVal->enc;
}
/* Return true if a parameter to xUpdate represents an unchanged column */
SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){
return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero);
}
|
| ︙ | ︙ | |||
87368 87369 87370 87371 87372 87373 87374 | ** ** A successful evaluation of this routine acquires the mutex on p. ** the mutex is released if any kind of error occurs. ** ** The error code stored in database p->db is overwritten with the return ** value in any case. */ | | | < | 88657 88658 88659 88660 88661 88662 88663 88664 88665 88666 88667 88668 88669 88670 88671 88672 88673 88674 88675 88676 88677 88678 88679 88680 88681 88682 88683 88684 88685 88686 88687 88688 |
**
** A successful evaluation of this routine acquires the mutex on p.
** the mutex is released if any kind of error occurs.
**
** The error code stored in database p->db is overwritten with the return
** value in any case.
*/
static int vdbeUnbind(Vdbe *p, unsigned int i){
Mem *pVar;
if( vdbeSafetyNotNull(p) ){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(p->db->mutex);
if( p->eVdbeState!=VDBE_READY_STATE ){
sqlite3Error(p->db, SQLITE_MISUSE);
sqlite3_mutex_leave(p->db->mutex);
sqlite3_log(SQLITE_MISUSE,
"bind on a busy prepared statement: [%s]", p->zSql);
return SQLITE_MISUSE_BKPT;
}
if( i>=(unsigned int)p->nVar ){
sqlite3Error(p->db, SQLITE_RANGE);
sqlite3_mutex_leave(p->db->mutex);
return SQLITE_RANGE;
}
pVar = &p->aVar[i];
sqlite3VdbeMemRelease(pVar);
pVar->flags = MEM_Null;
p->db->errCode = SQLITE_OK;
/* If the bit corresponding to this variable in Vdbe.expmask is set, then
** binding a new value to this variable invalidates the current query plan.
|
| ︙ | ︙ | |||
87423 87424 87425 87426 87427 87428 87429 |
void (*xDel)(void*), /* Destructor for the data */
u8 encoding /* Encoding for the data */
){
Vdbe *p = (Vdbe *)pStmt;
Mem *pVar;
int rc;
| | | 88711 88712 88713 88714 88715 88716 88717 88718 88719 88720 88721 88722 88723 88724 88725 |
void (*xDel)(void*), /* Destructor for the data */
u8 encoding /* Encoding for the data */
){
Vdbe *p = (Vdbe *)pStmt;
Mem *pVar;
int rc;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
if( zData!=0 ){
pVar = &p->aVar[i-1];
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
if( rc==SQLITE_OK && encoding!=0 ){
rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
}
|
| ︙ | ︙ | |||
87472 87473 87474 87475 87476 87477 87478 |
){
assert( xDel!=SQLITE_DYNAMIC );
return bindText(pStmt, i, zData, nData, xDel, 0);
}
SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
| | | | | | 88760 88761 88762 88763 88764 88765 88766 88767 88768 88769 88770 88771 88772 88773 88774 88775 88776 88777 88778 88779 88780 88781 88782 88783 88784 88785 88786 88787 88788 88789 88790 88791 88792 88793 88794 88795 88796 88797 88798 88799 88800 88801 88802 88803 88804 88805 88806 88807 88808 88809 88810 88811 88812 |
){
assert( xDel!=SQLITE_DYNAMIC );
return bindText(pStmt, i, zData, nData, xDel, 0);
}
SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
sqlite3_mutex_leave(p->db->mutex);
}
return rc;
}
SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
return sqlite3_bind_int64(p, i, (i64)iValue);
}
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
sqlite3_mutex_leave(p->db->mutex);
}
return rc;
}
SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
int rc;
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3_mutex_leave(p->db->mutex);
}
return rc;
}
SQLITE_API int sqlite3_bind_pointer(
sqlite3_stmt *pStmt,
int i,
void *pPtr,
const char *zPTtype,
void (*xDestructor)(void*)
){
int rc;
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
sqlite3_mutex_leave(p->db->mutex);
}else if( xDestructor ){
xDestructor(pPtr);
}
return rc;
|
| ︙ | ︙ | |||
87588 87589 87590 87591 87592 87593 87594 |
}
}
return rc;
}
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
| | | 88876 88877 88878 88879 88880 88881 88882 88883 88884 88885 88886 88887 88888 88889 88890 |
}
}
return rc;
}
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_INCRBLOB
sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
#else
rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
#endif
sqlite3_mutex_leave(p->db->mutex);
|
| ︙ | ︙ | |||
87748 87749 87750 87751 87752 87753 87754 |
return 0;
}
#endif
sqlite3_mutex_enter(pDb->mutex);
if( pStmt==0 ){
pNext = (sqlite3_stmt*)pDb->pVdbe;
}else{
| | | 89036 89037 89038 89039 89040 89041 89042 89043 89044 89045 89046 89047 89048 89049 89050 |
return 0;
}
#endif
sqlite3_mutex_enter(pDb->mutex);
if( pStmt==0 ){
pNext = (sqlite3_stmt*)pDb->pVdbe;
}else{
pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pVNext;
}
sqlite3_mutex_leave(pDb->mutex);
return pNext;
}
/*
** Return the value of a status counter for a prepared statement
|
| ︙ | ︙ | |||
87773 87774 87775 87776 87777 87778 87779 87780 87781 87782 87783 87784 87785 87786 87787 87788 |
}
#endif
if( op==SQLITE_STMTSTATUS_MEMUSED ){
sqlite3 *db = pVdbe->db;
sqlite3_mutex_enter(db->mutex);
v = 0;
db->pnBytesFreed = (int*)&v;
sqlite3VdbeDelete(pVdbe);
db->pnBytesFreed = 0;
sqlite3_mutex_leave(db->mutex);
}else{
v = pVdbe->aCounter[op];
if( resetFlag ) pVdbe->aCounter[op] = 0;
}
return (int)v;
}
| > > > | 89061 89062 89063 89064 89065 89066 89067 89068 89069 89070 89071 89072 89073 89074 89075 89076 89077 89078 89079 |
}
#endif
if( op==SQLITE_STMTSTATUS_MEMUSED ){
sqlite3 *db = pVdbe->db;
sqlite3_mutex_enter(db->mutex);
v = 0;
db->pnBytesFreed = (int*)&v;
assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
db->lookaside.pEnd = db->lookaside.pStart;
sqlite3VdbeDelete(pVdbe);
db->pnBytesFreed = 0;
db->lookaside.pEnd = db->lookaside.pTrueEnd;
sqlite3_mutex_leave(db->mutex);
}else{
v = pVdbe->aCounter[op];
if( resetFlag ) pVdbe->aCounter[op] = 0;
}
return (int)v;
}
|
| ︙ | ︙ | |||
88614 88615 88616 88617 88618 88619 88620 |
/*
** The string in pRec is known to look like an integer and to have a
** floating point value of rValue. Return true and set *piValue to the
** integer value if the string is in range to be an integer. Otherwise,
** return false.
*/
static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){
| | > | 89905 89906 89907 89908 89909 89910 89911 89912 89913 89914 89915 89916 89917 89918 89919 89920 |
/*
** The string in pRec is known to look like an integer and to have a
** floating point value of rValue. Return true and set *piValue to the
** integer value if the string is in range to be an integer. Otherwise,
** return false.
*/
static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){
i64 iValue;
iValue = sqlite3RealToI64(rValue);
if( sqlite3RealSameAsInt(rValue,iValue) ){
*piValue = iValue;
return 1;
}
return 0==sqlite3Atoi64(pRec->z, piValue, pRec->n, pRec->enc);
}
|
| ︙ | ︙ | |||
88776 88777 88778 88779 88780 88781 88782 |
** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
** none.
**
** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
** But it does set pMem->u.r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
| > > | | | | | | < | 90068 90069 90070 90071 90072 90073 90074 90075 90076 90077 90078 90079 90080 90081 90082 90083 90084 90085 90086 90087 90088 90089 90090 90091 90092 90093 |
** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
** none.
**
** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
** But it does set pMem->u.r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
assert( (pMem->flags & MEM_Null)==0
|| pMem->db==0 || pMem->db->mallocFailed );
if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null) ){
testcase( pMem->flags & MEM_Int );
testcase( pMem->flags & MEM_Real );
testcase( pMem->flags & MEM_IntReal );
return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null);
}
assert( pMem->flags & (MEM_Str|MEM_Blob) );
testcase( pMem->flags & MEM_Str );
testcase( pMem->flags & MEM_Blob );
return computeNumericType(pMem);
return 0;
}
#ifdef SQLITE_DEBUG
/*
** Write a nice string representation of the contents of cell pMem
** into buffer zBuf, length nBuf.
|
| ︙ | ︙ | |||
90031 90032 90033 90034 90035 90036 90037 |
** If either operand is NULL, the result is NULL.
*/
case OP_Add: /* same as TK_PLUS, in1, in2, out3 */
case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
| < | | < > | 91324 91325 91326 91327 91328 91329 91330 91331 91332 91333 91334 91335 91336 91337 91338 91339 91340 91341 91342 91343 91344 91345 91346 91347 91348 91349 91350 91351 |
** If either operand is NULL, the result is NULL.
*/
case OP_Add: /* same as TK_PLUS, in1, in2, out3 */
case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
u16 type1; /* Numeric type of left operand */
u16 type2; /* Numeric type of right operand */
i64 iA; /* Integer value of left operand */
i64 iB; /* Integer value of right operand */
double rA; /* Real value of left operand */
double rB; /* Real value of right operand */
pIn1 = &aMem[pOp->p1];
type1 = pIn1->flags;
pIn2 = &aMem[pOp->p2];
type2 = pIn2->flags;
pOut = &aMem[pOp->p3];
if( (type1 & type2 & MEM_Int)!=0 ){
int_math:
iA = pIn1->u.i;
iB = pIn2->u.i;
switch( pOp->opcode ){
case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break;
case OP_Multiply: if( sqlite3MulInt64(&iB,iA) ) goto fp_math; break;
case OP_Divide: {
|
| ︙ | ︙ | |||
90067 90068 90069 90070 90071 90072 90073 |
if( iA==-1 ) iA = 1;
iB %= iA;
break;
}
}
pOut->u.i = iB;
MemSetTypeFlag(pOut, MEM_Int);
| | > > > | 91359 91360 91361 91362 91363 91364 91365 91366 91367 91368 91369 91370 91371 91372 91373 91374 91375 91376 91377 91378 |
if( iA==-1 ) iA = 1;
iB %= iA;
break;
}
}
pOut->u.i = iB;
MemSetTypeFlag(pOut, MEM_Int);
}else if( ((type1 | type2) & MEM_Null)!=0 ){
goto arithmetic_result_is_null;
}else{
type1 = numericType(pIn1);
type2 = numericType(pIn2);
if( (type1 & type2 & MEM_Int)!=0 ) goto int_math;
fp_math:
rA = sqlite3VdbeRealValue(pIn1);
rB = sqlite3VdbeRealValue(pIn2);
switch( pOp->opcode ){
case OP_Add: rB += rA; break;
case OP_Subtract: rB -= rA; break;
case OP_Multiply: rB *= rA; break;
|
| ︙ | ︙ | |||
90884 90885 90886 90887 90888 90889 90890 |
VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2);
if( (pIn1->flags & MEM_Null)!=0 ){
goto jump_to_p2;
}
break;
}
| | | | > > > > > > > > > > > > | > | > > > > > | > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | > | > | 92179 92180 92181 92182 92183 92184 92185 92186 92187 92188 92189 92190 92191 92192 92193 92194 92195 92196 92197 92198 92199 92200 92201 92202 92203 92204 92205 92206 92207 92208 92209 92210 92211 92212 92213 92214 92215 92216 92217 92218 92219 92220 92221 92222 92223 92224 92225 92226 92227 92228 92229 92230 92231 92232 92233 92234 92235 92236 92237 92238 92239 92240 92241 92242 92243 92244 92245 92246 92247 92248 92249 92250 92251 92252 92253 92254 92255 92256 92257 92258 92259 92260 92261 92262 92263 92264 92265 92266 92267 92268 92269 92270 92271 92272 92273 92274 92275 92276 |
VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2);
if( (pIn1->flags & MEM_Null)!=0 ){
goto jump_to_p2;
}
break;
}
/* Opcode: IsType P1 P2 P3 P4 P5
** Synopsis: if typeof(P1.P3) in P5 goto P2
**
** Jump to P2 if the type of a column in a btree is one of the types specified
** by the P5 bitmask.
**
** P1 is normally a cursor on a btree for which the row decode cache is
** valid through at least column P3. In other words, there should have been
** a prior OP_Column for column P3 or greater. If the cursor is not valid,
** then this opcode might give spurious results.
** The the btree row has fewer than P3 columns, then use P4 as the
** datatype.
**
** If P1 is -1, then P3 is a register number and the datatype is taken
** from the value in that register.
**
** P5 is a bitmask of data types. SQLITE_INTEGER is the least significant
** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
**
** Take the jump to address P2 if and only if the datatype of the
** value determined by P1 and P3 corresponds to one of the bits in the
** P5 bitmask.
**
*/
case OP_IsType: { /* jump */
VdbeCursor *pC;
u16 typeMask;
u32 serialType;
assert( pOp->p1>=(-1) && pOp->p1<p->nCursor );
assert( pOp->p1>=0 || (pOp->p3>=0 && pOp->p3<=(p->nMem+1 - p->nCursor)) );
if( pOp->p1>=0 ){
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pOp->p3>=0 );
if( pOp->p3<pC->nHdrParsed ){
serialType = pC->aType[pOp->p3];
if( serialType>=12 ){
if( serialType&1 ){
typeMask = 0x04; /* SQLITE_TEXT */
}else{
typeMask = 0x08; /* SQLITE_BLOB */
}
}else{
static const unsigned char aMask[] = {
0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2,
0x01, 0x01, 0x10, 0x10
};
testcase( serialType==0 );
testcase( serialType==1 );
testcase( serialType==2 );
testcase( serialType==3 );
testcase( serialType==4 );
testcase( serialType==5 );
testcase( serialType==6 );
testcase( serialType==7 );
testcase( serialType==8 );
testcase( serialType==9 );
testcase( serialType==10 );
testcase( serialType==11 );
typeMask = aMask[serialType];
}
}else{
typeMask = 1 << (pOp->p4.i - 1);
testcase( typeMask==0x01 );
testcase( typeMask==0x02 );
testcase( typeMask==0x04 );
testcase( typeMask==0x08 );
testcase( typeMask==0x10 );
}
}else{
assert( memIsValid(&aMem[pOp->p3]) );
typeMask = 1 << (sqlite3_value_type((sqlite3_value*)&aMem[pOp->p3])-1);
testcase( typeMask==0x01 );
testcase( typeMask==0x02 );
testcase( typeMask==0x04 );
testcase( typeMask==0x08 );
testcase( typeMask==0x10 );
}
VdbeBranchTaken( (typeMask & pOp->p5)!=0, 2);
if( typeMask & pOp->p5 ){
goto jump_to_p2;
}
break;
}
/* Opcode: ZeroOrNull P1 P2 P3 * *
** Synopsis: r[P2] = 0 OR NULL
**
** If all both registers P1 and P3 are NOT NULL, then store a zero in
|
| ︙ | ︙ | |||
90939 90940 90941 90942 90943 90944 90945 90946 90947 90948 |
/* Opcode: IfNullRow P1 P2 P3 * *
** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2
**
** Check the cursor P1 to see if it is currently pointing at a NULL row.
** If it is, then set register P3 to NULL and jump immediately to P2.
** If P1 is not on a NULL row, then fall through without making any
** changes.
*/
case OP_IfNullRow: { /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
| > > > | | | 92305 92306 92307 92308 92309 92310 92311 92312 92313 92314 92315 92316 92317 92318 92319 92320 92321 92322 92323 92324 92325 92326 |
/* Opcode: IfNullRow P1 P2 P3 * *
** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2
**
** Check the cursor P1 to see if it is currently pointing at a NULL row.
** If it is, then set register P3 to NULL and jump immediately to P2.
** If P1 is not on a NULL row, then fall through without making any
** changes.
**
** If P1 is not an open cursor, then this opcode is a no-op.
*/
case OP_IfNullRow: { /* jump */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
if( ALWAYS(pC) && pC->nullRow ){
sqlite3VdbeMemSetNull(aMem + pOp->p3);
goto jump_to_p2;
}
break;
}
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
| ︙ | ︙ | |||
90994 90995 90996 90997 90998 90999 91000 | /* Opcode: Column P1 P2 P3 P4 P5 ** Synopsis: r[P3]=PX cursor P1 column P2 ** ** Interpret the data that cursor P1 points to as a structure built using ** the MakeRecord instruction. (See the MakeRecord opcode for additional ** information about the format of the data.) Extract the P2-th column | | | | > > | | | 92363 92364 92365 92366 92367 92368 92369 92370 92371 92372 92373 92374 92375 92376 92377 92378 92379 92380 92381 92382 92383 92384 92385 92386 92387 92388 92389 92390 92391 |
/* Opcode: Column P1 P2 P3 P4 P5
** Synopsis: r[P3]=PX cursor P1 column P2
**
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
** information about the format of the data.) Extract the P2-th column
** from this record. If there are less than (P2+1)
** values in the record, extract a NULL.
**
** The value extracted is stored in register P3.
**
** If the record contains fewer than P2 fields, then extract a NULL. Or,
** if the P4 argument is a P4_MEM use the value of the P4 argument as
** the result.
**
** If the OPFLAG_LENGTHARG bit is set in P5 then the result is guaranteed
** to only be used by the length() function or the equivalent. The content
** of large blobs is not loaded, thus saving CPU cycles. If the
** OPFLAG_TYPEOFARG bit is set then the result will only be used by the
** typeof() function or the IS NULL or IS NOT NULL operators or the
** equivalent. In this case, all content loading can be omitted.
*/
case OP_Column: {
u32 p2; /* column number to retrieve */
VdbeCursor *pC; /* The VDBE cursor */
BtCursor *pCrsr; /* The B-Tree cursor corresponding to pC */
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
int len; /* The length of the serialized data for the column */
|
| ︙ | ︙ | |||
92945 92946 92947 92948 92949 92950 92951 |
assert( oc!=OP_SeekGT || r.default_rc==-1 );
assert( oc!=OP_SeekLE || r.default_rc==-1 );
assert( oc!=OP_SeekGE || r.default_rc==+1 );
assert( oc!=OP_SeekLT || r.default_rc==+1 );
r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
| > > > | > > > | 94316 94317 94318 94319 94320 94321 94322 94323 94324 94325 94326 94327 94328 94329 94330 94331 94332 94333 94334 94335 94336 |
assert( oc!=OP_SeekGT || r.default_rc==-1 );
assert( oc!=OP_SeekLE || r.default_rc==-1 );
assert( oc!=OP_SeekGE || r.default_rc==+1 );
assert( oc!=OP_SeekLT || r.default_rc==+1 );
r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
{
int i;
for(i=0; i<r.nField; i++){
assert( memIsValid(&r.aMem[i]) );
if( i>0 ) REGISTER_TRACE(pOp->p3+i, &r.aMem[i]);
}
}
#endif
r.eqSeen = 0;
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
if( eqOnly && r.eqSeen==0 ){
|
| ︙ | ︙ | |||
93008 93009 93010 93011 93012 93013 93014 |
assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */
}
break;
}
| | | | | > | | | > > > > > > > > > > > | | | > > > | | > | | > > > > > | | > | | > < > | > | | | > > > > > > > > > | 94385 94386 94387 94388 94389 94390 94391 94392 94393 94394 94395 94396 94397 94398 94399 94400 94401 94402 94403 94404 94405 94406 94407 94408 94409 94410 94411 94412 94413 94414 94415 94416 94417 94418 94419 94420 94421 94422 94423 94424 94425 94426 94427 94428 94429 94430 94431 94432 94433 94434 94435 94436 94437 94438 94439 94440 94441 94442 94443 94444 94445 94446 94447 94448 94449 94450 94451 94452 94453 94454 94455 94456 94457 94458 94459 94460 94461 94462 94463 94464 94465 94466 94467 94468 94469 94470 94471 94472 94473 94474 94475 94476 94477 94478 94479 94480 94481 94482 94483 94484 94485 94486 94487 94488 94489 94490 94491 94492 94493 |
assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */
}
break;
}
/* Opcode: SeekScan P1 P2 * * P5
** Synopsis: Scan-ahead up to P1 rows
**
** This opcode is a prefix opcode to OP_SeekGE. In other words, this
** opcode must be immediately followed by OP_SeekGE. This constraint is
** checked by assert() statements.
**
** This opcode uses the P1 through P4 operands of the subsequent
** OP_SeekGE. In the text that follows, the operands of the subsequent
** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only
** the P1, P2 and P5 operands of this opcode are also used, and are called
** This.P1, This.P2 and This.P5.
**
** This opcode helps to optimize IN operators on a multi-column index
** where the IN operator is on the later terms of the index by avoiding
** unnecessary seeks on the btree, substituting steps to the next row
** of the b-tree instead. A correct answer is obtained if this opcode
** is omitted or is a no-op.
**
** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which
** is the desired entry that we want the cursor SeekGE.P1 to be pointing
** to. Call this SeekGE.P3/P4 row the "target".
**
** If the SeekGE.P1 cursor is not currently pointing to a valid row,
** then this opcode is a no-op and control passes through into the OP_SeekGE.
**
** If the SeekGE.P1 cursor is pointing to a valid row, then that row
** might be the target row, or it might be near and slightly before the
** target row, or it might be after the target row. If the cursor is
** currently before the target row, then this opcode attempts to position
** the cursor on or after the target row by invoking sqlite3BtreeStep()
** on the cursor between 1 and This.P1 times.
**
** The This.P5 parameter is a flag that indicates what to do if the
** cursor ends up pointing at a valid row that is past the target
** row. If This.P5 is false (0) then a jump is made to SeekGE.P2. If
** This.P5 is true (non-zero) then a jump is made to This.P2. The P5==0
** case occurs when there are no inequality constraints to the right of
** the IN constraing. The jump to SeekGE.P2 ends the loop. The P5!=0 case
** occurs when there are inequality constraints to the right of the IN
** operator. In that case, the This.P2 will point either directly to or
** to setup code prior to the OP_IdxGT or OP_IdxGE opcode that checks for
** loop terminate.
**
** Possible outcomes from this opcode:<ol>
**
** <li> If the cursor is initally not pointed to any valid row, then
** fall through into the subsequent OP_SeekGE opcode.
**
** <li> If the cursor is left pointing to a row that is before the target
** row, even after making as many as This.P1 calls to
** sqlite3BtreeNext(), then also fall through into OP_SeekGE.
**
** <li> If the cursor is left pointing at the target row, either because it
** was at the target row to begin with or because one or more
** sqlite3BtreeNext() calls moved the cursor to the target row,
** then jump to This.P2..,
**
** <li> If the cursor started out before the target row and a call to
** to sqlite3BtreeNext() moved the cursor off the end of the index
** (indicating that the target row definitely does not exist in the
** btree) then jump to SeekGE.P2, ending the loop.
**
** <li> If the cursor ends up on a valid row that is past the target row
** (indicating that the target row does not exist in the btree) then
** jump to SeekOP.P2 if This.P5==0 or to This.P2 if This.P5>0.
** </ol>
*/
case OP_SeekScan: {
VdbeCursor *pC;
int res;
int nStep;
UnpackedRecord r;
assert( pOp[1].opcode==OP_SeekGE );
/* If pOp->p5 is clear, then pOp->p2 points to the first instruction past the
** OP_IdxGT that follows the OP_SeekGE. Otherwise, it points to the first
** opcode past the OP_SeekGE itself. */
assert( pOp->p2>=(int)(pOp-aOp)+2 );
#ifdef SQLITE_DEBUG
if( pOp->p5==0 ){
/* There are no inequality constraints following the IN constraint. */
assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
assert( aOp[pOp->p2-1].opcode==OP_IdxGT
|| aOp[pOp->p2-1].opcode==OP_IdxGE );
testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
}else{
/* There are inequality constraints. */
assert( pOp->p2==(int)(pOp-aOp)+2 );
assert( aOp[pOp->p2-1].opcode==OP_SeekGE );
}
#endif
assert( pOp->p1>0 );
pC = p->apCsr[pOp[1].p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
assert( !pC->isTable );
if( !sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) ){
|
| ︙ | ︙ | |||
93103 93104 93105 93106 93107 93108 93109 |
}
}
#endif
res = 0; /* Not needed. Only used to silence a warning. */
while(1){
rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
if( rc ) goto abort_due_to_error;
| | > | > | 94513 94514 94515 94516 94517 94518 94519 94520 94521 94522 94523 94524 94525 94526 94527 94528 94529 94530 94531 94532 94533 94534 94535 94536 94537 94538 94539 94540 |
}
}
#endif
res = 0; /* Not needed. Only used to silence a warning. */
while(1){
rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
if( rc ) goto abort_due_to_error;
if( res>0 && pOp->p5==0 ){
seekscan_search_fail:
/* Jump to SeekGE.P2, ending the loop */
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then skip\n", pOp->p1 - nStep);
}
#endif
VdbeBranchTaken(1,3);
pOp++;
goto jump_to_p2;
}
if( res>=0 ){
/* Jump to This.P2, bypassing the OP_SeekGE opcode */
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then success\n", pOp->p1 - nStep);
}
#endif
VdbeBranchTaken(2,3);
goto jump_to_p2;
|
| ︙ | ︙ | |||
93190 93191 93192 93193 93194 93195 93196 | } break; } /* Opcode: IfNotOpen P1 P2 * * * ** Synopsis: if( !csr[P1] ) goto P2 ** | > | > > < | > > | 94602 94603 94604 94605 94606 94607 94608 94609 94610 94611 94612 94613 94614 94615 94616 94617 94618 94619 94620 94621 94622 94623 94624 94625 |
}
break;
}
/* Opcode: IfNotOpen P1 P2 * * *
** Synopsis: if( !csr[P1] ) goto P2
**
** If cursor P1 is not open or if P1 is set to a NULL row using the
** OP_NullRow opcode, then jump to instruction P2. Otherwise, fall through.
*/
case OP_IfNotOpen: { /* jump */
VdbeCursor *pCur;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pCur = p->apCsr[pOp->p1];
VdbeBranchTaken(pCur==0 || pCur->nullRow, 2);
if( pCur==0 || pCur->nullRow ){
goto jump_to_p2_and_check_for_interrupt;
}
break;
}
/* Opcode: Found P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
|
| ︙ | ︙ | |||
94386 94387 94388 94389 94390 94391 94392 | pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); rc = sqlite3VdbeSorterNext(db, pC); goto next_tail; case OP_Prev: /* jump */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); | | > > | > > | 95802 95803 95804 95805 95806 95807 95808 95809 95810 95811 95812 95813 95814 95815 95816 95817 95818 95819 95820 95821 95822 95823 95824 95825 95826 95827 95828 95829 95830 95831 95832 95833 |
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
rc = sqlite3VdbeSorterNext(db, pC);
goto next_tail;
case OP_Prev: /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5==0
|| pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
|| pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|| pC->seekOp==OP_Last || pC->seekOp==OP_IfNoHope
|| pC->seekOp==OP_NullRow);
rc = sqlite3BtreePrevious(pC->uc.pCursor, pOp->p3);
goto next_tail;
case OP_Next: /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5==0
|| pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
|| pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE
|| pC->seekOp==OP_Rewind || pC->seekOp==OP_Found
|| pC->seekOp==OP_NullRow|| pC->seekOp==OP_SeekRowid
|
| ︙ | ︙ | |||
94606 94607 94608 94609 94610 94611 94612 | assert( pC->deferredMoveto==0 ); assert( !pC->nullRow || pOp->opcode==OP_IdxRowid ); /* The IdxRowid and Seek opcodes are combined because of the commonality ** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */ rc = sqlite3VdbeCursorRestore(pC); | | | | | | 96026 96027 96028 96029 96030 96031 96032 96033 96034 96035 96036 96037 96038 96039 96040 96041 96042 96043 |
assert( pC->deferredMoveto==0 );
assert( !pC->nullRow || pOp->opcode==OP_IdxRowid );
/* The IdxRowid and Seek opcodes are combined because of the commonality
** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */
rc = sqlite3VdbeCursorRestore(pC);
/* sqlite3VdbeCursorRestore() may fail if the cursor has been disturbed
** since it was last positioned and an error (e.g. OOM or an IO error)
** occurs while trying to reposition it. */
if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( !pC->nullRow ){
rowid = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
|
| ︙ | ︙ | |||
95511 95512 95513 95514 95515 95516 95517 | break; } /* Opcode: OffsetLimit P1 P2 P3 * * ** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) ** ** This opcode performs a commonly used computation associated with | | | 96931 96932 96933 96934 96935 96936 96937 96938 96939 96940 96941 96942 96943 96944 96945 | break; } /* Opcode: OffsetLimit P1 P2 P3 * * ** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) ** ** This opcode performs a commonly used computation associated with ** LIMIT and OFFSET processing. r[P1] holds the limit counter. r[P3] ** holds the offset counter. The opcode computes the combined value ** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2] ** value computed is the total number of rows that will need to be ** visited in order to complete the query. ** ** If r[P3] is zero or negative, that means there is no OFFSET ** and r[P2] is set to be the value of the LIMIT, r[P1]. |
| ︙ | ︙ | |||
101108 101109 101110 101111 101112 101113 101114 101115 101116 101117 101118 101119 101120 101121 |
sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
const char *zName, /* Name of the journal file */
sqlite3_file *pJfd, /* Preallocated, blank file handle */
int flags, /* Opening flags */
int nSpill /* Bytes buffered before opening the file */
){
MemJournal *p = (MemJournal*)pJfd;
/* Zero the file-handle object. If nSpill was passed zero, initialize
** it using the sqlite3OsOpen() function of the underlying VFS. In this
** case none of the code in this module is executed as a result of calls
** made on the journal file-handle. */
memset(p, 0, sizeof(MemJournal));
if( nSpill==0 ){
| > > | 102528 102529 102530 102531 102532 102533 102534 102535 102536 102537 102538 102539 102540 102541 102542 102543 |
sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
const char *zName, /* Name of the journal file */
sqlite3_file *pJfd, /* Preallocated, blank file handle */
int flags, /* Opening flags */
int nSpill /* Bytes buffered before opening the file */
){
MemJournal *p = (MemJournal*)pJfd;
assert( zName || nSpill<0 || (flags & SQLITE_OPEN_EXCLUSIVE) );
/* Zero the file-handle object. If nSpill was passed zero, initialize
** it using the sqlite3OsOpen() function of the underlying VFS. In this
** case none of the code in this module is executed as a result of calls
** made on the journal file-handle. */
memset(p, 0, sizeof(MemJournal));
if( nSpill==0 ){
|
| ︙ | ︙ | |||
101550 101551 101552 101553 101554 101555 101556 |
memcpy(pDup, pExpr, sizeof(Expr));
memcpy(pExpr, &temp, sizeof(Expr));
if( ExprHasProperty(pExpr, EP_WinFunc) ){
if( ALWAYS(pExpr->y.pWin!=0) ){
pExpr->y.pWin->pOwner = pExpr;
}
}
| < | < | 102972 102973 102974 102975 102976 102977 102978 102979 102980 102981 102982 102983 102984 102985 102986 |
memcpy(pDup, pExpr, sizeof(Expr));
memcpy(pExpr, &temp, sizeof(Expr));
if( ExprHasProperty(pExpr, EP_WinFunc) ){
if( ALWAYS(pExpr->y.pWin!=0) ){
pExpr->y.pWin->pOwner = pExpr;
}
}
sqlite3ExprDeferredDelete(pParse, pDup);
}
}
/*
** Subqueries stores the original database, table and column names for their
** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
** Check to see if the zSpan given to this routine matches the zDb, zTab,
|
| ︙ | ︙ | |||
103646 103647 103648 103649 103650 103651 103652 |
pExpr = pExpr->pLeft;
assert( pExpr!=0 );
}
op = pExpr->op;
if( op==TK_REGISTER ) op = pExpr->op2;
if( op==TK_COLUMN || op==TK_AGG_COLUMN ){
assert( ExprUseYTab(pExpr) );
| | | < | 105066 105067 105068 105069 105070 105071 105072 105073 105074 105075 105076 105077 105078 105079 105080 105081 |
pExpr = pExpr->pLeft;
assert( pExpr!=0 );
}
op = pExpr->op;
if( op==TK_REGISTER ) op = pExpr->op2;
if( op==TK_COLUMN || op==TK_AGG_COLUMN ){
assert( ExprUseYTab(pExpr) );
assert( pExpr->y.pTab!=0 );
return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
}
if( op==TK_SELECT ){
assert( ExprUseXSelect(pExpr) );
assert( pExpr->x.pSelect!=0 );
assert( pExpr->x.pSelect->pEList!=0 );
assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
| ︙ | ︙ | |||
103766 103767 103768 103769 103770 103771 103772 103773 |
sqlite3 *db = pParse->db;
CollSeq *pColl = 0;
const Expr *p = pExpr;
while( p ){
int op = p->op;
if( op==TK_REGISTER ) op = p->op2;
if( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER ){
assert( ExprUseYTab(p) );
| > | < < | < | | | | < | 105185 105186 105187 105188 105189 105190 105191 105192 105193 105194 105195 105196 105197 105198 105199 105200 105201 105202 105203 105204 105205 105206 |
sqlite3 *db = pParse->db;
CollSeq *pColl = 0;
const Expr *p = pExpr;
while( p ){
int op = p->op;
if( op==TK_REGISTER ) op = p->op2;
if( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER ){
int j;
assert( ExprUseYTab(p) );
assert( p->y.pTab!=0 );
if( (j = p->iColumn)>=0 ){
const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]);
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
}
break;
}
if( op==TK_CAST || op==TK_UPLUS ){
p = p->pLeft;
continue;
}
if( op==TK_VECTOR ){
assert( ExprUseXList(p) );
|
| ︙ | ︙ | |||
104361 104362 104363 104364 104365 104366 104367 |
** referenced Expr plus one.
**
** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags,
** if appropriate.
*/
static void exprSetHeight(Expr *p){
int nHeight = p->pLeft ? p->pLeft->nHeight : 0;
| > | > | 105777 105778 105779 105780 105781 105782 105783 105784 105785 105786 105787 105788 105789 105790 105791 105792 105793 |
** referenced Expr plus one.
**
** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags,
** if appropriate.
*/
static void exprSetHeight(Expr *p){
int nHeight = p->pLeft ? p->pLeft->nHeight : 0;
if( NEVER(p->pRight) && p->pRight->nHeight>nHeight ){
nHeight = p->pRight->nHeight;
}
if( ExprUseXSelect(p) ){
heightOfSelect(p->x.pSelect, &nHeight);
}else if( p->x.pList ){
heightOfExprList(p->x.pList, &nHeight);
p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
}
p->nHeight = nHeight + 1;
|
| ︙ | ︙ | |||
104504 104505 104506 104507 104508 104509 104510 104511 104512 104513 104514 104515 104516 104517 |
Expr *pRight
){
if( pRoot==0 ){
assert( db->mallocFailed );
sqlite3ExprDelete(db, pLeft);
sqlite3ExprDelete(db, pRight);
}else{
if( pRight ){
pRoot->pRight = pRight;
pRoot->flags |= EP_Propagate & pRight->flags;
}
if( pLeft ){
pRoot->pLeft = pLeft;
pRoot->flags |= EP_Propagate & pLeft->flags;
| > > > > > > > > > > | < > > | 105922 105923 105924 105925 105926 105927 105928 105929 105930 105931 105932 105933 105934 105935 105936 105937 105938 105939 105940 105941 105942 105943 105944 105945 105946 105947 105948 105949 105950 105951 105952 105953 105954 105955 |
Expr *pRight
){
if( pRoot==0 ){
assert( db->mallocFailed );
sqlite3ExprDelete(db, pLeft);
sqlite3ExprDelete(db, pRight);
}else{
assert( ExprUseXList(pRoot) );
assert( pRoot->x.pSelect==0 );
if( pRight ){
pRoot->pRight = pRight;
pRoot->flags |= EP_Propagate & pRight->flags;
#if SQLITE_MAX_EXPR_DEPTH>0
pRoot->nHeight = pRight->nHeight+1;
}else{
pRoot->nHeight = 1;
#endif
}
if( pLeft ){
pRoot->pLeft = pLeft;
pRoot->flags |= EP_Propagate & pLeft->flags;
#if SQLITE_MAX_EXPR_DEPTH>0
if( pLeft->nHeight>=pRoot->nHeight ){
pRoot->nHeight = pLeft->nHeight+1;
}
#endif
}
}
}
/*
** Allocate an Expr node which joins as many as two subtrees.
**
** One or both of the subtrees can be NULL. Return a pointer to the new
|
| ︙ | ︙ | |||
104798 104799 104800 104801 104802 104803 104804 104805 104806 104807 104808 104809 104810 104811 |
}
/*
** Recursively delete an expression tree.
*/
static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
assert( p!=0 );
assert( !ExprUseUValue(p) || p->u.iValue>=0 );
assert( !ExprUseYWin(p) || !ExprUseYSub(p) );
assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed );
assert( p->op!=TK_FUNCTION || !ExprUseYSub(p) );
#ifdef SQLITE_DEBUG
if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){
assert( p->pLeft==0 );
| > | 106227 106228 106229 106230 106231 106232 106233 106234 106235 106236 106237 106238 106239 106240 106241 |
}
/*
** Recursively delete an expression tree.
*/
static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
assert( p!=0 );
assert( db!=0 );
assert( !ExprUseUValue(p) || p->u.iValue>=0 );
assert( !ExprUseYWin(p) || !ExprUseYSub(p) );
assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed );
assert( p->op!=TK_FUNCTION || !ExprUseYSub(p) );
#ifdef SQLITE_DEBUG
if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){
assert( p->pLeft==0 );
|
| ︙ | ︙ | |||
104829 104830 104831 104832 104833 104834 104835 |
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(p, EP_WinFunc) ){
sqlite3WindowDelete(db, p->y.pWin);
}
#endif
}
}
| < < < < | | 106259 106260 106261 106262 106263 106264 106265 106266 106267 106268 106269 106270 106271 106272 106273 106274 |
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(p, EP_WinFunc) ){
sqlite3WindowDelete(db, p->y.pWin);
}
#endif
}
}
if( !ExprHasProperty(p, EP_Static) ){
sqlite3DbNNFreeNN(db, p);
}
}
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
if( p ) sqlite3ExprDeleteNN(db, p);
}
/*
|
| ︙ | ︙ | |||
104865 104866 104867 104868 104869 104870 104871 |
**
** The pExpr might be deleted immediately on an OOM error.
**
** 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){
| | | > | 106291 106292 106293 106294 106295 106296 106297 106298 106299 106300 106301 106302 106303 106304 106305 106306 106307 |
**
** The pExpr might be deleted immediately on an OOM error.
**
** 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,
(void(*)(sqlite3*,void*))sqlite3ExprDelete,
pExpr);
}
/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
** expression.
*/
SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){
if( p ){
|
| ︙ | ︙ | |||
104940 104941 104942 104943 104944 104945 104946 |
|| ExprHasProperty(p, EP_WinFunc)
#endif
){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(p, EP_OuterON) );
| < | 106367 106368 106369 106370 106371 106372 106373 106374 106375 106376 106377 106378 106379 106380 |
|| ExprHasProperty(p, EP_WinFunc)
#endif
){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(p, EP_OuterON) );
assert( !ExprHasVVAProperty(p, EP_NoReduce) );
if( p->pLeft || p->x.pList ){
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
}else{
assert( p->pRight==0 );
nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;
}
|
| ︙ | ︙ | |||
105044 105045 105046 105047 105048 105049 105050 |
memcpy(zAlloc, p, nSize);
if( nSize<EXPR_FULLSIZE ){
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
}
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
| | | 106470 106471 106472 106473 106474 106475 106476 106477 106478 106479 106480 106481 106482 106483 106484 |
memcpy(zAlloc, p, nSize);
if( nSize<EXPR_FULLSIZE ){
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
}
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static);
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
pNew->flags |= staticFlag;
ExprClearVVAProperties(pNew);
if( dupFlags ){
ExprSetVVAProperty(pNew, EP_Immutable);
}
|
| ︙ | ︙ | |||
105620 105621 105622 105623 105624 105625 105626 105627 105628 |
/*
** Delete an entire expression list.
*/
static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
int i = pList->nExpr;
struct ExprList_item *pItem = pList->a;
assert( pList->nExpr>0 );
do{
sqlite3ExprDelete(db, pItem->pExpr);
| > | | | 107046 107047 107048 107049 107050 107051 107052 107053 107054 107055 107056 107057 107058 107059 107060 107061 107062 107063 107064 107065 107066 |
/*
** Delete an entire expression list.
*/
static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
int i = pList->nExpr;
struct ExprList_item *pItem = pList->a;
assert( pList->nExpr>0 );
assert( db!=0 );
do{
sqlite3ExprDelete(db, pItem->pExpr);
if( pItem->zEName ) sqlite3DbNNFreeNN(db, pItem->zEName);
pItem++;
}while( --i>0 );
sqlite3DbNNFreeNN(db, pList);
}
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
if( pList ) exprListDeleteNN(db, pList);
}
/*
** Return the bitwise-OR of all Expr.flags fields in the given
|
| ︙ | ︙ | |||
106803 106804 106805 106806 106807 106808 106809 106810 106811 106812 106813 106814 106815 106816 |
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
}
if( addrOnce ){
sqlite3VdbeJumpHere(v, addrOnce);
/* Subroutine return */
assert( ExprUseYSub(pExpr) );
assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|| pParse->nErr );
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
pExpr->y.sub.iAddr, 1);
| > | 108230 108231 108232 108233 108234 108235 108236 108237 108238 108239 108240 108241 108242 108243 108244 |
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
}
if( addrOnce ){
sqlite3VdbeAddOp1(v, OP_NullRow, iTab);
sqlite3VdbeJumpHere(v, addrOnce);
/* Subroutine return */
assert( ExprUseYSub(pExpr) );
assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|| pParse->nErr );
sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
pExpr->y.sub.iAddr, 1);
|
| ︙ | ︙ | |||
106916 106917 106918 106919 106920 106921 106922 |
sqlite3 *db = pParse->db;
pLimit = sqlite3Expr(db, TK_INTEGER, "0");
if( pLimit ){
pLimit->affExpr = SQLITE_AFF_NUMERIC;
pLimit = sqlite3PExpr(pParse, TK_NE,
sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit);
}
| | | 108344 108345 108346 108347 108348 108349 108350 108351 108352 108353 108354 108355 108356 108357 108358 |
sqlite3 *db = pParse->db;
pLimit = sqlite3Expr(db, TK_INTEGER, "0");
if( pLimit ){
pLimit->affExpr = SQLITE_AFF_NUMERIC;
pLimit = sqlite3PExpr(pParse, TK_NE,
sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit);
}
sqlite3ExprDeferredDelete(pParse, pSel->pLimit->pLeft);
pSel->pLimit->pLeft = pLimit;
}else{
/* If there is no pre-existing limit add a limit of 1 */
pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1");
pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
}
pSel->iLimit = 0;
|
| ︙ | ︙ | |||
107369 107370 107371 107372 107373 107374 107375 |
Table *pTab, /* The table containing the value */
int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */
int iCol, /* Index of the column to extract */
int regOut /* Extract the value into this register */
){
Column *pCol;
assert( v!=0 );
| | < < < | 108797 108798 108799 108800 108801 108802 108803 108804 108805 108806 108807 108808 108809 108810 108811 |
Table *pTab, /* The table containing the value */
int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */
int iCol, /* Index of the column to extract */
int regOut /* Extract the value into this register */
){
Column *pCol;
assert( v!=0 );
assert( pTab!=0 );
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
VdbeComment((v, "%s.rowid", pTab->zName));
}else{
int op;
int x;
if( IsVirtual(pTab) ){
|
| ︙ | ︙ | |||
107430 107431 107432 107433 107434 107435 107436 |
int iTable, /* The cursor pointing to the table */
int iReg, /* Store results here */
u8 p5 /* P5 value for OP_Column + FLAGS */
){
assert( pParse->pVdbe!=0 );
sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
| | | 108855 108856 108857 108858 108859 108860 108861 108862 108863 108864 108865 108866 108867 108868 108869 |
int iTable, /* The cursor pointing to the table */
int iReg, /* Store results here */
u8 p5 /* P5 value for OP_Column + FLAGS */
){
assert( pParse->pVdbe!=0 );
sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
VdbeOp *pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Column ) pOp->p5 = p5;
}
return iReg;
}
/*
** Generate code to move content from registers iFrom...iFrom+nReg-1
|
| ︙ | ︙ | |||
107499 107500 107501 107502 107503 107504 107505 |
}
/*
** If the last opcode is a OP_Copy, then set the do-not-merge flag (p5)
** so that a subsequent copy will not be merged into this one.
*/
static void setDoNotMergeFlagOnCopy(Vdbe *v){
| | | 108924 108925 108926 108927 108928 108929 108930 108931 108932 108933 108934 108935 108936 108937 108938 |
}
/*
** If the last opcode is a OP_Copy, then set the do-not-merge flag (p5)
** so that a subsequent copy will not be merged into this one.
*/
static void setDoNotMergeFlagOnCopy(Vdbe *v){
if( sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){
sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
}
}
/*
** Generate code to implement special SQL functions that are implemented
** in-line rather than by using the usual callbacks.
|
| ︙ | ︙ | |||
107622 107623 107624 107625 107626 107627 107628 107629 107630 107631 107632 107633 107634 107635 |
break;
}
#endif /* !defined(SQLITE_UNTESTABLE) */
}
return target;
}
/*
** Generate code into the current Vdbe to evaluate the given
** expression. Attempt to store the results in register "target".
** Return the register where results are stored.
**
** With this routine, there is no guarantee that results will
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 109047 109048 109049 109050 109051 109052 109053 109054 109055 109056 109057 109058 109059 109060 109061 109062 109063 109064 109065 109066 109067 109068 109069 109070 109071 109072 109073 109074 109075 109076 109077 109078 109079 109080 109081 109082 109083 109084 109085 109086 109087 109088 109089 109090 109091 109092 109093 109094 109095 109096 109097 109098 109099 109100 109101 109102 109103 109104 109105 109106 109107 |
break;
}
#endif /* !defined(SQLITE_UNTESTABLE) */
}
return target;
}
/*
** Check to see if pExpr is one of the indexed expressions on pParse->pIdxExpr.
** If it is, then resolve the expression by reading from the index and
** return the register into which the value has been read. If pExpr is
** not an indexed expression, then return negative.
*/
static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
Parse *pParse, /* The parsing context */
Expr *pExpr, /* The expression to potentially bypass */
int target /* Where to store the result of the expression */
){
IndexedExpr *p;
Vdbe *v;
for(p=pParse->pIdxExpr; p; p=p->pIENext){
int iDataCur = p->iDataCur;
if( iDataCur<0 ) continue;
if( pParse->iSelfTab ){
if( p->iDataCur!=pParse->iSelfTab-1 ) continue;
iDataCur = -1;
}
if( sqlite3ExprCompare(0, pExpr, p->pExpr, iDataCur)!=0 ) continue;
v = pParse->pVdbe;
assert( v!=0 );
if( p->bMaybeNullRow ){
/* If the index is on a NULL row due to an outer join, then we
** cannot extract the value from the index. The value must be
** computed using the original expression. */
int addr = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_IfNullRow, p->iIdxCur, addr+3, target);
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
sqlite3VdbeGoto(v, 0);
p = pParse->pIdxExpr;
pParse->pIdxExpr = 0;
sqlite3ExprCode(pParse, pExpr, target);
pParse->pIdxExpr = p;
sqlite3VdbeJumpHere(v, addr+2);
}else{
sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
}
return target;
}
return -1; /* Not found */
}
/*
** Generate code into the current Vdbe to evaluate the given
** expression. Attempt to store the results in register "target".
** Return the register where results are stored.
**
** With this routine, there is no guarantee that results will
|
| ︙ | ︙ | |||
107650 107651 107652 107653 107654 107655 107656 107657 107658 107659 107660 107661 107662 107663 107664 107665 107666 107667 107668 107669 107670 107671 107672 107673 107674 107675 107676 |
assert( target>0 && target<=pParse->nMem );
assert( v!=0 );
expr_code_doover:
if( pExpr==0 ){
op = TK_NULL;
}else{
assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
op = pExpr->op;
}
switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol;
assert( pAggInfo!=0 );
assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
assert( pCol->iMem>0 );
return pCol->iMem;
}else if( pAggInfo->useSortingIdx ){
Table *pTab = pCol->pTab;
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
pCol->iSorterColumn, target);
if( pCol->iColumn<0 ){
VdbeComment((v,"%s.rowid",pTab->zName));
| > > > > > | | 109122 109123 109124 109125 109126 109127 109128 109129 109130 109131 109132 109133 109134 109135 109136 109137 109138 109139 109140 109141 109142 109143 109144 109145 109146 109147 109148 109149 109150 109151 109152 109153 109154 109155 109156 109157 109158 109159 109160 109161 |
assert( target>0 && target<=pParse->nMem );
assert( v!=0 );
expr_code_doover:
if( pExpr==0 ){
op = TK_NULL;
}else if( pParse->pIdxExpr!=0
&& !ExprHasProperty(pExpr, EP_Leaf)
&& (r1 = sqlite3IndexedExprLookup(pParse, pExpr, target))>=0
){
return r1;
}else{
assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
op = pExpr->op;
}
switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol;
assert( pAggInfo!=0 );
assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
assert( pCol->iMem>0 );
return pCol->iMem;
}else if( pAggInfo->useSortingIdx ){
Table *pTab = pCol->pTab;
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
pCol->iSorterColumn, target);
if( pCol->iColumn<0 ){
VdbeComment((v,"%s.rowid",pTab->zName));
}else if( ALWAYS(pTab!=0) ){
VdbeComment((v,"%s.%s",
pTab->zName, pTab->aCol[pCol->iColumn].zCnName));
if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
}
}
return target;
|
| ︙ | ︙ | |||
107695 107696 107697 107698 107699 107700 107701 |
** expresssion. However, make sure the constant has the correct
** datatype by applying the Affinity of the table column to the
** constant.
*/
int aff;
iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
assert( ExprUseYTab(pExpr) );
| | | < < < | 109172 109173 109174 109175 109176 109177 109178 109179 109180 109181 109182 109183 109184 109185 109186 109187 |
** expresssion. However, make sure the constant has the correct
** datatype by applying the Affinity of the table column to the
** constant.
*/
int aff;
iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
assert( ExprUseYTab(pExpr) );
assert( pExpr->y.pTab!=0 );
aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
if( aff>SQLITE_AFF_BLOB ){
static const char zAff[] = "B\000C\000D\000E";
assert( SQLITE_AFF_BLOB=='A' );
assert( SQLITE_AFF_TEXT=='B' );
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
&zAff[(aff-'B')*2], P4_STATIC);
}
|
| ︙ | ︙ | |||
107761 107762 107763 107764 107765 107766 107767 107768 107769 107770 |
}else{
/* Coding an expression that is part of an index where column names
** in the index refer to the table to which the index belongs */
iTab = pParse->iSelfTab - 1;
}
}
assert( ExprUseYTab(pExpr) );
iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
pExpr->iColumn, iTab, target,
pExpr->op2);
| > < < < | 109235 109236 109237 109238 109239 109240 109241 109242 109243 109244 109245 109246 109247 109248 109249 109250 109251 109252 |
}else{
/* Coding an expression that is part of an index where column names
** in the index refer to the table to which the index belongs */
iTab = pParse->iSelfTab - 1;
}
}
assert( ExprUseYTab(pExpr) );
assert( pExpr->y.pTab!=0 );
iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
pExpr->iColumn, iTab, target,
pExpr->op2);
return iReg;
}
case TK_INTEGER: {
codeInteger(pParse, pExpr, 0, target);
return target;
}
case TK_TRUEFALSE: {
|
| ︙ | ︙ | |||
108265 108266 108267 108268 108269 108270 108271 108272 108273 108274 108275 108276 108277 108278 |
** Expr.iTable value is the table number for the right-hand table.
** The expression is only evaluated if that table is not currently
** on a LEFT JOIN NULL row.
*/
case TK_IF_NULL_ROW: {
int addrINR;
u8 okConstFactor = pParse->okConstFactor;
addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
/* Temporarily disable factoring of constant expressions, since
** even though expressions may appear to be constant, they are not
** really constant because they originate from the right-hand side
** of a LEFT JOIN. */
pParse->okConstFactor = 0;
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
| > > > > > > > > > > > > > > > | 109737 109738 109739 109740 109741 109742 109743 109744 109745 109746 109747 109748 109749 109750 109751 109752 109753 109754 109755 109756 109757 109758 109759 109760 109761 109762 109763 109764 109765 |
** Expr.iTable value is the table number for the right-hand table.
** The expression is only evaluated if that table is not currently
** on a LEFT JOIN NULL row.
*/
case TK_IF_NULL_ROW: {
int addrINR;
u8 okConstFactor = pParse->okConstFactor;
AggInfo *pAggInfo = pExpr->pAggInfo;
if( pAggInfo ){
assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
if( !pAggInfo->directMode ){
inReg = pAggInfo->aCol[pExpr->iAgg].iMem;
break;
}
if( pExpr->pAggInfo->useSortingIdx ){
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
pAggInfo->aCol[pExpr->iAgg].iSorterColumn,
target);
inReg = target;
break;
}
}
addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
/* Temporarily disable factoring of constant expressions, since
** even though expressions may appear to be constant, they are not
** really constant because they originate from the right-hand side
** of a LEFT JOIN. */
pParse->okConstFactor = 0;
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
| ︙ | ︙ | |||
108606 108607 108608 108609 108610 108611 108612 |
){
sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
}else{
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
if( inReg!=target+i ){
VdbeOp *pOp;
if( copyOp==OP_Copy
| | | 110093 110094 110095 110096 110097 110098 110099 110100 110101 110102 110103 110104 110105 110106 110107 |
){
sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
}else{
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
if( inReg!=target+i ){
VdbeOp *pOp;
if( copyOp==OP_Copy
&& (pOp=sqlite3VdbeGetLastOp(v))->opcode==OP_Copy
&& pOp->p1+pOp->p3+1==inReg
&& pOp->p2+pOp->p3+1==target+i
&& pOp->p5==0 /* The do-not-merge flag must be clear */
){
pOp->p3++;
}else{
sqlite3VdbeAddOp2(v, copyOp, inReg, target+i);
|
| ︙ | ︙ | |||
108805 108806 108807 108808 108809 108810 108811 108812 108813 108814 108815 108816 108817 108818 |
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
sqlite3VdbeAddOp2(v, op, r1, dest);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
testcase( regFree1==0 );
break;
}
case TK_BETWEEN: {
| > | 110292 110293 110294 110295 110296 110297 110298 110299 110300 110301 110302 110303 110304 110305 110306 |
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
testcase( regFree1==0 );
break;
}
case TK_BETWEEN: {
|
| ︙ | ︙ | |||
108979 108980 108981 108982 108983 108984 108985 108986 108987 108988 108989 108990 108991 108992 |
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
sqlite3VdbeAddOp2(v, op, r1, dest);
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
testcase( regFree1==0 );
break;
}
case TK_BETWEEN: {
| > | 110467 110468 110469 110470 110471 110472 110473 110474 110475 110476 110477 110478 110479 110480 110481 |
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest);
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
testcase( regFree1==0 );
break;
}
case TK_BETWEEN: {
|
| ︙ | ︙ | |||
109132 109133 109134 109135 109136 109137 109138 |
if( pA->op!=pB->op || pA->op==TK_RAISE ){
if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){
return 1;
}
if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){
return 1;
}
| > > > > > | > | 110621 110622 110623 110624 110625 110626 110627 110628 110629 110630 110631 110632 110633 110634 110635 110636 110637 110638 110639 110640 110641 |
if( pA->op!=pB->op || pA->op==TK_RAISE ){
if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){
return 1;
}
if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){
return 1;
}
if( pA->op==TK_AGG_COLUMN && pB->op==TK_COLUMN
&& pB->iTable<0 && pA->iTable==iTab
){
/* fall through */
}else{
return 2;
}
}
assert( !ExprHasProperty(pA, EP_IntValue) );
assert( !ExprHasProperty(pB, EP_IntValue) );
if( pA->u.zToken ){
if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
#ifndef SQLITE_OMIT_WINDOWFUNC
|
| ︙ | ︙ | |||
109434 109435 109436 109437 109438 109439 109440 |
testcase( pExpr->op==TK_GT );
testcase( pExpr->op==TK_GE );
/* The y.pTab=0 assignment in wherecode.c always happens after the
** impliesNotNullRow() test */
assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) );
assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) );
if( (pLeft->op==TK_COLUMN
| | | | 110929 110930 110931 110932 110933 110934 110935 110936 110937 110938 110939 110940 110941 110942 110943 110944 110945 110946 |
testcase( pExpr->op==TK_GT );
testcase( pExpr->op==TK_GE );
/* The y.pTab=0 assignment in wherecode.c always happens after the
** impliesNotNullRow() test */
assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) );
assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) );
if( (pLeft->op==TK_COLUMN
&& ALWAYS(pLeft->y.pTab!=0)
&& IsVirtual(pLeft->y.pTab))
|| (pRight->op==TK_COLUMN
&& ALWAYS(pRight->y.pTab!=0)
&& IsVirtual(pRight->y.pTab))
){
return WRC_Prune;
}
/* no break */ deliberate_fall_through
}
default:
|
| ︙ | ︙ | |||
109642 109643 109644 109645 109646 109647 109648 109649 109650 109651 109652 109653 109654 109655 109656 109657 109658 109659 109660 109661 109662 109663 109664 |
**
** As currently used, pExpr is always an aggregate function call. That
** fact is exploited for efficiency.
*/
SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){
Walker w;
struct RefSrcList x;
memset(&w, 0, sizeof(w));
memset(&x, 0, sizeof(x));
w.xExprCallback = exprRefToSrcList;
w.xSelectCallback = selectRefEnter;
w.xSelectCallback2 = selectRefLeave;
w.u.pRefSrcList = &x;
x.db = pParse->db;
x.pRef = pSrcList;
assert( pExpr->op==TK_AGG_FUNCTION );
assert( ExprUseXList(pExpr) );
sqlite3WalkExprList(&w, pExpr->x.pList);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(pExpr, EP_WinFunc) ){
sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
}
#endif
| > | | 111137 111138 111139 111140 111141 111142 111143 111144 111145 111146 111147 111148 111149 111150 111151 111152 111153 111154 111155 111156 111157 111158 111159 111160 111161 111162 111163 111164 111165 111166 111167 111168 |
**
** As currently used, pExpr is always an aggregate function call. That
** fact is exploited for efficiency.
*/
SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){
Walker w;
struct RefSrcList x;
assert( pParse->db!=0 );
memset(&w, 0, sizeof(w));
memset(&x, 0, sizeof(x));
w.xExprCallback = exprRefToSrcList;
w.xSelectCallback = selectRefEnter;
w.xSelectCallback2 = selectRefLeave;
w.u.pRefSrcList = &x;
x.db = pParse->db;
x.pRef = pSrcList;
assert( pExpr->op==TK_AGG_FUNCTION );
assert( ExprUseXList(pExpr) );
sqlite3WalkExprList(&w, pExpr->x.pList);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(pExpr, EP_WinFunc) ){
sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
}
#endif
if( x.aiExclude ) sqlite3DbNNFreeNN(pParse->db, x.aiExclude);
if( w.eCode & 0x01 ){
return 1;
}else if( w.eCode ){
return 0;
}else{
return -1;
}
|
| ︙ | ︙ | |||
109689 109690 109691 109692 109693 109694 109695 |
if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
&& pExpr->pAggInfo!=0
){
AggInfo *pAggInfo = pExpr->pAggInfo;
int iAgg = pExpr->iAgg;
Parse *pParse = pWalker->pParse;
sqlite3 *db = pParse->db;
| > | < > | 111185 111186 111187 111188 111189 111190 111191 111192 111193 111194 111195 111196 111197 111198 111199 111200 111201 111202 111203 111204 111205 111206 111207 111208 111209 111210 |
if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
&& pExpr->pAggInfo!=0
){
AggInfo *pAggInfo = pExpr->pAggInfo;
int iAgg = pExpr->iAgg;
Parse *pParse = pWalker->pParse;
sqlite3 *db = pParse->db;
if( pExpr->op!=TK_AGG_FUNCTION ){
assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_IF_NULL_ROW );
assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
if( pExpr ){
pAggInfo->aCol[iAgg].pCExpr = pExpr;
sqlite3ExprDeferredDelete(pParse, pExpr);
}
}
}else{
assert( pExpr->op==TK_AGG_FUNCTION );
assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
if( pExpr ){
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
sqlite3ExprDeferredDelete(pParse, pExpr);
}
|
| ︙ | ︙ | |||
109770 109771 109772 109773 109774 109775 109776 109777 109778 109779 109780 109781 109782 109783 109784 109785 109786 109787 109788 109789 109790 109791 109792 109793 109794 109795 109796 109797 |
NameContext *pNC = pWalker->u.pNC;
Parse *pParse = pNC->pParse;
SrcList *pSrcList = pNC->pSrcList;
AggInfo *pAggInfo = pNC->uNC.pAggInfo;
assert( pNC->ncFlags & NC_UAggInfo );
switch( pExpr->op ){
case TK_AGG_COLUMN:
case TK_COLUMN: {
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_COLUMN );
/* Check to see if the column is in one of the tables in the FROM
** clause of the aggregate query */
if( ALWAYS(pSrcList!=0) ){
SrcItem *pItem = pSrcList->a;
for(i=0; i<pSrcList->nSrc; i++, pItem++){
struct AggInfo_col *pCol;
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
if( pExpr->iTable==pItem->iCursor ){
/* If we reach this point, it means that pExpr refers to a table
** that is in the FROM clause of the aggregate query.
**
** Make an entry for the column in pAggInfo->aCol[] if there
** is not an entry there already.
*/
int k;
pCol = pAggInfo->aCol;
for(k=0; k<pAggInfo->nColumn; k++, pCol++){
| > > | | > > | | > | > > | > | 111267 111268 111269 111270 111271 111272 111273 111274 111275 111276 111277 111278 111279 111280 111281 111282 111283 111284 111285 111286 111287 111288 111289 111290 111291 111292 111293 111294 111295 111296 111297 111298 111299 111300 111301 111302 111303 111304 111305 111306 111307 111308 111309 111310 111311 111312 111313 111314 111315 111316 111317 111318 111319 111320 111321 111322 111323 111324 111325 111326 111327 111328 111329 111330 111331 111332 111333 111334 111335 111336 111337 111338 111339 111340 111341 111342 111343 111344 111345 111346 111347 111348 111349 111350 111351 |
NameContext *pNC = pWalker->u.pNC;
Parse *pParse = pNC->pParse;
SrcList *pSrcList = pNC->pSrcList;
AggInfo *pAggInfo = pNC->uNC.pAggInfo;
assert( pNC->ncFlags & NC_UAggInfo );
switch( pExpr->op ){
case TK_IF_NULL_ROW:
case TK_AGG_COLUMN:
case TK_COLUMN: {
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_COLUMN );
testcase( pExpr->op==TK_IF_NULL_ROW );
/* Check to see if the column is in one of the tables in the FROM
** clause of the aggregate query */
if( ALWAYS(pSrcList!=0) ){
SrcItem *pItem = pSrcList->a;
for(i=0; i<pSrcList->nSrc; i++, pItem++){
struct AggInfo_col *pCol;
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
if( pExpr->iTable==pItem->iCursor ){
/* If we reach this point, it means that pExpr refers to a table
** that is in the FROM clause of the aggregate query.
**
** Make an entry for the column in pAggInfo->aCol[] if there
** is not an entry there already.
*/
int k;
pCol = pAggInfo->aCol;
for(k=0; k<pAggInfo->nColumn; k++, pCol++){
if( pCol->iTable==pExpr->iTable
&& pCol->iColumn==pExpr->iColumn
&& pExpr->op!=TK_IF_NULL_ROW
){
break;
}
}
if( (k>=pAggInfo->nColumn)
&& (k = addAggInfoColumn(pParse->db, pAggInfo))>=0
){
pCol = &pAggInfo->aCol[k];
assert( ExprUseYTab(pExpr) );
pCol->pTab = pExpr->y.pTab;
pCol->iTable = pExpr->iTable;
pCol->iColumn = pExpr->iColumn;
pCol->iMem = ++pParse->nMem;
pCol->iSorterColumn = -1;
pCol->pCExpr = pExpr;
if( pAggInfo->pGroupBy && pExpr->op!=TK_IF_NULL_ROW ){
int j, n;
ExprList *pGB = pAggInfo->pGroupBy;
struct ExprList_item *pTerm = pGB->a;
n = pGB->nExpr;
for(j=0; j<n; j++, pTerm++){
Expr *pE = pTerm->pExpr;
if( pE->op==TK_COLUMN
&& pE->iTable==pExpr->iTable
&& pE->iColumn==pExpr->iColumn
){
pCol->iSorterColumn = j;
break;
}
}
}
if( pCol->iSorterColumn<0 ){
pCol->iSorterColumn = pAggInfo->nSortingColumn++;
}
}
/* There is now an entry for pExpr in pAggInfo->aCol[] (either
** because it was there before or because we just created it).
** Convert the pExpr to be a TK_AGG_COLUMN referring to that
** pAggInfo->aCol[] entry.
*/
ExprSetVVAProperty(pExpr, EP_NoReduce);
pExpr->pAggInfo = pAggInfo;
if( pExpr->op==TK_COLUMN ){
pExpr->op = TK_AGG_COLUMN;
}
pExpr->iAgg = (i16)k;
break;
} /* endif pExpr->iTable==pItem->iCursor */
} /* end loop over pSrcList */
}
return WRC_Prune;
}
|
| ︙ | ︙ | |||
113252 113253 113254 113255 113256 113257 113258 113259 113260 113261 113262 113263 113264 113265 |
){
int i; /* Index of column in the table */
assert( k>=0 && k<pIdx->nColumn );
i = pIdx->aiColumn[k];
if( NEVER(i==XN_ROWID) ){
VdbeComment((v,"%s.rowid",pIdx->zName));
}else if( i==XN_EXPR ){
VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
}else{
VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName));
}
}
#else
# define analyzeVdbeCommentIndexWithColumnName(a,b,c)
| > | 114757 114758 114759 114760 114761 114762 114763 114764 114765 114766 114767 114768 114769 114770 114771 |
){
int i; /* Index of column in the table */
assert( k>=0 && k<pIdx->nColumn );
i = pIdx->aiColumn[k];
if( NEVER(i==XN_ROWID) ){
VdbeComment((v,"%s.rowid",pIdx->zName));
}else if( i==XN_EXPR ){
assert( pIdx->bHasExpr );
VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
}else{
VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName));
}
}
#else
# define analyzeVdbeCommentIndexWithColumnName(a,b,c)
|
| ︙ | ︙ | |||
115254 115255 115256 115257 115258 115259 115260 115261 115262 115263 115264 115265 115266 115267 |
**
** Note that if an error occurred, it might be the case that
** no VDBE code was generated.
*/
SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
sqlite3 *db;
Vdbe *v;
assert( pParse->pToplevel==0 );
db = pParse->db;
assert( db->pParse==pParse );
if( pParse->nested ) return;
if( pParse->nErr ){
if( db->mallocFailed ) pParse->rc = SQLITE_NOMEM;
| > | 116760 116761 116762 116763 116764 116765 116766 116767 116768 116769 116770 116771 116772 116773 116774 |
**
** Note that if an error occurred, it might be the case that
** no VDBE code was generated.
*/
SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
sqlite3 *db;
Vdbe *v;
int iDb, i;
assert( pParse->pToplevel==0 );
db = pParse->db;
assert( db->pParse==pParse );
if( pParse->nested ) return;
if( pParse->nErr ){
if( db->mallocFailed ) pParse->rc = SQLITE_NOMEM;
|
| ︙ | ︙ | |||
115283 115284 115285 115286 115287 115288 115289 |
}
assert( !pParse->isMultiWrite
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
if( v ){
if( pParse->bReturning ){
Returning *pReturning = pParse->u1.pReturning;
int addrRewind;
| < | 116790 116791 116792 116793 116794 116795 116796 116797 116798 116799 116800 116801 116802 116803 |
}
assert( !pParse->isMultiWrite
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
if( v ){
if( pParse->bReturning ){
Returning *pReturning = pParse->u1.pReturning;
int addrRewind;
int reg;
if( pReturning->nRetCol ){
sqlite3VdbeAddOp0(v, OP_FkCheck);
addrRewind =
sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur);
VdbeCoverage(v);
|
| ︙ | ︙ | |||
115320 115321 115322 115323 115324 115325 115326 |
/* The cookie mask contains one bit for each database file open.
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
** set for each database that is used. Generate code to start a
** transaction on each used database and to verify the schema cookie
** on each used database.
*/
| < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | < | | | | | | | | < | 116826 116827 116828 116829 116830 116831 116832 116833 116834 116835 116836 116837 116838 116839 116840 116841 116842 116843 116844 116845 116846 116847 116848 116849 116850 116851 116852 116853 116854 116855 116856 116857 116858 116859 116860 116861 116862 116863 116864 116865 116866 116867 116868 116869 116870 116871 116872 116873 116874 116875 116876 116877 116878 116879 116880 116881 116882 116883 116884 116885 116886 116887 116888 116889 116890 116891 116892 116893 116894 116895 116896 116897 116898 116899 116900 116901 116902 |
/* The cookie mask contains one bit for each database file open.
** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are
** set for each database that is used. Generate code to start a
** transaction on each used database and to verify the schema cookie
** on each used database.
*/
assert( pParse->nErr>0 || sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
sqlite3VdbeJumpHere(v, 0);
assert( db->nDb>0 );
iDb = 0;
do{
Schema *pSchema;
if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
sqlite3VdbeUsesBtree(v, iDb);
pSchema = db->aDb[iDb].pSchema;
sqlite3VdbeAddOp4Int(v,
OP_Transaction, /* Opcode */
iDb, /* P1 */
DbMaskTest(pParse->writeMask,iDb), /* P2 */
pSchema->schema_cookie, /* P3 */
pSchema->iGeneration /* P4 */
);
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
VdbeComment((v,
"usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
}while( ++iDb<db->nDb );
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=0; i<pParse->nVtabLock; i++){
char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
}
pParse->nVtabLock = 0;
#endif
/* Once all the cookies have been verified and transactions opened,
** obtain the required table-locks. This is a no-op unless the
** shared-cache feature is enabled.
*/
codeTableLocks(pParse);
/* Initialize any AUTOINCREMENT data structures required.
*/
sqlite3AutoincrementBegin(pParse);
/* Code constant expressions that where factored out of inner loops.
**
** The pConstExpr list might also contain expressions that we simply
** want to keep around until the Parse object is deleted. Such
** expressions have iConstExprReg==0. Do not generate code for
** those expressions, of course.
*/
if( pParse->pConstExpr ){
ExprList *pEL = pParse->pConstExpr;
pParse->okConstFactor = 0;
for(i=0; i<pEL->nExpr; i++){
int iReg = pEL->a[i].u.iConstExprReg;
sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
}
}
if( pParse->bReturning ){
Returning *pRet = pParse->u1.pReturning;
if( pRet->nRetCol ){
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
}
}
/* Finally, jump back to the beginning of the executable code. */
sqlite3VdbeGoto(v, 1);
}
/* Get the VDBE program ready for execution
*/
assert( v!=0 || pParse->nErr );
assert( db->mallocFailed==0 || pParse->nErr );
if( pParse->nErr==0 ){
|
| ︙ | ︙ | |||
115574 115575 115576 115577 115578 115579 115580 |
p = sqlite3FindTable(db, zName, zDbase);
if( p==0 ){
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* If zName is the not the name of a table in the schema created using
** CREATE, then check to see if it is the name of an virtual table that
** can be an eponymous virtual table. */
| | | | 117073 117074 117075 117076 117077 117078 117079 117080 117081 117082 117083 117084 117085 117086 117087 117088 117089 117090 117091 117092 117093 117094 117095 117096 117097 117098 117099 117100 |
p = sqlite3FindTable(db, zName, zDbase);
if( p==0 ){
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* If zName is the not the name of a table in the schema created using
** CREATE, then check to see if it is the name of an virtual table that
** can be an eponymous virtual table. */
if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){
Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
pMod = sqlite3PragmaVtabRegister(db, zName);
}
if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
testcase( pMod->pEpoTab==0 );
return pMod->pEpoTab;
}
}
#endif
if( flags & LOCATE_NOERR ) return 0;
pParse->checkSchema = 1;
}else if( IsVirtual(p) && (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)!=0 ){
p = 0;
}
if( p==0 ){
const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
if( zDbase ){
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
|
| ︙ | ︙ | |||
115896 115897 115898 115899 115900 115901 115902 115903 115904 115905 115906 115907 |
** Delete memory allocated for the column names of a table or view (the
** Table.aCol[] array).
*/
SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
int i;
Column *pCol;
assert( pTable!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) );
sqlite3DbFree(db, pCol->zCnName);
}
| > | | | 117395 117396 117397 117398 117399 117400 117401 117402 117403 117404 117405 117406 117407 117408 117409 117410 117411 117412 117413 117414 117415 117416 117417 117418 117419 |
** Delete memory allocated for the column names of a table or view (the
** Table.aCol[] array).
*/
SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
int i;
Column *pCol;
assert( pTable!=0 );
assert( db!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) );
sqlite3DbFree(db, pCol->zCnName);
}
sqlite3DbNNFreeNN(db, pTable->aCol);
if( IsOrdinaryTable(pTable) ){
sqlite3ExprListDelete(db, pTable->u.tab.pDfltList);
}
if( db->pnBytesFreed==0 ){
pTable->aCol = 0;
pTable->nCol = 0;
if( IsOrdinaryTable(pTable) ){
pTable->u.tab.pDfltList = 0;
}
}
}
|
| ︙ | ︙ | |||
115942 115943 115944 115945 115946 115947 115948 | ** prior to doing any free() operations. Since schema Tables do not use ** lookaside, this number should not change. ** ** If malloc has already failed, it may be that it failed while allocating ** a Table object that was going to be marked ephemeral. So do not check ** that no lookaside memory is used in this case either. */ int nLookaside = 0; | > | | | 117442 117443 117444 117445 117446 117447 117448 117449 117450 117451 117452 117453 117454 117455 117456 117457 117458 117459 117460 117461 117462 117463 117464 117465 117466 117467 |
** prior to doing any free() operations. Since schema Tables do not use
** lookaside, this number should not change.
**
** If malloc has already failed, it may be that it failed while allocating
** a Table object that was going to be marked ephemeral. So do not check
** that no lookaside memory is used in this case either. */
int nLookaside = 0;
assert( db!=0 );
if( !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
nLookaside = sqlite3LookasideUsed(db, 0);
}
#endif
/* Delete all indices associated with this table. */
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
assert( pIndex->pSchema==pTable->pSchema
|| (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
if( db->pnBytesFreed==0 && !IsVirtual(pTable) ){
char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, 0
);
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
assert( pOld==pIndex || pOld==0 );
}
|
| ︙ | ︙ | |||
115989 115990 115991 115992 115993 115994 115995 115996 |
sqlite3DbFree(db, pTable);
/* Verify that no lookaside memory was used by schema tables */
assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) );
}
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Do not delete the table until the reference count reaches zero. */
if( !pTable ) return;
| > | | 117490 117491 117492 117493 117494 117495 117496 117497 117498 117499 117500 117501 117502 117503 117504 117505 117506 |
sqlite3DbFree(db, pTable);
/* Verify that no lookaside memory was used by schema tables */
assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) );
}
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Do not delete the table until the reference count reaches zero. */
assert( db!=0 );
if( !pTable ) return;
if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return;
deleteTable(db, pTable);
}
/*
** Unlink the given table from the hash tables and the delete the
** table structure with all its indices and foreign keys.
|
| ︙ | ︙ | |||
117394 117395 117396 117397 117398 117399 117400 | } return 0; } /* Recompute the colNotIdxed field of the Index. ** ** colNotIdxed is a bitmask that has a 0 bit representing each indexed | | > | 118896 118897 118898 118899 118900 118901 118902 118903 118904 118905 118906 118907 118908 118909 118910 118911 | } return 0; } /* Recompute the colNotIdxed field of the Index. ** ** colNotIdxed is a bitmask that has a 0 bit representing each indexed ** columns that are within the first 63 columns of the table and a 1 for ** all other bits (all columns that are not in the index). The ** high-order bit of colNotIdxed is always 1. All unindexed columns ** of the table have a 1. ** ** 2019-10-24: For the purpose of this computation, virtual columns are ** not considered to be covered by the index, even if they are in the ** index, because we do not trust the logic in whereIndexExprTrans() to be ** able to find all instances of a reference to the indexed table column |
| ︙ | ︙ | |||
117422 117423 117424 117425 117426 117427 117428 |
if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){
testcase( x==BMS-1 );
testcase( x==BMS-2 );
if( x<BMS-1 ) m |= MASKBIT(x);
}
}
pIdx->colNotIdxed = ~m;
| | | 118925 118926 118927 118928 118929 118930 118931 118932 118933 118934 118935 118936 118937 118938 118939 |
if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){
testcase( x==BMS-1 );
testcase( x==BMS-2 );
if( x<BMS-1 ) m |= MASKBIT(x);
}
}
pIdx->colNotIdxed = ~m;
assert( (pIdx->colNotIdxed>>63)==1 ); /* See note-20221022-a */
}
/*
** This routine runs at the end of parsing a CREATE TABLE statement that
** has a WITHOUT ROWID clause. The job of this routine is to convert both
** internal schema data structures and the generated VDBE code so that they
** are appropriate for a WITHOUT ROWID table instead of a rowid table.
|
| ︙ | ︙ | |||
118163 118164 118165 118166 118167 118168 118169 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) /* ** The Table structure pTable is really a VIEW. Fill in the names of ** the columns of the view in the pTable structure. Return the number ** of errors. If an error is seen leave an error message in pParse->zErrMsg. */ | | | 119666 119667 119668 119669 119670 119671 119672 119673 119674 119675 119676 119677 119678 119679 119680 |
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** The Table structure pTable is really a VIEW. Fill in the names of
** the columns of the view in the pTable structure. Return the number
** of errors. If an error is seen leave an error message in pParse->zErrMsg.
*/
static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
Table *pSelTab; /* A fake table from which we get the result set */
Select *pSel; /* Copy of the SELECT that implements the view */
int nErr = 0; /* Number of errors encountered */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
#ifndef SQLITE_OMIT_VIRTUALTABLE
int rc;
#endif
|
| ︙ | ︙ | |||
118188 118189 118190 118191 118192 118193 118194 |
db->nSchemaLock--;
return rc;
}
#endif
#ifndef SQLITE_OMIT_VIEW
/* A positive nCol means the columns names for this view are
| | > | | 119691 119692 119693 119694 119695 119696 119697 119698 119699 119700 119701 119702 119703 119704 119705 119706 119707 119708 |
db->nSchemaLock--;
return rc;
}
#endif
#ifndef SQLITE_OMIT_VIEW
/* A positive nCol means the columns names for this view are
** already known. This routine is not called unless either the
** table is virtual or nCol is zero.
*/
assert( pTable->nCol<=0 );
/* A negative nCol is a special marker meaning that we are currently
** trying to compute the column names. If we enter this routine with
** a negative nCol, it means two or more views form a loop, like this:
**
** CREATE VIEW one AS SELECT * FROM two;
** CREATE VIEW two AS SELECT * FROM one;
|
| ︙ | ︙ | |||
118285 118286 118287 118288 118289 118290 118291 118292 118293 118294 118295 118296 118297 118298 |
}
pTable->pSchema->schemaFlags |= DB_UnresetViews;
if( db->mallocFailed ){
sqlite3DeleteColumnNames(db, pTable);
}
#endif /* SQLITE_OMIT_VIEW */
return nErr;
}
#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifndef SQLITE_OMIT_VIEW
/*
** Clear the column names from every VIEW in database idx.
*/
| > > > > > | 119789 119790 119791 119792 119793 119794 119795 119796 119797 119798 119799 119800 119801 119802 119803 119804 119805 119806 119807 |
}
pTable->pSchema->schemaFlags |= DB_UnresetViews;
if( db->mallocFailed ){
sqlite3DeleteColumnNames(db, pTable);
}
#endif /* SQLITE_OMIT_VIEW */
return nErr;
}
SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable!=0 );
if( !IsVirtual(pTable) && pTable->nCol>0 ) return 0;
return viewGetColumnNames(pParse, pTable);
}
#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifndef SQLITE_OMIT_VIEW
/*
** Clear the column names from every VIEW in database idx.
*/
|
| ︙ | ︙ | |||
119151 119152 119153 119154 119155 119156 119157 |
if( zName==0 ) goto exit_create_index;
assert( pName->z!=0 );
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName,"index",pTab->zName) ){
goto exit_create_index;
}
if( !IN_RENAME_OBJECT ){
if( !db->init.busy ){
| | | 120660 120661 120662 120663 120664 120665 120666 120667 120668 120669 120670 120671 120672 120673 120674 |
if( zName==0 ) goto exit_create_index;
assert( pName->z!=0 );
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName,"index",pTab->zName) ){
goto exit_create_index;
}
if( !IN_RENAME_OBJECT ){
if( !db->init.busy ){
if( sqlite3FindTable(db, zName, pDb->zDbSName)!=0 ){
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
goto exit_create_index;
}
}
if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){
if( !ifNotExist ){
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
| ︙ | ︙ | |||
119304 119305 119306 119307 119308 119309 119310 119311 119312 119313 119314 119315 119316 119317 119318 119319 119320 119321 119322 119323 119324 119325 119326 119327 119328 |
if( pIndex->aColExpr==0 ){
pIndex->aColExpr = pList;
pList = 0;
}
j = XN_EXPR;
pIndex->aiColumn[i] = XN_EXPR;
pIndex->uniqNotNull = 0;
}else{
j = pCExpr->iColumn;
assert( j<=0x7fff );
if( j<0 ){
j = pTab->iPKey;
}else{
if( pTab->aCol[j].notNull==0 ){
pIndex->uniqNotNull = 0;
}
if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
pIndex->bHasVCol = 1;
}
}
pIndex->aiColumn[i] = (i16)j;
}
zColl = 0;
if( pListItem->pExpr->op==TK_COLLATE ){
int nColl;
| > > | 120813 120814 120815 120816 120817 120818 120819 120820 120821 120822 120823 120824 120825 120826 120827 120828 120829 120830 120831 120832 120833 120834 120835 120836 120837 120838 120839 |
if( pIndex->aColExpr==0 ){
pIndex->aColExpr = pList;
pList = 0;
}
j = XN_EXPR;
pIndex->aiColumn[i] = XN_EXPR;
pIndex->uniqNotNull = 0;
pIndex->bHasExpr = 1;
}else{
j = pCExpr->iColumn;
assert( j<=0x7fff );
if( j<0 ){
j = pTab->iPKey;
}else{
if( pTab->aCol[j].notNull==0 ){
pIndex->uniqNotNull = 0;
}
if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
pIndex->bHasVCol = 1;
pIndex->bHasExpr = 1;
}
}
pIndex->aiColumn[i] = (i16)j;
}
zColl = 0;
if( pListItem->pExpr->op==TK_COLLATE ){
int nColl;
|
| ︙ | ︙ | |||
119804 119805 119806 119807 119808 119809 119810 119811 119812 119813 119814 119815 |
}
/*
** Delete an IdList.
*/
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
int i;
if( pList==0 ) return;
assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
for(i=0; i<pList->nId; i++){
sqlite3DbFree(db, pList->a[i].zName);
}
| > | | 121315 121316 121317 121318 121319 121320 121321 121322 121323 121324 121325 121326 121327 121328 121329 121330 121331 121332 121333 121334 121335 |
}
/*
** Delete an IdList.
*/
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
int i;
assert( db!=0 );
if( pList==0 ) return;
assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
for(i=0; i<pList->nId; i++){
sqlite3DbFree(db, pList->a[i].zName);
}
sqlite3DbNNFreeNN(db, pList);
}
/*
** Return the index in pList of the identifier named zId. Return -1
** if not found.
*/
SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){
|
| ︙ | ︙ | |||
120012 120013 120014 120015 120016 120017 120018 120019 120020 |
/*
** Delete an entire SrcList including all its substructure.
*/
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
int i;
SrcItem *pItem;
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
| > | | | | | 121524 121525 121526 121527 121528 121529 121530 121531 121532 121533 121534 121535 121536 121537 121538 121539 121540 121541 121542 121543 121544 121545 121546 121547 121548 121549 121550 121551 121552 121553 121554 |
/*
** Delete an entire SrcList including all its substructure.
*/
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
int i;
SrcItem *pItem;
assert( db!=0 );
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
sqlite3DeleteTable(db, pItem->pTab);
if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
if( pItem->fg.isUsing ){
sqlite3IdListDelete(db, pItem->u3.pUsing);
}else if( pItem->u3.pOn ){
sqlite3ExprDelete(db, pItem->u3.pOn);
}
}
sqlite3DbNNFreeNN(db, pList);
}
/*
** This routine is called by the parser to add a new term to the
** end of a growing FROM clause. The "p" parameter is the part of
** the FROM clause that has already been constructed. "p" is NULL
** if this is the first term of the FROM clause. pTable and pDatabase
|
| ︙ | ︙ | |||
121279 121280 121281 121282 121283 121284 121285 121286 121287 121288 121289 121290 121291 |
** The Schema.cache_size variable is not cleared.
*/
SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
Hash temp1;
Hash temp2;
HashElem *pElem;
Schema *pSchema = (Schema *)p;
temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash);
sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
| > > | | | 122792 122793 122794 122795 122796 122797 122798 122799 122800 122801 122802 122803 122804 122805 122806 122807 122808 122809 122810 122811 122812 122813 122814 122815 122816 122817 122818 122819 122820 |
** The Schema.cache_size variable is not cleared.
*/
SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
Hash temp1;
Hash temp2;
HashElem *pElem;
Schema *pSchema = (Schema *)p;
sqlite3 xdb;
memset(&xdb, 0, sizeof(xdb));
temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash);
sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
}
sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
sqlite3DeleteTable(&xdb, pTab);
}
sqlite3HashClear(&temp1);
sqlite3HashClear(&pSchema->fkeyHash);
pSchema->pSeqTab = 0;
if( pSchema->schemaFlags & DB_SchemaLoaded ){
pSchema->iGeneration++;
}
|
| ︙ | ︙ | |||
121390 121391 121392 121393 121394 121395 121396 | /* Return true if table pTab is read-only. ** ** A table is read-only if any of the following are true: ** ** 1) It is a virtual table and no implementation of the xUpdate method ** has been provided ** | > > > > | | > > > > > > > > > > > > > > > > > > > > | | > | > | | 122905 122906 122907 122908 122909 122910 122911 122912 122913 122914 122915 122916 122917 122918 122919 122920 122921 122922 122923 122924 122925 122926 122927 122928 122929 122930 122931 122932 122933 122934 122935 122936 122937 122938 122939 122940 122941 122942 122943 122944 122945 122946 122947 122948 122949 122950 122951 122952 122953 122954 122955 122956 122957 122958 122959 122960 122961 122962 122963 122964 122965 122966 122967 122968 122969 122970 |
/* Return true if table pTab is read-only.
**
** A table is read-only if any of the following are true:
**
** 1) It is a virtual table and no implementation of the xUpdate method
** has been provided
**
** 2) A trigger is currently being coded and the table is a virtual table
** that is SQLITE_VTAB_DIRECTONLY or if PRAGMA trusted_schema=OFF and
** the table is not SQLITE_VTAB_INNOCUOUS.
**
** 3) It is a system table (i.e. sqlite_schema), this call is not
** part of a nested parse and writable_schema pragma has not
** been specified
**
** 4) The table is a shadow table, the database connection is in
** defensive mode, and the current sqlite3_prepare()
** is for a top-level SQL statement.
*/
static int vtabIsReadOnly(Parse *pParse, Table *pTab){
if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
return 1;
}
/* Within triggers:
** * Do not allow DELETE, INSERT, or UPDATE of SQLITE_VTAB_DIRECTONLY
** virtual tables
** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS
** virtual tables if PRAGMA trusted_schema=ON.
*/
if( pParse->pToplevel!=0
&& pTab->u.vtab.p->eVtabRisk >
((pParse->db->flags & SQLITE_TrustedSchema)!=0)
){
sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
pTab->zName);
}
return 0;
}
static int tabIsReadOnly(Parse *pParse, Table *pTab){
sqlite3 *db;
if( IsVirtual(pTab) ){
return vtabIsReadOnly(pParse, pTab);
}
if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0;
db = pParse->db;
if( (pTab->tabFlags & TF_Readonly)!=0 ){
return sqlite3WritableSchema(db)==0 && pParse->nested==0;
}
assert( pTab->tabFlags & TF_Shadow );
return sqlite3ReadOnlyShadowTables(db);
}
/*
** Check to make sure the given table is writable.
**
** If pTab is not writable -> generate an error message and return 1.
** If pTab is writable but other errors have occurred -> return 1.
** If pTab is writable and no prior errors -> return 0;
*/
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( tabIsReadOnly(pParse, pTab) ){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
#ifndef SQLITE_OMIT_VIEW
|
| ︙ | ︙ | |||
121776 121777 121778 121779 121780 121781 121782 |
sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
if( HasRowid(pTab) ){
sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1,
pTab->zName, P4_STATIC);
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->pSchema==pTab->pSchema );
| < | > > | 123317 123318 123319 123320 123321 123322 123323 123324 123325 123326 123327 123328 123329 123330 123331 123332 123333 123334 |
sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
if( HasRowid(pTab) ){
sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1,
pTab->zName, P4_STATIC);
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->pSchema==pTab->pSchema );
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
sqlite3VdbeAddOp3(v, OP_Clear, pIdx->tnum, iDb, memCnt ? memCnt : -1);
}else{
sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
}
}
}else
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
{
u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
|
| ︙ | ︙ | |||
121978 121979 121980 121981 121982 121983 121984 | sqlite3AuthContextPop(&sContext); sqlite3SrcListDelete(db, pTabList); sqlite3ExprDelete(db, pWhere); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) sqlite3ExprListDelete(db, pOrderBy); sqlite3ExprDelete(db, pLimit); #endif | | | 123520 123521 123522 123523 123524 123525 123526 123527 123528 123529 123530 123531 123532 123533 123534 | sqlite3AuthContextPop(&sContext); sqlite3SrcListDelete(db, pTabList); sqlite3ExprDelete(db, pWhere); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) sqlite3ExprListDelete(db, pOrderBy); sqlite3ExprDelete(db, pLimit); #endif if( aToOpen ) sqlite3DbNNFreeNN(db, aToOpen); return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView |
| ︙ | ︙ | |||
123061 123062 123063 123064 123065 123066 123067 |
** first matching character and recursively continue the match from
** that point.
**
** For a case-insensitive search, set variable cx to be the same as
** c but in the other case and search the input string for either
** c or cx.
*/
| | | 124603 124604 124605 124606 124607 124608 124609 124610 124611 124612 124613 124614 124615 124616 124617 |
** first matching character and recursively continue the match from
** that point.
**
** For a case-insensitive search, set variable cx to be the same as
** c but in the other case and search the input string for either
** c or cx.
*/
if( c<0x80 ){
char zStop[3];
int bMatch;
if( noCase ){
zStop[0] = sqlite3Toupper(c);
zStop[1] = sqlite3Tolower(c);
zStop[2] = 0;
}else{
|
| ︙ | ︙ | |||
123144 123145 123146 123147 123148 123149 123150 |
}
/*
** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and
** non-zero if there is no match.
*/
SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
| > > > > > | > > > > > > | > | 124686 124687 124688 124689 124690 124691 124692 124693 124694 124695 124696 124697 124698 124699 124700 124701 124702 124703 124704 124705 124706 124707 124708 124709 124710 124711 124712 124713 124714 124715 124716 124717 124718 124719 124720 |
}
/*
** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and
** non-zero if there is no match.
*/
SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
if( zString==0 ){
return zGlobPattern!=0;
}else if( zGlobPattern==0 ){
return 1;
}else {
return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
}
}
/*
** The sqlite3_strlike() interface. Return 0 on a match and non-zero for
** a miss - like strcmp().
*/
SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
if( zStr==0 ){
return zPattern!=0;
}else if( zPattern==0 ){
return 1;
}else{
return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
}
}
/*
** Count the number of times that the LIKE operator (or GLOB which is
** just a variation of LIKE) gets called. This is used for testing
** only.
*/
|
| ︙ | ︙ | |||
126146 126147 126148 126149 126150 126151 126152 126153 126154 126155 126156 |
** hash table.
*/
SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
FKey *pFKey; /* Iterator variable */
FKey *pNext; /* Copy of pFKey->pNextFrom */
assert( IsOrdinaryTable(pTab) );
for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
/* Remove the FK from the fkeyHash hash table. */
| > | | 127700 127701 127702 127703 127704 127705 127706 127707 127708 127709 127710 127711 127712 127713 127714 127715 127716 127717 127718 127719 |
** hash table.
*/
SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
FKey *pFKey; /* Iterator variable */
FKey *pNext; /* Copy of pFKey->pNextFrom */
assert( IsOrdinaryTable(pTab) );
assert( db!=0 );
for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
/* Remove the FK from the fkeyHash hash table. */
if( db->pnBytesFreed==0 ){
if( pFKey->pPrevTo ){
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
}else{
void *p = (void *)pFKey->pNextTo;
const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p);
}
|
| ︙ | ︙ | |||
126280 126281 126282 126283 126284 126285 126286 126287 126288 126289 126290 126291 126292 126293 |
char aff;
if( x>=0 ){
aff = pTab->aCol[x].affinity;
}else if( x==XN_ROWID ){
aff = SQLITE_AFF_INTEGER;
}else{
assert( x==XN_EXPR );
assert( pIdx->aColExpr!=0 );
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
}
if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
pIdx->zColAff[n] = aff;
}
| > | 127835 127836 127837 127838 127839 127840 127841 127842 127843 127844 127845 127846 127847 127848 127849 |
char aff;
if( x>=0 ){
aff = pTab->aCol[x].affinity;
}else if( x==XN_ROWID ){
aff = SQLITE_AFF_INTEGER;
}else{
assert( x==XN_EXPR );
assert( pIdx->bHasExpr );
assert( pIdx->aColExpr!=0 );
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
}
if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
pIdx->zColAff[n] = aff;
}
|
| ︙ | ︙ | |||
126343 126344 126345 126346 126347 126348 126349 |
if( pTab->tabFlags & TF_Strict ){
if( iReg==0 ){
/* Move the previous opcode (which should be OP_MakeRecord) forward
** by one slot and insert a new OP_TypeCheck where the current
** OP_MakeRecord is found */
VdbeOp *pPrev;
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
| | | 127899 127900 127901 127902 127903 127904 127905 127906 127907 127908 127909 127910 127911 127912 127913 |
if( pTab->tabFlags & TF_Strict ){
if( iReg==0 ){
/* Move the previous opcode (which should be OP_MakeRecord) forward
** by one slot and insert a new OP_TypeCheck where the current
** OP_MakeRecord is found */
VdbeOp *pPrev;
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
pPrev = sqlite3VdbeGetLastOp(v);
assert( pPrev!=0 );
assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed );
pPrev->opcode = OP_TypeCheck;
sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3);
}else{
/* Insert an isolated OP_Typecheck */
sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol);
|
| ︙ | ︙ | |||
126381 126382 126383 126384 126385 126386 126387 |
}
assert( zColAff!=0 );
i = sqlite3Strlen30NN(zColAff);
if( i ){
if( iReg ){
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
}else{
| | | 127937 127938 127939 127940 127941 127942 127943 127944 127945 127946 127947 127948 127949 127950 127951 |
}
assert( zColAff!=0 );
i = sqlite3Strlen30NN(zColAff);
if( i ){
if( iReg ){
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
}else{
assert( sqlite3VdbeGetLastOp(v)->opcode==OP_MakeRecord
|| sqlite3VdbeDb(v)->mallocFailed );
sqlite3VdbeChangeP4(v, -1, zColAff, i);
}
}
}
/*
|
| ︙ | ︙ | |||
126467 126468 126469 126470 126471 126472 126473 |
testcase( pTab->tabFlags & TF_HasStored );
/* Before computing generated columns, first go through and make sure
** that appropriate affinity has been applied to the regular columns
*/
sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
if( (pTab->tabFlags & TF_HasStored)!=0 ){
| | | 128023 128024 128025 128026 128027 128028 128029 128030 128031 128032 128033 128034 128035 128036 128037 |
testcase( pTab->tabFlags & TF_HasStored );
/* Before computing generated columns, first go through and make sure
** that appropriate affinity has been applied to the regular columns
*/
sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
if( (pTab->tabFlags & TF_HasStored)!=0 ){
pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Affinity ){
/* Change the OP_Affinity argument to '@' (NONE) for all stored
** columns. '@' is the no-op affinity and those columns have not
** yet been computed. */
int ii, jj;
char *zP4 = pOp->p4.z;
assert( zP4!=0 );
|
| ︙ | ︙ | |||
127373 127374 127375 127376 127377 127378 127379 |
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore);
}else if( pSelect ){
if( regFromSelect!=regData ){
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
}
}else{
| | > > > > > | 128929 128930 128931 128932 128933 128934 128935 128936 128937 128938 128939 128940 128941 128942 128943 128944 128945 128946 128947 128948 |
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore);
}else if( pSelect ){
if( regFromSelect!=regData ){
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
}
}else{
Expr *pX = pList->a[k].pExpr;
int y = sqlite3ExprCodeTarget(pParse, pX, iRegStore);
if( y!=iRegStore ){
sqlite3VdbeAddOp2(v,
ExprHasProperty(pX, EP_Subquery) ? OP_Copy : OP_SCopy, y, iRegStore);
}
}
}
/* Run the BEFORE and INSTEAD OF triggers, if there are any
*/
endOfLoop = sqlite3VdbeMakeLabel(pParse);
|
| ︙ | ︙ | |||
127510 127511 127512 127513 127514 127515 127516 |
#endif
{
int isReplace = 0;/* Set to true if constraints may cause a replace */
int bUseSeek; /* True to use OPFLAG_SEEKRESULT */
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
);
| > | > | 129071 129072 129073 129074 129075 129076 129077 129078 129079 129080 129081 129082 129083 129084 129085 129086 129087 |
#endif
{
int isReplace = 0;/* Set to true if constraints may cause a replace */
int bUseSeek; /* True to use OPFLAG_SEEKRESULT */
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
);
if( db->flags & SQLITE_ForeignKeys ){
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
}
/* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
** constraints or (b) there are no triggers and this table is not a
** parent table in a foreign key constraint. It is safe to set the
** flag in the second case as if any REPLACE constraint is hit, an
** OP_Delete or OP_IdxDelete instruction will be executed on each
** cursor that is disturbed. And these instructions both clear the
|
| ︙ | ︙ | |||
127594 127595 127596 127597 127598 127599 127600 | insert_cleanup: sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pList); sqlite3UpsertDelete(db, pUpsert); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); | | | 129157 129158 129159 129160 129161 129162 129163 129164 129165 129166 129167 129168 129169 129170 129171 | insert_cleanup: sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pList); sqlite3UpsertDelete(db, pUpsert); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx); } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView |
| ︙ | ︙ | |||
129847 129848 129849 129850 129851 129852 129853 129854 129855 129856 129857 129858 129859 129860 |
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
/* Version 3.39.0 and later */
int (*deserialize)(sqlite3*,const char*,unsigned char*,
sqlite3_int64,sqlite3_int64,unsigned);
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
| > > | 131410 131411 131412 131413 131414 131415 131416 131417 131418 131419 131420 131421 131422 131423 131424 131425 |
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
/* Version 3.39.0 and later */
int (*deserialize)(sqlite3*,const char*,unsigned char*,
sqlite3_int64,sqlite3_int64,unsigned);
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
/* Version 3.40.0 and later */
int (*value_encoding)(sqlite3_value*);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
|
| ︙ | ︙ | |||
130171 130172 130173 130174 130175 130176 130177 130178 130179 130180 130181 130182 130183 130184 | #define sqlite3_vtab_in_next sqlite3_api->vtab_in_next /* Version 3.39.0 and later */ #ifndef SQLITE_OMIT_DESERIALIZE #define sqlite3_deserialize sqlite3_api->deserialize #define sqlite3_serialize sqlite3_api->serialize #endif #define sqlite3_db_name sqlite3_api->db_name #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; | > > | 131736 131737 131738 131739 131740 131741 131742 131743 131744 131745 131746 131747 131748 131749 131750 131751 | #define sqlite3_vtab_in_next sqlite3_api->vtab_in_next /* Version 3.39.0 and later */ #ifndef SQLITE_OMIT_DESERIALIZE #define sqlite3_deserialize sqlite3_api->deserialize #define sqlite3_serialize sqlite3_api->serialize #endif #define sqlite3_db_name sqlite3_api->db_name /* Version 3.40.0 and later */ #define sqlite3_value_encoding sqlite3_api->value_encoding #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; |
| ︙ | ︙ | |||
130683 130684 130685 130686 130687 130688 130689 | #ifndef SQLITE_OMIT_DESERIALIZE sqlite3_deserialize, sqlite3_serialize, #else 0, 0, #endif | | > > | 132250 132251 132252 132253 132254 132255 132256 132257 132258 132259 132260 132261 132262 132263 132264 132265 132266 | #ifndef SQLITE_OMIT_DESERIALIZE sqlite3_deserialize, sqlite3_serialize, #else 0, 0, #endif sqlite3_db_name, /* Version 3.40.0 and later */ sqlite3_value_type }; /* True if x is the directory separator character */ #if SQLITE_OS_WIN # define DirSep(X) ((X)=='/'||(X)=='\\') #else |
| ︙ | ︙ | |||
132700 132701 132702 132703 132704 132705 132706 132707 132708 132709 132710 132711 132712 132713 132714 132715 132716 132717 132718 132719 132720 132721 132722 132723 132724 132725 132726 132727 132728 132729 132730 132731 132732 132733 132734 132735 132736 132737 132738 132739 132740 132741 132742 132743 132744 132745 132746 132747 132748 132749 132750 132751 132752 132753 132754 132755 132756 132757 132758 132759 132760 132761 132762 132763 132764 132765 132766 132767 132768 132769 132770 132771 132772 132773 132774 132775 132776 132777 |
** Return or set the local value of the temp_store_directory flag. Changing
** the value sets a specific directory to be used for temporary files.
** Setting to a null string reverts to the default temporary directory search.
** If temporary directory is changed, then invalidateTempStorage.
**
*/
case PragTyp_TEMP_STORE_DIRECTORY: {
if( !zRight ){
returnSingleText(v, sqlite3_temp_directory);
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
int res;
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory");
goto pragma_out;
}
}
if( SQLITE_TEMP_STORE==0
|| (SQLITE_TEMP_STORE==1 && db->temp_store<=1)
|| (SQLITE_TEMP_STORE==2 && db->temp_store==1)
){
invalidateTempStorage(pParse);
}
sqlite3_free(sqlite3_temp_directory);
if( zRight[0] ){
sqlite3_temp_directory = sqlite3_mprintf("%s", zRight);
}else{
sqlite3_temp_directory = 0;
}
#endif /* SQLITE_OMIT_WSD */
}
break;
}
#if SQLITE_OS_WIN
/*
** PRAGMA data_store_directory
** PRAGMA data_store_directory = ""|"directory_name"
**
** Return or set the local value of the data_store_directory flag. Changing
** the value sets a specific directory to be used for database files that
** were specified with a relative pathname. Setting to a null string reverts
** to the default database directory, which for database files specified with
** a relative path will probably be based on the current directory for the
** process. Database file specified with an absolute path are not impacted
** by this setting, regardless of its value.
**
*/
case PragTyp_DATA_STORE_DIRECTORY: {
if( !zRight ){
returnSingleText(v, sqlite3_data_directory);
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
int res;
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory");
goto pragma_out;
}
}
sqlite3_free(sqlite3_data_directory);
if( zRight[0] ){
sqlite3_data_directory = sqlite3_mprintf("%s", zRight);
}else{
sqlite3_data_directory = 0;
}
#endif /* SQLITE_OMIT_WSD */
}
break;
}
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
/*
** PRAGMA [schema.]lock_proxy_file
| > > > > > > | 134269 134270 134271 134272 134273 134274 134275 134276 134277 134278 134279 134280 134281 134282 134283 134284 134285 134286 134287 134288 134289 134290 134291 134292 134293 134294 134295 134296 134297 134298 134299 134300 134301 134302 134303 134304 134305 134306 134307 134308 134309 134310 134311 134312 134313 134314 134315 134316 134317 134318 134319 134320 134321 134322 134323 134324 134325 134326 134327 134328 134329 134330 134331 134332 134333 134334 134335 134336 134337 134338 134339 134340 134341 134342 134343 134344 134345 134346 134347 134348 134349 134350 134351 134352 |
** Return or set the local value of the temp_store_directory flag. Changing
** the value sets a specific directory to be used for temporary files.
** Setting to a null string reverts to the default temporary directory search.
** If temporary directory is changed, then invalidateTempStorage.
**
*/
case PragTyp_TEMP_STORE_DIRECTORY: {
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( !zRight ){
returnSingleText(v, sqlite3_temp_directory);
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
int res;
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory");
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
goto pragma_out;
}
}
if( SQLITE_TEMP_STORE==0
|| (SQLITE_TEMP_STORE==1 && db->temp_store<=1)
|| (SQLITE_TEMP_STORE==2 && db->temp_store==1)
){
invalidateTempStorage(pParse);
}
sqlite3_free(sqlite3_temp_directory);
if( zRight[0] ){
sqlite3_temp_directory = sqlite3_mprintf("%s", zRight);
}else{
sqlite3_temp_directory = 0;
}
#endif /* SQLITE_OMIT_WSD */
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
break;
}
#if SQLITE_OS_WIN
/*
** PRAGMA data_store_directory
** PRAGMA data_store_directory = ""|"directory_name"
**
** Return or set the local value of the data_store_directory flag. Changing
** the value sets a specific directory to be used for database files that
** were specified with a relative pathname. Setting to a null string reverts
** to the default database directory, which for database files specified with
** a relative path will probably be based on the current directory for the
** process. Database file specified with an absolute path are not impacted
** by this setting, regardless of its value.
**
*/
case PragTyp_DATA_STORE_DIRECTORY: {
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( !zRight ){
returnSingleText(v, sqlite3_data_directory);
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
int res;
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory");
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
goto pragma_out;
}
}
sqlite3_free(sqlite3_data_directory);
if( zRight[0] ){
sqlite3_data_directory = sqlite3_mprintf("%s", zRight);
}else{
sqlite3_data_directory = 0;
}
#endif /* SQLITE_OMIT_WSD */
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
break;
}
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
/*
** PRAGMA [schema.]lock_proxy_file
|
| ︙ | ︙ | |||
133477 133478 133479 133480 133481 133482 133483 |
sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
*/
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx, *pPk;
| | | > > > > > > | > > > > > > > > > > > > > > > > > > > | > > > > | > > > > > | | > > | > > > > | > | > > > > | > > > > | > > > > > | | > > > | > > > > > > > > | | | > > > > > > > > > > > > > > > > | | | > < > < | > > | < > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < | 135052 135053 135054 135055 135056 135057 135058 135059 135060 135061 135062 135063 135064 135065 135066 135067 135068 135069 135070 135071 135072 135073 135074 135075 135076 135077 135078 135079 135080 135081 135082 135083 135084 135085 135086 135087 135088 135089 135090 135091 135092 135093 135094 135095 135096 135097 135098 135099 135100 135101 135102 135103 135104 135105 135106 135107 135108 135109 135110 135111 135112 135113 135114 135115 135116 135117 135118 135119 135120 135121 135122 135123 135124 135125 135126 135127 135128 135129 135130 135131 135132 135133 135134 135135 135136 135137 135138 135139 135140 135141 135142 135143 135144 135145 135146 135147 135148 135149 135150 135151 135152 135153 135154 135155 135156 135157 135158 135159 135160 135161 135162 135163 135164 135165 135166 135167 135168 135169 135170 135171 135172 135173 135174 135175 135176 135177 135178 135179 135180 135181 135182 135183 135184 135185 135186 135187 135188 135189 135190 135191 135192 135193 135194 135195 135196 135197 135198 135199 135200 135201 135202 135203 135204 135205 135206 135207 135208 135209 135210 135211 135212 135213 135214 135215 135216 135217 135218 135219 135220 135221 135222 135223 135224 135225 135226 135227 135228 135229 135230 135231 135232 135233 135234 135235 135236 135237 135238 135239 135240 135241 135242 135243 135244 135245 135246 135247 |
sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
*/
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx, *pPk;
Index *pPrior = 0; /* Previous index */
int loopTop;
int iDataCur, iIdxCur;
int r1 = -1;
int bStrict; /* True for a STRICT table */
int r2; /* Previous key for WITHOUT ROWID tables */
int mxCol; /* Maximum non-virtual column number */
if( !IsOrdinaryTable(pTab) ) continue;
if( pObjTab && pObjTab!=pTab ) continue;
if( isQuick || HasRowid(pTab) ){
pPk = 0;
r2 = 0;
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
r2 = sqlite3GetTempRange(pParse, pPk->nKeyCol);
sqlite3VdbeAddOp3(v, OP_Null, 1, r2, r2+pPk->nKeyCol-1);
}
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
1, 0, &iDataCur, &iIdxCur);
/* reg[7] counts the number of entries in the table.
** reg[8+i] counts the number of entries in the i-th index
*/
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
}
assert( pParse->nMem>=8+j );
assert( sqlite3NoTempsInRange(pParse,1,7+j) );
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
/* Fetch the right-most column from the table. This will cause
** the entire record header to be parsed and sanity checked. It
** will also prepopulate the cursor column cache that is used
** by the OP_IsType code, so it is a required step.
*/
mxCol = pTab->nCol-1;
while( mxCol>=0
&& ((pTab->aCol[mxCol].colFlags & COLFLAG_VIRTUAL)!=0
|| pTab->iPKey==mxCol) ) mxCol--;
if( mxCol>=0 ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, mxCol, 3);
sqlite3VdbeTypeofColumn(v, 3);
}
if( !isQuick ){
if( pPk ){
/* Verify WITHOUT ROWID keys are in ascending order */
int a1;
char *zErr;
a1 = sqlite3VdbeAddOp4Int(v, OP_IdxGT, iDataCur, 0,r2,pPk->nKeyCol);
VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_IsNull, r2); VdbeCoverage(v);
zErr = sqlite3MPrintf(db,
"row not in PRIMARY KEY order for %s",
pTab->zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, a1);
sqlite3VdbeJumpHere(v, a1+1);
for(j=0; j<pPk->nKeyCol; j++){
sqlite3ExprCodeLoadIndexColumn(pParse, pPk, iDataCur, j, r2+j);
}
}
}
/* Verify datatypes for all columns:
**
** (1) NOT NULL columns may not contain a NULL
** (2) Datatype must be exact for non-ANY columns in STRICT tables
** (3) Datatype for TEXT columns in non-STRICT tables must be
** NULL, TEXT, or BLOB.
** (4) Datatype for numeric columns in non-STRICT tables must not
** be a TEXT value that can be losslessly converted to numeric.
*/
bStrict = (pTab->tabFlags & TF_Strict)!=0;
for(j=0; j<pTab->nCol; j++){
char *zErr;
Column *pCol = pTab->aCol + j; /* The column to be checked */
int labelError; /* Jump here to report an error */
int labelOk; /* Jump here if all looks ok */
int p1, p3, p4; /* Operands to the OP_IsType opcode */
int doTypeCheck; /* Check datatypes (besides NOT NULL) */
if( j==pTab->iPKey ) continue;
if( bStrict ){
doTypeCheck = pCol->eCType>COLTYPE_ANY;
}else{
doTypeCheck = pCol->affinity>SQLITE_AFF_BLOB;
}
if( pCol->notNull==0 && !doTypeCheck ) continue;
/* Compute the operands that will be needed for OP_IsType */
p4 = SQLITE_NULL;
if( pCol->colFlags & COLFLAG_VIRTUAL ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
p1 = -1;
p3 = 3;
}else{
if( pCol->iDflt ){
sqlite3_value *pDfltValue = 0;
sqlite3ValueFromExpr(db, sqlite3ColumnExpr(pTab,pCol), ENC(db),
pCol->affinity, &pDfltValue);
if( pDfltValue ){
p4 = sqlite3_value_type(pDfltValue);
sqlite3ValueFree(pDfltValue);
}
}
p1 = iDataCur;
if( !HasRowid(pTab) ){
testcase( j!=sqlite3TableColumnToStorage(pTab, j) );
p3 = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), j);
}else{
p3 = sqlite3TableColumnToStorage(pTab,j);
testcase( p3!=j);
}
}
labelError = sqlite3VdbeMakeLabel(pParse);
labelOk = sqlite3VdbeMakeLabel(pParse);
if( pCol->notNull ){
/* (1) NOT NULL columns may not contain a NULL */
int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
sqlite3VdbeChangeP5(v, 0x0f);
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pCol->zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
if( doTypeCheck ){
sqlite3VdbeGoto(v, labelError);
sqlite3VdbeJumpHere(v, jmp2);
}else{
/* VDBE byte code will fall thru */
}
}
if( bStrict && doTypeCheck ){
/* (2) Datatype must be exact for non-ANY columns in STRICT tables*/
static unsigned char aStdTypeMask[] = {
0x1f, /* ANY */
0x18, /* BLOB */
0x11, /* INT */
0x11, /* INTEGER */
0x13, /* REAL */
0x14 /* TEXT */
};
sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
assert( pCol->eCType>=1 && pCol->eCType<=sizeof(aStdTypeMask) );
sqlite3VdbeChangeP5(v, aStdTypeMask[pCol->eCType-1]);
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "non-%s value in %s.%s",
sqlite3StdType[pCol->eCType-1],
pTab->zName, pTab->aCol[j].zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
}else if( !bStrict && pCol->affinity==SQLITE_AFF_TEXT ){
/* (3) Datatype for TEXT columns in non-STRICT tables must be
** NULL, TEXT, or BLOB. */
sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "NUMERIC value in %s.%s",
pTab->zName, pTab->aCol[j].zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
}else if( !bStrict && pCol->affinity>=SQLITE_AFF_NUMERIC ){
/* (4) Datatype for numeric columns in non-STRICT tables must not
** be a TEXT value that can be converted to numeric. */
sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
sqlite3VdbeChangeP5(v, 0x1b); /* NULL, INT, FLOAT, or BLOB */
VdbeCoverage(v);
if( p1>=0 ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
}
sqlite3VdbeAddOp4(v, OP_Affinity, 3, 1, 0, "C", P4_STATIC);
sqlite3VdbeAddOp4Int(v, OP_IsType, -1, labelOk, 3, p4);
sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "TEXT value in %s.%s",
pTab->zName, pTab->aCol[j].zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
}
sqlite3VdbeResolveLabel(v, labelError);
integrityCheckResultRow(v);
sqlite3VdbeResolveLabel(v, labelOk);
}
/* Verify CHECK constraints */
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
if( db->mallocFailed==0 ){
int addrCkFault = sqlite3VdbeMakeLabel(pParse);
int addrCkOk = sqlite3VdbeMakeLabel(pParse);
|
| ︙ | ︙ | |||
133632 133633 133634 133635 133636 133637 133638 133639 133640 133641 133642 133643 133644 133645 |
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);
}
}
}
}
{
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList endCode[] = {
{ OP_AddImm, 1, 0, 0}, /* 0 */
| > > > | 135321 135322 135323 135324 135325 135326 135327 135328 135329 135330 135331 135332 135333 135334 135335 135336 135337 |
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 */
|
| ︙ | ︙ | |||
135030 135031 135032 135033 135034 135035 135036 |
*/
SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){
sqlite3 *db = pParse->db;
assert( db!=0 );
assert( db->pParse==pParse );
assert( pParse->nested==0 );
#ifndef SQLITE_OMIT_SHARED_CACHE
| | | | | 136722 136723 136724 136725 136726 136727 136728 136729 136730 136731 136732 136733 136734 136735 136736 136737 136738 136739 136740 136741 136742 136743 136744 |
*/
SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){
sqlite3 *db = pParse->db;
assert( db!=0 );
assert( db->pParse==pParse );
assert( pParse->nested==0 );
#ifndef SQLITE_OMIT_SHARED_CACHE
if( pParse->aTableLock ) sqlite3DbNNFreeNN(db, pParse->aTableLock);
#endif
while( pParse->pCleanup ){
ParseCleanup *pCleanup = pParse->pCleanup;
pParse->pCleanup = pCleanup->pNext;
pCleanup->xCleanup(db, pCleanup->pPtr);
sqlite3DbNNFreeNN(db, pCleanup);
}
if( pParse->aLabel ) sqlite3DbNNFreeNN(db, pParse->aLabel);
if( pParse->pConstExpr ){
sqlite3ExprListDelete(db, pParse->pConstExpr);
}
assert( db->lookaside.bDisable >= pParse->disableLookaside );
db->lookaside.bDisable -= pParse->disableLookaside;
db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
assert( pParse->db->pParse==pParse );
|
| ︙ | ︙ | |||
135161 135162 135163 135164 135165 135166 135167 |
/* For a long-term use prepared statement avoid the use of
** lookaside memory.
*/
if( prepFlags & SQLITE_PREPARE_PERSISTENT ){
sParse.disableLookaside++;
DisableLookaside;
}
| | | 136853 136854 136855 136856 136857 136858 136859 136860 136861 136862 136863 136864 136865 136866 136867 |
/* For a long-term use prepared statement avoid the use of
** lookaside memory.
*/
if( prepFlags & SQLITE_PREPARE_PERSISTENT ){
sParse.disableLookaside++;
DisableLookaside;
}
sParse.prepFlags = prepFlags & 0xff;
/* Check to verify that it is possible to get a read lock on all
** database schemas. The inability to get a read lock indicates that
** some other database connection is holding a write-lock, which in
** turn means that the other connection has made uncommitted changes
** to the schema.
**
|
| ︙ | ︙ | |||
135202 135203 135204 135205 135206 135207 135208 |
testcase( db->flags & SQLITE_ReadUncommit );
goto end_prepare;
}
}
}
}
| > | > | 136894 136895 136896 136897 136898 136899 136900 136901 136902 136903 136904 136905 136906 136907 136908 136909 136910 |
testcase( db->flags & SQLITE_ReadUncommit );
goto end_prepare;
}
}
}
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( db->pDisconnect ) sqlite3VtabUnlockList(db);
#endif
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
testcase( nBytes==mxLen );
testcase( nBytes==mxLen+1 );
if( nBytes>mxLen ){
|
| ︙ | ︙ | |||
135597 135598 135599 135600 135601 135602 135603 135604 135605 135606 135607 135608 135609 135610 135611 135612 135613 135614 135615 135616 135617 135618 135619 135620 135621 135622 |
** Delete all the content of a Select structure. Deallocate the structure
** itself depending on the value of bFree
**
** If bFree==1, call sqlite3DbFree() on the p object.
** If bFree==0, Leave the first Select object unfreed
*/
static void clearSelect(sqlite3 *db, Select *p, int bFree){
while( p ){
Select *pPrior = p->pPrior;
sqlite3ExprListDelete(db, p->pEList);
sqlite3SrcListDelete(db, p->pSrc);
sqlite3ExprDelete(db, p->pWhere);
sqlite3ExprListDelete(db, p->pGroupBy);
sqlite3ExprDelete(db, p->pHaving);
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprDelete(db, p->pLimit);
if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
sqlite3WindowListDelete(db, p->pWinDefn);
}
while( p->pWin ){
assert( p->pWin->ppThis==&p->pWin );
sqlite3WindowUnlinkFromSelect(p->pWin);
}
#endif
| > | | 137291 137292 137293 137294 137295 137296 137297 137298 137299 137300 137301 137302 137303 137304 137305 137306 137307 137308 137309 137310 137311 137312 137313 137314 137315 137316 137317 137318 137319 137320 137321 137322 137323 137324 137325 |
** Delete all the content of a Select structure. Deallocate the structure
** itself depending on the value of bFree
**
** If bFree==1, call sqlite3DbFree() on the p object.
** If bFree==0, Leave the first Select object unfreed
*/
static void clearSelect(sqlite3 *db, Select *p, int bFree){
assert( db!=0 );
while( p ){
Select *pPrior = p->pPrior;
sqlite3ExprListDelete(db, p->pEList);
sqlite3SrcListDelete(db, p->pSrc);
sqlite3ExprDelete(db, p->pWhere);
sqlite3ExprListDelete(db, p->pGroupBy);
sqlite3ExprDelete(db, p->pHaving);
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprDelete(db, p->pLimit);
if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
sqlite3WindowListDelete(db, p->pWinDefn);
}
while( p->pWin ){
assert( p->pWin->ppThis==&p->pWin );
sqlite3WindowUnlinkFromSelect(p->pWin);
}
#endif
if( bFree ) sqlite3DbNNFreeNN(db, p);
p = pPrior;
bFree = 1;
}
}
/*
** Initialize a SelectDest structure.
|
| ︙ | ︙ | |||
137022 137023 137024 137025 137026 137027 137028 137029 137030 |
}
/*
** Deallocate a KeyInfo object
*/
SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
if( p ){
assert( p->nRef>0 );
p->nRef--;
| > | | 138717 138718 138719 138720 138721 138722 138723 138724 138725 138726 138727 138728 138729 138730 138731 138732 138733 138734 |
}
/*
** Deallocate a KeyInfo object
*/
SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
if( p ){
assert( p->db!=0 );
assert( p->nRef>0 );
p->nRef--;
if( p->nRef==0 ) sqlite3DbNNFreeNN(p->db, p);
}
}
/*
** Make a new pointer to a KeyInfo object
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo *p){
|
| ︙ | ︙ | |||
137209 137210 137211 137212 137213 137214 137215 |
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut,
nKey+1+nColumn+nRefKey);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
VdbeCoverage(v);
| | > > > | 138905 138906 138907 138908 138909 138910 138911 138912 138913 138914 138915 138916 138917 138918 138919 138920 138921 138922 138923 138924 138925 138926 138927 138928 138929 |
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut,
nKey+1+nColumn+nRefKey);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
VdbeCoverage(v);
assert( p->iLimit==0 && p->iOffset==0 );
sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab);
bSeq = 0;
}else{
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
codeOffset(v, p->iOffset, addrContinue);
iSortTab = iTab;
bSeq = 1;
if( p->iOffset>0 ){
sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
}
}
for(i=0, iCol=nKey+bSeq-1; i<nColumn; i++){
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
if( aOutEx[i].fg.bSorterRef ) continue;
#endif
if( aOutEx[i].u.x.iOrderByCol==0 ) iCol++;
}
|
| ︙ | ︙ | |||
137341 137342 137343 137344 137345 137346 137347 | sqlite3VdbeResolveLabel(v, addrBreak); } /* ** Return a pointer to a string containing the 'declaration type' of the ** expression pExpr. The string may be treated as static by the caller. ** | < < < | 139040 139041 139042 139043 139044 139045 139046 139047 139048 139049 139050 139051 139052 139053 | sqlite3VdbeResolveLabel(v, addrBreak); } /* ** Return a pointer to a string containing the 'declaration type' of the ** expression pExpr. The string may be treated as static by the caller. ** ** The declaration type is the exact datatype definition extracted from the ** original CREATE TABLE statement if the expression is a column. The ** declaration type for a ROWID field is INTEGER. Exactly when an expression ** is considered a column can be complex in the presence of subqueries. The ** result-set expression in all of the following SELECT statements is ** considered a column by this function. ** |
| ︙ | ︙ | |||
139209 139210 139211 139212 139213 139214 139215 | sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v); /* Jump to the this point in order to terminate the query. */ sqlite3VdbeResolveLabel(v, labelEnd); | | > | | 140905 140906 140907 140908 140909 140910 140911 140912 140913 140914 140915 140916 140917 140918 140919 140920 140921 140922 140923 |
sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE);
sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v);
/* Jump to the this point in order to terminate the query.
*/
sqlite3VdbeResolveLabel(v, labelEnd);
/* Reassemble the compound query so that it will be freed correctly
** by the calling function */
if( pSplit->pPrior ){
sqlite3ParserAddCleanup(pParse,
(void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior);
}
pSplit->pPrior = pPrior;
pPrior->pNext = pSplit;
sqlite3ExprListDelete(db, pPrior->pOrderBy);
pPrior->pOrderBy = 0;
/*** TBD: Insert subroutine calls to close cursors on incomplete
|
| ︙ | ︙ | |||
139242 139243 139244 139245 139246 139247 139248 | ** ** The isOuterJoin column indicates that the replacement will occur into a ** position in the parent that NULL-able due to an OUTER JOIN. Either the ** target slot in the parent is the right operand of a LEFT JOIN, or one of ** the left operands of a RIGHT JOIN. In either case, we need to potentially ** bypass the substituted expression with OP_IfNullRow. ** | | | 140939 140940 140941 140942 140943 140944 140945 140946 140947 140948 140949 140950 140951 140952 140953 | ** ** The isOuterJoin column indicates that the replacement will occur into a ** position in the parent that NULL-able due to an OUTER JOIN. Either the ** target slot in the parent is the right operand of a LEFT JOIN, or one of ** the left operands of a RIGHT JOIN. In either case, we need to potentially ** bypass the substituted expression with OP_IfNullRow. ** ** Suppose the original expression is an integer constant. Even though the table ** has the nullRow flag set, because the expression is an integer constant, ** it will not be NULLed out. So instead, we insert an OP_IfNullRow opcode ** that checks to see if the nullRow flag is set on the table. If the nullRow ** flag is set, then the value in the register is set to NULL and the original ** expression is bypassed. If the nullRow flag is not set, then the original ** expression runs to populate the register. ** |
| ︙ | ︙ | |||
139268 139269 139270 139271 139272 139273 139274 139275 139276 139277 139278 139279 139280 139281 |
*/
typedef struct SubstContext {
Parse *pParse; /* The parsing context */
int iTable; /* Replace references to this table */
int iNewTable; /* New table number */
int isOuterJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
ExprList *pEList; /* Replacement expressions */
} SubstContext;
/* Forward Declarations */
static void substExprList(SubstContext*, ExprList*);
static void substSelect(SubstContext*, Select*, int);
/*
| > | 140965 140966 140967 140968 140969 140970 140971 140972 140973 140974 140975 140976 140977 140978 140979 |
*/
typedef struct SubstContext {
Parse *pParse; /* The parsing context */
int iTable; /* Replace references to this table */
int iNewTable; /* New table number */
int isOuterJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
ExprList *pEList; /* Replacement expressions */
ExprList *pCList; /* Collation sequences for replacement expr */
} SubstContext;
/* Forward Declarations */
static void substExprList(SubstContext*, ExprList*);
static void substSelect(SubstContext*, Select*, int);
/*
|
| ︙ | ︙ | |||
139309 139310 139311 139312 139313 139314 139315 |
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
if( pExpr->iColumn<0 ){
pExpr->op = TK_NULL;
}else
#endif
{
Expr *pNew;
| > | | > | 141007 141008 141009 141010 141011 141012 141013 141014 141015 141016 141017 141018 141019 141020 141021 141022 141023 141024 141025 141026 141027 141028 141029 141030 141031 141032 141033 141034 141035 |
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
if( pExpr->iColumn<0 ){
pExpr->op = TK_NULL;
}else
#endif
{
Expr *pNew;
int iColumn = pExpr->iColumn;
Expr *pCopy = pSubst->pEList->a[iColumn].pExpr;
Expr ifNullRow;
assert( pSubst->pEList!=0 && iColumn<pSubst->pEList->nExpr );
assert( pExpr->pRight==0 );
if( sqlite3ExprIsVector(pCopy) ){
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
}else{
sqlite3 *db = pSubst->pParse->db;
if( pSubst->isOuterJoin && pCopy->op!=TK_COLUMN ){
memset(&ifNullRow, 0, sizeof(ifNullRow));
ifNullRow.op = TK_IF_NULL_ROW;
ifNullRow.pLeft = pCopy;
ifNullRow.iTable = pSubst->iNewTable;
ifNullRow.iColumn = -99;
ifNullRow.flags = EP_IfNullRow;
pCopy = &ifNullRow;
}
testcase( ExprHasProperty(pCopy, EP_Subquery) );
pNew = sqlite3ExprDup(db, pCopy, 0);
if( db->mallocFailed ){
sqlite3ExprDelete(db, pNew);
|
| ︙ | ︙ | |||
139348 139349 139350 139351 139352 139353 139354 |
pExpr->u.iValue = sqlite3ExprTruthValue(pExpr);
pExpr->op = TK_INTEGER;
ExprSetProperty(pExpr, EP_IntValue);
}
/* Ensure that the expression now has an implicit collation sequence,
** just as it did when it was a column of a view or sub-query. */
| > | | > > > | | | > | 141048 141049 141050 141051 141052 141053 141054 141055 141056 141057 141058 141059 141060 141061 141062 141063 141064 141065 141066 141067 141068 141069 141070 141071 |
pExpr->u.iValue = sqlite3ExprTruthValue(pExpr);
pExpr->op = TK_INTEGER;
ExprSetProperty(pExpr, EP_IntValue);
}
/* Ensure that the expression now has an implicit collation sequence,
** just as it did when it was a column of a view or sub-query. */
{
CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse,
pSubst->pCList->a[iColumn].pExpr
);
if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){
pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
(pColl ? pColl->zName : "BINARY")
);
}
}
ExprClearProperty(pExpr, EP_Collate);
}
}
}else{
if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){
pExpr->iTable = pSubst->iNewTable;
|
| ︙ | ︙ | |||
139544 139545 139546 139547 139548 139549 139550 139551 139552 139553 139554 139555 139556 139557 | memset(&w, 0, sizeof(w)); w.u.aiCol = aCsrMap; w.xExprCallback = renumberCursorsCb; w.xSelectCallback = sqlite3SelectWalkNoop; sqlite3WalkSelect(&w, p); } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** This routine attempts to flatten subqueries as a performance optimization. ** This routine returns 1 if it makes changes and 0 if no flattening occurs. ** ** To understand the concept of flattening, consider the following | > > > > > > > > > > > > | 141249 141250 141251 141252 141253 141254 141255 141256 141257 141258 141259 141260 141261 141262 141263 141264 141265 141266 141267 141268 141269 141270 141271 141272 141273 141274 |
memset(&w, 0, sizeof(w));
w.u.aiCol = aCsrMap;
w.xExprCallback = renumberCursorsCb;
w.xSelectCallback = sqlite3SelectWalkNoop;
sqlite3WalkSelect(&w, p);
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/*
** If pSel is not part of a compound SELECT, return a pointer to its
** expression list. Otherwise, return a pointer to the expression list
** of the leftmost SELECT in the compound.
*/
static ExprList *findLeftmostExprlist(Select *pSel){
while( pSel->pPrior ){
pSel = pSel->pPrior;
}
return pSel->pEList;
}
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
** This routine attempts to flatten subqueries as a performance optimization.
** This routine returns 1 if it makes changes and 0 if no flattening occurs.
**
** To understand the concept of flattening, consider the following
|
| ︙ | ︙ | |||
139589 139590 139591 139592 139593 139594 139595 | ** for flattening. (This is due to ticket [2f7170d73bf9abf80] ** from 2015-02-09.) ** ** (3) If the subquery is the right operand of a LEFT JOIN then ** (3a) the subquery may not be a join and ** (3b) the FROM clause of the subquery may not contain a virtual ** table and | | > | 141306 141307 141308 141309 141310 141311 141312 141313 141314 141315 141316 141317 141318 141319 141320 141321 | ** for flattening. (This is due to ticket [2f7170d73bf9abf80] ** from 2015-02-09.) ** ** (3) If the subquery is the right operand of a LEFT JOIN then ** (3a) the subquery may not be a join and ** (3b) the FROM clause of the subquery may not contain a virtual ** table and ** (**) Was: "The outer query may not have a GROUP BY." This case ** is now managed correctly ** (3d) the outer query may not be DISTINCT. ** See also (26) for restrictions on RIGHT JOIN. ** ** (4) The subquery can not be DISTINCT. ** ** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT ** sub-queries that were excluded from this optimization. Restriction |
| ︙ | ︙ | |||
139697 139698 139699 139700 139701 139702 139703 | ** function in the select list or ORDER BY clause, flattening ** is not attempted. ** ** (26) The subquery may not be the right operand of a RIGHT JOIN. ** See also (3) for restrictions on LEFT JOIN. ** ** (27) The subquery may not contain a FULL or RIGHT JOIN unless it | | < | < < < < < | 141415 141416 141417 141418 141419 141420 141421 141422 141423 141424 141425 141426 141427 141428 141429 141430 141431 141432 141433 141434 141435 | ** function in the select list or ORDER BY clause, flattening ** is not attempted. ** ** (26) The subquery may not be the right operand of a RIGHT JOIN. ** See also (3) for restrictions on LEFT JOIN. ** ** (27) The subquery may not contain a FULL or RIGHT JOIN unless it ** is the first element of the parent query. Two subcases: ** (27a) the subquery is not a compound query. ** (27b) the subquery is a compound query and the RIGHT JOIN occurs ** in any arm of the compound query. (See also (17g).) ** ** (28) The subquery is not a MATERIALIZED CTE. ** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. |
| ︙ | ︙ | |||
139801 139802 139803 139804 139805 139806 139807 | ** ** If we flatten the above, we would get ** ** (t1 LEFT OUTER JOIN t2) JOIN t3 ** ** which is not at all the same thing. ** | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 141513 141514 141515 141516 141517 141518 141519 141520 141521 141522 141523 141524 141525 141526 141527 141528 141529 141530 141531 141532 141533 141534 141535 141536 141537 141538 141539 141540 141541 141542 141543 141544 141545 141546 141547 |
**
** If we flatten the above, we would get
**
** (t1 LEFT OUTER JOIN t2) JOIN t3
**
** which is not at all the same thing.
**
** See also tickets #306, #350, and #3300.
*/
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
if( pSubSrc->nSrc>1 /* (3a) */
|| IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
){
return 0;
}
isOuterJoin = 1;
}
assert( pSubSrc->nSrc>0 ); /* True by restriction (7) */
if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
return 0; /* Restriction (27a) */
}
if( pSubitem->fg.isCte && pSubitem->u2.pCteUse->eM10d==M10d_Yes ){
return 0; /* (28) */
}
/* Restriction (17): If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
** that make up the compound SELECT are allowed to be aggregate or distinct
** queries.
*/
if( pSub->pPrior ){
if( pSub->pOrderBy ){
|
| ︙ | ︙ | |||
140146 140147 140148 140149 140150 140151 140152 140153 140154 140155 140156 140157 140158 140159 140160 140161 140162 140163 140164 140165 140166 140167 140168 140169 140170 140171 |
if( db->mallocFailed==0 ){
SubstContext x;
x.pParse = pParse;
x.iTable = iParent;
x.iNewTable = iNewParent;
x.isOuterJoin = isOuterJoin;
x.pEList = pSub->pEList;
substSelect(&x, pParent, 0);
}
/* The flattened query is a compound if either the inner or the
** outer query is a compound. */
pParent->selFlags |= pSub->selFlags & SF_Compound;
assert( (pSub->selFlags & SF_Distinct)==0 ); /* restriction (17b) */
/*
** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
**
** One is tempted to try to add a and b to combine the limits. But this
** does not work if either limit is negative.
*/
if( pSub->pLimit ){
pParent->pLimit = pSub->pLimit;
pSub->pLimit = 0;
}
| > | | 141814 141815 141816 141817 141818 141819 141820 141821 141822 141823 141824 141825 141826 141827 141828 141829 141830 141831 141832 141833 141834 141835 141836 141837 141838 141839 141840 141841 141842 141843 141844 141845 141846 141847 141848 |
if( db->mallocFailed==0 ){
SubstContext x;
x.pParse = pParse;
x.iTable = iParent;
x.iNewTable = iNewParent;
x.isOuterJoin = isOuterJoin;
x.pEList = pSub->pEList;
x.pCList = findLeftmostExprlist(pSub);
substSelect(&x, pParent, 0);
}
/* The flattened query is a compound if either the inner or the
** outer query is a compound. */
pParent->selFlags |= pSub->selFlags & SF_Compound;
assert( (pSub->selFlags & SF_Distinct)==0 ); /* restriction (17b) */
/*
** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
**
** One is tempted to try to add a and b to combine the limits. But this
** does not work if either limit is negative.
*/
if( pSub->pLimit ){
pParent->pLimit = pSub->pLimit;
pSub->pLimit = 0;
}
/* Recompute the SrcItem.colUsed masks for the flattened
** tables. */
for(i=0; i<nSubSrc; i++){
recomputeColumnsUsed(pParent, &pSrc->a[i+iFrom]);
}
}
/* Finially, delete what is left of the subquery and return
|
| ︙ | ︙ | |||
140628 140629 140630 140631 140632 140633 140634 140635 140636 140637 140638 140639 140640 140641 |
pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
unsetJoinExpr(pNew, -1, 1);
x.pParse = pParse;
x.iTable = pSrc->iCursor;
x.iNewTable = pSrc->iCursor;
x.isOuterJoin = 0;
x.pEList = pSubq->pEList;
pNew = substExpr(&x, pNew);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){
/* Restriction 6c has prevented push-down in this case */
sqlite3ExprDelete(pParse->db, pNew);
nChng--;
break;
| > | 142297 142298 142299 142300 142301 142302 142303 142304 142305 142306 142307 142308 142309 142310 142311 |
pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
unsetJoinExpr(pNew, -1, 1);
x.pParse = pParse;
x.iTable = pSrc->iCursor;
x.iNewTable = pSrc->iCursor;
x.isOuterJoin = 0;
x.pEList = pSubq->pEList;
x.pCList = findLeftmostExprlist(pSubq);
pNew = substExpr(&x, pNew);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){
/* Restriction 6c has prevented push-down in this case */
sqlite3ExprDelete(pParse->db, pNew);
nChng--;
break;
|
| ︙ | ︙ | |||
140731 140732 140733 140734 140735 140736 140737 140738 140739 140740 140741 140742 140743 140744 |
assert( !p->pGroupBy );
if( p->pWhere
|| p->pEList->nExpr!=1
|| p->pSrc->nSrc!=1
|| p->pSrc->a[0].pSelect
|| pAggInfo->nFunc!=1
){
return 0;
}
pTab = p->pSrc->a[0].pTab;
assert( pTab!=0 );
assert( !IsView(pTab) );
if( !IsOrdinaryTable(pTab) ) return 0;
| > | 142401 142402 142403 142404 142405 142406 142407 142408 142409 142410 142411 142412 142413 142414 142415 |
assert( !p->pGroupBy );
if( p->pWhere
|| p->pEList->nExpr!=1
|| p->pSrc->nSrc!=1
|| p->pSrc->a[0].pSelect
|| pAggInfo->nFunc!=1
|| p->pHaving
){
return 0;
}
pTab = p->pSrc->a[0].pTab;
assert( pTab!=0 );
assert( !IsView(pTab) );
if( !IsOrdinaryTable(pTab) ) return 0;
|
| ︙ | ︙ | |||
141151 141152 141153 141154 141155 141156 141157 |
pParse->pWith = pWith->pOuter;
}
}
}
#endif
/*
| | | | 142822 142823 142824 142825 142826 142827 142828 142829 142830 142831 142832 142833 142834 142835 142836 142837 142838 |
pParse->pWith = pWith->pOuter;
}
}
}
#endif
/*
** The SrcItem structure passed as the second argument represents a
** sub-query in the FROM clause of a SELECT statement. This function
** allocates and populates the SrcItem.pTab object. If successful,
** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
** SQLITE_NOMEM.
*/
SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
Select *pSel = pFrom->pSelect;
Table *pTab;
|
| ︙ | ︙ | |||
141986 141987 141988 141989 141990 141991 141992 |
sqlite3TreeViewSelect(0, p, 0);
}
#endif
}
/*
** Check to see if the pThis entry of pTabList is a self-join of a prior view.
| | | 143657 143658 143659 143660 143661 143662 143663 143664 143665 143666 143667 143668 143669 143670 143671 |
sqlite3TreeViewSelect(0, p, 0);
}
#endif
}
/*
** Check to see if the pThis entry of pTabList is a self-join of a prior view.
** If it is, then return the SrcItem for the prior view. If it is not,
** then return 0.
*/
static SrcItem *isSelfJoinView(
SrcList *pTabList, /* Search for self-joins in this FROM clause */
SrcItem *pThis /* Search for prior reference to this subquery */
){
SrcItem *pItem;
|
| ︙ | ︙ | |||
142724 142725 142726 142727 142728 142729 142730 |
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(pParse);
if( (p->selFlags & SF_FixedLimit)==0 ){
p->nSelectRow = 320; /* 4 billion rows */
}
| | | 144395 144396 144397 144398 144399 144400 144401 144402 144403 144404 144405 144406 144407 144408 144409 |
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(pParse);
if( (p->selFlags & SF_FixedLimit)==0 ){
p->nSelectRow = 320; /* 4 billion rows */
}
if( p->pLimit ) computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
sSort.sortFlags |= SORTFLAG_UseSorter;
}
/* Open an ephemeral index to use for the distinct set.
*/
|
| ︙ | ︙ | |||
142946 142947 142948 142949 142950 142951 142952 |
SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
sqlite3TreeViewSelect(0, p, 0);
if( minMaxFlag ){
sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag);
sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY");
}
for(ii=0; ii<pAggInfo->nColumn; ii++){
| > | > > | > > | 144617 144618 144619 144620 144621 144622 144623 144624 144625 144626 144627 144628 144629 144630 144631 144632 144633 144634 144635 144636 144637 |
SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
sqlite3TreeViewSelect(0, p, 0);
if( minMaxFlag ){
sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag);
sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY");
}
for(ii=0; ii<pAggInfo->nColumn; ii++){
struct AggInfo_col *pCol = &pAggInfo->aCol[ii];
sqlite3DebugPrintf(
"agg-column[%d] pTab=%s iTable=%d iColumn=%d iMem=%d"
" iSorterColumn=%d\n",
ii, pCol->pTab ? pCol->pTab->zName : "NULL",
pCol->iTable, pCol->iColumn, pCol->iMem,
pCol->iSorterColumn);
sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
}
for(ii=0; ii<pAggInfo->nFunc; ii++){
sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
ii, pAggInfo->aFunc[ii].iMem);
sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
}
|
| ︙ | ︙ | |||
143025 143026 143027 143028 143029 143030 143031 |
** This might involve two separate loops with an OP_Sort in between, or
** it might be a single loop that uses an index to extract information
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct,
| | | 144701 144702 144703 144704 144705 144706 144707 144708 144709 144710 144711 144712 144713 144714 144715 |
** This might involve two separate loops with an OP_Sort in between, or
** it might be a single loop that uses an index to extract information
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct,
p, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY)
| (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0
);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDistinct);
goto select_end;
}
eDist = sqlite3WhereIsDistinct(pWInfo);
|
| ︙ | ︙ | |||
143068 143069 143070 143071 143072 143073 143074 143075 143076 143077 |
nCol++;
j++;
}
}
regBase = sqlite3GetTempRange(pParse, nCol);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
j = nGroupBy;
for(i=0; i<pAggInfo->nColumn; i++){
struct AggInfo_col *pCol = &pAggInfo->aCol[i];
if( pCol->iSorterColumn>=j ){
| > < | < > | 144744 144745 144746 144747 144748 144749 144750 144751 144752 144753 144754 144755 144756 144757 144758 144759 144760 144761 144762 144763 144764 144765 144766 |
nCol++;
j++;
}
}
regBase = sqlite3GetTempRange(pParse, nCol);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
j = nGroupBy;
pAggInfo->directMode = 1;
for(i=0; i<pAggInfo->nColumn; i++){
struct AggInfo_col *pCol = &pAggInfo->aCol[i];
if( pCol->iSorterColumn>=j ){
sqlite3ExprCode(pParse, pCol->pCExpr, j + regBase);
j++;
}
}
pAggInfo->directMode = 0;
regRecord = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nCol);
SELECTTRACE(1,pParse,p,("WhereEnd\n"));
sqlite3WhereEnd(pWInfo);
|
| ︙ | ︙ | |||
143324 143325 143326 143327 143328 143329 143330 |
** be an appropriate ORDER BY expression for the optimization.
*/
assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 );
assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 );
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
| | | 145000 145001 145002 145003 145004 145005 145006 145007 145008 145009 145010 145011 145012 145013 145014 |
** be an appropriate ORDER BY expression for the optimization.
*/
assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 );
assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 );
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
pDistinct, p, minMaxFlag|distFlag, 0);
if( pWInfo==0 ){
goto select_end;
}
SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
eDist = sqlite3WhereIsDistinct(pWInfo);
updateAccumulator(pParse, regAcc, pAggInfo, eDist);
if( eDist!=WHERE_DISTINCT_NOOP ){
|
| ︙ | ︙ | |||
143967 143968 143969 143970 143971 143972 143973 143974 143975 143976 143977 143978 143979 143980 |
/* if we are not initializing,
** build the sqlite_schema entry
*/
if( !db->init.busy ){
Vdbe *v;
char *z;
/* Make an entry in the sqlite_schema table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, iDb);
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
testcase( z==0 );
| > > > > > > > > > > > > > > > > > | 145643 145644 145645 145646 145647 145648 145649 145650 145651 145652 145653 145654 145655 145656 145657 145658 145659 145660 145661 145662 145663 145664 145665 145666 145667 145668 145669 145670 145671 145672 145673 |
/* if we are not initializing,
** build the sqlite_schema entry
*/
if( !db->init.busy ){
Vdbe *v;
char *z;
/* If this is a new CREATE TABLE statement, and if shadow tables
** are read-only, and the trigger makes a change to a shadow table,
** then raise an error - do not allow the trigger to be created. */
if( sqlite3ReadOnlyShadowTables(db) ){
TriggerStep *pStep;
for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){
if( pStep->zTarget!=0
&& sqlite3ShadowTableName(db, pStep->zTarget)
){
sqlite3ErrorMsg(pParse,
"trigger \"%s\" may not write to shadow table \"%s\"",
pTrig->zName, pStep->zTarget);
goto triggerfinish_cleanup;
}
}
}
/* Make an entry in the sqlite_schema table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, iDb);
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
testcase( z==0 );
|
| ︙ | ︙ | |||
144791 144792 144793 144794 144795 144796 144797 | memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sSubParse; sSubParse.pTriggerTab = pTab; sSubParse.pToplevel = pTop; sSubParse.zAuthContext = pTrigger->zName; sSubParse.eTriggerOp = pTrigger->op; sSubParse.nQueryLoop = pParse->nQueryLoop; | | | 146484 146485 146486 146487 146488 146489 146490 146491 146492 146493 146494 146495 146496 146497 146498 |
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = &sSubParse;
sSubParse.pTriggerTab = pTab;
sSubParse.pToplevel = pTop;
sSubParse.zAuthContext = pTrigger->zName;
sSubParse.eTriggerOp = pTrigger->op;
sSubParse.nQueryLoop = pParse->nQueryLoop;
sSubParse.prepFlags = pParse->prepFlags;
v = sqlite3GetVdbe(&sSubParse);
if( v ){
VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
pTrigger->zName, onErrorText(orconf),
(pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"),
(pTrigger->op==TK_UPDATE ? "UPDATE" : ""),
|
| ︙ | ︙ | |||
145137 145138 145139 145140 145141 145142 145143 145144 |
**
** If column as REAL affinity and the table is an ordinary b-tree table
** (not a virtual table) then the value might have been stored as an
** integer. In that case, add an OP_RealAffinity opcode to make sure
** it has been converted into REAL.
*/
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
assert( pTab!=0 );
| > > > | | | | 146830 146831 146832 146833 146834 146835 146836 146837 146838 146839 146840 146841 146842 146843 146844 146845 146846 146847 146848 146849 146850 146851 146852 146853 146854 146855 146856 146857 146858 146859 146860 146861 146862 |
**
** If column as REAL affinity and the table is an ordinary b-tree table
** (not a virtual table) then the value might have been stored as an
** integer. In that case, add an OP_RealAffinity opcode to make sure
** it has been converted into REAL.
*/
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
Column *pCol;
assert( pTab!=0 );
assert( pTab->nCol>i );
pCol = &pTab->aCol[i];
if( pCol->iDflt ){
sqlite3_value *pValue = 0;
u8 enc = ENC(sqlite3VdbeDb(v));
assert( !IsView(pTab) );
VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName));
assert( i<pTab->nCol );
sqlite3ValueFromExpr(sqlite3VdbeDb(v),
sqlite3ColumnExpr(pTab,pCol), enc,
pCol->affinity, &pValue);
if( pValue ){
sqlite3VdbeAppendP4(v, pValue, P4_MEM);
}
}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( pCol->affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
}
#endif
}
/*
** Check to see if column iCol of index pIdx references any of the
|
| ︙ | ︙ | |||
146592 146593 146594 146595 146596 146597 146598 146599 146600 146601 146602 146603 146604 146605 |
nn = pIdx->nKeyCol;
for(ii=0; ii<nn; ii++){
Expr *pExpr;
sCol[0].u.zToken = (char*)pIdx->azColl[ii];
if( pIdx->aiColumn[ii]==XN_EXPR ){
assert( pIdx->aColExpr!=0 );
assert( pIdx->aColExpr->nExpr>ii );
pExpr = pIdx->aColExpr->a[ii].pExpr;
if( pExpr->op!=TK_COLLATE ){
sCol[0].pLeft = pExpr;
pExpr = &sCol[0];
}
}else{
sCol[0].pLeft = &sCol[1];
| > | 148288 148289 148290 148291 148292 148293 148294 148295 148296 148297 148298 148299 148300 148301 148302 |
nn = pIdx->nKeyCol;
for(ii=0; ii<nn; ii++){
Expr *pExpr;
sCol[0].u.zToken = (char*)pIdx->azColl[ii];
if( pIdx->aiColumn[ii]==XN_EXPR ){
assert( pIdx->aColExpr!=0 );
assert( pIdx->aColExpr->nExpr>ii );
assert( pIdx->bHasExpr );
pExpr = pIdx->aColExpr->a[ii].pExpr;
if( pExpr->op!=TK_COLLATE ){
sCol[0].pLeft = pExpr;
pExpr = &sCol[0];
}
}else{
sCol[0].pLeft = &sCol[1];
|
| ︙ | ︙ | |||
146905 146906 146907 146908 146909 146910 146911 146912 146913 146914 146915 146916 146917 146918 |
u8 saved_mTrace; /* Saved trace settings */
Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True if vacuuming a :memory: database */
int nRes; /* Bytes of reserved space at the end of each page */
int nDb; /* Number of attached databases */
const char *zDbMain; /* Schema name of database to vacuum */
const char *zOut; /* Name of output file */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
return SQLITE_ERROR; /* IMP: R-12218-18073 */
}
if( db->nVdbeActive>1 ){
sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
| > | 148602 148603 148604 148605 148606 148607 148608 148609 148610 148611 148612 148613 148614 148615 148616 |
u8 saved_mTrace; /* Saved trace settings */
Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True if vacuuming a :memory: database */
int nRes; /* Bytes of reserved space at the end of each page */
int nDb; /* Number of attached databases */
const char *zDbMain; /* Schema name of database to vacuum */
const char *zOut; /* Name of output file */
u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
return SQLITE_ERROR; /* IMP: R-12218-18073 */
}
if( db->nVdbeActive>1 ){
sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
|
| ︙ | ︙ | |||
146976 146977 146978 146979 146980 146981 146982 146983 146984 146985 146986 146987 |
i64 sz = 0;
if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
rc = SQLITE_ERROR;
sqlite3SetString(pzErrMsg, db, "output file already exists");
goto end_of_vacuum;
}
db->mDbFlags |= DBFLAG_VacuumInto;
}
nRes = sqlite3BtreeGetRequestedReserve(pMain);
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
| > > > > > | | 148674 148675 148676 148677 148678 148679 148680 148681 148682 148683 148684 148685 148686 148687 148688 148689 148690 148691 148692 148693 148694 148695 148696 148697 148698 |
i64 sz = 0;
if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
rc = SQLITE_ERROR;
sqlite3SetString(pzErrMsg, db, "output file already exists");
goto end_of_vacuum;
}
db->mDbFlags |= DBFLAG_VacuumInto;
/* For a VACUUM INTO, the pager-flags are set to the same values as
** they are for the database being vacuumed, except that PAGER_CACHESPILL
** is always set. */
pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK);
}
nRes = sqlite3BtreeGetRequestedReserve(pMain);
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL);
/* Begin a transaction and take an exclusive lock on the main database
** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
** to ensure that we do not try to change the page-size on a WAL database.
*/
rc = execSql(db, pzErrMsg, "BEGIN");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
| ︙ | ︙ | |||
147494 147495 147496 147497 147498 147499 147500 |
** connection db is decremented immediately (which may lead to the
** structure being xDisconnected and free). Any other VTable structures
** in the list are moved to the sqlite3.pDisconnect list of the associated
** database connection.
*/
SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
assert( IsVirtual(p) );
| > | | 149197 149198 149199 149200 149201 149202 149203 149204 149205 149206 149207 149208 149209 149210 149211 149212 |
** connection db is decremented immediately (which may lead to the
** structure being xDisconnected and free). Any other VTable structures
** in the list are moved to the sqlite3.pDisconnect list of the associated
** database connection.
*/
SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
assert( IsVirtual(p) );
assert( db!=0 );
if( db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
if( p->u.vtab.azArg ){
int i;
for(i=0; i<p->u.vtab.nArg; i++){
if( i!=1 ) sqlite3DbFree(db, p->u.vtab.azArg[i]);
}
sqlite3DbFree(db, p->u.vtab.azArg);
}
|
| ︙ | ︙ | |||
148294 148295 148296 148297 148298 148299 148300 | int rc = 0; /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; assert( ExprUseYTab(pExpr) ); pTab = pExpr->y.pTab; | | | 149998 149999 150000 150001 150002 150003 150004 150005 150006 150007 150008 150009 150010 150011 150012 | int rc = 0; /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; assert( ExprUseYTab(pExpr) ); pTab = pExpr->y.pTab; if( NEVER(pTab==0) ) return pDef; if( !IsVirtual(pTab) ) return pDef; pVtab = sqlite3GetVTable(db, pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction==0 ) return pDef; |
| ︙ | ︙ | |||
148901 148902 148903 148904 148905 148906 148907 | }; /* ** An instance of the following structure keeps track of a mapping ** between VDBE cursor numbers and bits of the bitmasks in WhereTerm. ** ** The VDBE cursor numbers are small integers contained in | | | 150605 150606 150607 150608 150609 150610 150611 150612 150613 150614 150615 150616 150617 150618 150619 | }; /* ** An instance of the following structure keeps track of a mapping ** between VDBE cursor numbers and bits of the bitmasks in WhereTerm. ** ** The VDBE cursor numbers are small integers contained in ** SrcItem.iCursor and Expr.iTable fields. For any given WHERE ** clause, the cursor numbers might not begin with 0 and they might ** contain gaps in the numbering sequence. But we want to make maximum ** use of the bits in our bitmasks. This structure provides a mapping ** from the sparse cursor numbers into consecutive integers beginning ** with 0. ** ** If WhereMaskSet.ix[A]==B it means that The A-th bit of a Bitmask |
| ︙ | ︙ | |||
148972 148973 148974 148975 148976 148977 148978 | #ifndef SQLITE_QUERY_PLANNER_LIMIT # define SQLITE_QUERY_PLANNER_LIMIT 20000 #endif #ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR # define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000 #endif | < < < < < < < < < < < < < < > < < > < | 150676 150677 150678 150679 150680 150681 150682 150683 150684 150685 150686 150687 150688 150689 150690 150691 150692 150693 150694 150695 150696 150697 150698 150699 150700 150701 150702 150703 150704 150705 150706 150707 150708 150709 150710 150711 150712 150713 150714 150715 150716 150717 150718 150719 150720 150721 150722 150723 150724 150725 150726 |
#ifndef SQLITE_QUERY_PLANNER_LIMIT
# define SQLITE_QUERY_PLANNER_LIMIT 20000
#endif
#ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR
# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000
#endif
/*
** The WHERE clause processing routine has two halves. The
** first part does the start of the WHERE loop and the second
** half does the tail of the WHERE loop. An instance of
** this structure is returned by the first half and passed
** into the second half to give some continuity.
**
** An instance of this object holds the complete state of the query
** planner.
*/
struct WhereInfo {
Parse *pParse; /* Parsing and code generating context */
SrcList *pTabList; /* List of tables in the join */
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
ExprList *pResultSet; /* Result set of the query */
#if WHERETRACE_ENABLED
Expr *pWhere; /* The complete WHERE clause */
#endif
Select *pSelect; /* The entire SELECT statement containing WHERE */
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
u8 nLevel; /* Number of nested loop */
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */
u8 eDistinct; /* One of the WHERE_DISTINCT_* values */
unsigned bDeferredSeek :1; /* Uses OP_DeferredSeek */
unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */
unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */
unsigned sorted :1; /* True if really sorted (not just grouped) */
LogEst nRowOut; /* Estimated number of output rows */
int iTop; /* The very beginning of the WHERE loop */
int iEndWhere; /* End of the WHERE clause itself */
WhereLoop *pLoops; /* List of all WhereLoop objects */
WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
WhereClause sWC; /* Decomposition of the WHERE clause */
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
WhereLevel a[1]; /* Information about each nest loop in WHERE */
};
|
| ︙ | ︙ | |||
149171 149172 149173 149174 149175 149176 149177 149178 149179 149180 149181 149182 149183 149184 | #define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ #define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */ #define WHERE_IN_SEEKSCAN 0x00100000 /* Seek-scan optimization for IN */ #define WHERE_TRANSCONS 0x00200000 /* Uses a transitive constraint */ #define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */ #define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */ #define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */ #endif /* !defined(SQLITE_WHEREINT_H) */ /************** End of whereInt.h ********************************************/ /************** Continuing where we left off in wherecode.c ******************/ #ifndef SQLITE_OMIT_EXPLAIN | > | 150860 150861 150862 150863 150864 150865 150866 150867 150868 150869 150870 150871 150872 150873 150874 | #define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ #define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */ #define WHERE_IN_SEEKSCAN 0x00100000 /* Seek-scan optimization for IN */ #define WHERE_TRANSCONS 0x00200000 /* Uses a transitive constraint */ #define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */ #define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */ #define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */ #define WHERE_VIEWSCAN 0x02000000 /* A full-scan of a VIEW or subquery */ #endif /* !defined(SQLITE_WHEREINT_H) */ /************** End of whereInt.h ********************************************/ /************** Continuing where we left off in wherecode.c ******************/ #ifndef SQLITE_OMIT_EXPLAIN |
| ︙ | ︙ | |||
149779 149780 149781 149782 149783 149784 149785 |
if( !db->mallocFailed ){
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
pExpr->iTable = iTab;
}
sqlite3ExprDelete(db, pX);
}else{
| > | | 151469 151470 151471 151472 151473 151474 151475 151476 151477 151478 151479 151480 151481 151482 151483 151484 |
if( !db->mallocFailed ){
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
pExpr->iTable = iTab;
}
sqlite3ExprDelete(db, pX);
}else{
int n = sqlite3ExprVectorSize(pX->pLeft);
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
}
pX = pExpr;
}
if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev );
|
| ︙ | ︙ | |||
150049 150050 150051 150052 150053 150054 150055 |
Vdbe *v, /* prepared statement under construction */
WhereLevel *pLevel, /* The loop that contains the LIKE operator */
WhereTerm *pTerm /* The upper or lower bound just coded */
){
if( pTerm->wtFlags & TERM_LIKEOPT ){
VdbeOp *pOp;
assert( pLevel->iLikeRepCntr>0 );
| | | 151740 151741 151742 151743 151744 151745 151746 151747 151748 151749 151750 151751 151752 151753 151754 |
Vdbe *v, /* prepared statement under construction */
WhereLevel *pLevel, /* The loop that contains the LIKE operator */
WhereTerm *pTerm /* The upper or lower bound just coded */
){
if( pTerm->wtFlags & TERM_LIKEOPT ){
VdbeOp *pOp;
assert( pLevel->iLikeRepCntr>0 );
pOp = sqlite3VdbeGetLastOp(v);
assert( pOp!=0 );
assert( pOp->opcode==OP_String8
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed );
pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */
pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */
}
}
|
| ︙ | ︙ | |||
150373 150374 150375 150376 150377 150378 150379 |
}
}else{
assert( nReg==1 || pParse->nErr );
sqlite3ExprCode(pParse, p, iReg);
}
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 152064 152065 152066 152067 152068 152069 152070 152071 152072 152073 152074 152075 152076 152077 |
}
}else{
assert( nReg==1 || pParse->nErr );
sqlite3ExprCode(pParse, p, iReg);
}
}
/*
** The pTruth expression is always true because it is the WHERE clause
** a partial index that is driving a query loop. Look through all of the
** WHERE clause terms on the query, and if any of those terms must be
** true because pTruth is true, then mark those WHERE clause terms as
** coded.
*/
|
| ︙ | ︙ | |||
150578 150579 150580 150581 150582 150583 150584 150585 150586 150587 150588 150589 150590 150591 |
WhereTerm *pTerm = pLoop->aLTerm[0];
int regRowid;
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
regRowid = sqlite3GetTempReg(pParse);
regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid);
sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
addrNxt, regRowid, 1);
VdbeCoverage(pParse->pVdbe);
}else{
u16 nEq = pLoop->u.btree.nEq;
int r1;
char *zStartAff;
| > > | 152132 152133 152134 152135 152136 152137 152138 152139 152140 152141 152142 152143 152144 152145 152146 152147 |
WhereTerm *pTerm = pLoop->aLTerm[0];
int regRowid;
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
regRowid = sqlite3GetTempReg(pParse);
regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid);
sqlite3VdbeAddOp2(pParse->pVdbe, OP_MustBeInt, regRowid, addrNxt);
VdbeCoverage(pParse->pVdbe);
sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
addrNxt, regRowid, 1);
VdbeCoverage(pParse->pVdbe);
}else{
u16 nEq = pLoop->u.btree.nEq;
int r1;
char *zStartAff;
|
| ︙ | ︙ | |||
150729 150730 150731 150732 150733 150734 150735 |
}else{
Expr *pRight = pTerm->pExpr->pRight;
codeExprOrVector(pParse, pRight, iTarget, 1);
if( pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET
&& pLoop->u.vtab.bOmitOffset
){
assert( pTerm->eOperator==WO_AUX );
| | | | | 152285 152286 152287 152288 152289 152290 152291 152292 152293 152294 152295 152296 152297 152298 152299 152300 152301 |
}else{
Expr *pRight = pTerm->pExpr->pRight;
codeExprOrVector(pParse, pRight, iTarget, 1);
if( pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET
&& pLoop->u.vtab.bOmitOffset
){
assert( pTerm->eOperator==WO_AUX );
assert( pWInfo->pSelect!=0 );
assert( pWInfo->pSelect->iOffset>0 );
sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pSelect->iOffset);
VdbeComment((v,"Zero OFFSET counter"));
}
}
}
sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
|
| ︙ | ︙ | |||
150839 150840 150841 150842 150843 150844 150845 150846 150847 150848 150849 150850 150851 150852 |
assert( pTerm->pExpr!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
iReleaseReg = ++pParse->nMem;
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
addrNxt = pLevel->addrNxt;
if( pLevel->regFilter ){
sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
iRowidReg, 1);
VdbeCoverage(v);
filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady);
}
sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
VdbeCoverage(v);
| > > | 152395 152396 152397 152398 152399 152400 152401 152402 152403 152404 152405 152406 152407 152408 152409 152410 |
assert( pTerm->pExpr!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
iReleaseReg = ++pParse->nMem;
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
addrNxt = pLevel->addrNxt;
if( pLevel->regFilter ){
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
VdbeCoverage(v);
sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
iRowidReg, 1);
VdbeCoverage(v);
filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady);
}
sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
VdbeCoverage(v);
|
| ︙ | ︙ | |||
151190 151191 151192 151193 151194 151195 151196 151197 151198 151199 151200 151201 151202 151203 |
** should we try before giving up and going with a seek. The cost
** of a seek is proportional to the logarithm of the of the number
** of entries in the tree, so basing the number of steps to try
** on the estimated number of rows in the btree seems like a good
** guess. */
addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
VdbeCoverage(v);
}
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
VdbeCoverage(v);
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT );
| > > > > > | 152748 152749 152750 152751 152752 152753 152754 152755 152756 152757 152758 152759 152760 152761 152762 152763 152764 152765 152766 |
** should we try before giving up and going with a seek. The cost
** of a seek is proportional to the logarithm of the of the number
** of entries in the tree, so basing the number of steps to try
** on the estimated number of rows in the btree seems like a good
** guess. */
addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
if( pRangeStart ){
sqlite3VdbeChangeP5(v, 1);
sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1);
addrSeekScan = 0;
}
VdbeCoverage(v);
}
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
VdbeCoverage(v);
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT );
|
| ︙ | ︙ | |||
151265 151266 151267 151268 151269 151270 151271 |
}else if( bStopAtNull ){
if( regBignull==0 ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
endEq = 0;
}
nConstraint++;
}
| | | | 152828 152829 152830 152831 152832 152833 152834 152835 152836 152837 152838 152839 152840 152841 152842 152843 |
}else if( bStopAtNull ){
if( regBignull==0 ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
endEq = 0;
}
nConstraint++;
}
if( zStartAff ) sqlite3DbNNFreeNN(db, zStartAff);
if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff);
/* Top of the loop body */
if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v);
/* Check if the index cursor is past the end of the range. */
if( nConstraint ){
if( regBignull ){
|
| ︙ | ︙ | |||
151328 151329 151330 151331 151332 151333 151334 |
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j);
}
sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont,
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
}
if( pLevel->iLeftJoin==0 ){
| < < < < < < < < < < < < < < < < < < < < < | 152891 152892 152893 152894 152895 152896 152897 152898 152899 152900 152901 152902 152903 152904 |
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j);
}
sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont,
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
}
if( pLevel->iLeftJoin==0 ){
/* If a partial index is driving the loop, try to eliminate WHERE clause
** terms from the query that must be true due to the WHERE clause of
** the partial index.
**
** 2019-11-02 ticket 623eff57e76d45f6: This optimization does not work
** for a LEFT JOIN.
*/
|
| ︙ | ︙ | |||
151461 151462 151463 151464 151465 151466 151467 |
** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
*/
if( pWInfo->nLevel>1 ){
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
| | | 153003 153004 153005 153006 153007 153008 153009 153010 153011 153012 153013 153014 153015 153016 153017 |
** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
*/
if( pWInfo->nLevel>1 ){
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
pOrTab = sqlite3DbMallocRawNN(db,
sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
if( pOrTab==0 ) return notReady;
pOrTab->nAlloc = (u8)(nNotReady + 1);
pOrTab->nSrc = pOrTab->nAlloc;
memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem));
origSrc = pWInfo->pTabList->a;
for(k=1; k<=nNotReady; k++){
|
| ︙ | ︙ | |||
151714 151715 151716 151717 151718 151719 151720 |
** loop to point to this spot, which is the top of the next containing
** loop. The byte-code formatter will use that P2 value as a hint to
** indent everything in between the this point and the final OP_Return.
** See tag-20220407a in vdbe.c and shell.c */
assert( pLevel->op==OP_Return );
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
| | | 153256 153257 153258 153259 153260 153261 153262 153263 153264 153265 153266 153267 153268 153269 153270 |
** loop to point to this spot, which is the top of the next containing
** loop. The byte-code formatter will use that P2 value as a hint to
** indent everything in between the this point and the final OP_Return.
** See tag-20220407a in vdbe.c and shell.c */
assert( pLevel->op==OP_Return );
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
if( pWInfo->nLevel>1 ){ sqlite3DbFreeNN(db, pOrTab); }
if( !untestedTerms ) disableTerm(pLevel, pTerm);
}else
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
{
/* Case 6: There is no usable index. We must do a complete
** scan of the entire table.
|
| ︙ | ︙ | |||
152342 152343 152344 152345 152346 152347 152348 |
** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07
** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975
** 2019-09-03 https://sqlite.org/src/info/0f0428096f17252a
*/
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|| (ALWAYS( ExprUseYTab(pLeft) )
| | | 153884 153885 153886 153887 153888 153889 153890 153891 153892 153893 153894 153895 153896 153897 153898 |
** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07
** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975
** 2019-09-03 https://sqlite.org/src/info/0f0428096f17252a
*/
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|| (ALWAYS( ExprUseYTab(pLeft) )
&& ALWAYS(pLeft->y.pTab)
&& IsVirtual(pLeft->y.pTab)) /* Might be numeric */
){
int isNum;
double rDummy;
isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8);
if( isNum<=0 ){
if( iTo==1 && zNew[0]=='-' ){
|
| ︙ | ︙ | |||
152459 152460 152461 152462 152463 152464 152465 |
** virtual table on their second argument, which is the same as
** the left-hand side operand in their in-fix form.
**
** vtab_column MATCH expression
** MATCH(expression,vtab_column)
*/
pCol = pList->a[1].pExpr;
| | < | 154001 154002 154003 154004 154005 154006 154007 154008 154009 154010 154011 154012 154013 154014 154015 |
** virtual table on their second argument, which is the same as
** the left-hand side operand in their in-fix form.
**
** vtab_column MATCH expression
** MATCH(expression,vtab_column)
*/
pCol = pList->a[1].pExpr;
assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
if( ExprIsVtab(pCol) ){
for(i=0; i<ArraySize(aOp); i++){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
*peOp2 = aOp[i].eOp2;
*ppRight = pList->a[0].pExpr;
*ppLeft = pCol;
|
| ︙ | ︙ | |||
152485 152486 152487 152488 152489 152490 152491 |
**
** Historically, xFindFunction expected to see lower-case function
** names. But for this use case, xFindFunction is expected to deal
** with function names in an arbitrary case.
*/
pCol = pList->a[0].pExpr;
assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) );
| | | 154026 154027 154028 154029 154030 154031 154032 154033 154034 154035 154036 154037 154038 154039 154040 |
**
** Historically, xFindFunction expected to see lower-case function
** names. But for this use case, xFindFunction is expected to deal
** with function names in an arbitrary case.
*/
pCol = pList->a[0].pExpr;
assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) );
assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
if( ExprIsVtab(pCol) ){
sqlite3_vtab *pVtab;
sqlite3_module *pMod;
void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
void *pNotUsed;
pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab;
assert( pVtab!=0 );
|
| ︙ | ︙ | |||
152510 152511 152512 152513 152514 152515 152516 |
}
}
}
}else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
int res = 0;
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
| | < | | | 154051 154052 154053 154054 154055 154056 154057 154058 154059 154060 154061 154062 154063 154064 154065 154066 154067 154068 154069 154070 |
}
}
}
}else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
int res = 0;
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
assert( pLeft->op!=TK_COLUMN || (ExprUseYTab(pLeft) && pLeft->y.pTab!=0) );
if( ExprIsVtab(pLeft) ){
res++;
}
assert( pRight==0 || pRight->op!=TK_COLUMN
|| (ExprUseYTab(pRight) && pRight->y.pTab!=0) );
if( pRight && ExprIsVtab(pRight) ){
res++;
SWAP(Expr*, pLeft, pRight);
}
*ppLeft = pLeft;
*ppRight = pRight;
if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE;
|
| ︙ | ︙ | |||
153065 153066 153067 153068 153069 153070 153071 153072 153073 153074 153075 153076 153077 153078 |
int iCur;
for(i=0; mPrereq>1; i++, mPrereq>>=1){}
iCur = pFrom->a[i].iCursor;
for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr==0 ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
aiCurCol[0] = iCur;
aiCurCol[1] = XN_EXPR;
return 1;
}
}
}
| > | 154605 154606 154607 154608 154609 154610 154611 154612 154613 154614 154615 154616 154617 154618 154619 |
int iCur;
for(i=0; mPrereq>1; i++, mPrereq>>=1){}
iCur = pFrom->a[i].iCursor;
for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr==0 ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
assert( pIdx->bHasExpr );
if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
aiCurCol[0] = iCur;
aiCurCol[1] = XN_EXPR;
return 1;
}
}
}
|
| ︙ | ︙ | |||
153678 153679 153680 153681 153682 153683 153684 | ** 5. The ORDER BY clause, if any, will be made available to the xBestIndex ** method. ** ** LIMIT and OFFSET terms are ignored by most of the planner code. They ** exist only so that they may be passed to the xBestIndex method of the ** single virtual table in the FROM clause of the SELECT. */ | | > | < | 155219 155220 155221 155222 155223 155224 155225 155226 155227 155228 155229 155230 155231 155232 155233 155234 155235 |
** 5. The ORDER BY clause, if any, will be made available to the xBestIndex
** method.
**
** LIMIT and OFFSET terms are ignored by most of the planner code. They
** exist only so that they may be passed to the xBestIndex method of the
** single virtual table in the FROM clause of the SELECT.
*/
SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
if( p->pGroupBy==0
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
&& (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
){
ExprList *pOrderBy = p->pOrderBy;
int iCsr = p->pSrc->a[0].iCursor;
int ii;
|
| ︙ | ︙ | |||
154672 154673 154674 154675 154676 154677 154678 154679 154680 154681 154682 154683 154684 154685 154686 154687 154688 154689 154690 154691 154692 154693 154694 |
sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost);
sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows);
}
#else
#define whereTraceIndexInfoInputs(A)
#define whereTraceIndexInfoOutputs(A)
#endif
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** Return TRUE if the WHERE clause term pTerm is of a form where it
** could be used with an index to access pSrc, assuming an appropriate
** index existed.
*/
static int termCanDriveIndex(
const WhereTerm *pTerm, /* WHERE clause term to check */
const SrcItem *pSrc, /* Table we are trying to access */
const Bitmask notReady /* Tables in outer loops of the join */
){
char aff;
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
assert( (pSrc->fg.jointype & JT_RIGHT)==0 );
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < | < < < | | < | 156213 156214 156215 156216 156217 156218 156219 156220 156221 156222 156223 156224 156225 156226 156227 156228 156229 156230 156231 156232 156233 156234 156235 156236 156237 156238 156239 156240 156241 156242 156243 156244 156245 156246 156247 156248 156249 156250 156251 156252 156253 156254 156255 156256 156257 156258 156259 156260 156261 156262 156263 156264 156265 156266 156267 156268 156269 156270 156271 156272 156273 156274 156275 156276 156277 156278 156279 156280 156281 156282 156283 |
sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost);
sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows);
}
#else
#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.
**
** pTerm must be EP_OuterON if pSrc is the right operand of an
** outer join. pTerm can be either EP_OuterON or EP_InnerON if pSrc
** is the left operand of a RIGHT join.
**
** See https://sqlite.org/forum/forumpost/206d99a16dd9212f
** for an example of a WHERE clause constraints that may not be used on
** the right table of a RIGHT JOIN because the constraint implies a
** not-NULL condition on the left table of the RIGHT JOIN.
*/
static int constraintCompatibleWithOuterJoin(
const WhereTerm *pTerm, /* WHERE clause term to check */
const SrcItem *pSrc /* Table we are trying to access */
){
assert( (pSrc->fg.jointype&(JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ); /* By caller */
testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
|| pTerm->pExpr->w.iJoin != pSrc->iCursor
){
return 0;
}
if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0
&& ExprHasProperty(pTerm->pExpr, EP_InnerON)
){
return 0;
}
return 1;
}
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** Return TRUE if the WHERE clause term pTerm is of a form where it
** could be used with an index to access pSrc, assuming an appropriate
** index existed.
*/
static int termCanDriveIndex(
const WhereTerm *pTerm, /* WHERE clause term to check */
const SrcItem *pSrc, /* Table we are trying to access */
const Bitmask notReady /* Tables in outer loops of the join */
){
char aff;
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
assert( (pSrc->fg.jointype & JT_RIGHT)==0 );
if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
&& !constraintCompatibleWithOuterJoin(pTerm,pSrc)
){
return 0; /* See https://sqlite.org/forum/forumpost/51e6959f61 */
}
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
if( pTerm->u.x.leftColumn<0 ) return 0;
aff = pSrc->pTab->aCol[pTerm->u.x.leftColumn].affinity;
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
testcase( pTerm->pExpr->op==TK_IS );
|
| ︙ | ︙ | |||
155109 155110 155111 155112 155113 155114 155115 |
testcase( pTerm->eOperator & WO_ALL );
if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
assert( pTerm->u.x.leftColumn>=XN_ROWID );
assert( pTerm->u.x.leftColumn<pTab->nCol );
| < < < < < | < < < | < < < | | < | 156681 156682 156683 156684 156685 156686 156687 156688 156689 156690 156691 156692 156693 156694 156695 156696 156697 156698 |
testcase( pTerm->eOperator & WO_ALL );
if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
assert( pTerm->u.x.leftColumn>=XN_ROWID );
assert( pTerm->u.x.leftColumn<pTab->nCol );
if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
&& !constraintCompatibleWithOuterJoin(pTerm,pSrc)
){
continue;
}
nTerm++;
pTerm->wtFlags |= TERM_OK;
}
/* If the ORDER BY clause contains only columns in the current
** virtual table then allocate space for the aOrderBy part of
|
| ︙ | ︙ | |||
155497 155498 155499 155500 155501 155502 155503 |
aStat[1] = aSample[i].anEq[iCol];
}else{
/* At this point, the (iCol+1) field prefix of aSample[i] is the first
** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec
** is larger than all samples in the array. */
tRowcnt iUpper, iGap;
if( i>=pIdx->nSample ){
| | | 157057 157058 157059 157060 157061 157062 157063 157064 157065 157066 157067 157068 157069 157070 157071 |
aStat[1] = aSample[i].anEq[iCol];
}else{
/* At this point, the (iCol+1) field prefix of aSample[i] is the first
** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec
** is larger than all samples in the array. */
tRowcnt iUpper, iGap;
if( i>=pIdx->nSample ){
iUpper = pIdx->nRowEst0;
}else{
iUpper = aSample[i].anLt[iCol];
}
if( iLower>=iUpper ){
iGap = 0;
}else{
|
| ︙ | ︙ | |||
156126 156127 156128 156129 156130 156131 156132 |
sqlite3DbFreeNN(db, p->u.btree.pIndex);
p->u.btree.pIndex = 0;
}
}
}
/*
| | > | > > > > | > | 157686 157687 157688 157689 157690 157691 157692 157693 157694 157695 157696 157697 157698 157699 157700 157701 157702 157703 157704 157705 157706 157707 157708 157709 157710 157711 |
sqlite3DbFreeNN(db, p->u.btree.pIndex);
p->u.btree.pIndex = 0;
}
}
}
/*
** Deallocate internal memory used by a WhereLoop object. Leave the
** object in an initialized state, as if it had been newly allocated.
*/
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
if( p->aLTerm!=p->aLTermSpace ){
sqlite3DbFreeNN(db, p->aLTerm);
p->aLTerm = p->aLTermSpace;
p->nLSlot = ArraySize(p->aLTermSpace);
}
whereLoopClearUnion(db, p);
p->nLTerm = 0;
p->wsFlags = 0;
}
/*
** Increase the memory allocation for pLoop->aLTerm[] to be at least n.
*/
static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
WhereTerm **paNew;
|
| ︙ | ︙ | |||
156155 156156 156157 156158 156159 156160 156161 |
}
/*
** Transfer content from the second pLoop into the first.
*/
static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
whereLoopClearUnion(db, pTo);
| > | > > | > < | | < < < < < < < < < < < | 157721 157722 157723 157724 157725 157726 157727 157728 157729 157730 157731 157732 157733 157734 157735 157736 157737 157738 157739 157740 157741 157742 157743 157744 157745 157746 157747 157748 157749 157750 157751 157752 157753 157754 157755 157756 157757 157758 157759 157760 157761 157762 157763 157764 157765 157766 157767 157768 157769 157770 157771 157772 157773 157774 157775 157776 157777 |
}
/*
** Transfer content from the second pLoop into the first.
*/
static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
whereLoopClearUnion(db, pTo);
if( pFrom->nLTerm > pTo->nLSlot
&& whereLoopResize(db, pTo, pFrom->nLTerm)
){
memset(pTo, 0, WHERE_LOOP_XFER_SZ);
return SQLITE_NOMEM_BKPT;
}
memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ);
memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0]));
if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){
pFrom->u.vtab.needFree = 0;
}else if( (pFrom->wsFlags & WHERE_AUTO_INDEX)!=0 ){
pFrom->u.btree.pIndex = 0;
}
return SQLITE_OK;
}
/*
** Delete a WhereLoop object
*/
static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
assert( db!=0 );
whereLoopClear(db, p);
sqlite3DbNNFreeNN(db, p);
}
/*
** Free a WhereInfo structure
*/
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
assert( pWInfo!=0 );
assert( db!=0 );
sqlite3WhereClauseClear(&pWInfo->sWC);
while( pWInfo->pLoops ){
WhereLoop *p = pWInfo->pLoops;
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
while( pWInfo->pMemToFree ){
WhereMemBlock *pNext = pWInfo->pMemToFree->pNext;
sqlite3DbNNFreeNN(db, pWInfo->pMemToFree);
pWInfo->pMemToFree = pNext;
}
sqlite3DbNNFreeNN(db, pWInfo);
}
/*
** 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.
|
| ︙ | ︙ | |||
156772 156773 156774 156775 156776 156777 156778 |
}
if( pTerm->prereqRight & pNew->maskSelf ) continue;
/* Do not allow the upper bound of a LIKE optimization range constraint
** to mix with a lower range bound from some other source */
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
| < < < < < < < < < < < < < | < < < | < < < | | | < < > | > > > | 158330 158331 158332 158333 158334 158335 158336 158337 158338 158339 158340 158341 158342 158343 158344 158345 158346 158347 158348 158349 158350 158351 158352 158353 158354 158355 158356 158357 158358 158359 158360 158361 158362 158363 |
}
if( pTerm->prereqRight & pNew->maskSelf ) continue;
/* Do not allow the upper bound of a LIKE optimization range constraint
** to mix with a lower range bound from some other source */
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
&& !constraintCompatibleWithOuterJoin(pTerm,pSrc)
){
continue;
}
if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE;
}else{
pBuilder->bldFlags1 |= SQLITE_BLDF1_INDEXED;
}
pNew->wsFlags = saved_wsFlags;
pNew->u.btree.nEq = saved_nEq;
pNew->u.btree.nBtm = saved_nBtm;
pNew->u.btree.nTop = saved_nTop;
pNew->nLTerm = saved_nLTerm;
if( pNew->nLTerm>=pNew->nLSlot
&& whereLoopResize(db, pNew, pNew->nLTerm+1)
){
break; /* OOM while trying to enlarge the pNew->aLTerm array */
}
pNew->aLTerm[pNew->nLTerm++] = pTerm;
pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf;
assert( nInMul==0
|| (pNew->wsFlags & WHERE_COLUMN_NULL)!=0
|| (pNew->wsFlags & WHERE_COLUMN_IN)!=0
|| (pNew->wsFlags & WHERE_SKIPSCAN)!=0
|
| ︙ | ︙ | |||
156901 156902 156903 156904 156905 156906 156907 |
}else{
pNew->wsFlags |= WHERE_UNQ_WANTED;
}
}
if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS;
}else if( eOp & WO_ISNULL ){
pNew->wsFlags |= WHERE_COLUMN_NULL;
| > > > > | | | | | < < | | | | | | | | | | | | | | | | | | | | < < | | | > | 158442 158443 158444 158445 158446 158447 158448 158449 158450 158451 158452 158453 158454 158455 158456 158457 158458 158459 158460 158461 158462 158463 158464 158465 158466 158467 158468 158469 158470 158471 158472 158473 158474 158475 158476 158477 158478 158479 158480 158481 158482 158483 158484 158485 158486 158487 158488 |
}else{
pNew->wsFlags |= WHERE_UNQ_WANTED;
}
}
if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS;
}else if( eOp & WO_ISNULL ){
pNew->wsFlags |= WHERE_COLUMN_NULL;
}else{
int nVecLen = whereRangeVectorLen(
pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
);
if( eOp & (WO_GT|WO_GE) ){
testcase( eOp & WO_GT );
testcase( eOp & WO_GE );
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
pNew->u.btree.nBtm = nVecLen;
pBtm = pTerm;
pTop = 0;
if( pTerm->wtFlags & TERM_LIKEOPT ){
/* Range constraints that come from the LIKE optimization are
** always used in pairs. */
pTop = &pTerm[1];
assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
assert( pTop->wtFlags & TERM_LIKEOPT );
assert( pTop->eOperator==WO_LT );
if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
pNew->aLTerm[pNew->nLTerm++] = pTop;
pNew->wsFlags |= WHERE_TOP_LIMIT;
pNew->u.btree.nTop = 1;
}
}else{
assert( eOp & (WO_LT|WO_LE) );
testcase( eOp & WO_LT );
testcase( eOp & WO_LE );
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
pNew->u.btree.nTop = nVecLen;
pTop = pTerm;
pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
pNew->aLTerm[pNew->nLTerm-2] : 0;
}
}
/* At this point pNew->nOut is set to the number of rows expected to
** be visited by the index scan before considering term pTerm, or the
** values of nIn and nInMul. In other words, assuming that all
** "x IN(...)" terms are replaced with "x = ?". This block updates
** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */
|
| ︙ | ︙ | |||
157175 157176 157177 157178 157179 157180 157181 157182 157183 157184 157185 157186 157187 157188 |
&& (pTerm->wtFlags & TERM_VNULL)==0
){
return 1;
}
}
return 0;
}
/*
** Add all WhereLoop objects for a single table of the join where the table
** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
** a b-tree table, not a virtual table.
**
** The costs (WhereLoop.rRun) of the b-tree loops added by this function
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 158717 158718 158719 158720 158721 158722 158723 158724 158725 158726 158727 158728 158729 158730 158731 158732 158733 158734 158735 158736 158737 158738 158739 158740 158741 158742 158743 158744 158745 158746 158747 158748 158749 158750 158751 158752 158753 158754 158755 158756 158757 158758 158759 158760 158761 158762 158763 158764 158765 158766 158767 158768 158769 158770 158771 158772 158773 158774 158775 158776 158777 158778 158779 158780 158781 158782 158783 158784 158785 158786 158787 158788 158789 158790 158791 158792 158793 158794 158795 158796 158797 158798 158799 158800 158801 158802 158803 158804 158805 158806 158807 158808 158809 158810 158811 158812 158813 158814 158815 158816 158817 158818 |
&& (pTerm->wtFlags & TERM_VNULL)==0
){
return 1;
}
}
return 0;
}
/*
** Structure passed to the whereIsCoveringIndex Walker callback.
*/
struct CoveringIndexCheck {
Index *pIdx; /* The index */
int iTabCur; /* Cursor number for the corresponding table */
};
/*
** Information passed in is pWalk->u.pCovIdxCk. Call is pCk.
**
** If the Expr node references the table with cursor pCk->iTabCur, then
** make sure that column is covered by the index pCk->pIdx. We know that
** all columns less than 63 (really BMS-1) are covered, so we don't need
** to check them. But we do need to check any column at 63 or greater.
**
** If the index does not cover the column, then set pWalk->eCode to
** non-zero and return WRC_Abort to stop the search.
**
** If this node does not disprove that the index can be a covering index,
** then just return WRC_Continue, to continue the search.
*/
static int whereIsCoveringIndexWalkCallback(Walker *pWalk, Expr *pExpr){
int i; /* Loop counter */
const Index *pIdx; /* The index of interest */
const i16 *aiColumn; /* Columns contained in the index */
u16 nColumn; /* Number of columns in the index */
if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_AGG_COLUMN ) return WRC_Continue;
if( pExpr->iColumn<(BMS-1) ) return WRC_Continue;
if( pExpr->iTable!=pWalk->u.pCovIdxCk->iTabCur ) return WRC_Continue;
pIdx = pWalk->u.pCovIdxCk->pIdx;
aiColumn = pIdx->aiColumn;
nColumn = pIdx->nColumn;
for(i=0; i<nColumn; i++){
if( aiColumn[i]==pExpr->iColumn ) return WRC_Continue;
}
pWalk->eCode = 1;
return WRC_Abort;
}
/*
** pIdx is an index that covers all of the low-number columns used by
** pWInfo->pSelect (columns from 0 through 62). But there are columns
** in pWInfo->pSelect beyond 62. This routine tries to answer the question
** of whether pIdx covers *all* columns in the query.
**
** Return 0 if pIdx is a covering index. Return non-zero if pIdx is
** not a covering index or if we are unable to determine if pIdx is a
** covering index.
**
** This routine is an optimization. It is always safe to return non-zero.
** But returning zero when non-zero should have been returned can lead to
** incorrect bytecode and assertion faults.
*/
static SQLITE_NOINLINE u32 whereIsCoveringIndex(
WhereInfo *pWInfo, /* The WHERE clause context */
Index *pIdx, /* Index that is being tested */
int iTabCur /* Cursor for the table being indexed */
){
int i;
struct CoveringIndexCheck ck;
Walker w;
if( pWInfo->pSelect==0 ){
/* We don't have access to the full query, so we cannot check to see
** if pIdx is covering. Assume it is not. */
return 1;
}
for(i=0; i<pIdx->nColumn; i++){
if( pIdx->aiColumn[i]>=BMS-1 ) break;
}
if( i>=pIdx->nColumn ){
/* pIdx does not index any columns greater than 62, but we know from
** colMask that columns greater than 62 are used, so this is not a
** covering index */
return 1;
}
ck.pIdx = pIdx;
ck.iTabCur = iTabCur;
memset(&w, 0, sizeof(w));
w.xExprCallback = whereIsCoveringIndexWalkCallback;
w.xSelectCallback = sqlite3SelectWalkNoop;
w.u.pCovIdxCk = &ck;
w.eCode = 0;
sqlite3WalkSelect(&w, pWInfo->pSelect);
return w.eCode;
}
/*
** Add all WhereLoop objects for a single table of the join where the table
** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
** a b-tree table, not a virtual table.
**
** The costs (WhereLoop.rRun) of the b-tree loops added by this function
|
| ︙ | ︙ | |||
157378 157379 157380 157381 157382 157383 157384 157385 157386 157387 157388 157389 157390 157391 157392 157393 157394 157395 157396 157397 157398 157399 157400 157401 157402 157403 |
** better.
*/
#ifdef SQLITE_ENABLE_STAT4
pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0);
#else
pNew->rRun = rSize + 16;
#endif
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
}else{
Bitmask m;
if( pProbe->isCovering ){
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
m = 0;
}else{
m = pSrc->colUsed & pProbe->colNotIdxed;
pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
}
/* Full scan via index */
if( b
|| !HasRowid(pTab)
|| pProbe->pPartIdxWhere!=0
| > > > > > > | 159008 159009 159010 159011 159012 159013 159014 159015 159016 159017 159018 159019 159020 159021 159022 159023 159024 159025 159026 159027 159028 159029 159030 159031 159032 159033 159034 159035 159036 159037 159038 159039 |
** better.
*/
#ifdef SQLITE_ENABLE_STAT4
pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0);
#else
pNew->rRun = rSize + 16;
#endif
if( IsView(pTab) || (pTab->tabFlags & TF_Ephemeral)!=0 ){
pNew->wsFlags |= WHERE_VIEWSCAN;
}
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
if( rc ) break;
}else{
Bitmask m;
if( pProbe->isCovering ){
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
m = 0;
}else{
m = pSrc->colUsed & pProbe->colNotIdxed;
if( m==TOPBIT ){
m = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
}
pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
}
/* Full scan via index */
if( b
|| !HasRowid(pTab)
|| pProbe->pPartIdxWhere!=0
|
| ︙ | ︙ | |||
158104 158105 158106 158107 158108 158109 158110 | int bFirstPastRJ = 0; int hasRightJoin = 0; WhereLoop *pNew; /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; | | > > > > > > | 159740 159741 159742 159743 159744 159745 159746 159747 159748 159749 159750 159751 159752 159753 159754 159755 159756 159757 159758 159759 159760 |
int bFirstPastRJ = 0;
int hasRightJoin = 0;
WhereLoop *pNew;
/* Loop over the tables in the join, from left to right */
pNew = pBuilder->pNew;
/* Verify that pNew has already been initialized */
assert( pNew->nLTerm==0 );
assert( pNew->wsFlags==0 );
assert( pNew->nLSlot>=ArraySize(pNew->aLTermSpace) );
assert( pNew->aLTerm!=0 );
pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT;
for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
Bitmask mUnusable = 0;
pNew->iTab = iTab;
pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
if( bFirstPastRJ
|
| ︙ | ︙ | |||
158609 158610 158611 158612 158613 158614 158615 |
** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation
** error occurs.
*/
static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int mxChoice; /* Maximum number of simultaneous paths tracked */
int nLoop; /* Number of terms in the join */
Parse *pParse; /* Parsing context */
| < < | 160251 160252 160253 160254 160255 160256 160257 160258 160259 160260 160261 160262 160263 160264 160265 160266 160267 160268 160269 160270 160271 160272 160273 160274 160275 160276 160277 160278 160279 160280 160281 160282 |
** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation
** error occurs.
*/
static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int mxChoice; /* Maximum number of simultaneous paths tracked */
int nLoop; /* Number of terms in the join */
Parse *pParse; /* Parsing context */
int iLoop; /* Loop counter over the terms of the join */
int ii, jj; /* Loop counters */
int mxI = 0; /* Index of next entry to replace */
int nOrderBy; /* Number of ORDER BY clause terms */
LogEst mxCost = 0; /* Maximum cost of a set of paths */
LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
WherePath *aFrom; /* All nFrom paths at the previous level */
WherePath *aTo; /* The nTo best paths at the current level */
WherePath *pFrom; /* An element of aFrom[] that we are working on */
WherePath *pTo; /* An element of aTo[] that we are working on */
WhereLoop *pWLoop; /* One of the WhereLoop objects */
WhereLoop **pX; /* Used to divy up the pSpace memory */
LogEst *aSortCost = 0; /* Sorting and partial sorting costs */
char *pSpace; /* Temporary memory used by this routine */
int nSpace; /* Bytes of space allocated at pSpace */
pParse = pWInfo->pParse;
nLoop = pWInfo->nLevel;
/* TUNING: For simple queries, only the best path is tracked.
** For 2-way joins, the 5 best paths are followed.
** For joins of 3 or more tables, track the 10 best paths */
mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10);
assert( nLoop<=pWInfo->pTabList->nSrc );
WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst));
|
| ︙ | ︙ | |||
158651 158652 158653 158654 158655 158656 158657 |
}else{
nOrderBy = pWInfo->pOrderBy->nExpr;
}
/* Allocate and initialize space for aTo, aFrom and aSortCost[] */
nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
nSpace += sizeof(LogEst) * nOrderBy;
| | | 160291 160292 160293 160294 160295 160296 160297 160298 160299 160300 160301 160302 160303 160304 160305 |
}else{
nOrderBy = pWInfo->pOrderBy->nExpr;
}
/* Allocate and initialize space for aTo, aFrom and aSortCost[] */
nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
nSpace += sizeof(LogEst) * nOrderBy;
pSpace = sqlite3StackAllocRawNN(pParse->db, nSpace);
if( pSpace==0 ) return SQLITE_NOMEM_BKPT;
aTo = (WherePath*)pSpace;
aFrom = aTo+mxChoice;
memset(aFrom, 0, sizeof(aFrom[0]));
pX = (WhereLoop**)(aFrom+mxChoice);
for(ii=mxChoice*2, pFrom=aTo; ii>0; ii--, pFrom++, pX += nLoop){
pFrom->aLoop = pX;
|
| ︙ | ︙ | |||
158701 158702 158703 158704 158705 158706 158707 |
for(iLoop=0; iLoop<nLoop; iLoop++){
nTo = 0;
for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
LogEst rCost; /* Cost of path (pFrom+pWLoop) */
LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
| | | > > | 160341 160342 160343 160344 160345 160346 160347 160348 160349 160350 160351 160352 160353 160354 160355 160356 160357 160358 160359 160360 160361 160362 160363 160364 160365 160366 160367 160368 160369 160370 160371 160372 160373 160374 160375 160376 160377 160378 |
for(iLoop=0; iLoop<nLoop; iLoop++){
nTo = 0;
for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
LogEst rCost; /* Cost of path (pFrom+pWLoop) */
LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */
Bitmask maskNew; /* Mask of src visited by (..) */
Bitmask revMask; /* Mask of rev-order loops for (..) */
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<3 ){
/* Do not use an automatic index if the this loop is expected
** to run less than 1.25 times. It is tempting to also exclude
** automatic index usage on an outer loop, but sometimes an automatic
** index is useful in the outer loop of a correlated subquery. */
assert( 10==sqlite3LogEst(2) );
continue;
}
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
isOrdered = pFrom->isOrdered;
if( isOrdered<0 ){
revMask = 0;
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
iLoop, pWLoop, &revMask);
}else{
revMask = pFrom->revLoop;
}
if( isOrdered>=0 && isOrdered<nOrderBy ){
|
| ︙ | ︙ | |||
158749 158750 158751 158752 158753 158754 158755 158756 158757 158758 158759 158760 158761 158762 |
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy,
rUnsorted, rCost));
}else{
rCost = rUnsorted;
rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
/* Check to see if pWLoop should be added to the set of
** mxChoice best-so-far paths.
**
** First look for an existing path among best-so-far paths
** that covers the same set of loops and has the same isOrdered
** setting as the current path candidate.
| > > > > > > > | 160391 160392 160393 160394 160395 160396 160397 160398 160399 160400 160401 160402 160403 160404 160405 160406 160407 160408 160409 160410 160411 |
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy,
rUnsorted, rCost));
}else{
rCost = rUnsorted;
rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
/* TUNING: A full-scan of a VIEW or subquery in the outer loop
** is not so bad. */
if( iLoop==0 && (pWLoop->wsFlags & WHERE_VIEWSCAN)!=0 ){
rCost += -10;
nOut += -30;
}
/* Check to see if pWLoop should be added to the set of
** mxChoice best-so-far paths.
**
** First look for an existing path among best-so-far paths
** that covers the same set of loops and has the same isOrdered
** setting as the current path candidate.
|
| ︙ | ︙ | |||
158900 158901 158902 158903 158904 158905 158906 |
aTo = aFrom;
aFrom = pFrom;
nFrom = nTo;
}
if( nFrom==0 ){
sqlite3ErrorMsg(pParse, "no query solution");
| | | 160549 160550 160551 160552 160553 160554 160555 160556 160557 160558 160559 160560 160561 160562 160563 |
aTo = aFrom;
aFrom = pFrom;
nFrom = nTo;
}
if( nFrom==0 ){
sqlite3ErrorMsg(pParse, "no query solution");
sqlite3StackFreeNN(pParse->db, pSpace);
return SQLITE_ERROR;
}
/* Find the lowest cost path. pFrom will be left pointing to that path */
pFrom = aFrom;
for(ii=1; ii<nFrom; ii++){
if( pFrom->rCost>aFrom[ii].rCost ) pFrom = &aFrom[ii];
|
| ︙ | ︙ | |||
158982 158983 158984 158985 158986 158987 158988 |
}
}
pWInfo->nRowOut = pFrom->nRow;
/* Free temporary memory and return success */
| | | 160631 160632 160633 160634 160635 160636 160637 160638 160639 160640 160641 160642 160643 160644 160645 |
}
}
pWInfo->nRowOut = pFrom->nRow;
/* Free temporary memory and return success */
sqlite3StackFreeNN(pParse->db, pSpace);
return SQLITE_OK;
}
/*
** 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
|
| ︙ | ︙ | |||
159280 159281 159282 159283 159284 159285 159286 159287 159288 159289 159290 159291 159292 159293 |
pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName,
(double)sqlite3LogEstToInt(pTab->nRowLogEst)));
}
}
nSearch += pLoop->nOut;
}
}
/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop. Later, the calling routine
** should invoke sqlite3WhereEnd() with the return value of this function
** in order to complete the WHERE clause processing.
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 160929 160930 160931 160932 160933 160934 160935 160936 160937 160938 160939 160940 160941 160942 160943 160944 160945 160946 160947 160948 160949 160950 160951 160952 160953 160954 160955 160956 160957 160958 160959 160960 160961 160962 160963 160964 160965 160966 160967 160968 160969 160970 160971 160972 160973 160974 160975 160976 160977 160978 160979 160980 160981 160982 160983 160984 160985 160986 160987 160988 160989 160990 160991 160992 160993 160994 160995 160996 160997 160998 160999 161000 161001 161002 161003 161004 161005 161006 161007 161008 161009 161010 161011 161012 161013 |
pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName,
(double)sqlite3LogEstToInt(pTab->nRowLogEst)));
}
}
nSearch += pLoop->nOut;
}
}
/*
** This is an sqlite3ParserAddCleanup() callback that is invoked to
** free the Parse->pIdxExpr list when the Parse object is destroyed.
*/
static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){
Parse *pParse = (Parse*)pObject;
while( pParse->pIdxExpr!=0 ){
IndexedExpr *p = pParse->pIdxExpr;
pParse->pIdxExpr = p->pIENext;
sqlite3ExprDelete(db, p->pExpr);
sqlite3DbFreeNN(db, p);
}
}
/*
** The index pIdx is used by a query and contains one or more expressions.
** In other words pIdx is an index on an expression. iIdxCur is the cursor
** number for the index and iDataCur is the cursor number for the corresponding
** table.
**
** This routine adds IndexedExpr entries to the Parse->pIdxExpr field for
** each of the expressions in the index so that the expression code generator
** will know to replace occurrences of the indexed expression with
** references to the corresponding column of the index.
*/
static SQLITE_NOINLINE void whereAddIndexedExpr(
Parse *pParse, /* Add IndexedExpr entries to pParse->pIdxExpr */
Index *pIdx, /* The index-on-expression that contains the expressions */
int iIdxCur, /* Cursor number for pIdx */
SrcItem *pTabItem /* The FROM clause entry for the table */
){
int i;
IndexedExpr *p;
Table *pTab;
assert( pIdx->bHasExpr );
pTab = pIdx->pTable;
for(i=0; i<pIdx->nColumn; 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(pExpr) ) continue;
p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
if( p==0 ) break;
p->pIENext = pParse->pIdxExpr;
p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
p->iDataCur = pTabItem->iCursor;
p->iIdxCur = iIdxCur;
p->iIdxCol = i;
p->bMaybeNullRow = bMaybeNullRow;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
p->zIdxName = pIdx->zName;
#endif
pParse->pIdxExpr = p;
if( p->pIENext==0 ){
sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pParse);
}
}
}
/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop. Later, the calling routine
** should invoke sqlite3WhereEnd() with the return value of this function
** in order to complete the WHERE clause processing.
|
| ︙ | ︙ | |||
159375 159376 159377 159378 159379 159380 159381 | */ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */ | | | 161095 161096 161097 161098 161099 161100 161101 161102 161103 161104 161105 161106 161107 161108 161109 |
*/
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */
Select *pSelect, /* The entire SELECT statement */
u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number
** If WHERE_USE_LIMIT, then the limit amount */
){
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
int nTabList; /* Number of elements in pTabList */
WhereInfo *pWInfo; /* Will become the return value of this function */
|
| ︙ | ︙ | |||
159444 159445 159446 159447 159448 159449 159450 159451 159452 159453 159454 159455 159456 159457 159458 |
sqlite3DbFree(db, pWInfo);
pWInfo = 0;
goto whereBeginError;
}
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
pWInfo->pWhere = pWhere;
pWInfo->pResultSet = pResultSet;
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
pWInfo->nLevel = nTabList;
pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(pParse);
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->iLimit = iAuxArg;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
| > > < | < | 161164 161165 161166 161167 161168 161169 161170 161171 161172 161173 161174 161175 161176 161177 161178 161179 161180 161181 161182 161183 161184 161185 161186 161187 161188 |
sqlite3DbFree(db, pWInfo);
pWInfo = 0;
goto whereBeginError;
}
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
#if WHERETRACE_ENABLED
pWInfo->pWhere = pWhere;
#endif
pWInfo->pResultSet = pResultSet;
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
pWInfo->nLevel = nTabList;
pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(pParse);
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->iLimit = iAuxArg;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
pWInfo->pSelect = pSelect;
memset(&pWInfo->nOBSat, 0,
offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */
pMaskSet = &pWInfo->sMaskSet;
pMaskSet->n = 0;
pMaskSet->ix[0] = -99; /* Initialize ix[0] to a value that can never be
|
| ︙ | ︙ | |||
159523 159524 159525 159526 159527 159528 159529 |
}
}
#endif
}
/* Analyze all of the subexpressions. */
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
| > | > | 161243 161244 161245 161246 161247 161248 161249 161250 161251 161252 161253 161254 161255 161256 161257 161258 161259 |
}
}
#endif
}
/* Analyze all of the subexpressions. */
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
if( pSelect && pSelect->pLimit ){
sqlite3WhereAddLimit(&pWInfo->sWC, pSelect);
}
if( pParse->nErr ) goto whereBeginError;
/* Special case: WHERE terms that do not refer to any tables in the join
** (constant expressions). Evaluate each such term, and jump over all the
** generated code if the result is not true.
**
** Do not do this if the expression contains non-deterministic functions
|
| ︙ | ︙ | |||
159826 159827 159828 159829 159830 159831 159832 159833 159834 159835 159836 159837 159838 159839 |
op = OP_OpenWrite;
pWInfo->aiCurOnePass[1] = iIndexCur;
}else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){
iIndexCur = iAuxArg;
op = OP_ReopenIdx;
}else{
iIndexCur = pParse->nTab++;
}
pLevel->iIdxCur = iIndexCur;
assert( pIx!=0 );
assert( pIx->pSchema==pTab->pSchema );
assert( iIndexCur>=0 );
if( op ){
sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
| > > > | 161548 161549 161550 161551 161552 161553 161554 161555 161556 161557 161558 161559 161560 161561 161562 161563 161564 |
op = OP_OpenWrite;
pWInfo->aiCurOnePass[1] = iIndexCur;
}else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){
iIndexCur = iAuxArg;
op = OP_ReopenIdx;
}else{
iIndexCur = pParse->nTab++;
if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){
whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem);
}
}
pLevel->iIdxCur = iIndexCur;
assert( pIx!=0 );
assert( pIx->pSchema==pTab->pSchema );
assert( iIndexCur>=0 );
if( op ){
sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
|
| ︙ | ︙ | |||
159948 159949 159950 159951 159952 159953 159954 |
VdbeModuleComment((v, "Begin WHERE-core"));
pWInfo->iEndWhere = sqlite3VdbeCurrentAddr(v);
return pWInfo;
/* Jump here if malloc fails */
whereBeginError:
if( pWInfo ){
| < < | 161673 161674 161675 161676 161677 161678 161679 161680 161681 161682 161683 161684 161685 161686 |
VdbeModuleComment((v, "Begin WHERE-core"));
pWInfo->iEndWhere = sqlite3VdbeCurrentAddr(v);
return pWInfo;
/* Jump here if malloc fails */
whereBeginError:
if( pWInfo ){
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
}
return 0;
}
/*
|
| ︙ | ︙ | |||
160168 160169 160170 160171 160172 160173 160174 |
sqlite3VdbeJumpHere(v, addr);
}
VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
}
assert( pWInfo->nLevel<=pTabList->nSrc );
| < | 161891 161892 161893 161894 161895 161896 161897 161898 161899 161900 161901 161902 161903 161904 |
sqlite3VdbeJumpHere(v, addr);
}
VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
}
assert( pWInfo->nLevel<=pTabList->nSrc );
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
int k, last;
VdbeOp *pOp, *pLastOp;
Index *pIdx = 0;
SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
Table *pTab = pTabItem->pTab;
assert( pTab!=0 );
|
| ︙ | ︙ | |||
160221 160222 160223 160224 160225 160226 160227 160228 160229 160230 160231 160232 160233 160234 |
if( pIdx
&& !db->mallocFailed
){
if( pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable) ){
last = iEnd;
}else{
last = pWInfo->iEndWhere;
}
k = pLevel->addrBody + 1;
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeAddopTrace ){
printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
}
/* Proof that the "+1" on the k value above is safe */
| > > > > > > > > > > | 161943 161944 161945 161946 161947 161948 161949 161950 161951 161952 161953 161954 161955 161956 161957 161958 161959 161960 161961 161962 161963 161964 161965 161966 |
if( pIdx
&& !db->mallocFailed
){
if( pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable) ){
last = iEnd;
}else{
last = pWInfo->iEndWhere;
}
if( pIdx->bHasExpr ){
IndexedExpr *p = pParse->pIdxExpr;
while( p ){
if( p->iIdxCur==pLevel->iIdxCur ){
p->iDataCur = -1;
p->iIdxCur = -1;
}
p = p->pIENext;
}
}
k = pLevel->addrBody + 1;
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeAddopTrace ){
printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
}
/* Proof that the "+1" on the k value above is safe */
|
| ︙ | ︙ | |||
161215 161216 161217 161218 161219 161220 161221 |
){
if( pAppend ){
int i;
int nInit = pList ? pList->nExpr : 0;
for(i=0; i<pAppend->nExpr; i++){
sqlite3 *db = pParse->db;
Expr *pDup = sqlite3ExprDup(db, pAppend->a[i].pExpr, 0);
| < | 162947 162948 162949 162950 162951 162952 162953 162954 162955 162956 162957 162958 162959 162960 |
){
if( pAppend ){
int i;
int nInit = pList ? pList->nExpr : 0;
for(i=0; i<pAppend->nExpr; i++){
sqlite3 *db = pParse->db;
Expr *pDup = sqlite3ExprDup(db, pAppend->a[i].pExpr, 0);
if( db->mallocFailed ){
sqlite3ExprDelete(db, pDup);
break;
}
if( bIntToNull ){
int iDummy;
Expr *pSub;
|
| ︙ | ︙ | |||
162486 162487 162488 162489 162490 162491 162492 |
break;
default: assert( op==OP_Lt ); /* no-op */ break;
}
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone);
/* This block runs if reg1 is not NULL, but reg2 is. */
sqlite3VdbeJumpHere(v, addr);
| | | | < | 164217 164218 164219 164220 164221 164222 164223 164224 164225 164226 164227 164228 164229 164230 164231 164232 164233 |
break;
default: assert( op==OP_Lt ); /* no-op */ break;
}
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone);
/* This block runs if reg1 is not NULL, but reg2 is. */
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp2(v, OP_IsNull, reg2,
(op==OP_Gt || op==OP_Ge) ? addrDone : lbl);
VdbeCoverage(v);
}
/* Register reg1 currently contains csr1.peerVal (the peer-value from csr1).
** This block adds (or subtracts for DESC) the numeric value in regVal
** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob),
** then leave reg1 as it is. In pseudo-code, this is implemented as:
**
|
| ︙ | ︙ | |||
170066 170067 170068 170069 170070 170071 170072 |
** will take responsibility for freeing the Table structure.
*/
sqlite3DeleteTable(db, pParse->pNewTable);
}
if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
}
| | | 171796 171797 171798 171799 171800 171801 171802 171803 171804 171805 171806 171807 171808 171809 171810 |
** will take responsibility for freeing the Table structure.
*/
sqlite3DeleteTable(db, pParse->pNewTable);
}
if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
}
if( pParse->pVList ) sqlite3DbNNFreeNN(db, pParse->pVList);
db->pParse = pParentParse;
assert( nErr==0 || pParse->rc!=SQLITE_OK );
return nErr;
}
#ifdef SQLITE_ENABLE_NORMALIZE
|
| ︙ | ︙ | |||
171422 171423 171424 171425 171426 171427 171428 |
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
assert( ((uptr)p)<=szAlloc + (uptr)pStart );
db->lookaside.pEnd = p;
db->lookaside.bDisable = 0;
db->lookaside.bMalloced = pBuf==0 ?1:0;
db->lookaside.nSlot = nBig+nSm;
}else{
| | | | > | 173152 173153 173154 173155 173156 173157 173158 173159 173160 173161 173162 173163 173164 173165 173166 173167 173168 173169 173170 173171 173172 173173 173174 173175 173176 173177 173178 |
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
assert( ((uptr)p)<=szAlloc + (uptr)pStart );
db->lookaside.pEnd = p;
db->lookaside.bDisable = 0;
db->lookaside.bMalloced = pBuf==0 ?1:0;
db->lookaside.nSlot = nBig+nSm;
}else{
db->lookaside.pStart = 0;
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
db->lookaside.pSmallInit = 0;
db->lookaside.pSmallFree = 0;
db->lookaside.pMiddle = 0;
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
db->lookaside.pEnd = 0;
db->lookaside.bDisable = 1;
db->lookaside.sz = 0;
db->lookaside.bMalloced = 0;
db->lookaside.nSlot = 0;
}
db->lookaside.pTrueEnd = db->lookaside.pEnd;
assert( sqlite3LookasideUsed(db,0)==0 );
#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
}
/*
** Return the mutex associated with a database connection.
|
| ︙ | ︙ | |||
171512 171513 171514 171515 171516 171517 171518 171519 171520 171521 171522 171523 171524 171525 |
/*
** Configuration settings for an individual database connection
*/
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
va_start(ap, op);
switch( op ){
case SQLITE_DBCONFIG_MAINDBNAME: {
/* IMP: R-06824-28531 */
/* IMP: R-36257-52125 */
db->aDb[0].zDbSName = va_arg(ap,char*);
rc = SQLITE_OK;
| > | 173243 173244 173245 173246 173247 173248 173249 173250 173251 173252 173253 173254 173255 173256 173257 |
/*
** Configuration settings for an individual database connection
*/
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
sqlite3_mutex_enter(db->mutex);
va_start(ap, op);
switch( op ){
case SQLITE_DBCONFIG_MAINDBNAME: {
/* IMP: R-06824-28531 */
/* IMP: R-36257-52125 */
db->aDb[0].zDbSName = va_arg(ap,char*);
rc = SQLITE_OK;
|
| ︙ | ︙ | |||
171577 171578 171579 171580 171581 171582 171583 171584 171585 171586 171587 171588 171589 171590 |
break;
}
}
break;
}
}
va_end(ap);
return rc;
}
/*
** This is the default collating function named "BINARY" which is always
** available.
*/
| > | 173309 173310 173311 173312 173313 173314 173315 173316 173317 173318 173319 173320 173321 173322 173323 |
break;
}
}
break;
}
}
va_end(ap);
sqlite3_mutex_leave(db->mutex);
return rc;
}
/*
** This is the default collating function named "BINARY" which is always
** available.
*/
|
| ︙ | ︙ | |||
173947 173948 173949 173950 173951 173952 173953 173954 173955 173956 173957 173958 173959 173960 |
createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0);
createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0);
if( db->mallocFailed ){
goto opendb_out;
}
/* Parse the filename/URI argument
**
** Only allow sensible combinations of bits in the flags argument.
** Throw an error if any non-sense combination is used. If we
** do not block illegal combinations here, it could trigger
** assert() statements in deeper layers. Sensible combinations
** are:
| > > > > > > > > > > > > > | 175680 175681 175682 175683 175684 175685 175686 175687 175688 175689 175690 175691 175692 175693 175694 175695 175696 175697 175698 175699 175700 175701 175702 175703 175704 175705 175706 |
createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0);
createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0);
if( db->mallocFailed ){
goto opendb_out;
}
#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
/* Process magic filenames ":localStorage:" and ":sessionStorage:" */
if( zFilename && zFilename[0]==':' ){
if( strcmp(zFilename, ":localStorage:")==0 ){
zFilename = "file:local?vfs=kvvfs";
flags |= SQLITE_OPEN_URI;
}else if( strcmp(zFilename, ":sessionStorage:")==0 ){
zFilename = "file:session?vfs=kvvfs";
flags |= SQLITE_OPEN_URI;
}
}
#endif /* SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) */
/* Parse the filename/URI argument
**
** Only allow sensible combinations of bits in the flags argument.
** Throw an error if any non-sense combination is used. If we
** do not block illegal combinations here, it could trigger
** assert() statements in deeper layers. Sensible combinations
** are:
|
| ︙ | ︙ | |||
175376 175377 175378 175379 175380 175381 175382 |
/*
** Recover as many snapshots as possible from the wal file associated with
** schema zDb of database db.
*/
SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
int rc = SQLITE_ERROR;
| < > | 177122 177123 177124 177125 177126 177127 177128 177129 177130 177131 177132 177133 177134 177135 177136 177137 |
/*
** Recover as many snapshots as possible from the wal file associated with
** schema zDb of database db.
*/
SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
int rc = SQLITE_ERROR;
#ifndef SQLITE_OMIT_WAL
int iDb;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE_BKPT;
}
#endif
|
| ︙ | ︙ | |||
176932 176933 176934 176935 176936 176937 176938 |
struct Fts3MultiSegReader {
/* Used internally by sqlite3Fts3SegReaderXXX() calls */
Fts3SegReader **apSegment; /* Array of Fts3SegReader objects */
int nSegment; /* Size of apSegment array */
int nAdvance; /* How many seg-readers to advance */
Fts3SegFilter *pFilter; /* Pointer to filter object */
char *aBuffer; /* Buffer to merge doclists in */
| | | 178678 178679 178680 178681 178682 178683 178684 178685 178686 178687 178688 178689 178690 178691 178692 |
struct Fts3MultiSegReader {
/* Used internally by sqlite3Fts3SegReaderXXX() calls */
Fts3SegReader **apSegment; /* Array of Fts3SegReader objects */
int nSegment; /* Size of apSegment array */
int nAdvance; /* How many seg-readers to advance */
Fts3SegFilter *pFilter; /* Pointer to filter object */
char *aBuffer; /* Buffer to merge doclists in */
i64 nBuffer; /* Allocated size of aBuffer[] in bytes */
int iColFilter; /* If >=0, filter for this column */
int bRestart;
/* Used by fts3.c only. */
int nCost; /* Cost of running iterator */
int bLookup; /* True if a lookup of a single entry. */
|
| ︙ | ︙ | |||
179628 179629 179630 179631 179632 179633 179634 |
** not true for order=DESC. For example, a doclist containing (1, -1)
** may be smaller than (-1), as in the first example the -1 may be stored
** as a single-byte delta, whereas in the second it must be stored as a
** FTS3_VARINT_MAX byte varint.
**
** Similar padding is added in the fts3DoclistOrMerge() function.
*/
| | | 181374 181375 181376 181377 181378 181379 181380 181381 181382 181383 181384 181385 181386 181387 181388 |
** not true for order=DESC. For example, a doclist containing (1, -1)
** may be smaller than (-1), as in the first example the -1 may be stored
** as a single-byte delta, whereas in the second it must be stored as a
** FTS3_VARINT_MAX byte varint.
**
** Similar padding is added in the fts3DoclistOrMerge() function.
*/
pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1);
pTS->anOutput[0] = nDoclist;
if( pTS->aaOutput[0] ){
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
memset(&pTS->aaOutput[0][nDoclist], 0, FTS3_VARINT_MAX);
}else{
return SQLITE_NOMEM;
}
|
| ︙ | ︙ | |||
181116 181117 181118 181119 181120 181121 181122 |
nDistance = nMaxUndeferred - iPrev;
}else{
p1 = pPhrase->doclist.pList;
p2 = aPoslist;
nDistance = iPrev - nMaxUndeferred;
}
| | | 182862 182863 182864 182865 182866 182867 182868 182869 182870 182871 182872 182873 182874 182875 182876 |
nDistance = nMaxUndeferred - iPrev;
}else{
p1 = pPhrase->doclist.pList;
p2 = aPoslist;
nDistance = iPrev - nMaxUndeferred;
}
aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING);
if( !aOut ){
sqlite3_free(aPoslist);
return SQLITE_NOMEM;
}
pPhrase->doclist.pList = aOut;
assert( p1 && p2 );
|
| ︙ | ︙ | |||
181485 181486 181487 181488 181489 181490 181491 |
}
}
/* Check if the current entries really are a phrase match */
if( bEof==0 ){
int nList = 0;
int nByte = a[p->nToken-1].nList;
| | | 183231 183232 183233 183234 183235 183236 183237 183238 183239 183240 183241 183242 183243 183244 183245 |
}
}
/* Check if the current entries really are a phrase match */
if( bEof==0 ){
int nList = 0;
int nByte = a[p->nToken-1].nList;
char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING);
if( !aDoclist ) return SQLITE_NOMEM;
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
for(i=0; i<(p->nToken-1); i++){
if( a[i].bIgnore==0 ){
char *pL = a[i].pList;
|
| ︙ | ︙ | |||
185721 185722 185723 185724 185725 185726 185727 |
}
if( c->iOffset>iStartOffset ){
int n = c->iOffset-iStartOffset;
if( n>c->nAllocated ){
char *pNew;
c->nAllocated = n+20;
| | | 187467 187468 187469 187470 187471 187472 187473 187474 187475 187476 187477 187478 187479 187480 187481 |
}
if( c->iOffset>iStartOffset ){
int n = c->iOffset-iStartOffset;
if( n>c->nAllocated ){
char *pNew;
c->nAllocated = n+20;
pNew = sqlite3_realloc64(c->zToken, c->nAllocated);
if( !pNew ) return SQLITE_NOMEM;
c->zToken = pNew;
}
porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes);
*pzToken = c->zToken;
*piStartOffset = iStartOffset;
*piEndOffset = c->iOffset;
|
| ︙ | ︙ | |||
186473 186474 186475 186476 186477 186478 186479 |
}
if( c->iOffset>iStartOffset ){
int i, n = c->iOffset-iStartOffset;
if( n>c->nTokenAllocated ){
char *pNew;
c->nTokenAllocated = n+20;
| | | 188219 188220 188221 188222 188223 188224 188225 188226 188227 188228 188229 188230 188231 188232 188233 |
}
if( c->iOffset>iStartOffset ){
int i, n = c->iOffset-iStartOffset;
if( n>c->nTokenAllocated ){
char *pNew;
c->nTokenAllocated = n+20;
pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated);
if( !pNew ) return SQLITE_NOMEM;
c->pToken = pNew;
}
for(i=0; i<n; i++){
/* TODO(shess) This needs expansion to handle UTF-8
** case-insensitivity.
*/
|
| ︙ | ︙ | |||
187635 187636 187637 187638 187639 187640 187641 |
PendingList **pp, /* IN/OUT: Pointer to PendingList struct */
sqlite3_int64 i /* Value to append to data */
){
PendingList *p = *pp;
/* Allocate or grow the PendingList as required. */
if( !p ){
| | | | | | 189381 189382 189383 189384 189385 189386 189387 189388 189389 189390 189391 189392 189393 189394 189395 189396 189397 189398 189399 189400 189401 189402 189403 189404 189405 189406 189407 189408 189409 189410 189411 |
PendingList **pp, /* IN/OUT: Pointer to PendingList struct */
sqlite3_int64 i /* Value to append to data */
){
PendingList *p = *pp;
/* Allocate or grow the PendingList as required. */
if( !p ){
p = sqlite3_malloc64(sizeof(*p) + 100);
if( !p ){
return SQLITE_NOMEM;
}
p->nSpace = 100;
p->aData = (char *)&p[1];
p->nData = 0;
}
else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){
i64 nNew = p->nSpace * 2;
p = sqlite3_realloc64(p, sizeof(*p) + nNew);
if( !p ){
sqlite3_free(*pp);
*pp = 0;
return SQLITE_NOMEM;
}
p->nSpace = (int)nNew;
p->aData = (char *)&p[1];
}
/* Append the new serialized varint to the end of the list. */
p->nData += sqlite3Fts3PutVarint(&p->aData[p->nData], i);
p->aData[p->nData] = '\0';
*pp = p;
|
| ︙ | ︙ | |||
188208 188209 188210 188211 188212 188213 188214 |
);
}
if( rc==SQLITE_OK ){
int nByte = sqlite3_blob_bytes(p->pSegments);
*pnBlob = nByte;
if( paBlob ){
| | | 189954 189955 189956 189957 189958 189959 189960 189961 189962 189963 189964 189965 189966 189967 189968 |
);
}
if( rc==SQLITE_OK ){
int nByte = sqlite3_blob_bytes(p->pSegments);
*pnBlob = nByte;
if( paBlob ){
char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING);
if( !aByte ){
rc = SQLITE_NOMEM;
}else{
if( pnLoad && nByte>(FTS3_NODE_CHUNK_THRESHOLD) ){
nByte = FTS3_NODE_CHUNKSIZE;
*pnLoad = nByte;
}
|
| ︙ | ︙ | |||
188325 188326 188327 188328 188329 188330 188331 |
char *aCopy;
PendingList *pList = (PendingList *)fts3HashData(pElem);
int nCopy = pList->nData+1;
int nTerm = fts3HashKeysize(pElem);
if( (nTerm+1)>pReader->nTermAlloc ){
sqlite3_free(pReader->zTerm);
| | | | 190071 190072 190073 190074 190075 190076 190077 190078 190079 190080 190081 190082 190083 190084 190085 190086 190087 190088 190089 190090 190091 190092 190093 |
char *aCopy;
PendingList *pList = (PendingList *)fts3HashData(pElem);
int nCopy = pList->nData+1;
int nTerm = fts3HashKeysize(pElem);
if( (nTerm+1)>pReader->nTermAlloc ){
sqlite3_free(pReader->zTerm);
pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2);
if( !pReader->zTerm ) return SQLITE_NOMEM;
pReader->nTermAlloc = (nTerm+1)*2;
}
memcpy(pReader->zTerm, fts3HashKey(pElem), nTerm);
pReader->zTerm[nTerm] = '\0';
pReader->nTerm = nTerm;
aCopy = (char*)sqlite3_malloc64(nCopy);
if( !aCopy ) return SQLITE_NOMEM;
memcpy(aCopy, pList->aData, nCopy);
pReader->nNode = pReader->nDoclist = nCopy;
pReader->aNode = pReader->aDoclist = aCopy;
pReader->ppNextElem++;
assert( pReader->aNode );
}
|
| ︙ | ︙ | |||
188620 188621 188622 188623 188624 188625 188626 |
#endif
if( iStartLeaf==0 ){
if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB;
nExtra = nRoot + FTS3_NODE_PADDING;
}
| | | 190366 190367 190368 190369 190370 190371 190372 190373 190374 190375 190376 190377 190378 190379 190380 |
#endif
if( iStartLeaf==0 ){
if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB;
nExtra = nRoot + FTS3_NODE_PADDING;
}
pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra);
if( !pReader ){
return SQLITE_NOMEM;
}
memset(pReader, 0, sizeof(Fts3SegReader));
pReader->iIdx = iAge;
pReader->bLookup = bLookup!=0;
pReader->iStartBlock = iStartLeaf;
|
| ︙ | ︙ | |||
188712 188713 188714 188715 188716 188717 188718 |
for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){
char *zKey = (char *)fts3HashKey(pE);
int nKey = fts3HashKeysize(pE);
if( nTerm==0 || (nKey>=nTerm && 0==memcmp(zKey, zTerm, nTerm)) ){
if( nElem==nAlloc ){
Fts3HashElem **aElem2;
nAlloc += 16;
| | | 190458 190459 190460 190461 190462 190463 190464 190465 190466 190467 190468 190469 190470 190471 190472 |
for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){
char *zKey = (char *)fts3HashKey(pE);
int nKey = fts3HashKeysize(pE);
if( nTerm==0 || (nKey>=nTerm && 0==memcmp(zKey, zTerm, nTerm)) ){
if( nElem==nAlloc ){
Fts3HashElem **aElem2;
nAlloc += 16;
aElem2 = (Fts3HashElem **)sqlite3_realloc64(
aElem, nAlloc*sizeof(Fts3HashElem *)
);
if( !aElem2 ){
rc = SQLITE_NOMEM;
nElem = 0;
break;
}
|
| ︙ | ︙ | |||
189046 189047 189048 189049 189050 189051 189052 |
** and the static node buffer (p->nNodeSize bytes) is not large
** enough. Use a separately malloced buffer instead This wastes
** p->nNodeSize bytes, but since this scenario only comes about when
** the database contain two terms that share a prefix of almost 2KB,
** this is not expected to be a serious problem.
*/
assert( pTree->aData==(char *)&pTree[1] );
| | | | 190792 190793 190794 190795 190796 190797 190798 190799 190800 190801 190802 190803 190804 190805 190806 190807 190808 190809 190810 190811 190812 190813 190814 190815 190816 190817 190818 190819 190820 190821 190822 190823 190824 |
** and the static node buffer (p->nNodeSize bytes) is not large
** enough. Use a separately malloced buffer instead This wastes
** p->nNodeSize bytes, but since this scenario only comes about when
** the database contain two terms that share a prefix of almost 2KB,
** this is not expected to be a serious problem.
*/
assert( pTree->aData==(char *)&pTree[1] );
pTree->aData = (char *)sqlite3_malloc64(nReq);
if( !pTree->aData ){
return SQLITE_NOMEM;
}
}
if( pTree->zTerm ){
/* There is no prefix-length field for first term in a node */
nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nPrefix);
}
nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nSuffix);
memcpy(&pTree->aData[nData], &zTerm[nPrefix], nSuffix);
pTree->nData = nData + nSuffix;
pTree->nEntry++;
if( isCopyTerm ){
if( pTree->nMalloc<nTerm ){
char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2);
if( !zNew ){
return SQLITE_NOMEM;
}
pTree->nMalloc = nTerm*2;
pTree->zMalloc = zNew;
}
pTree->zTerm = pTree->zMalloc;
|
| ︙ | ︙ | |||
189090 189091 189092 189093 189094 189095 189096 | ** current node. Create a new node (a right-sibling of the current node). ** If this is the first node in the tree, the term is added to it. ** ** Otherwise, the term is not added to the new node, it is left empty for ** now. Instead, the term is inserted into the parent of pTree. If pTree ** has no parent, one is created here. */ | | | 190836 190837 190838 190839 190840 190841 190842 190843 190844 190845 190846 190847 190848 190849 190850 |
** current node. Create a new node (a right-sibling of the current node).
** If this is the first node in the tree, the term is added to it.
**
** Otherwise, the term is not added to the new node, it is left empty for
** now. Instead, the term is inserted into the parent of pTree. If pTree
** has no parent, one is created here.
*/
pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize);
if( !pNew ){
return SQLITE_NOMEM;
}
memset(pNew, 0, sizeof(SegmentNode));
pNew->nData = 1 + FTS3_VARINT_MAX;
pNew->aData = (char *)&pNew[1];
|
| ︙ | ︙ | |||
189228 189229 189230 189231 189232 189233 189234 |
const char *zTerm, /* Pointer to buffer containing term */
int nTerm, /* Size of term in bytes */
const char *aDoclist, /* Pointer to buffer containing doclist */
int nDoclist /* Size of doclist in bytes */
){
int nPrefix; /* Size of term prefix in bytes */
int nSuffix; /* Size of term suffix in bytes */
| | | | | 190974 190975 190976 190977 190978 190979 190980 190981 190982 190983 190984 190985 190986 190987 190988 190989 190990 190991 190992 190993 190994 190995 190996 190997 190998 190999 191000 191001 191002 191003 |
const char *zTerm, /* Pointer to buffer containing term */
int nTerm, /* Size of term in bytes */
const char *aDoclist, /* Pointer to buffer containing doclist */
int nDoclist /* Size of doclist in bytes */
){
int nPrefix; /* Size of term prefix in bytes */
int nSuffix; /* Size of term suffix in bytes */
i64 nReq; /* Number of bytes required on leaf page */
int nData;
SegmentWriter *pWriter = *ppWriter;
if( !pWriter ){
int rc;
sqlite3_stmt *pStmt;
/* Allocate the SegmentWriter structure */
pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter));
if( !pWriter ) return SQLITE_NOMEM;
memset(pWriter, 0, sizeof(SegmentWriter));
*ppWriter = pWriter;
/* Allocate a buffer in which to accumulate data */
pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize);
if( !pWriter->aData ) return SQLITE_NOMEM;
pWriter->nSize = p->nNodeSize;
/* Find the next free blockid in the %_segments table */
rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pStmt, 0);
if( rc!=SQLITE_OK ) return rc;
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
| ︙ | ︙ | |||
189318 189319 189320 189321 189322 189323 189324 |
/* Increase the total number of bytes written to account for the new entry. */
pWriter->nLeafData += nReq;
/* If the buffer currently allocated is too small for this entry, realloc
** the buffer to make it large enough.
*/
if( nReq>pWriter->nSize ){
| | | 191064 191065 191066 191067 191068 191069 191070 191071 191072 191073 191074 191075 191076 191077 191078 |
/* Increase the total number of bytes written to account for the new entry. */
pWriter->nLeafData += nReq;
/* If the buffer currently allocated is too small for this entry, realloc
** the buffer to make it large enough.
*/
if( nReq>pWriter->nSize ){
char *aNew = sqlite3_realloc64(pWriter->aData, nReq);
if( !aNew ) return SQLITE_NOMEM;
pWriter->aData = aNew;
pWriter->nSize = nReq;
}
assert( nData+nReq<=pWriter->nSize );
/* Append the prefix-compressed term and doclist to the buffer. */
|
| ︙ | ︙ | |||
189343 189344 189345 189346 189347 189348 189349 |
/* Save the current term so that it can be used to prefix-compress the next.
** If the isCopyTerm parameter is true, then the buffer pointed to by
** zTerm is transient, so take a copy of the term data. Otherwise, just
** store a copy of the pointer.
*/
if( isCopyTerm ){
if( nTerm>pWriter->nMalloc ){
| | | 191089 191090 191091 191092 191093 191094 191095 191096 191097 191098 191099 191100 191101 191102 191103 |
/* Save the current term so that it can be used to prefix-compress the next.
** If the isCopyTerm parameter is true, then the buffer pointed to by
** zTerm is transient, so take a copy of the term data. Otherwise, just
** store a copy of the pointer.
*/
if( isCopyTerm ){
if( nTerm>pWriter->nMalloc ){
char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2);
if( !zNew ){
return SQLITE_NOMEM;
}
pWriter->nMalloc = nTerm*2;
pWriter->zMalloc = zNew;
pWriter->zTerm = zNew;
}
|
| ︙ | ︙ | |||
189651 189652 189653 189654 189655 189656 189657 | ** ** If successful, return SQLITE_OK. Otherwise, if an OOM error is encountered ** trying to resize the buffer, return SQLITE_NOMEM. */ static int fts3MsrBufferData( Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ char *pList, | | | | 191397 191398 191399 191400 191401 191402 191403 191404 191405 191406 191407 191408 191409 191410 191411 191412 191413 191414 191415 191416 |
**
** If successful, return SQLITE_OK. Otherwise, if an OOM error is encountered
** trying to resize the buffer, return SQLITE_NOMEM.
*/
static int fts3MsrBufferData(
Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */
char *pList,
i64 nList
){
if( nList>pMsr->nBuffer ){
char *pNew;
pMsr->nBuffer = nList*2;
pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
if( !pNew ) return SQLITE_NOMEM;
pMsr->aBuffer = pNew;
}
assert( nList>0 );
memcpy(pMsr->aBuffer, pList, nList);
return SQLITE_OK;
|
| ︙ | ︙ | |||
189712 189713 189714 189715 189716 189717 189718 |
rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0);
j++;
}
if( rc!=SQLITE_OK ) return rc;
fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){
| | | 191458 191459 191460 191461 191462 191463 191464 191465 191466 191467 191468 191469 191470 191471 191472 |
rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0);
j++;
}
if( rc!=SQLITE_OK ) return rc;
fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){
rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1);
if( rc!=SQLITE_OK ) return rc;
assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
pList = pMsr->aBuffer;
}
if( pMsr->iColFilter>=0 ){
fts3ColumnFilter(pMsr->iColFilter, 1, &pList, &nList);
|
| ︙ | ︙ | |||
189849 189850 189851 189852 189853 189854 189855 |
pCsr->apSegment[i]->nOffsetList = 0;
pCsr->apSegment[i]->iDocid = 0;
}
return SQLITE_OK;
}
| | | | 191595 191596 191597 191598 191599 191600 191601 191602 191603 191604 191605 191606 191607 191608 191609 191610 191611 191612 191613 |
pCsr->apSegment[i]->nOffsetList = 0;
pCsr->apSegment[i]->iDocid = 0;
}
return SQLITE_OK;
}
static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){
if( nReq>pCsr->nBuffer ){
char *aNew;
pCsr->nBuffer = nReq*2;
aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer);
if( !aNew ){
return SQLITE_NOMEM;
}
pCsr->aBuffer = aNew;
}
return SQLITE_OK;
}
|
| ︙ | ︙ | |||
189944 189945 189946 189947 189948 189949 189950 |
if( nMerge==1
&& !isIgnoreEmpty
&& !isFirst
&& (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0)
){
pCsr->nDoclist = apSegment[0]->nDoclist;
if( fts3SegReaderIsPending(apSegment[0]) ){
| | > | 191690 191691 191692 191693 191694 191695 191696 191697 191698 191699 191700 191701 191702 191703 191704 191705 |
if( nMerge==1
&& !isIgnoreEmpty
&& !isFirst
&& (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0)
){
pCsr->nDoclist = apSegment[0]->nDoclist;
if( fts3SegReaderIsPending(apSegment[0]) ){
rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist,
(i64)pCsr->nDoclist);
pCsr->aDoclist = pCsr->aBuffer;
}else{
pCsr->aDoclist = apSegment[0]->aDoclist;
}
if( rc==SQLITE_OK ) rc = SQLITE_ROW;
}else{
int nDoclist = 0; /* Size of doclist */
|
| ︙ | ︙ | |||
189997 189998 189999 190000 190001 190002 190003 |
}else{
if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB;
iDelta = (i64)((u64)iDocid - (u64)iPrev);
}
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
| | > | 191744 191745 191746 191747 191748 191749 191750 191751 191752 191753 191754 191755 191756 191757 191758 191759 |
}else{
if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB;
iDelta = (i64)((u64)iDocid - (u64)iPrev);
}
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
rc = fts3GrowSegReaderBuffer(pCsr,
(i64)nByte+nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc;
if( isFirst ){
char *a = &pCsr->aBuffer[nDoclist];
int nWrite;
nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a);
|
| ︙ | ︙ | |||
190023 190024 190025 190026 190027 190028 190029 |
}
}
}
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
| | | 191771 191772 191773 191774 191775 191776 191777 191778 191779 191780 191781 191782 191783 191784 191785 |
}
}
}
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc;
memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
pCsr->aDoclist = pCsr->aBuffer;
pCsr->nDoclist = nDoclist;
rc = SQLITE_ROW;
}
}
|
| ︙ | ︙ | |||
190736 190737 190738 190739 190740 190741 190742 |
** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a
** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc
** to reflect the new size of the pBlob->a[] buffer.
*/
static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
int nAlloc = nMin;
| | | 192484 192485 192486 192487 192488 192489 192490 192491 192492 192493 192494 192495 192496 192497 192498 |
** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a
** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc
** to reflect the new size of the pBlob->a[] buffer.
*/
static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
int nAlloc = nMin;
char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc);
if( a ){
pBlob->nAlloc = nAlloc;
pBlob->a = a;
}else{
*pRc = SQLITE_NOMEM;
}
}
|
| ︙ | ︙ | |||
191533 191534 191535 191536 191537 191538 191539 |
if( rc==SQLITE_OK ){
int rc2;
sqlite3_bind_int64(pSelect, 1, iAbsLevel);
while( SQLITE_ROW==sqlite3_step(pSelect) ){
if( nIdx>=nAlloc ){
int *aNew;
nAlloc += 16;
| | | 193281 193282 193283 193284 193285 193286 193287 193288 193289 193290 193291 193292 193293 193294 193295 |
if( rc==SQLITE_OK ){
int rc2;
sqlite3_bind_int64(pSelect, 1, iAbsLevel);
while( SQLITE_ROW==sqlite3_step(pSelect) ){
if( nIdx>=nAlloc ){
int *aNew;
nAlloc += 16;
aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int));
if( !aNew ){
rc = SQLITE_NOMEM;
break;
}
aIdx = aNew;
}
aIdx[nIdx++] = sqlite3_column_int(pSelect, 0);
|
| ︙ | ︙ | |||
191907 191908 191909 191910 191911 191912 191913 |
int nSeg = 0; /* Number of input segments */
sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */
Blob hint = {0, 0, 0}; /* Hint read from %_stat table */
int bDirtyHint = 0; /* True if blob 'hint' has been modified */
/* Allocate space for the cursor, filter and writer objects */
const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
| | | 193655 193656 193657 193658 193659 193660 193661 193662 193663 193664 193665 193666 193667 193668 193669 |
int nSeg = 0; /* Number of input segments */
sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */
Blob hint = {0, 0, 0}; /* Hint read from %_stat table */
int bDirtyHint = 0; /* True if blob 'hint' has been modified */
/* Allocate space for the cursor, filter and writer objects */
const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc);
if( !pWriter ) return SQLITE_NOMEM;
pFilter = (Fts3SegFilter *)&pWriter[1];
pCsr = (Fts3MultiSegReader *)&pFilter[1];
rc = fts3IncrmergeHintLoad(p, &hint);
while( rc==SQLITE_OK && nRem>0 ){
const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex;
|
| ︙ | ︙ | |||
192543 192544 192545 192546 192547 192548 192549 |
*ppData = 0;
*pnData = 0;
if( p->pList==0 ){
return SQLITE_OK;
}
| | | | 194291 194292 194293 194294 194295 194296 194297 194298 194299 194300 194301 194302 194303 194304 194305 194306 194307 194308 194309 194310 194311 194312 194313 194314 194315 194316 194317 194318 194319 194320 194321 194322 194323 194324 194325 |
*ppData = 0;
*pnData = 0;
if( p->pList==0 ){
return SQLITE_OK;
}
pRet = (char *)sqlite3_malloc64(p->pList->nData);
if( !pRet ) return SQLITE_NOMEM;
nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy);
*pnData = p->pList->nData - nSkip;
*ppData = pRet;
memcpy(pRet, &p->pList->aData[nSkip], *pnData);
return SQLITE_OK;
}
/*
** Add an entry for token pToken to the pCsr->pDeferred list.
*/
SQLITE_PRIVATE int sqlite3Fts3DeferToken(
Fts3Cursor *pCsr, /* Fts3 table cursor */
Fts3PhraseToken *pToken, /* Token to defer */
int iCol /* Column that token must appear in (or -1) */
){
Fts3DeferredToken *pDeferred;
pDeferred = sqlite3_malloc64(sizeof(*pDeferred));
if( !pDeferred ){
return SQLITE_NOMEM;
}
memset(pDeferred, 0, sizeof(*pDeferred));
pDeferred->pToken = pToken;
pDeferred->pNext = pCsr->pDeferred;
pDeferred->iCol = iCol;
|
| ︙ | ︙ | |||
201278 201279 201280 201281 201282 201283 201284 |
** since the write might do a rebalance which would disrupt the read
** cursor. */
return SQLITE_LOCKED_VTAB;
}
rtreeReference(pRtree);
assert(nData>=1);
| | | 203026 203027 203028 203029 203030 203031 203032 203033 203034 203035 203036 203037 203038 203039 203040 |
** since the write might do a rebalance which would disrupt the read
** cursor. */
return SQLITE_LOCKED_VTAB;
}
rtreeReference(pRtree);
assert(nData>=1);
memset(&cell, 0, sizeof(cell));
/* Constraint handling. A write operation on an r-tree table may return
** SQLITE_CONSTRAINT for two reasons:
**
** 1. A duplicate rowid value, or
** 2. The supplied data violates the "x2>=x1" constraint.
**
|
| ︙ | ︙ | |||
204142 204143 204144 204145 204146 204147 204148 |
sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT);
}else{
sqlite3_bind_value(pUp, 2, aData[2]);
}
sqlite3_free(p);
nChange = 1;
}
| | | 205890 205891 205892 205893 205894 205895 205896 205897 205898 205899 205900 205901 205902 205903 205904 |
sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT);
}else{
sqlite3_bind_value(pUp, 2, aData[2]);
}
sqlite3_free(p);
nChange = 1;
}
for(jj=1; jj<nData-2; jj++){
nChange++;
sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
}
if( nChange ){
sqlite3_step(pUp);
rc = sqlite3_reset(pUp);
}
|
| ︙ | ︙ | |||
204745 204746 204747 204748 204749 204750 204751 |
if( !zPattern ){
return;
}
pExpr = uregex_open(zPattern, -1, 0, 0, &status);
if( U_SUCCESS(status) ){
sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
| | > | | 206493 206494 206495 206496 206497 206498 206499 206500 206501 206502 206503 206504 206505 206506 206507 206508 206509 |
if( !zPattern ){
return;
}
pExpr = uregex_open(zPattern, -1, 0, 0, &status);
if( U_SUCCESS(status) ){
sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
pExpr = sqlite3_get_auxdata(p, 0);
}
if( !pExpr ){
icuFunctionError(p, "uregex_open", status);
return;
}
}
/* Configure the text that the regular expression operates on. */
uregex_setText(pExpr, zString, -1, &status);
|
| ︙ | ︙ | |||
212501 212502 212503 212504 212505 212506 212507 |
** written by the sqlite_dbpage virtual table, start a write transaction
** on them all.
*/
static int dbpageBegin(sqlite3_vtab *pVtab){
DbpageTable *pTab = (DbpageTable *)pVtab;
sqlite3 *db = pTab->db;
int i;
| > | | | | 214250 214251 214252 214253 214254 214255 214256 214257 214258 214259 214260 214261 214262 214263 214264 214265 214266 214267 214268 214269 |
** written by the sqlite_dbpage virtual table, start a write transaction
** on them all.
*/
static int dbpageBegin(sqlite3_vtab *pVtab){
DbpageTable *pTab = (DbpageTable *)pVtab;
sqlite3 *db = pTab->db;
int i;
int rc = SQLITE_OK;
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
}
return rc;
}
/*
** Invoke this routine to register the "dbpage" virtual table module
*/
SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
|
| ︙ | ︙ | |||
219229 219230 219231 219232 219233 219234 219235 | static void sqlite3Fts5BufferZero(Fts5Buffer*); static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*); static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...); static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...); #define fts5BufferZero(x) sqlite3Fts5BufferZero(x) | | | 220979 220980 220981 220982 220983 220984 220985 220986 220987 220988 220989 220990 220991 220992 220993 |
static void sqlite3Fts5BufferZero(Fts5Buffer*);
static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
#define fts5BufferZero(x) sqlite3Fts5BufferZero(x)
#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,(i64)c)
#define fts5BufferFree(a) sqlite3Fts5BufferFree(a)
#define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)
#define fts5BufferSet(a,b,c,d) sqlite3Fts5BufferSet(a,b,c,d)
#define fts5BufferGrow(pRc,pBuf,nn) ( \
(u32)((pBuf)->n) + (u32)(nn) <= (u32)((pBuf)->nSpace) ? 0 : \
sqlite3Fts5BufferSize((pRc),(pBuf),(nn)+(pBuf)->n) \
|
| ︙ | ︙ | |||
231106 231107 231108 231109 231110 231111 231112 |
}
/* Write the rowid. */
if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
}else{
assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
| | > > | 232856 232857 232858 232859 232860 232861 232862 232863 232864 232865 232866 232867 232868 232869 232870 232871 232872 |
}
/* Write the rowid. */
if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
}else{
assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
fts5BufferAppendVarint(&p->rc, &pPage->buf,
(u64)iRowid - (u64)pWriter->iPrevRowid
);
}
pWriter->iPrevRowid = iRowid;
pWriter->bFirstRowidInDoclist = 0;
pWriter->bFirstRowidInPage = 0;
}
}
|
| ︙ | ︙ | |||
231870 231871 231872 231873 231874 231875 231876 |
fts5StructureRelease(pStruct);
}
return fts5IndexReturn(p);
}
static void fts5AppendRowid(
Fts5Index *p,
| | | | 233622 233623 233624 233625 233626 233627 233628 233629 233630 233631 233632 233633 233634 233635 233636 233637 233638 233639 233640 233641 233642 233643 233644 233645 233646 |
fts5StructureRelease(pStruct);
}
return fts5IndexReturn(p);
}
static void fts5AppendRowid(
Fts5Index *p,
u64 iDelta,
Fts5Iter *pUnused,
Fts5Buffer *pBuf
){
UNUSED_PARAM(pUnused);
fts5BufferAppendVarint(&p->rc, pBuf, iDelta);
}
static void fts5AppendPoslist(
Fts5Index *p,
u64 iDelta,
Fts5Iter *pMulti,
Fts5Buffer *pBuf
){
int nData = pMulti->base.nData;
int nByte = nData + 9 + 9 + FTS5_DATA_ZERO_PADDING;
assert( nData>0 );
if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nByte) ){
|
| ︙ | ︙ | |||
231955 231956 231957 231958 231959 231960 231961 |
){
assert( pBuf->n!=0 || (*piLastRowid)==0 );
fts5BufferSafeAppendVarint(pBuf, iRowid - *piLastRowid);
*piLastRowid = iRowid;
}
#endif
| | | | | | 233707 233708 233709 233710 233711 233712 233713 233714 233715 233716 233717 233718 233719 233720 233721 233722 233723 233724 |
){
assert( pBuf->n!=0 || (*piLastRowid)==0 );
fts5BufferSafeAppendVarint(pBuf, iRowid - *piLastRowid);
*piLastRowid = iRowid;
}
#endif
#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
fts5BufferSafeAppendVarint((pBuf), (u64)(iRowid) - (u64)(iLastRowid)); \
(iLastRowid) = (iRowid); \
}
/*
** Swap the contents of buffer *p1 with that of *p2.
*/
static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
Fts5Buffer tmp = *p1;
|
| ︙ | ︙ | |||
232229 232230 232231 232232 232233 232234 232235 |
){
Fts5Structure *pStruct;
Fts5Buffer *aBuf;
int nBuf = 32;
int nMerge = 1;
void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
| | | 233981 233982 233983 233984 233985 233986 233987 233988 233989 233990 233991 233992 233993 233994 233995 |
){
Fts5Structure *pStruct;
Fts5Buffer *aBuf;
int nBuf = 32;
int nMerge = 1;
void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
xMerge = fts5MergeRowidLists;
xAppend = fts5AppendRowid;
}else{
nMerge = FTS5_MERGE_NLIST-1;
nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
xMerge = fts5MergePrefixLists;
|
| ︙ | ︙ | |||
232268 232269 232270 232271 232272 232273 232274 |
for(;
fts5MultiIterEof(p, p1)==0;
fts5MultiIterNext2(p, p1, &dummy)
){
Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
p1->xSetOutputs(p1, pSeg);
if( p1->base.nData ){
| | | 234020 234021 234022 234023 234024 234025 234026 234027 234028 234029 234030 234031 234032 234033 234034 |
for(;
fts5MultiIterEof(p, p1)==0;
fts5MultiIterNext2(p, p1, &dummy)
){
Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
p1->xSetOutputs(p1, pSeg);
if( p1->base.nData ){
xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
iLastRowid = p1->base.iRowid;
}
}
fts5MultiIterFree(p1);
}
pToken[0] = FTS5_MAIN_PREFIX + iIdx;
|
| ︙ | ︙ | |||
232316 232317 232318 232319 232320 232321 232322 |
fts5BufferZero(&aBuf[iStore]);
}
}
}
iLastRowid = 0;
}
| | | 234068 234069 234070 234071 234072 234073 234074 234075 234076 234077 234078 234079 234080 234081 234082 |
fts5BufferZero(&aBuf[iStore]);
}
}
}
iLastRowid = 0;
}
xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
iLastRowid = p1->base.iRowid;
}
assert( (nBuf%nMerge)==0 );
for(i=0; i<nBuf; i+=nMerge){
int iFree;
if( p->rc==SQLITE_OK ){
|
| ︙ | ︙ | |||
236632 236633 236634 236635 236636 236637 236638 |
static void fts5SourceIdFunc(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
sqlite3_value **apUnused /* Function arguments */
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
| | | 238384 238385 238386 238387 238388 238389 238390 238391 238392 238393 238394 238395 238396 238397 238398 |
static void fts5SourceIdFunc(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
sqlite3_value **apUnused /* Function arguments */
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "fts5: 2022-10-26 11:11:31 3dfdfb3f12edb3f4267942598efd05d573e13b7c5d6cdbc3404373f41b8993dd", -1, SQLITE_TRANSIENT);
}
/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
*/
static int fts5ShadowName(const char *zName){
|
| ︙ | ︙ |
Changes to extsrc/sqlite3.h.
| ︙ | ︙ | |||
142 143 144 145 146 147 148 | ** been edited in any way since it was last checked in, then the last ** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ | | | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | ** been edited in any way since it was last checked in, then the last ** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.40.0" #define SQLITE_VERSION_NUMBER 3040000 #define SQLITE_SOURCE_ID "2022-10-26 11:11:31 3dfdfb3f12edb3f4267942598efd05d573e13b7c5d6cdbc3404373f41b8993dd" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ | |||
666 667 668 669 670 671 672 | #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods | | > > > > | | | | | | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 | #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods ** of an [sqlite3_io_methods] object. These values are ordered from ** lest restrictive to most restrictive. ** ** The argument to xLock() is always SHARED or higher. The argument to ** xUnlock is either SHARED or NONE. */ #define SQLITE_LOCK_NONE 0 /* xUnlock() only */ #define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */ #define SQLITE_LOCK_RESERVED 2 /* xLock() only */ #define SQLITE_LOCK_PENDING 3 /* xLock() only */ #define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */ /* ** CAPI3REF: Synchronization Type Flags ** ** When SQLite invokes the xSync() method of an ** [sqlite3_io_methods] object it uses a combination of ** these integer values as the second argument. |
| ︙ | ︙ | |||
750 751 752 753 754 755 756 | ** <ul> ** <li> [SQLITE_LOCK_NONE], ** <li> [SQLITE_LOCK_SHARED], ** <li> [SQLITE_LOCK_RESERVED], ** <li> [SQLITE_LOCK_PENDING], or ** <li> [SQLITE_LOCK_EXCLUSIVE]. ** </ul> | > > > > > > > | | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 | ** <ul> ** <li> [SQLITE_LOCK_NONE], ** <li> [SQLITE_LOCK_SHARED], ** <li> [SQLITE_LOCK_RESERVED], ** <li> [SQLITE_LOCK_PENDING], or ** <li> [SQLITE_LOCK_EXCLUSIVE]. ** </ul> ** 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 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 ** 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. ** ** The xFileControl() method is a generic interface that allows custom ** VFS implementations to directly control an open file using the |
| ︙ | ︙ | |||
855 856 857 858 859 860 861 | ** ** <ul> ** <li>[[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) | | | < | 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | ** ** <ul> ** <li>[[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. ** This capability is only available if SQLite is compiled with [SQLITE_DEBUG]. ** ** <li>[[SQLITE_FCNTL_SIZE_HINT]] ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the ** current transaction. This hint is not guaranteed to be accurate but it ** is often close. The underlying VFS might choose to preallocate database ** file space based on this hint in order to help writes to the database |
| ︙ | ︙ | |||
3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 | ** (Mutexes will block any actual concurrency, but in this mode ** there is no harm in trying.) ** ** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt> ** <dd>The database is opened [shared cache] enabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** ** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt> ** <dd>The database is opened [shared cache] disabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** ** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt> ** <dd>The database connection comes up in "extended result code mode". ** In other words, the database behaves has if ** [sqlite3_extended_result_codes(db,1)] where called on the database ** connection as soon as the connection is created. In addition to setting ** the extended result code mode, this flag also causes [sqlite3_open_v2()] ** to return an extended result code.</dd> ** ** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt> | > > > | | 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 | ** (Mutexes will block any actual concurrency, but in this mode ** there is no harm in trying.) ** ** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt> ** <dd>The database is opened [shared cache] enabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** The [use of shared cache mode is discouraged] and hence shared cache ** capabilities may be omitted from many builds of SQLite. In such cases, ** this option is a no-op. ** ** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt> ** <dd>The database is opened [shared cache] disabled, overriding ** the default shared cache setting provided by ** [sqlite3_enable_shared_cache()].)^ ** ** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt> ** <dd>The database connection comes up in "extended result code mode". ** In other words, the database behaves has if ** [sqlite3_extended_result_codes(db,1)] where called on the database ** connection as soon as the connection is created. In addition to setting ** the extended result code mode, this flag also causes [sqlite3_open_v2()] ** to return an extended result code.</dd> ** ** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt> ** <dd>The database filename is not allowed to contain a symbolic link</dd> ** </dl>)^ ** ** If the 3rd parameter to sqlite3_open_v2() is not one of the ** required combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] ** then the behavior is undefined. Historic versions of SQLite ** have silently ignored surplus bits in the flags parameter to |
| ︙ | ︙ | |||
5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 | ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If ** such a conversion is possible without loss of information (in other ** words, if the value is a string that looks like a number) ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** ** ^Within the [xUpdate] method of a [virtual table], the ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation ** that the xUpdate method call was invoked to implement and if ** and the prior [xColumn] method call that was invoked to extracted ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column | > > > > > > > > > > | 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 | ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If ** such a conversion is possible without loss of information (in other ** words, if the value is a string that looks like a number) ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** ** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8], ** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current encoding ** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) ** returns something other than SQLITE_TEXT, then the return value from ** sqlite3_value_encoding(X) is meaningless. ^Calls to ** sqlite3_value_text(X), sqlite3_value_text16(X), sqlite3_value_text16be(X), ** sqlite3_value_text16le(X), sqlite3_value_bytes(X), or ** sqlite3_value_bytes16(X) might change the encoding of the value X and ** thus change the return from subsequent calls to sqlite3_value_encoding(X). ** ** ^Within the [xUpdate] method of a [virtual table], the ** sqlite3_value_nochange(X) interface returns true if and only if ** the column corresponding to X is unchanged by the UPDATE operation ** that the xUpdate method call was invoked to implement and if ** and the prior [xColumn] method call that was invoked to extracted ** the value for that column returned without setting a result (probably ** because it queried [sqlite3_vtab_nochange()] and found that the column |
| ︙ | ︙ | |||
5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 | SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); SQLITE_API int sqlite3_value_bytes(sqlite3_value*); SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values ** METHOD: sqlite3_value ** ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype | > | 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 | SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); SQLITE_API int sqlite3_value_bytes(sqlite3_value*); SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); SQLITE_API int sqlite3_value_frombind(sqlite3_value*); SQLITE_API int sqlite3_value_encoding(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values ** METHOD: sqlite3_value ** ** The sqlite3_value_subtype(V) function returns the subtype for ** an [application-defined SQL function] argument V. The subtype |
| ︙ | ︙ | |||
5621 5622 5623 5624 5625 5626 5627 | ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory | | | 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 | ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory ** allocation error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the ** value of N in any subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set ** N=0 in calls to sqlite3_aggregate_context(C,N) so that no |
| ︙ | ︙ | |||
6461 6462 6463 6464 6465 6466 6467 | ** CAPI3REF: Autovacuum Compaction Amount Callback ** METHOD: sqlite3 ** ** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback ** function C that is invoked prior to each autovacuum of the database ** file. ^The callback is passed a copy of the generic data pointer (P), ** the schema-name of the attached database that is being autovacuumed, | | | 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 | ** CAPI3REF: Autovacuum Compaction Amount Callback ** METHOD: sqlite3 ** ** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback ** function C that is invoked prior to each autovacuum of the database ** file. ^The callback is passed a copy of the generic data pointer (P), ** the schema-name of the attached database that is being autovacuumed, ** the size of the database file in pages, the number of free pages, ** and the number of bytes per page, respectively. The callback should ** return the number of free pages that should be removed by the ** autovacuum. ^If the callback returns zero, then no autovacuum happens. ** ^If the value returned is greater than or equal to the number of ** free pages, then a complete autovacuum happens. ** ** <p>^If there are multiple ATTACH-ed database files that are being |
| ︙ | ︙ | |||
6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 | /* ** CAPI3REF: Enable Or Disable Shared Pager Cache ** ** ^(This routine enables or disables the sharing of the database cache ** and schema data structures between [database connection | connections] ** to the same database. Sharing is enabled if the argument is true ** and disabled if the argument is false.)^ ** ** ^Cache sharing is enabled and disabled for an entire process. ** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). ** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent | > > > > > | 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 | /* ** CAPI3REF: Enable Or Disable Shared Pager Cache ** ** ^(This routine enables or disables the sharing of the database cache ** and schema data structures between [database connection | connections] ** to the same database. Sharing is enabled if the argument is true ** and disabled if the argument is false.)^ ** ** This interface is omitted if SQLite is compiled with ** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE] ** compile-time option is recommended because the ** [use of shared cache mode is discouraged]. ** ** ^Cache sharing is enabled and disabled for an entire process. ** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). ** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent |
| ︙ | ︙ | |||
6680 6681 6682 6683 6684 6685 6686 | ** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). ** ** ^Setting the heap limits to zero disables the heap limiter mechanism. ** ** ^The soft heap limit may not be greater than the hard heap limit. ** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) ** is invoked with a value of N that is greater than the hard heap limit, | | | 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 | ** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). ** ** ^Setting the heap limits to zero disables the heap limiter mechanism. ** ** ^The soft heap limit may not be greater than the hard heap limit. ** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) ** is invoked with a value of N that is greater than the hard heap limit, ** the soft heap limit is set to the value of the hard heap limit. ** ^The soft heap limit is automatically enabled whenever the hard heap ** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and ** the soft heap limit is outside the range of 1..N, then the soft heap ** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the ** hard heap limit is enabled makes the soft heap limit equal to the ** hard heap limit. ** |
| ︙ | ︙ | |||
8975 8976 8977 8978 8979 8980 8981 | ** However, the application must guarantee that the destination ** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] ** and so no error code is reported, but the operations may malfunction ** nevertheless. Use of the destination database connection while a | | | 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 | ** However, the application must guarantee that the destination ** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] ** and so no error code is reported, but the operations may malfunction ** nevertheless. Use of the destination database connection while a ** backup is in progress might also cause a mutex deadlock. ** ** If running in [shared cache mode], the application must ** guarantee that the shared cache used by the destination database ** is not accessed while the backup is running. In practice this means ** that the application must guarantee that the disk file being ** backed up to is not accessed by any connection within the process, ** not just the specific connection that was passed to sqlite3_backup_init(). |
| ︙ | ︙ | |||
9403 9404 9405 9406 9407 9408 9409 | ** These constants define all valid values for the "checkpoint mode" passed ** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ | | | 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 | ** These constants define all valid values for the "checkpoint mode" passed ** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ #define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */ #define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */ /* ** CAPI3REF: Virtual Table Interface Configuration ** ** This function may be called by either the [xConnect] or [xCreate] method ** of a [virtual table] implementation to configure |
| ︙ | ︙ |
Changes to src/alerts.c.
| ︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 147 |
return;
}
db_multi_exec(
"ALTER TABLE repository.pending_alert"
" ADD COLUMN sentMod BOOLEAN DEFAULT false;"
);
}
/*
** Enable triggers that automatically populate the pending_alert
| > > > > > > > > > > > > > > > > > > > > > > > | > | | | < | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > | > | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
return;
}
db_multi_exec(
"ALTER TABLE repository.pending_alert"
" ADD COLUMN sentMod BOOLEAN DEFAULT false;"
);
}
/*
** Process deferred alert events. Return the number of errors.
*/
static int alert_process_deferred_triggers(void){
if( db_table_exists("temp","deferred_chat_events")
&& db_table_exists("repository","chat")
){
const char *zChatUser = db_get("chat-timeline-user", 0);
if( zChatUser && zChatUser[0] ){
db_multi_exec(
"INSERT INTO chat(mtime,lmtime,xfrom,xmsg)"
" SELECT julianday(), "
" strftime('%%Y-%%m-%%dT%%H:%%M:%%S','now','localtime'),"
" %Q,"
" chat_msg_from_event(type, objid, user, comment)\n"
" FROM deferred_chat_events;\n",
zChatUser
);
}
}
return 0;
}
/*
** Enable triggers that automatically populate the pending_alert
** table. (Later:) Also add triggers that automatically relay timeline
** events to chat, if chat is configured for that.
*/
void alert_create_trigger(void){
if( db_table_exists("repository","pending_alert") ){
db_multi_exec(
"DROP TRIGGER IF EXISTS repository.alert_trigger1;\n" /* Purge legacy */
"CREATE TRIGGER temp.alert_trigger1\n"
"AFTER INSERT ON repository.event BEGIN\n"
" INSERT INTO pending_alert(eventid)\n"
" SELECT printf('%%.1c%%d',new.type,new.objid) WHERE true\n"
" ON CONFLICT(eventId) DO NOTHING;\n"
"END;"
);
}
if( db_table_exists("repository","chat")
&& db_get("chat-timeline-user", "")[0]!=0
){
/* Record events that will be relayed to chat, but do not relay
** them immediately, as the chat_msg_from_event() function requires
** that TAGXREF be up-to-date, and that has not happened yet when
** the insert into the EVENT table occurs. Make arrangements to
** invoke alert_process_deferred_triggers() when the transaction
** commits. The TAGXREF table will be ready by then. */
db_multi_exec(
"CREATE TABLE temp.deferred_chat_events(\n"
" type TEXT,\n"
" objid INT,\n"
" user TEXT,\n"
" comment TEXT\n"
");\n"
"CREATE TRIGGER temp.chat_trigger1\n"
"AFTER INSERT ON repository.event BEGIN\n"
" INSERT INTO deferred_chat_events"
" VALUES(new.type,new.objid,new.user,new.comment);\n"
"END;\n"
);
db_commit_hook(alert_process_deferred_triggers, 1);
}
}
/*
** Disable triggers the event_pending and chat triggers.
**
** This must be called before rebuilding the EVENT table, for example
** via the "fossil rebuild" command.
*/
void alert_drop_trigger(void){
db_multi_exec(
"DROP TRIGGER IF EXISTS temp.alert_trigger1;\n"
"DROP TRIGGER IF EXISTS repository.alert_trigger1;\n" /* Purge legacy */
"DROP TRIGGER IF EXISTS temp.chat_trigger1;\n"
);
}
/*
** Return true if email alerts are active.
*/
int alert_enabled(void){
|
| ︙ | ︙ |
Changes to src/browse.c.
| ︙ | ︙ | |||
191 192 193 194 195 196 197 |
}else{
zHeader = mprintf("All Top-level Files");
}
}else{
if( zCI ){
zHeader = mprintf("Files in %s/ of %s", zD, zCI);
}else{
| | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
}else{
zHeader = mprintf("All Top-level Files");
}
}else{
if( zCI ){
zHeader = mprintf("Files in %s/ of %s", zD, zCI);
}else{
zHeader = mprintf("All Files in %s/", zD);
}
}
zRegexp = P("re");
if( zRegexp ){
zHeader = mprintf("%z matching \"%s\"", zHeader, zRegexp);
zMatch = mprintf(" matching \"%h\"", zRegexp);
}else{
|
| ︙ | ︙ | |||
745 746 747 748 749 750 751 |
}else{
zHeader = mprintf("All Top-level Files");
}
}else{
if( zCI ){
zHeader = mprintf("Files in %s/ of %s", zD, zCI);
}else{
| | | 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 |
}else{
zHeader = mprintf("All Top-level Files");
}
}else{
if( zCI ){
zHeader = mprintf("Files in %s/ of %s", zD, zCI);
}else{
zHeader = mprintf("All Files in %s/", zD);
}
}
style_header("%s", zHeader);
fossil_free(zHeader);
/* Compute the title of the page */
blob_zero(&dirname);
|
| ︙ | ︙ | |||
843 844 845 846 847 848 849 |
if( zCI && strcmp(zCI,"tip")==0 ){
@ <h2>%s(zObjType) in the %z(href("%R/info?name=tip"))latest check-in</a>
}else if( isBranchCI ){
@ <h2>%s(zObjType) in the %z(href("%R/info?name=%T",zCI))latest check-in\
@ </a> for branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a>
if( blob_size(&dirname) ){
| | | | > > > > | 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 |
if( zCI && strcmp(zCI,"tip")==0 ){
@ <h2>%s(zObjType) in the %z(href("%R/info?name=tip"))latest check-in</a>
}else if( isBranchCI ){
@ <h2>%s(zObjType) in the %z(href("%R/info?name=%T",zCI))latest check-in\
@ </a> for branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a>
if( blob_size(&dirname) ){
@ and %s(blob_str(&dirname))
}
}else if( zCI ){
@ <h2>%s(zObjType) for check-in \
@ %z(href("%R/info?name=%T",zCI))%h(zCI)</a>
if( blob_size(&dirname) ){
@ and %s(blob_str(&dirname))
}
}else{
int n = db_int(0, "SELECT count(*) FROM plink");
@ <h2>%s(zObjType) from all %d(n) check-ins %s(blob_str(&dirname))
}
if( useMtime ){
@ sorted by modification time</h2>
}else{
@ sorted by filename</h2>
}
if( zNow ){
@ <p>File ages are expressed relative to the check-in time of
@ %z(href("%R/timeline?c=%t",zNow))%s(zNow)</a>.</p>
}
/* Generate tree of lists.
**
** Each file and directory is a list element: <li>. Files have class=file
** and if the filename as the suffix "xyz" the file also has class=file-xyz.
** Directories have class=dir. The directory specfied by the name= query
** parameter (or the top-level directory if there is no name= query parameter)
|
| ︙ | ︙ |
Changes to src/builtin.c.
| ︙ | ︙ | |||
146 147 148 149 150 151 152 |
while( zList[0] ){
int i = atoi(zList);
if( i>0 && i<=count(aBuiltinFiles) ){
blob_appendf(pOut, "/* %s */\n", aBuiltinFiles[i-1].zName);
blob_append(pOut, (const char*)aBuiltinFiles[i-1].pData,
aBuiltinFiles[i-1].nByte);
}
| | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
while( zList[0] ){
int i = atoi(zList);
if( i>0 && i<=count(aBuiltinFiles) ){
blob_appendf(pOut, "/* %s */\n", aBuiltinFiles[i-1].zName);
blob_append(pOut, (const char*)aBuiltinFiles[i-1].pData,
aBuiltinFiles[i-1].nByte);
}
while( zList[0] && fossil_isdigit(zList[0]) ) zList++;
while( zList[0] && !fossil_isdigit(zList[0]) ) zList++;
}
return;
}
/*
** WEBPAGE: builtin loadavg-exempt
**
|
| ︙ | ︙ | |||
482 483 484 485 486 487 488 |
*/
static int builtinVtabColumn(
sqlite3_vtab_cursor *cur, /* The cursor */
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
int i /* Which column to return */
){
builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
| | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
*/
static int builtinVtabColumn(
sqlite3_vtab_cursor *cur, /* The cursor */
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
int i /* Which column to return */
){
builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
const struct BuiltinFileTable *pFile = aBuiltinFiles + pCur->iRowid - 1;
switch( i ){
case 0: /* name */
sqlite3_result_text(ctx, pFile->zName, -1, SQLITE_STATIC);
break;
case 1: /* size */
sqlite3_result_int(ctx, pFile->nByte);
break;
|
| ︙ | ︙ | |||
513 514 515 516 517 518 519 |
/*
** Return TRUE if the cursor has been moved off of the last
** row of output.
*/
static int builtinVtabEof(sqlite3_vtab_cursor *cur){
builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
| | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
/*
** Return TRUE if the cursor has been moved off of the last
** row of output.
*/
static int builtinVtabEof(sqlite3_vtab_cursor *cur){
builtinVtab_cursor *pCur = (builtinVtab_cursor*)cur;
return pCur->iRowid>count(aBuiltinFiles);
}
/*
** This method is called to "rewind" the builtinVtab_cursor object back
** to the first row of output. This method is always called at least
** once prior to any call to builtinVtabColumn() or builtinVtabRowid() or
** builtinVtabEof().
|
| ︙ | ︙ |
Changes to src/chat.c.
| ︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 | */ /* ** SETTING: chat-alert-sound width=10 ** ** This is the name of the builtin sound file to use for the alert tone. ** The value must be the name of a builtin WAV file. */ /* ** WEBPAGE: chat loadavg-exempt ** ** Start up a browser-based chat session. ** ** This is the main page that humans use to access the chatroom. Simply ** point a web-browser at /chat and the screen fills with the latest | > > > > > > > > > > > > | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | */ /* ** SETTING: chat-alert-sound width=10 ** ** This is the name of the builtin sound file to use for the alert tone. ** The value must be the name of a builtin WAV file. */ /* ** SETTING: chat-timeline-user width=10 ** ** If this setting is defined and is not an empty string, then ** timeline events are posted to the chat as they arrive. The synthesized ** chat messages appear to come from the user identified by this setting, ** not the user on the timeline event. ** ** All chat messages that come from the chat-timeline-user are interpreted ** as text/x-fossil-wiki instead of as text/markdown. For this reason, ** the chat-timeline-user name should probably not be a real user. */ /* ** WEBPAGE: chat loadavg-exempt ** ** Start up a browser-based chat session. ** ** This is the main page that humans use to access the chatroom. Simply ** point a web-browser at /chat and the screen fills with the latest |
| ︙ | ︙ | |||
413 414 415 416 417 418 419 | ** it into HTML that is safe to insert using innerHTML. As of 2021-09-19, ** it does so by using markdown_to_html() to convert markdown-formatted ** zMsg to HTML. ** ** Space to hold the returned string is obtained from fossil_malloc() ** and must be freed by the caller. */ | | > > | > > > > > > | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
** it into HTML that is safe to insert using innerHTML. As of 2021-09-19,
** it does so by using markdown_to_html() to convert markdown-formatted
** zMsg to HTML.
**
** Space to hold the returned string is obtained from fossil_malloc()
** and must be freed by the caller.
*/
static char *chat_format_to_html(const char *zMsg, int isWiki){
Blob out;
blob_init(&out, "", 0);
if( zMsg==0 || zMsg[0]==0 ){
/* No-op */
}else if( isWiki ){
/* Used for chat-timeline-user. The zMsg is text/x-fossil-wiki. */
Blob bIn;
blob_init(&bIn, zMsg, (int)strlen(zMsg));
wiki_convert(&bIn, &out, WIKI_INLINE);
}else{
/* The common case: zMsg is text/markdown */
Blob bIn;
blob_init(&bIn, zMsg, (int)strlen(zMsg));
markdown_to_html(&bIn, NULL, &out);
}
return blob_str(&out);
}
|
| ︙ | ︙ | |||
440 441 442 443 444 445 446 |
*/
void chat_test_formatter_cmd(void){
int i;
char *zOut;
db_find_and_open_repository(0,0);
g.perm.Hyperlink = 1;
for(i=0; i<g.argc; i++){
| | | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
*/
void chat_test_formatter_cmd(void){
int i;
char *zOut;
db_find_and_open_repository(0,0);
g.perm.Hyperlink = 1;
for(i=0; i<g.argc; i++){
zOut = chat_format_to_html(g.argv[i], 0);
fossil_print("[%d]: %s\n", i, zOut);
fossil_free(zOut);
}
}
/*
** WEBPAGE: chat-poll hidden loadavg-exempt
|
| ︙ | ︙ | |||
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
** in a prominent manner and then stop polling for new messages.
*/
void chat_poll_webpage(void){
Blob json; /* The json to be constructed and returned */
sqlite3_int64 dataVersion; /* Data version. Used for polling. */
const int iDelay = 1000; /* Delay until next poll (milliseconds) */
int nDelay; /* Maximum delay.*/
int msgid = atoi(PD("name","0"));
const int msgBefore = atoi(PD("before","0"));
int nLimit = msgBefore>0 ? atoi(PD("n","0")) : 0;
const int bRaw = P("raw")!=0;
Blob sql = empty_blob;
Stmt q1;
nDelay = db_get_int("chat-poll-timeout",420); /* Default about 7 minutes */
login_check_credentials();
if( !g.perm.Chat ) {
chat_emit_permissions_error(1);
return;
}
chat_create_tables();
cgi_set_content_type("application/json");
dataVersion = db_int64(0, "PRAGMA data_version");
blob_append_sql(&sql,
"SELECT msgid, datetime(mtime), xfrom, xmsg, length(file),"
" fname, fmime, %s, lmtime"
" FROM chat ",
| > > > > | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
** in a prominent manner and then stop polling for new messages.
*/
void chat_poll_webpage(void){
Blob json; /* The json to be constructed and returned */
sqlite3_int64 dataVersion; /* Data version. Used for polling. */
const int iDelay = 1000; /* Delay until next poll (milliseconds) */
int nDelay; /* Maximum delay.*/
const char *zChatUser; /* chat-timeline-user */
int isWiki = 0; /* True if chat message is x-fossil-wiki */
int msgid = atoi(PD("name","0"));
const int msgBefore = atoi(PD("before","0"));
int nLimit = msgBefore>0 ? atoi(PD("n","0")) : 0;
const int bRaw = P("raw")!=0;
Blob sql = empty_blob;
Stmt q1;
nDelay = db_get_int("chat-poll-timeout",420); /* Default about 7 minutes */
login_check_credentials();
if( !g.perm.Chat ) {
chat_emit_permissions_error(1);
return;
}
zChatUser = db_get("chat-timeline-user",0);
chat_create_tables();
cgi_set_content_type("application/json");
dataVersion = db_int64(0, "PRAGMA data_version");
blob_append_sql(&sql,
"SELECT msgid, datetime(mtime), xfrom, xmsg, length(file),"
" fname, fmime, %s, lmtime"
" FROM chat ",
|
| ︙ | ︙ | |||
617 618 619 620 621 622 623 624 625 626 627 628 |
blob_appendf(&json, "\"mtime\":\"%.10sT%sZ\",", zDate, zDate+11);
if( zLMtime && zLMtime[0] ){
blob_appendf(&json, "\"lmtime\":%!j,", zLMtime);
}
blob_append(&json, "\"xfrom\":", -1);
if(zFrom){
blob_appendf(&json, "%!j,", zFrom);
}else{
/* see https://fossil-scm.org/forum/forumpost/e0be0eeb4c */
blob_appendf(&json, "null,");
}
blob_appendf(&json, "\"uclr\":%!j,",
| > > | | | 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 |
blob_appendf(&json, "\"mtime\":\"%.10sT%sZ\",", zDate, zDate+11);
if( zLMtime && zLMtime[0] ){
blob_appendf(&json, "\"lmtime\":%!j,", zLMtime);
}
blob_append(&json, "\"xfrom\":", -1);
if(zFrom){
blob_appendf(&json, "%!j,", zFrom);
isWiki = fossil_strcmp(zFrom,zChatUser)==0;
}else{
/* see https://fossil-scm.org/forum/forumpost/e0be0eeb4c */
blob_appendf(&json, "null,");
isWiki = 0;
}
blob_appendf(&json, "\"uclr\":%!j,",
isWiki ? "transparent" : user_color(zFrom ? zFrom : "nobody"));
if(bRaw){
blob_appendf(&json, "\"xmsg\":%!j,", zRawMsg);
}else{
zMsg = chat_format_to_html(zRawMsg ? zRawMsg : "", isWiki);
blob_appendf(&json, "\"xmsg\":%!j,", zMsg);
fossil_free(zMsg);
}
if( nByte==0 ){
blob_appendf(&json, "\"fsize\":0");
}else{
|
| ︙ | ︙ | |||
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
** /chat-poll (without the wrapper array) or a JSON-format error
** response, as documented for ajax_route_error().
*/
void chat_fetch_one(void){
Blob json = empty_blob; /* The json to be constructed and returned */
const int fRaw = PD("raw",0)!=0;
const int msgid = atoi(PD("name","0"));
Stmt q;
login_check_credentials();
if( !g.perm.Chat ) {
chat_emit_permissions_error(0);
return;
}
chat_create_tables();
cgi_set_content_type("application/json");
db_prepare(&q,
"SELECT datetime(mtime), xfrom, xmsg, length(file),"
" fname, fmime, lmtime"
" FROM chat WHERE msgid=%d AND mdel IS NULL",
msgid);
| > > > | 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
** /chat-poll (without the wrapper array) or a JSON-format error
** response, as documented for ajax_route_error().
*/
void chat_fetch_one(void){
Blob json = empty_blob; /* The json to be constructed and returned */
const int fRaw = PD("raw",0)!=0;
const int msgid = atoi(PD("name","0"));
const char *zChatUser;
int isWiki;
Stmt q;
login_check_credentials();
if( !g.perm.Chat ) {
chat_emit_permissions_error(0);
return;
}
zChatUser = db_get("chat-timeline-user",0);
chat_create_tables();
cgi_set_content_type("application/json");
db_prepare(&q,
"SELECT datetime(mtime), xfrom, xmsg, length(file),"
" fname, fmime, lmtime"
" FROM chat WHERE msgid=%d AND mdel IS NULL",
msgid);
|
| ︙ | ︙ | |||
714 715 716 717 718 719 720 721 722 723 724 725 |
blob_appendf(&json, "\"mtime\":\"%.10sT%sZ\",", zDate, zDate+11);
if( zLMtime && zLMtime[0] ){
blob_appendf(&json, "\"lmtime\":%!j,", zLMtime);
}
blob_append(&json, "\"xfrom\":", -1);
if(zFrom){
blob_appendf(&json, "%!j,", zFrom);
}else{
/* see https://fossil-scm.org/forum/forumpost/e0be0eeb4c */
blob_appendf(&json, "null,");
}
blob_appendf(&json, "\"uclr\":%!j,",
| > > | | | 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 |
blob_appendf(&json, "\"mtime\":\"%.10sT%sZ\",", zDate, zDate+11);
if( zLMtime && zLMtime[0] ){
blob_appendf(&json, "\"lmtime\":%!j,", zLMtime);
}
blob_append(&json, "\"xfrom\":", -1);
if(zFrom){
blob_appendf(&json, "%!j,", zFrom);
isWiki = fossil_strcmp(zFrom, zChatUser)==0;
}else{
/* see https://fossil-scm.org/forum/forumpost/e0be0eeb4c */
blob_appendf(&json, "null,");
isWiki = 0;
}
blob_appendf(&json, "\"uclr\":%!j,",
isWiki ? "transparent" : user_color(zFrom ? zFrom : "nobody"));
blob_append(&json,"\"xmsg\":", 7);
if(fRaw){
blob_appendf(&json, "%!j,", zRawMsg);
}else{
char * zMsg = chat_format_to_html(zRawMsg ? zRawMsg : "", isWiki);
blob_appendf(&json, "%!j,", zMsg);
fossil_free(zMsg);
}
if( nByte==0 ){
blob_appendf(&json, "\"fsize\":0");
}else{
blob_appendf(&json, "\"fsize\":%d,\"fname\":%!j,\"fmime\":%!j",
|
| ︙ | ︙ | |||
846 847 848 849 850 851 852 853 854 855 856 857 858 859 |
if( pDb==0 ){
fossil_fatal("Out of memory");
}
blob_init(&chatDb, (const char*)pDb, (int)szDb);
cgi_set_content_type("application/x-sqlite3");
cgi_set_content(&chatDb);
}
/*
** COMMAND: chat
**
** Usage: %fossil chat [SUBCOMMAND] [--remote URL] [ARGS...]
**
** This command performs actions associated with the /chat instance
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 |
if( pDb==0 ){
fossil_fatal("Out of memory");
}
blob_init(&chatDb, (const char*)pDb, (int)szDb);
cgi_set_content_type("application/x-sqlite3");
cgi_set_content(&chatDb);
}
/*
** SQL Function: chat_msg_from_event(TYPE,OBJID,USER,MSG)
**
** This function returns HTML text that describes an entry from the EVENT
** table (that is, a timeline event) for display in chat. Parameters:
**
** TYPE The event type. 'ci', 'w', 't', 'g', and so forth
** OBJID EVENT.OBJID
** USER coalesce(EVENT.EUSER,EVENT.USER)
** MSG coalesce(EVENT.ECOMMENT, EVENT.COMMENT)
**
** This function is intended to be called by the temp.chat_trigger1 trigger
** which is created by alert_create_trigger() routine.
*/
void chat_msg_from_event(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zType = (const char*)sqlite3_value_text(argv[0]);
int rid = sqlite3_value_int(argv[1]);
const char *zUser = (const char*)sqlite3_value_text(argv[2]);
const char *zMsg = (const char*)sqlite3_value_text(argv[3]);
char *zRes = 0;
if( zType==0 || zUser==0 || zMsg==0 ) return;
if( zType[0]=='c' ){
/* Check-ins */
char *zBranch;
char *zUuid;
zBranch = db_text(0,
"SELECT value FROM tagxref"
" WHERE tagxref.rid=%d"
" AND tagxref.tagid=%d"
" AND tagxref.tagtype>0",
rid, TAG_BRANCH);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zRes = mprintf("%W (check-in: <a href='%R/info/%S'>%S</a>, "
"user: <a href='%R/timeline?u=%t&c=%S'>%h</a>, "
"branch: <a href='%R/timeline?r=%t&c=%S'>%h</a>)",
zMsg,
zUuid, zUuid,
zUser, zUuid, zUser,
zBranch, zUuid, zBranch
);
fossil_free(zBranch);
fossil_free(zUuid);
}else if( zType[0]=='w' ){
/* Wiki page changes */
char *zUuid;
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
wiki_hyperlink_override(zUuid);
if( zMsg[0]=='-' ){
zRes = mprintf("Delete wiki page <a href='%R/whistory?name=%t'>%h</a>",
zMsg+1, zMsg+1);
}else if( zMsg[0]=='+' ){
zRes = mprintf("Added wiki page <a href='%R/whistory?name=%t'>%h</a>",
zMsg+1, zMsg+1);
}else if( zMsg[0]==':' ){
zRes = mprintf("<a href='%R/wdiff?id=%!S'>Changes</a> to wiki page "
"<a href='%R/whistory?name=%t'>%h</a>",
zUuid, zMsg+1, zMsg+1);
}else{
zRes = mprintf("%W", zMsg);
}
wiki_hyperlink_override(0);
fossil_free(zUuid);
}else{
/* Anything else */
zRes = mprintf("%W", zMsg);
}
if( zRes ){
sqlite3_result_text(context, zRes, -1, fossil_free);
}
}
/*
** COMMAND: chat
**
** Usage: %fossil chat [SUBCOMMAND] [--remote URL] [ARGS...]
**
** This command performs actions associated with the /chat instance
|
| ︙ | ︙ |
Changes to src/checkin.c.
| ︙ | ︙ | |||
95 96 97 98 99 100 101 102 |
if( isDir==1 ){
vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0, SymFILE);
}else if( isDir==0 ){
fossil_warning("not found: %s", &zName[nRoot]);
}else if( file_access(zName, R_OK) ){
fossil_fatal("cannot open %s", &zName[nRoot]);
}else{
db_multi_exec(
| > | > > | | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
if( isDir==1 ){
vfile_scan(&name, nRoot-1, scanFlags, pIgnore, 0, SymFILE);
}else if( isDir==0 ){
fossil_warning("not found: %s", &zName[nRoot]);
}else if( file_access(zName, R_OK) ){
fossil_fatal("cannot open %s", &zName[nRoot]);
}else{
/* Only add unmanaged file paths specified on the command line. */
db_multi_exec(
"INSERT OR IGNORE INTO sfile(pathname)"
" SELECT %Q WHERE NOT EXISTS"
" (SELECT 1 FROM vfile WHERE pathname=%Q)",
&zName[nRoot], &zName[nRoot]
);
}
blob_reset(&name);
}
}
}
|
| ︙ | ︙ | |||
1764 1765 1766 1767 1768 1769 1770 |
"SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || mhash, merge"
" FROM vmerge"
" WHERE (vmerge.id=-1 OR vmerge.id=-2)"
" ORDER BY 1");
while( db_step(&q)==SQLITE_ROW ){
const char *zCherrypickUuid = db_column_text(&q, 0);
int mid = db_column_int(&q, 1);
| | | < | 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 |
"SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || mhash, merge"
" FROM vmerge"
" WHERE (vmerge.id=-1 OR vmerge.id=-2)"
" ORDER BY 1");
while( db_step(&q)==SQLITE_ROW ){
const char *zCherrypickUuid = db_column_text(&q, 0);
int mid = db_column_int(&q, 1);
if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
blob_appendf(pOut, "Q %s\n", zCherrypickUuid);
}
db_finalize(&q);
if( p->pCksum ) blob_appendf(pOut, "R %b\n", p->pCksum);
zColor = p->zColor;
if( p->zBranch && p->zBranch[0] ){
/* Set tags for the new branch */
|
| ︙ | ︙ | |||
2086 2087 2088 2089 2090 2091 2092 |
static int tagCmp(const void *a, const void *b){
char **pA = (char**)a;
char **pB = (char**)b;
return fossil_strcmp(pA[0], pB[0]);
}
/*
| | | 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 |
static int tagCmp(const void *a, const void *b){
char **pA = (char**)a;
char **pB = (char**)b;
return fossil_strcmp(pA[0], pB[0]);
}
/*
** COMMAND: ci#
** COMMAND: commit
**
** Usage: %fossil commit ?OPTIONS? ?FILE...?
** or: %fossil ci ?OPTIONS? ?FILE...?
**
** Create a new version containing all of the changes in the current
** checkout. You will be prompted to enter a check-in comment unless
|
| ︙ | ︙ |
Changes to src/checkout.c.
| ︙ | ︙ | |||
255 256 257 258 259 260 261 | db_reset(&stmt); db_finalize(&stmt); } /* ** COMMAND: checkout* | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | db_reset(&stmt); db_finalize(&stmt); } /* ** COMMAND: checkout* ** COMMAND: co# ** ** Usage: %fossil checkout ?VERSION | --latest? ?OPTIONS? ** or: %fossil co ?VERSION | --latest? ?OPTIONS? ** ** NOTE: Most people use "fossil update" instead of "fossil checkout" for ** day-to-day operations. If you are new to Fossil and trying to learn your ** way around, it is recommended that you become familiar with the |
| ︙ | ︙ |
Changes to src/clone.c.
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
if( find_option("save-http-password",0,0)!=0 ){
urlFlags &= ~URL_PROMPT_PW;
urlFlags |= URL_REMEMBER_PW;
}
if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
| | > > > > > | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
if( find_option("save-http-password",0,0)!=0 ){
urlFlags &= ~URL_PROMPT_PW;
urlFlags |= URL_REMEMBER_PW;
}
if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE;
if( find_option("unversioned","u",0)!=0 ){
syncFlags |= SYNC_UNVERSIONED;
if( syncFlags & SYNC_VERBOSE ){
syncFlags |= SYNC_UV_TRACE;
}
}
zHttpAuth = find_option("httpauth","B",1);
zDefaultUser = find_option("admin-user","A",1);
zWorkDir = find_option("workdir", 0, 1);
clone_ssh_find_options();
url_proxy_options();
g.zHttpCmd = find_option("transport-command",0,1);
|
| ︙ | ︙ |
Changes to src/comformat.c.
| ︙ | ︙ | |||
511 512 513 514 515 516 517 518 519 |
** 1. The global --comfmtflags (alias --comment-format) command-line option.
** 2. The local (per-repository) "comment-format" setting.
** 3. The global (all-repositories) "comment-format" setting.
** 4. The default value COMMENT_PRINT_DEFAULT.
*/
int get_comment_format(){
int comFmtFlags;
/* The global command-line option is present, or the value has been cached. */
if( g.comFmtFlags!=COMMENT_PRINT_UNSET ){
| > > > > > > > | < | | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 |
** 1. The global --comfmtflags (alias --comment-format) command-line option.
** 2. The local (per-repository) "comment-format" setting.
** 3. The global (all-repositories) "comment-format" setting.
** 4. The default value COMMENT_PRINT_DEFAULT.
*/
int get_comment_format(){
int comFmtFlags;
/* We must cache this result, else running the timeline can end up
** querying the comment-format setting from the global db once per
** timeline entry, which brings it to a crawl if that db is
** network-mounted. Discussed in:
** https://fossil-scm.org/forum/forumpost/9aaefe4e536e01bf */
/* The global command-line option is present, or the value has been cached. */
if( g.comFmtFlags!=COMMENT_PRINT_UNSET ){
return g.comFmtFlags;
}
/* Load the local (per-repository) or global (all-repositories) value, and use
** g.comFmtFlags as a cache. */
comFmtFlags = db_get_int("comment-format", COMMENT_PRINT_UNSET);
if( comFmtFlags!=COMMENT_PRINT_UNSET ){
g.comFmtFlags = comFmtFlags;
return comFmtFlags;
}
/* Fallback to the default value. */
g.comFmtFlags = COMMENT_PRINT_DEFAULT;
return g.comFmtFlags;
}
/*
**
** COMMAND: test-comment-format
**
** Usage: %fossil test-comment-format ?OPTIONS? PREFIX TEXT ?ORIGTEXT?
|
| ︙ | ︙ |
Changes to src/copybtn.js.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
elButton.style.opacity = 1;
if( idTarget ) elButton.setAttribute("data-copytarget",idTarget);
if( cchLength ) elButton.setAttribute("data-copylength",cchLength);
elButton.onclick = clickCopyButton;
return elButton;
}
setTimeout(function(){
| | | | < | | | | | < < | | < | | | | | | | | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
elButton.style.opacity = 1;
if( idTarget ) elButton.setAttribute("data-copytarget",idTarget);
if( cchLength ) elButton.setAttribute("data-copylength",cchLength);
elButton.onclick = clickCopyButton;
return elButton;
}
setTimeout(function(){
var elButtons = document.getElementsByClassName("copy-button");
for ( var i=0; i<elButtons.length; i++ ){
initCopyButton(elButtons[i],0,0);
}
},1);
/* The onclick handler for the "Copy Button". */
function clickCopyButton(e){
e.preventDefault(); /* Mandatory for <a> and <button>. */
e.stopPropagation();
if( this.getAttribute("data-copylocked") ) return;
this.setAttribute("data-copylocked","1");
this.style.transition = "opacity 400ms ease-in-out";
this.style.opacity = 0;
var idTarget = this.getAttribute("data-copytarget");
var elTarget = document.getElementById(idTarget);
if( elTarget ){
var text = elTarget.innerText.replace(/^\s+|\s+$/g,"");
var cchLength = parseInt(this.getAttribute("data-copylength"));
if( !isNaN(cchLength) && cchLength>0 ){
text = text.slice(0,cchLength); /* Assume single-byte chars. */
}
copyTextToClipboard(text);
}
setTimeout(function(){
this.style.transition = "";
this.style.opacity = 1;
this.removeAttribute("data-copylocked");
}.bind(this),400);
}
/* Create a temporary <textarea> element and copy the contents to clipboard. */
function copyTextToClipboard(text){
if( window.clipboardData && window.clipboardData.setData ){
window.clipboardData.setData("Text",text);
}else{
var elTextarea = document.createElement("textarea");
elTextarea.style.position = "fixed";
elTextarea.value = text;
document.body.appendChild(elTextarea);
elTextarea.select();
try{
document.execCommand("copy");
}catch(err){
}finally{
document.body.removeChild(elTextarea);
}
}
}
|
Changes to src/db.c.
| ︙ | ︙ | |||
123 124 125 126 127 128 129 |
int wrTxn; /* Outer-most TNX is a write */
Stmt *pAllStmt; /* List of all unfinalized statements */
int nPrepare; /* Number of calls to sqlite3_prepare_v2() */
int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
struct sCommitHook {
int (*xHook)(void); /* Functions to call at db_end_transaction() */
int sequence; /* Call functions in sequence order */
| | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
int wrTxn; /* Outer-most TNX is a write */
Stmt *pAllStmt; /* List of all unfinalized statements */
int nPrepare; /* Number of calls to sqlite3_prepare_v2() */
int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
struct sCommitHook {
int (*xHook)(void); /* Functions to call at db_end_transaction() */
int sequence; /* Call functions in sequence order */
} aHook[6];
char *azDeleteOnFail[3]; /* Files to delete on a failure */
char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
int nBeforeCommit; /* Number of entries in azBeforeCommit */
int nPriorChanges; /* sqlite3_total_changes() at transaction start */
const char *zStartFile; /* File in which transaction was started */
int iStartLine; /* Line of zStartFile where transaction started */
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
|
| ︙ | ︙ | |||
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 |
db_obscure, 0, 0);
sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0,
db_protected_setting_func, 0, 0);
sqlite3_create_function(db, "win_reserved", 1, SQLITE_UTF8, 0,
db_win_reserved_func,0,0);
sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
url_nouser_func,0,0);
}
#if USE_SEE
/*
** This is a pointer to the saved database encryption key string.
*/
static char *zSavedKey = 0;
| > > > > | 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 |
db_obscure, 0, 0);
sqlite3_create_function(db, "protected_setting", 1, SQLITE_UTF8, 0,
db_protected_setting_func, 0, 0);
sqlite3_create_function(db, "win_reserved", 1, SQLITE_UTF8, 0,
db_win_reserved_func,0,0);
sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
url_nouser_func,0,0);
sqlite3_create_function(db, "chat_msg_from_event", 4,
SQLITE_UTF8 | SQLITE_INNOCUOUS, 0,
chat_msg_from_event, 0, 0);
}
#if USE_SEE
/*
** This is a pointer to the saved database encryption key string.
*/
static char *zSavedKey = 0;
|
| ︙ | ︙ | |||
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 |
** only necessary (or functional) on Windows.
*/
void db_read_saved_encryption_key_from_process_via_th1(
const char *zConfig /* The TH1 script to evaluate. */
){
int rc;
char *zResult;
Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_NEED_CONFIG | TH_INIT_NO_REPO);
rc = Th_Eval(g.interp, 0, zConfig, -1);
zResult = (char*)Th_GetResult(g.interp, 0);
if( rc!=TH_OK ){
fossil_fatal("script for pid key failed: %s", zResult);
}
if( zResult ){
DWORD processId = 0;
LPVOID pAddress = NULL;
SIZE_T nSize = 0;
parse_pid_key_value(zResult, &processId, &pAddress, &nSize);
db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
}
}
#endif /* defined(_WIN32) */
#endif /* USE_SEE */
/*
** If the database file zDbFile has a name that suggests that it is
** encrypted, then prompt for the database encryption key and return it
| > > > | 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 |
** only necessary (or functional) on Windows.
*/
void db_read_saved_encryption_key_from_process_via_th1(
const char *zConfig /* The TH1 script to evaluate. */
){
int rc;
char *zResult;
char *zPwd = file_getcwd(0, 0);
Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_NEED_CONFIG | TH_INIT_NO_REPO);
rc = Th_Eval(g.interp, 0, zConfig, -1);
zResult = (char*)Th_GetResult(g.interp, 0);
if( rc!=TH_OK ){
fossil_fatal("script for pid key failed: %s", zResult);
}
if( zResult ){
DWORD processId = 0;
LPVOID pAddress = NULL;
SIZE_T nSize = 0;
parse_pid_key_value(zResult, &processId, &pAddress, &nSize);
db_read_saved_encryption_key_from_process(processId, pAddress, nSize);
}
file_chdir(zPwd, 0);
fossil_free(zPwd);
}
#endif /* defined(_WIN32) */
#endif /* USE_SEE */
/*
** If the database file zDbFile has a name that suggests that it is
** encrypted, then prompt for the database encryption key and return it
|
| ︙ | ︙ | |||
2801 2802 2803 2804 2805 2806 2807 |
blob_reset(&hash);
rid = content_put(&manifest);
manifest_crosslink(rid, &manifest, MC_NONE);
}
}
/*
| | | 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 |
blob_reset(&hash);
rid = content_put(&manifest);
manifest_crosslink(rid, &manifest, MC_NONE);
}
}
/*
** COMMAND: new#
** COMMAND: init
**
** Usage: %fossil new ?OPTIONS? FILENAME
** or: %fossil init ?OPTIONS? FILENAME
**
** Create a repository for a new project in the file named FILENAME.
** This command is distinct from "clone". The "clone" command makes
|
| ︙ | ︙ |
Changes to src/default.css.
| ︙ | ︙ | |||
234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
div.columns > ul li:first-child {
margin-top:0px;
}
.columns li {
break-inside: avoid;
page-break-inside: avoid;
}
.filetree {
margin: 1em 0;
line-height: 1.5;
}
.filetree > ul {
display: inline-block;
}
| > > > | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
div.columns > ul li:first-child {
margin-top:0px;
}
.columns li {
break-inside: avoid;
page-break-inside: avoid;
}
body.help .columns li {
white-space: nowrap /* keep command name aliases from wrapping */;
}
.filetree {
margin: 1em 0;
line-height: 1.5;
}
.filetree > ul {
display: inline-block;
}
|
| ︙ | ︙ | |||
575 576 577 578 579 580 581 582 583 584 585 586 587 588 |
padding: 0 0.35em 0 0.5em;
}
table.diff td.difftxt > pre {
min-width: 100%;
max-width: 100%;
}
table.diff td > pre {
/* Workaround for "slight wiggle" when using mouse-wheel in some FF
versions, apparently caused by the increased line-height forcing
these elements to be a *tick* larger than they should be but not
large enough to force a scroll bar to show up. */
overflow-y: hidden;
}
tr.diffskip.jchunk {
| > | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
padding: 0 0.35em 0 0.5em;
}
table.diff td.difftxt > pre {
min-width: 100%;
max-width: 100%;
}
table.diff td > pre {
box-sizing: border-box;
/* Workaround for "slight wiggle" when using mouse-wheel in some FF
versions, apparently caused by the increased line-height forcing
these elements to be a *tick* larger than they should be but not
large enough to force a scroll bar to show up. */
overflow-y: hidden;
}
tr.diffskip.jchunk {
|
| ︙ | ︙ |
Changes to src/dispatch.c.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
** An instance of this object defines everything we need to know about an
** individual command, webpage, or setting.
*/
struct CmdOrPage {
const char *zName; /* Name. Webpages start with "/". Commands do not */
void (*xFunc)(void); /* Implementation function, or NULL for settings */
const char *zHelp; /* Raw help text */
unsigned int eCmdFlags; /* Flags */
};
/***************************************************************************
** These macros must match similar macros in mkindex.c
** Allowed values for CmdOrPage.eCmdFlags.
*/
#define CMDFLAG_1ST_TIER 0x0001 /* Most important commands */
#define CMDFLAG_2ND_TIER 0x0002 /* Obscure and seldom used commands */
#define CMDFLAG_TEST 0x0004 /* Commands for testing only */
#define CMDFLAG_WEBPAGE 0x0008 /* Web pages */
#define CMDFLAG_COMMAND 0x0010 /* A command */
#define CMDFLAG_SETTING 0x0020 /* A setting */
#define CMDFLAG_VERSIONABLE 0x0040 /* A versionable setting */
#define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */
#define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */
#define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret POST content */
/* NOTE: 0x0400 = CMDFLAG_SENSITIVE in mkindex.c! */
#define CMDFLAG_HIDDEN 0x0800 /* Elide from most listings */
#define CMDFLAG_LDAVG_EXEMPT 0x1000 /* Exempt from load_control() */
/**************************************************************************/
/* Values for the 2nd parameter to dispatch_name_search() */
#define CMDFLAG_ANY 0x0038 /* Match anything */
#define CMDFLAG_PREFIX 0x0200 /* Prefix match is ok */
#endif /* INTERFACE */
| > > | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
** An instance of this object defines everything we need to know about an
** individual command, webpage, or setting.
*/
struct CmdOrPage {
const char *zName; /* Name. Webpages start with "/". Commands do not */
void (*xFunc)(void); /* Implementation function, or NULL for settings */
const char *zHelp; /* Raw help text */
int iHelp; /* Index of help variable */
unsigned int eCmdFlags; /* Flags */
};
/***************************************************************************
** These macros must match similar macros in mkindex.c
** Allowed values for CmdOrPage.eCmdFlags.
*/
#define CMDFLAG_1ST_TIER 0x0001 /* Most important commands */
#define CMDFLAG_2ND_TIER 0x0002 /* Obscure and seldom used commands */
#define CMDFLAG_TEST 0x0004 /* Commands for testing only */
#define CMDFLAG_WEBPAGE 0x0008 /* Web pages */
#define CMDFLAG_COMMAND 0x0010 /* A command */
#define CMDFLAG_SETTING 0x0020 /* A setting */
#define CMDFLAG_VERSIONABLE 0x0040 /* A versionable setting */
#define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */
#define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */
#define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret POST content */
/* NOTE: 0x0400 = CMDFLAG_SENSITIVE in mkindex.c! */
#define CMDFLAG_HIDDEN 0x0800 /* Elide from most listings */
#define CMDFLAG_LDAVG_EXEMPT 0x1000 /* Exempt from load_control() */
#define CMDFLAG_ALIAS 0x2000 /* Command aliases */
/**************************************************************************/
/* Values for the 2nd parameter to dispatch_name_search() */
#define CMDFLAG_ANY 0x0038 /* Match anything */
#define CMDFLAG_PREFIX 0x0200 /* Prefix match is ok */
#endif /* INTERFACE */
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 82 83 84 85 86 87 88 | ** ** The page_index.h file is generated by the mkindex program which scans all ** source code files looking for header comments on the functions that ** implement command and webpages. */ #include "page_index.h" #define MX_COMMAND count(aCommand) /* ** Given a command, webpage, or setting name in zName, find the corresponding ** CmdOrPage object and return a pointer to that object in *ppCmd. ** ** The eType field is CMDFLAG_COMMAND to look up commands, CMDFLAG_WEBPAGE to ** look up webpages, CMDFLAG_SETTING to look up settings, or CMDFLAG_ANY to look | > | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | ** ** The page_index.h file is generated by the mkindex program which scans all ** source code files looking for header comments on the functions that ** implement command and webpages. */ #include "page_index.h" #define MX_COMMAND count(aCommand) #define MX_HELP_DUP 5 /* Upper bound estimate on help string duplication */ /* ** Given a command, webpage, or setting name in zName, find the corresponding ** CmdOrPage object and return a pointer to that object in *ppCmd. ** ** The eType field is CMDFLAG_COMMAND to look up commands, CMDFLAG_WEBPAGE to ** look up webpages, CMDFLAG_SETTING to look up settings, or CMDFLAG_ANY to look |
| ︙ | ︙ | |||
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 |
}
/*
** Display help for all commands based on provided flags.
*/
static void display_all_help(int mask, int useHtml, int rawOut){
int i;
if( useHtml ) fossil_print("<!--\n");
fossil_print("Help text for:\n");
if( mask & CMDFLAG_1ST_TIER ) fossil_print(" * Commands\n");
if( mask & CMDFLAG_2ND_TIER ) fossil_print(" * Auxiliary commands\n");
if( mask & CMDFLAG_TEST ) fossil_print(" * Test commands\n");
if( mask & CMDFLAG_WEBPAGE ) fossil_print(" * Web pages\n");
if( mask & CMDFLAG_SETTING ) fossil_print(" * Settings\n");
if( useHtml ){
fossil_print("-->\n");
fossil_print("<!-- start_all_help -->\n");
}else{
fossil_print("---\n");
}
for(i=0; i<MX_COMMAND; i++){
if( (aCommand[i].eCmdFlags & mask)==0 ) continue;
else if(aCommand[i].eCmdFlags & CMDFLAG_HIDDEN) continue;
| > > > > > > > > > > > | | | | > | > > | | | > | | | | | | > | > | | > | | > > > | < | < > | > > | > > > | 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
}
/*
** Display help for all commands based on provided flags.
*/
static void display_all_help(int mask, int useHtml, int rawOut){
int i;
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help string occurrences */
int bktHelp[FOSSIL_MX_CMDIDX][MX_HELP_DUP] = {0};/* Help strings -> commands*/
if( useHtml ) fossil_print("<!--\n");
fossil_print("Help text for:\n");
if( mask & CMDFLAG_1ST_TIER ) fossil_print(" * Commands\n");
if( mask & CMDFLAG_2ND_TIER ) fossil_print(" * Auxiliary commands\n");
if( mask & CMDFLAG_ALIAS ) fossil_print(" * Aliases\n");
if( mask & CMDFLAG_TEST ) fossil_print(" * Test commands\n");
if( mask & CMDFLAG_WEBPAGE ) fossil_print(" * Web pages\n");
if( mask & CMDFLAG_SETTING ) fossil_print(" * Settings\n");
if( useHtml ){
fossil_print("-->\n");
fossil_print("<!-- start_all_help -->\n");
}else{
fossil_print("---\n");
}
/* Fill in help string buckets */
for(i=0; i<MX_COMMAND; i++){
if( (aCommand[i].eCmdFlags & mask)==0 ) continue;
else if(aCommand[i].eCmdFlags & CMDFLAG_HIDDEN) continue;
bktHelp[aCommand[i].iHelp][occHelp[aCommand[i].iHelp]++] = i;
}
for(i=0; i<MX_COMMAND; i++){
if( (aCommand[i].eCmdFlags & mask)==0 ) continue;
else if(aCommand[i].eCmdFlags & CMDFLAG_HIDDEN) continue;
if( occHelp[aCommand[i].iHelp] > 0 ){
int j;
if( useHtml ){
Blob html;
blob_init(&html, 0, 0);
help_to_html(aCommand[i].zHelp, &html);
for(j=0; j<occHelp[aCommand[i].iHelp]; j++){
fossil_print("<h1>%h</h1>\n",
aCommand[bktHelp[aCommand[i].iHelp][j]].zName);
}
fossil_print("%s\n<hr>\n", blob_str(&html));
blob_reset(&html);
}else if( rawOut ){
for(j=0; j<occHelp[aCommand[i].iHelp]; j++)
fossil_print("# %s\n", aCommand[bktHelp[aCommand[i].iHelp][j]].zName);
fossil_print("%s\n\n", aCommand[i].zHelp);
}else{
Blob txt;
blob_init(&txt, 0, 0);
help_to_text(aCommand[i].zHelp, &txt);
for(j=0; j<occHelp[aCommand[i].iHelp]; j++){
fossil_print("# %s%s\n",
aCommand[bktHelp[aCommand[i].iHelp][j]].zName,
(aCommand[i].eCmdFlags & CMDFLAG_VERSIONABLE)!=0 ?
" (versionable)" : "");
}
fossil_print("%s\n\n", blob_str(&txt));
blob_reset(&txt);
}
occHelp[aCommand[i].iHelp] = 0;
}
}
if( useHtml ){
fossil_print("<!-- end_all_help -->\n");
}else{
fossil_print("---\n");
}
version_cmd();
}
/*
** COMMAND: test-all-help
**
** Usage: %fossil test-all-help ?OPTIONS?
**
** Show help text for commands and pages. Useful for proof-reading.
** Defaults to just the CLI commands. Specify --www to see only the
** web pages, or --everything to see both commands and pages.
**
** Options:
** -a|--aliases Show aliases.
** -e|--everything Show all commands and pages. Omit aliases to
** avoid duplicates.
** -h|--html Transform output to HTML.
** -o|--options Show global options.
** -r|--raw No output formatting.
** -s|--settings Show settings.
** -t|--test Include test- commands.
** -w|--www Show WWW pages.
*/
void test_all_help_cmd(void){
int mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER;
int useHtml = find_option("html","h",0)!=0;
int rawOut = find_option("raw","r",0)!=0;
if( find_option("www","w",0) ){
mask = CMDFLAG_WEBPAGE;
}
if( find_option("everything","e",0) ){
mask = CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER | CMDFLAG_WEBPAGE |
CMDFLAG_ALIAS | CMDFLAG_SETTING | CMDFLAG_TEST;
}
if( find_option("settings","s",0) ){
mask = CMDFLAG_SETTING;
}
if( find_option("aliases","a",0) ){
mask = CMDFLAG_ALIAS;
}
if( find_option("test","t",0) ){
mask |= CMDFLAG_TEST;
}
display_all_help(mask, useHtml, rawOut);
}
/*
|
| ︙ | ︙ | |||
653 654 655 656 657 658 659 660 661 662 663 664 665 666 |
void test_command_stats_cmd(void){
fossil_print("commands: %4d\n",
countCmds( CMDFLAG_COMMAND ));
fossil_print(" 1st tier %4d\n",
countCmds( CMDFLAG_1ST_TIER ));
fossil_print(" 2nd tier %4d\n",
countCmds( CMDFLAG_2ND_TIER ));
fossil_print(" test %4d\n",
countCmds( CMDFLAG_TEST ));
fossil_print("web-pages: %4d\n",
countCmds( CMDFLAG_WEBPAGE ));
fossil_print("settings: %4d\n",
countCmds( CMDFLAG_SETTING ));
fossil_print("total entries: %4d\n", MX_COMMAND);
| > > | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 |
void test_command_stats_cmd(void){
fossil_print("commands: %4d\n",
countCmds( CMDFLAG_COMMAND ));
fossil_print(" 1st tier %4d\n",
countCmds( CMDFLAG_1ST_TIER ));
fossil_print(" 2nd tier %4d\n",
countCmds( CMDFLAG_2ND_TIER ));
fossil_print(" alias %4d\n",
countCmds( CMDFLAG_ALIAS ));
fossil_print(" test %4d\n",
countCmds( CMDFLAG_TEST ));
fossil_print("web-pages: %4d\n",
countCmds( CMDFLAG_WEBPAGE ));
fossil_print("settings: %4d\n",
countCmds( CMDFLAG_SETTING ));
fossil_print("total entries: %4d\n", MX_COMMAND);
|
| ︙ | ︙ | |||
826 827 828 829 830 831 832 |
@ <div class="helpPage">
help_to_html(pCmd->zHelp, cgi_output_blob());
@ </div>
}
}
}else{
int i;
| | > > > > > > > | > > > > > > > > | > > > > > > > > > > > > > > > | 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 |
@ <div class="helpPage">
help_to_html(pCmd->zHelp, cgi_output_blob());
@ </div>
}
}
}else{
int i;
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help str occurrences */
int bktHelp[FOSSIL_MX_CMDIDX][MX_HELP_DUP] = {0};/* Help str -> commands */
style_header("Help");
@ <a name='commands'></a>
@ <h1>Available commands:</h1>
@ <div class="columns" style="column-width: 12ex;">
@ <ul>
/* Fill in help string buckets */
for(i=0; i<MX_COMMAND; i++){
if(aCommand[i].eCmdFlags & CMDFLAG_HIDDEN) continue;
bktHelp[aCommand[i].iHelp][occHelp[aCommand[i].iHelp]++] = i;
}
for(i=0; i<MX_COMMAND; i++){
const char *z = aCommand[i].zName;
const char *zBoldOn = aCommand[i].eCmdFlags&CMDFLAG_1ST_TIER?"<b>" :"";
const char *zBoldOff = aCommand[i].eCmdFlags&CMDFLAG_1ST_TIER?"</b>":"";
if( '/'==*z || strncmp(z,"test",4)==0 ) continue;
if( (aCommand[i].eCmdFlags & CMDFLAG_SETTING)!=0 ) continue;
else if( (aCommand[i].eCmdFlags & CMDFLAG_HIDDEN)!=0 ) continue;
else if( (aCommand[i].eCmdFlags & CMDFLAG_ALIAS)!=0 ) continue;
@ <li><a href="%R/help?cmd=%s(z)">%s(zBoldOn)%s(z)%s(zBoldOff)</a>
/* Output aliases */
if( occHelp[aCommand[i].iHelp] > 1 ){
int j;
int aliases[MX_HELP_DUP], nAliases=0;
for(j=0; j<occHelp[aCommand[i].iHelp]; j++){
if( bktHelp[aCommand[i].iHelp][j] != i ){
if( aCommand[bktHelp[aCommand[i].iHelp][j]].eCmdFlags & CMDFLAG_ALIAS ){
aliases[nAliases++] = bktHelp[aCommand[i].iHelp][j];
}
}
}
if( nAliases>0 ){
int k;
@(\
for(k=0; k<nAliases; k++){
@<a href="%R/help?cmd=%s(aCommand[aliases[k]].zName)">\
@%s(aCommand[aliases[k]].zName)</a>%s((k<nAliases-1)?", ":"")\
}
@)\
}
}
@ </li>
}
@ </ul></div>
@ <a name='webpages'></a>
@ <h1>Available web UI pages:</h1>
@ <div class="columns" style="column-width: 18ex;">
@ <ul>
for(i=0; i<MX_COMMAND; i++){
|
| ︙ | ︙ | |||
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 |
/*
** WEBPAGE: test-all-help
**
** Show all help text on a single page. Useful for proof-reading.
*/
void test_all_help_page(void){
int i;
Blob buf;
blob_init(&buf,0,0);
style_set_current_feature("test");
style_header("All Help Text");
@ <dl>
for(i=0; i<MX_COMMAND; i++){
const char *zDesc;
unsigned int e = aCommand[i].eCmdFlags;
if( e & CMDFLAG_1ST_TIER ){
zDesc = "1st tier command";
}else if( e & CMDFLAG_2ND_TIER ){
zDesc = "2nd tier command";
}else if( e & CMDFLAG_TEST ){
zDesc = "test command";
}else if( e & CMDFLAG_WEBPAGE ){
if( e & CMDFLAG_RAWCONTENT ){
zDesc = "raw-content web page";
}else{
zDesc = "web page";
| > > > > > > > > > | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 |
/*
** WEBPAGE: test-all-help
**
** Show all help text on a single page. Useful for proof-reading.
*/
void test_all_help_page(void){
int i;
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help string occurrences */
int bktHelp[FOSSIL_MX_CMDIDX][MX_HELP_DUP] = {0};/* Help strings -> commands*/
Blob buf;
blob_init(&buf,0,0);
style_set_current_feature("test");
style_header("All Help Text");
@ <dl>
/* Fill in help string buckets */
for(i=0; i<MX_COMMAND; i++){
if(aCommand[i].eCmdFlags & CMDFLAG_HIDDEN) continue;
bktHelp[aCommand[i].iHelp][occHelp[aCommand[i].iHelp]++] = i;
}
for(i=0; i<MX_COMMAND; i++){
const char *zDesc;
unsigned int e = aCommand[i].eCmdFlags;
if( e & CMDFLAG_1ST_TIER ){
zDesc = "1st tier command";
}else if( e & CMDFLAG_2ND_TIER ){
zDesc = "2nd tier command";
}else if( e & CMDFLAG_ALIAS ){
zDesc = "alias";
}else if( e & CMDFLAG_TEST ){
zDesc = "test command";
}else if( e & CMDFLAG_WEBPAGE ){
if( e & CMDFLAG_RAWCONTENT ){
zDesc = "raw-content web page";
}else{
zDesc = "web page";
|
| ︙ | ︙ | |||
938 939 940 941 942 943 944 |
if( e & CMDFLAG_BOOLEAN ){
blob_appendf(&buf, "boolean ");
}
blob_appendf(&buf,"setting");
zDesc = blob_str(&buf);
}
if( memcmp(aCommand[i].zName, "test", 4)==0 ) continue;
| > > > > > > > > > > > > > > > > > > > > > | > | | | > > | 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 |
if( e & CMDFLAG_BOOLEAN ){
blob_appendf(&buf, "boolean ");
}
blob_appendf(&buf,"setting");
zDesc = blob_str(&buf);
}
if( memcmp(aCommand[i].zName, "test", 4)==0 ) continue;
if( occHelp[aCommand[i].iHelp] > 0 ){
int j;
for(j=0; j<occHelp[aCommand[i].iHelp]; j++){
unsigned int e = aCommand[bktHelp[aCommand[i].iHelp][j]].eCmdFlags;
if( e & CMDFLAG_1ST_TIER ){
zDesc = "1st tier command";
}else if( e & CMDFLAG_2ND_TIER ){
zDesc = "2nd tier command";
}else if( e & CMDFLAG_ALIAS ){
zDesc = "alias";
}else if( e & CMDFLAG_TEST ){
zDesc = "test command";
}else if( e & CMDFLAG_WEBPAGE ){
if( e & CMDFLAG_RAWCONTENT ){
zDesc = "raw-content web page";
}else{
zDesc = "web page";
}
}
@ <dt><big><b>%s(aCommand[bktHelp[aCommand[i].iHelp][j]].zName)</b>
@</big> (%s(zDesc))</dt>
}
@ <dd>
help_to_html(aCommand[i].zHelp, cgi_output_blob());
@ </dd>
occHelp[aCommand[i].iHelp] = 0;
}
}
@ </dl>
blob_reset(&buf);
style_finish_page();
}
static void multi_column_list(const char **azWord, int nWord){
|
| ︙ | ︙ |
Changes to src/encode.c.
| ︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
blob_append(p, """, 6);
j = i+1;
break;
case '\'':
if( j<i ) blob_append(p, zIn+j, i-j);
blob_append(p, "'", 5);
j = i+1;
break;
}
}
if( j<i ) blob_append(p, zIn+j, i-j);
}
| > > > > > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
blob_append(p, """, 6);
j = i+1;
break;
case '\'':
if( j<i ) blob_append(p, zIn+j, i-j);
blob_append(p, "'", 5);
j = i+1;
break;
case '\r':
if( j<i ) blob_append(p, zIn+j, i-j);
blob_append(p, " ", 1);
j = i+1;
break;
}
}
if( j<i ) blob_append(p, zIn+j, i-j);
}
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
491 492 493 494 495 496 497 498 499 500 501 502 503 504 |
#ifdef _WIN32
rc = win32_chdir(zPath, bChroot);
#else
rc = chdir(zPath);
if( !rc && bChroot ){
rc = chroot(zPath);
if( !rc ) rc = chdir("/");
}
#endif
fossil_path_free(zPath);
return rc;
}
/*
| > | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 |
#ifdef _WIN32
rc = win32_chdir(zPath, bChroot);
#else
rc = chdir(zPath);
if( !rc && bChroot ){
rc = chroot(zPath);
if( !rc ) rc = chdir("/");
g.fJail = 1;
}
#endif
fossil_path_free(zPath);
return rc;
}
/*
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 | ** in time. The default mode is -l. ** ** For the -l|--log mode: If "-b|--brief" is specified one line per revision ** is printed, otherwise the full comment is printed. The "-n|--limit N" ** and "--offset P" options limits the output to the first N changes ** after skipping P changes. ** | | > > > | | | | | > > | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
** in time. The default mode is -l.
**
** For the -l|--log mode: If "-b|--brief" is specified one line per revision
** is printed, otherwise the full comment is printed. The "-n|--limit N"
** and "--offset P" options limits the output to the first N changes
** after skipping P changes.
**
** The -i mode will print various facts about FILENAME, including its
** hash and the check-in and time when the current version of the file
** was created. Use -v for additional information. Add the -r VERSION
** option to see similar information about the same file for the check-in
** specified by VERSION.
**
** In the -s mode prints the status as <status> <revision>. This is
** a quick status and does not check for up-to-date-ness of the file.
**
** In the -p mode, there's an optional flag "-r|--revision REVISION".
** The specified version (or the latest checked out version) is printed
** to stdout. The -p mode is another form of the "cat" command.
**
** Options:
** -b|--brief Display a brief (one line / revision) summary
** --case-sensitive B Enable or disable case-sensitive filenames. B is a
** boolean: "yes", "no", "true", "false", etc.
** -i|--id Print the artifact ID
** -l|--log Select log mode (the default)
** -n|--limit N Display the first N changes (default unlimited).
** N less than 0 means no limit.
** --offset P Skip P changes
** -p|--print Select print mode
** -r|--revision R Print the given revision (or ckout, if none is given)
** to stdout (only in print mode)
** -s|--status Select status mode (print a status indicator for FILE)
** -v|--verbose On the -i option, show all check-ins that use the
** file, not just the earliest check-in
** -W|--width N Width of lines (default is to auto-detect). Must be
** more than 22 or else 0 to indicate no limit.
**
** See also: [[artifact]], [[cat]], [[descendants]], [[info]], [[leaves]]
*/
void finfo_cmd(void){
db_must_be_within_tree();
if( find_option("status","s",0) ){
Stmt q;
|
| ︙ | ︙ | |||
140 141 142 143 144 145 146 147 148 149 150 |
}
blob_write_to_file(&record, "-");
blob_reset(&record);
blob_reset(&fname);
}else if( find_option("id","i",0) ){
Blob fname;
int rid;
const char *zRevision = find_option("revision", "r", 1);
verify_all_options();
| > > | | | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
}
blob_write_to_file(&record, "-");
blob_reset(&record);
blob_reset(&fname);
}else if( find_option("id","i",0) ){
Blob fname;
int rid;
int whatisFlags = WHATIS_BRIEF;
const char *zRevision = find_option("revision", "r", 1);
if( find_option("verbose","v",0)!=0 ) whatisFlags = 0;
verify_all_options();
if( zRevision==0 ) zRevision = "current";
if( g.argc!=3 ) usage("FILENAME");
file_tree_name(g.argv[2], &fname, 0, 1);
rid = db_int(0, "SELECT rid FROM blob WHERE uuid ="
" (SELECT uuid FROM files_of_checkin(%Q)"
" WHERE filename=%B %s)",
zRevision, &fname, filename_collation());
if( rid==0 ) {
fossil_fatal("file not found for revision %s: %s",
zRevision, blob_str(&fname));
}
whatis_rid(rid,whatisFlags);
blob_reset(&fname);
}else{
Blob line;
Stmt q;
Blob fname;
int rid;
const char *zFilename;
|
| ︙ | ︙ |
Changes to src/href.js.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | ** ** The <script> must have an id='href-data'. DELAY is the number ** milliseconds delay prior to populating href= and action=. If the ** mouseover boolean is true, then the href= rewrite is further delayed ** until the first mousedown event that occurs after the timer expires. */ var antiRobot = 0; | < | | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
**
** The <script> must have an id='href-data'. DELAY is the number
** milliseconds delay prior to populating href= and action=. If the
** mouseover boolean is true, then the href= rewrite is further delayed
** until the first mousedown event that occurs after the timer expires.
*/
var antiRobot = 0;
function antiRobotGo(){
if( antiRobot!=3 ) return;
antiRobot = 7;
var anchors = document.getElementsByTagName("a");
for(var i=0; i<anchors.length; i++){
var j = anchors[i];
if(j.hasAttribute("data-href")) j.href=j.getAttribute("data-href");
}
var forms = document.getElementsByTagName("form");
for(var i=0; i<forms.length; i++){
var j = forms[i];
if(j.hasAttribute("data-action")) j.action=j.getAttribute("data-action");
}
}
function antiRobotDefense(){
var x = document.getElementById("href-data");
var jx = x.textContent || x.innerText;
var g = JSON.parse(jx);
if( g.mouseover ){
document.body.onmousedown=function(){
antiRobot |= 2;
antiRobotGo();
document.body.onmousedown=null;
}
document.body.onmousemove=function(){
antiRobot |= 2;
antiRobotGo();
document.body.onmousemove=null;
}
}else{
antiRobot |= 2;
}
if( g.delay>0 ){
setTimeout(function(){
antiRobot |= 1;
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
2451 2452 2453 2454 2455 2456 2457 |
url_initialize(&url, g.zPath);
url_add_parameter(&url, "name", zName);
url_add_parameter(&url, "ci", zCI); /* no-op if zCI is NULL */
if( zCI==0 && !isFile ){
/* If there is no ci= query parameter, then prefer to interpret
| | | 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 |
url_initialize(&url, g.zPath);
url_add_parameter(&url, "name", zName);
url_add_parameter(&url, "ci", zCI); /* no-op if zCI is NULL */
if( zCI==0 && !isFile ){
/* If there is no ci= query parameter, then prefer to interpret
** name= as a hash for /artifact and /whatis. But not for /file.
** For /file, a name= without a ci= will prefer to use the default
** "tip" value for ci=. */
rid = name_to_rid(zName);
}
if( rid==0 ){
rid = artifact_from_ci_and_filename(0);
}
|
| ︙ | ︙ |
Changes to src/login.c.
| ︙ | ︙ | |||
2121 2122 2123 2124 2125 2126 2127 | ** COMMAND: login-group* ** ** Usage: %fossil login-group ?SUBCOMMAND? ?OPTIONS? ** ** Run various subcommands to manage login-group related settings of the open ** repository or of the repository identified by the -R or --repository option. ** | | | > | > | > | < | | | | | < < < | | | | 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 |
** COMMAND: login-group*
**
** Usage: %fossil login-group ?SUBCOMMAND? ?OPTIONS?
**
** Run various subcommands to manage login-group related settings of the open
** repository or of the repository identified by the -R or --repository option.
**
** > fossil login-group ?-R REPO?
**
** Show the login-group to which REPO, or if invoked from within a checkout
** the repository on which the current checkout is based, belongs.
**
** > fossil login-group join ?-R? REPO ?--name NAME?
**
** This subcommand must be invoked from within a checkout to either: add
** the open repository to the login group that REPO is a member, in which
** case the optional "--name" argument is not required; or create a new
** login group between the open repository and REPO, in which case the new
** group NAME is determined by the mandatory "--name" option. REPO may be
** specified with or without the -R flag.
**
** > fossil login-group leave ?-R REPO?
**
** Take the repository REPO, or if invoked from within a checkout the
** repository on which the current checkout is based, out of whatever
** login group it is a member.
**
** About Login Groups:
**
** A login-group is a set of repositories that share user credentials.
** If a user is logged into one member of the group, then that user can
** access any other group member as long as they have an entry in the USER
** table of that member. If a user changes their password using web
** interface, their password is also automatically changed in every other
** member of the login group.
*/
void login_group_command(void){
|
| ︙ | ︙ | |||
2201 2202 2203 2204 2205 2206 2207 |
/* Show the current login group information */
zLGName = login_group_name();
if( zLGName==0 ){
fossil_print("Not currently a part of any login-group\n");
return;
}
fossil_print("Now part of login-group \"%s\" with:\n", zLGName);
| | | 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 |
/* Show the current login group information */
zLGName = login_group_name();
if( zLGName==0 ){
fossil_print("Not currently a part of any login-group\n");
return;
}
fossil_print("Now part of login-group \"%s\" with:\n", zLGName);
db_prepare(&q, "SELECT value FROM config WHERE name LIKE 'peer-repo-%%'");
while( db_step(&q)==SQLITE_ROW ){
fossil_print(" %s\n", db_column_text(&q,0));
}
db_finalize(&q);
}
|
Changes to src/main.c.
| ︙ | ︙ | |||
1509 1510 1511 1512 1513 1514 1515 |
if( strncmp(zRepo, zDir, n)!=0 ){
fossil_fatal("repo %s not under chroot dir %s", zRepo, zDir);
}
zRepo += n;
if( *zRepo == '\0' ) zRepo = "/";
}else {
zRepo = "/";
| < | 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 |
if( strncmp(zRepo, zDir, n)!=0 ){
fossil_fatal("repo %s not under chroot dir %s", zRepo, zDir);
}
zRepo += n;
if( *zRepo == '\0' ) zRepo = "/";
}else {
zRepo = "/";
}
if( file_chdir(zDir, 1) ){
fossil_panic("unable to chroot into %s", zDir);
}
}else{
for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
if( zDir[i]!='/' ) fossil_fatal("bad repository name: %s", zRepo);
|
| ︙ | ︙ | |||
2449 2450 2451 2452 2453 2454 2455 |
** Set CGI parameter "HOME" to VALUE. This is legacy. Use
** setenv: instead.
*/
cgi_setenv("HOME", blob_str(&value));
blob_reset(&value);
continue;
}
| | | > > > > | 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 |
** Set CGI parameter "HOME" to VALUE. This is legacy. Use
** setenv: instead.
*/
cgi_setenv("HOME", blob_str(&value));
blob_reset(&value);
continue;
}
if( blob_eq(&key, "skin:") ){
/* skin: LABEL
**
** Use one of the built-in skins defined by LABEL. LABEL is the
** name of the subdirectory under the skins/ directory that holds
** the elements of the built-in skin. If LABEL does not match,
** this directive is a silent no-op. It may alternately be
** an absolute path to a directory which holds skin definition
** files (header.txt, footer.txt, etc.). If LABEL is empty,
** the skin stored in the CONFIG db table is used.
*/
blob_token(&line, &value);
fossil_free(skin_use_alternative(blob_str(&value), 1));
blob_reset(&value);
continue;
}
if( blob_eq(&key, "jsmode:") && blob_token(&line, &value) ){
/* jsmode: MODE
**
|
| ︙ | ︙ | |||
2718 2719 2720 2721 2722 2723 2724 | ** the redirect-to-https setting. ** --notfound URL Use URL as the "HTTP 404, object not found" page. ** --out FILE Write the HTTP reply to FILE instead of to ** standard output ** --pkey FILE Read the private key used for TLS from FILE. ** --repolist If REPOSITORY is directory, URL "/" lists all repos ** --scgi Interpret input as SCGI rather than HTTP | | > | 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 |
** the redirect-to-https setting.
** --notfound URL Use URL as the "HTTP 404, object not found" page.
** --out FILE Write the HTTP reply to FILE instead of to
** standard output
** --pkey FILE Read the private key used for TLS from FILE.
** --repolist If REPOSITORY is directory, URL "/" lists all repos
** --scgi Interpret input as SCGI rather than HTTP
** --skin LABEL Use override skin LABEL. Use an empty string ("")
** to force use of the current local skin config.
** --th-trace Trace TH1 execution (for debugging purposes)
** --usepidkey Use saved encryption key from parent process. This is
** only necessary when using SEE on Windows.
**
** See also: [[cgi]], [[server]], [[winsrv]]
*/
void cmd_http(void){
|
| ︙ | ︙ | |||
3046 3047 3048 3049 3050 3051 3052 | ** and bundled modes might result in a single ** amalgamated script or several, but both approaches ** result in fewer HTTP requests than the separate mode. ** --mainmenu FILE Override the mainmenu config setting with the contents ** of the given file. ** --max-latency N Do not let any single HTTP request run for more than N ** seconds (only works on unix) | | | | 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 | ** and bundled modes might result in a single ** amalgamated script or several, but both approaches ** result in fewer HTTP requests than the separate mode. ** --mainmenu FILE Override the mainmenu config setting with the contents ** of the given file. ** --max-latency N Do not let any single HTTP request run for more than N ** seconds (only works on unix) ** -B|--nobrowser Do not automatically launch a web-browser for the ** "fossil ui" command. ** --nocompress Do not compress HTTP replies ** --nojail Drop root privileges but do not enter the chroot jail ** --nossl do not force redirects to SSL even if the repository ** setting "redirect-to-https" requests it. This is set ** by default for the "ui" command. ** --notfound URL Redirect to URL if a page is not found. ** -p|--page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci" ** --pkey FILE Read the private key used for TLS from FILE. ** -P|--port TCPPORT listen to request on port TCPPORT ** --repolist If REPOSITORY is dir, URL "/" lists repos. ** --scgi Accept SCGI rather than HTTP ** --skin LABEL Use override skin LABEL ** --th-trace trace TH1 execution (for debugging purposes) ** --usepidkey Use saved encryption key from parent process. This is |
| ︙ | ︙ | |||
3122 3123 3124 3125 3126 3127 3128 |
zTimeout = find_option("max-latency",0,1);
#endif
g.useLocalauth = find_option("localauth", 0, 0)!=0;
Th_InitTraceLog();
zPort = find_option("port", "P", 1);
isUiCmd = g.argv[1][0]=='u';
if( isUiCmd ){
| | | | 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 |
zTimeout = find_option("max-latency",0,1);
#endif
g.useLocalauth = find_option("localauth", 0, 0)!=0;
Th_InitTraceLog();
zPort = find_option("port", "P", 1);
isUiCmd = g.argv[1][0]=='u';
if( isUiCmd ){
zInitPage = find_option("page", "p", 1);
if( zInitPage && zInitPage[0]=='/' ) zInitPage++;
zFossilCmd = find_option("fossilcmd", 0, 1);
}
zNotFound = find_option("notfound", 0, 1);
allowRepoList = find_option("repolist",0,0)!=0;
if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1;
zAltBase = find_option("baseurl", 0, 1);
fCreate = find_option("create",0,0)!=0;
if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
if( zAltBase ){
set_base_url(zAltBase);
}
g.sslNotAvailable = find_option("nossl", 0, 0)!=0 || isUiCmd;
fNoBrowser = find_option("nobrowser", "B", 0)!=0;
decode_ssl_options();
if( find_option("https",0,0)!=0 || g.httpUseSSL ){
cgi_replace_parameter("HTTPS","on");
}
if( find_option("localhost", 0, 0)!=0 ){
flags |= HTTP_SERVER_LOCALHOST;
}
|
| ︙ | ︙ | |||
3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 |
}else{
zIpAddr = mprintf("%.*s", i, zPort);
}
zPort += i+1;
}
}
iPort = mxPort = atoi(zPort);
}else{
iPort = db_get_int("http-port", 8080);
mxPort = iPort+100;
}
if( isUiCmd && !fNoBrowser ){
char *zBrowserArg;
const char *zProtocol = g.httpUseSSL ? "https" : "http";
| > | 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 |
}else{
zIpAddr = mprintf("%.*s", i, zPort);
}
zPort += i+1;
}
}
iPort = mxPort = atoi(zPort);
if( iPort<=0 ) fossil_fatal("port number must be greater than zero");
}else{
iPort = db_get_int("http-port", 8080);
mxPort = iPort+100;
}
if( isUiCmd && !fNoBrowser ){
char *zBrowserArg;
const char *zProtocol = g.httpUseSSL ? "https" : "http";
|
| ︙ | ︙ |
Changes to src/merge.c.
| ︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 |
"FROM vfile WHERE id=%d",
vid, integrateFlag?5:3, idm
);
zName = db_column_text(&q, 1);
zFullName = mprintf("%s%s", g.zLocalRoot, zName);
if( file_isfile_or_link(zFullName)
&& !db_exists("SELECT 1 FROM fv WHERE fn=%Q", zName) ){
| > > > > > | > > | 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 |
"FROM vfile WHERE id=%d",
vid, integrateFlag?5:3, idm
);
zName = db_column_text(&q, 1);
zFullName = mprintf("%s%s", g.zLocalRoot, zName);
if( file_isfile_or_link(zFullName)
&& !db_exists("SELECT 1 FROM fv WHERE fn=%Q", zName) ){
/* Name of backup file with Original content */
char *zOrig = file_newname(zFullName, "original", 1);
/* Backup previously unanaged file before to be overwritten */
file_copy(zFullName, zOrig);
fossil_free(zOrig);
fossil_print("ADDED %s (overwrites an unmanaged file)", zName);
if( !dryRunFlag ) fossil_print(", original copy backed up locally");
fossil_print("\n");
nOverwrite++;
}else{
fossil_print("ADDED %s\n", zName);
}
fossil_free(zFullName);
if( !dryRunFlag ){
undo_save(zName);
|
| ︙ | ︙ |
Changes to src/name.c.
| ︙ | ︙ | |||
842 843 844 845 846 847 848 849 850 851 |
case CFTYPE_TICKET: zType = "Ticket-change"; break;
case CFTYPE_CONTROL: zType = "Tag-change"; break;
default: break;
}
return zType;
}
/*
** Generate a description of artifact "rid"
*/
| > > > > > > > > | | | 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 |
case CFTYPE_TICKET: zType = "Ticket-change"; break;
case CFTYPE_CONTROL: zType = "Tag-change"; break;
default: break;
}
return zType;
}
/*
** Flag values for whatis_rid().
*/
#if INTERFACE
#define WHATIS_VERBOSE 0x01 /* Extra output */
#define WHATIS_BRIEF 0x02 /* Omit unnecessary output */
#endif
/*
** Generate a description of artifact "rid"
*/
void whatis_rid(int rid, int flags){
Stmt q;
int cnt;
/* Basic information about the object. */
db_prepare(&q,
"SELECT uuid, size, datetime(mtime,toLocal()), ipaddr"
" FROM blob, rcvfrom"
" WHERE rid=%d"
" AND rcvfrom.rcvid=blob.rcvid",
rid);
if( db_step(&q)==SQLITE_ROW ){
if( flags & WHATIS_VERBOSE ){
fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
fossil_print("size: %d bytes\n", db_column_int(&q,1));
fossil_print("received: %s from %s\n",
db_column_text(&q, 2),
db_column_text(&q, 3));
}else{
fossil_print("artifact: %s\n", db_column_text(&q,0));
|
| ︙ | ︙ | |||
938 939 940 941 942 943 944 |
"SELECT filename.name, blob.uuid, datetime(event.mtime,toLocal()),"
" coalesce(euser,user), coalesce(ecomment,comment)"
" FROM mlink, filename, blob, event"
" WHERE mlink.fid=%d"
" AND filename.fnid=mlink.fnid"
" AND event.objid=mlink.mid"
" AND blob.rid=mlink.mid"
| | | > > > > | 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 |
"SELECT filename.name, blob.uuid, datetime(event.mtime,toLocal()),"
" coalesce(euser,user), coalesce(ecomment,comment)"
" FROM mlink, filename, blob, event"
" WHERE mlink.fid=%d"
" AND filename.fnid=mlink.fnid"
" AND event.objid=mlink.mid"
" AND blob.rid=mlink.mid"
" ORDER BY event.mtime %s /*sort*/",
rid,
(flags & WHATIS_BRIEF) ? "LIMIT 1" : "DESC");
while( db_step(&q)==SQLITE_ROW ){
if( flags & WHATIS_BRIEF ){
fossil_print("mtime: %s\n", db_column_text(&q,2));
}
fossil_print("file: %s\n", db_column_text(&q,0));
fossil_print(" part of [%S] by %s on %s\n",
db_column_text(&q, 1),
db_column_text(&q, 3),
db_column_text(&q, 2));
fossil_print(" ");
comment_print(db_column_text(&q,4), 0, 12, -1, get_comment_format());
|
| ︙ | ︙ | |||
973 974 975 976 977 978 979 |
" WHERE blob.rid=%d",
rid
);
while( db_step(&q)==SQLITE_ROW ){
fossil_print("attachment: %s\n", db_column_text(&q,0));
fossil_print(" attached to %s %s\n",
db_column_text(&q,5), db_column_text(&q,4));
| | | 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 |
" WHERE blob.rid=%d",
rid
);
while( db_step(&q)==SQLITE_ROW ){
fossil_print("attachment: %s\n", db_column_text(&q,0));
fossil_print(" attached to %s %s\n",
db_column_text(&q,5), db_column_text(&q,4));
if( flags & WHATIS_VERBOSE ){
fossil_print(" via %s (%d)\n",
db_column_text(&q,7), db_column_int(&q,6));
}else{
fossil_print(" via %s\n",
db_column_text(&q,7));
}
fossil_print(" by user %s on %s\n",
|
| ︙ | ︙ |
Changes to src/patch.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to implement the "patch" command */ #include "config.h" #include "patch.h" #include <assert.h> /* ** Try to compute the name of the computer on which this process |
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 |
@ eventual must give up and return an empty message set. This setting
@ determines how long /chat-poll will wait before giving up. The
@ default setting of approximately 7 minutes works well on many systems.
@ Shorter delays might be required on installations that use proxies
@ or web-servers with short timeouts. For best efficiency, this value
@ should be larger rather than smaller.
@ (Property: "chat-poll-timeout")</p>
@ <hr />
multiple_choice_attribute("Alert sound",
"chat-alert-sound", "snd", azAlerts[0],
count(azAlerts)/2, azAlerts);
@ <p>The sound used in the client-side chat to indicate that a new
@ chat message has arrived.
| > > > > > > > > | 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 |
@ eventual must give up and return an empty message set. This setting
@ determines how long /chat-poll will wait before giving up. The
@ default setting of approximately 7 minutes works well on many systems.
@ Shorter delays might be required on installations that use proxies
@ or web-servers with short timeouts. For best efficiency, this value
@ should be larger rather than smaller.
@ (Property: "chat-poll-timeout")</p>
@ <hr />
entry_attribute("Chat Timeline Robot Username", 15,
"chat-timeline-user", "chatrobot", "", 0);
@ <p>If this setting is not an empty string, then any changes that appear
@ on the timeline are announced in the chatroom under the username
@ supplied. The username does not need to actually exist in the USER table.
@ Suggested username: "chat-robot".
@ (Property: "chat-timeline-user")</p>
@ <hr />
multiple_choice_attribute("Alert sound",
"chat-alert-sound", "snd", azAlerts[0],
count(azAlerts)/2, azAlerts);
@ <p>The sound used in the client-side chat to indicate that a new
@ chat message has arrived.
|
| ︙ | ︙ |
Changes to src/skins.c.
| ︙ | ︙ | |||
69 70 71 72 73 74 75 76 77 78 79 80 81 82 | ** ** The following static variable holds the name of the alternative skin, ** or NULL if the skin should be as configured. */ static struct BuiltinSkin *pAltSkin = 0; static char *zAltSkinDir = 0; static int iDraftSkin = 0; /* ** 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. ** ** The following array holds the value for all known skin details. | > > > > > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | ** ** The following static variable holds the name of the alternative skin, ** or NULL if the skin should be as configured. */ static struct BuiltinSkin *pAltSkin = 0; static char *zAltSkinDir = 0; static int iDraftSkin = 0; /* ** 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 = 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. ** ** The following array holds the value for all known skin details. |
| ︙ | ︙ | |||
137 138 139 140 141 142 143 |
** 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){
| < | | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
** 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 i;
Blob err = BLOB_INITIALIZER;
if(rank > nSkinRank) return 0;
nSkinRank = rank;
if( zName && 1==rank && strchr(zName, '/')!=0 ){
zAltSkinDir = fossil_strdup(zName);
return 0;
}
if( zName && sqlite3_strglob("draft[1-9]", zName)==0 ){
skin_use_draft(zName[5] - '0');
return 0;
|
| ︙ | ︙ | |||
847 848 849 850 851 852 853 |
"%R/setup_skinedit?w=%d&basis=%h&sk=%d",j,zBasis,iSkin);
}
@ <form action="%R/setup_skinedit" method="post"><div>
login_insert_csrf_secret();
@ <input type='hidden' name='w' value='%d(ii)'>
@ <input type='hidden' name='sk' value='%d(iSkin)'>
@ <h2>Edit %s(zTitle):</h2>
| | | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 |
"%R/setup_skinedit?w=%d&basis=%h&sk=%d",j,zBasis,iSkin);
}
@ <form action="%R/setup_skinedit" method="post"><div>
login_insert_csrf_secret();
@ <input type='hidden' name='w' value='%d(ii)'>
@ <input type='hidden' name='sk' value='%d(iSkin)'>
@ <h2>Edit %s(zTitle):</h2>
if( P("submit") && cgi_csrf_safe(0) && (zOrig==0 || strcmp(zOrig,zContent)!=0) ){
db_set_mprintf(zContent, 0, "draft%d-%s",iSkin,zFile);
}
@ <textarea name="%s(zFile)" rows="10" cols="80">\
@ %h(zContent)</textarea>
@ <br />
@ <input type="submit" name="submit" value="Apply Changes" />
if( isRevert ){
|
| ︙ | ︙ | |||
1196 1197 1198 1199 1200 1201 1202 |
nBase -= strlen(zPattern)-1;
zBase[nBase] = 0;
}
fossil_free(zPattern);
}
login_check_credentials();
style_header("Skins");
| | | > > > > > > | | | < > | 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 |
nBase -= strlen(zPattern)-1;
zBase[nBase] = 0;
}
fossil_free(zPattern);
}
login_check_credentials();
style_header("Skins");
if( iDraftSkin || nSkinRank<=1 ){
@ <p class="warning">Warning:
if( iDraftSkin>0 ){
@ you are using a draft skin,
}else{
@ this fossil instance was started with a hard-coded skin
@ value,
}
@ 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.
@ </p>
}
@ <p>The following skins are available for this repository:</p>
@ <ul>
if( pAltSkin==0 && zAltSkinDir==0 && iDraftSkin==0 ){
@ <li> Standard skin for this repository ← <i>Currently in use</i>
}else{
|
| ︙ | ︙ |
Changes to src/stash.c.
| ︙ | ︙ | |||
691 692 693 694 695 696 697 |
}else{
undo_begin();
undo_save_stash(0);
stash_drop(stashid);
undo_finish();
}
}else
| | > > > | | < < < < < | < | | > > > > > > > > > > > > > > > > | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
}else{
undo_begin();
undo_save_stash(0);
stash_drop(stashid);
undo_finish();
}
}else
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);
}else{
if( g.argc>4 ) usage("apply STASHID");
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
}
zCom = db_text(0, "SELECT comment FROM stash WHERE stashid=%d", stashid);
zDate = db_text(0, "SELECT datetime(ctime) FROM stash WHERE stashid=%d",
stashid);
zHash = db_text(0, "SELECT hash FROM stash WHERE stashid=%d", stashid);
undo_begin();
stash_apply(stashid, 0);
if( popped ) undo_save_stash(stashid);
fossil_print("%s stash:\n%5d: [%.14s] from %s\n",
popped ? "Popped" : "Applied", stashid, zHash, zDate);
if( zCom && *zCom ){
fossil_print(" ");
comment_print(zCom, 0, 7, -1, get_comment_format());
}
fossil_free(zCom);
fossil_free(zDate);
fossil_free(zHash);
undo_finish();
if( popped ) stash_drop(stashid);
}else
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();
|
| ︙ | ︙ |
Changes to src/statrep.c.
| ︙ | ︙ | |||
195 196 197 198 199 200 201 |
current year */
char showYearTotal = 0; /* Flag telling us when to show
the per-year event totals */
int nMaxEvents = 1; /* for calculating length of graph
bars. */
int iterations = 0; /* number of weeks/months we iterate
over */
| < < < < < | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
current year */
char showYearTotal = 0; /* Flag telling us when to show
the per-year event totals */
int nMaxEvents = 1; /* for calculating length of graph
bars. */
int iterations = 0; /* number of weeks/months we iterate
over */
stats_report_init_view();
db_prepare(&query,
"SELECT substr(date(mtime),1,%d) AS timeframe,"
" count(*) AS eventCount"
" FROM v_reports"
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY timeframe"
" ORDER BY timeframe DESC",
|
| ︙ | ︙ | |||
475 476 477 478 479 480 481 |
static void stats_report_day_of_week(const char *zUserName){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int rowClass = 0; /* counter for alternating
row colors */
int nMaxEvents = 1; /* max number of events for
all rows. */
| < < < < | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 |
static void stats_report_day_of_week(const char *zUserName){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int rowClass = 0; /* counter for alternating
row colors */
int nMaxEvents = 1; /* max number of events for
all rows. */
static const char *const daysOfWeek[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
};
stats_report_init_view();
db_prepare(&query,
"SELECT cast(strftime('%%w', mtime) AS INTEGER) dow,"
" COUNT(*) AS eventCount"
" FROM v_reports"
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY dow ORDER BY dow", zUserName);
@ <h1>Timeline Events (%h(stats_report_label_for_type())) by Day of the Week
|
| ︙ | ︙ | |||
548 549 550 551 552 553 554 555 556 557 558 559 560 561 |
if(!nCount) continue /* arguable! Possible? */;
else if(!nSize) nSize = 1;
rowClass = ++nRowNumber % 2;
@<tr class='row%d(rowClass)'>
@ <td>%d(dayNum)</td>
@ <td>%s(daysOfWeek[dayNum])</td>
@ <td>%d(nCount)</td>
@ <td>
@ <div class='statistics-report-graph-line'
@ style='width:%d(nSize)%%;'> </div>
@ </td>
@</tr>
}
@ </tbody></table>
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 |
if(!nCount) continue /* arguable! Possible? */;
else if(!nSize) nSize = 1;
rowClass = ++nRowNumber % 2;
@<tr class='row%d(rowClass)'>
@ <td>%d(dayNum)</td>
@ <td>%s(daysOfWeek[dayNum])</td>
@ <td>%d(nCount)</td>
@ <td>
@ <div class='statistics-report-graph-line'
@ style='width:%d(nSize)%%;'> </div>
@ </td>
@</tr>
}
@ </tbody></table>
db_finalize(&query);
}
/*
** Implements the "byhour" view for /reports. If zUserName is not NULL
** then the report is restricted to events created by the named user
** account.
*/
static void stats_report_hour_of_day(const char *zUserName){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int rowClass = 0; /* counter for alternating
row colors */
int nMaxEvents = 1; /* max number of events for
all rows. */
stats_report_init_view();
db_prepare(&query,
"SELECT cast(strftime('%%H', mtime) AS INTEGER) hod,"
" COUNT(*) AS eventCount"
" FROM v_reports"
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY hod ORDER BY hod", zUserName);
@ <h1>Timeline Events (%h(stats_report_label_for_type())) by Hour of Day
if( zUserName ){
@ for user %h(zUserName)
}
@ </h1>
db_multi_exec(
"CREATE TEMP VIEW piechart(amt,label) AS"
" SELECT count(*), strftime('%%H', mtime) hod"
" FROM v_reports"
" WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
" GROUP BY 2 ORDER BY hod;",
zUserName
);
if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
@ <center><svg width=700 height=400>
piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
@ </svg></centre><hr />
}
style_table_sorter();
@ <table class='statistics-report-table-events sortable' border='0' \
@ cellpadding='2' cellspacing='0' data-column-types='nnx' data-init-sort='1'>
@ <thead><tr>
@ <th>Hour</th>
@ <th>Events</th>
@ <th width='90%%'><!-- relative commits graph --></th>
@ </tr></thead><tbody>
while( SQLITE_ROW == db_step(&query) ){
const int nCount = db_column_int(&query, 1);
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
const int hourNum =db_column_int(&query, 0);
const int nCount = db_column_int(&query, 1);
int nSize = nCount
? (int)(100 * nCount / nMaxEvents)
: 0;
if(!nCount) continue /* arguable! Possible? */;
else if(!nSize) nSize = 1;
rowClass = ++nRowNumber % 2;
@<tr class='row%d(rowClass)'>
@ <td>%d(hourNum)</td>
@ <td>%d(nCount)</td>
@ <td>
@ <div class='statistics-report-graph-line'
@ style='width:%d(nSize)%%;'> </div>
@ </td>
@</tr>
}
@ </tbody></table>
|
| ︙ | ︙ | |||
707 708 709 710 711 712 713 714 715 716 717 718 719 720 | #define RPT_BYFILE 1 #define RPT_BYMONTH 2 #define RPT_BYUSER 3 #define RPT_BYWEEK 4 #define RPT_BYWEEKDAY 5 #define RPT_BYYEAR 6 #define RPT_LASTCHNG 7 /* Last change made for each user */ #define RPT_NONE 0 /* None of the above */ /* ** WEBPAGE: reports ** ** Shows activity reports for the repository. ** | > | 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 | #define RPT_BYFILE 1 #define RPT_BYMONTH 2 #define RPT_BYUSER 3 #define RPT_BYWEEK 4 #define RPT_BYWEEKDAY 5 #define RPT_BYYEAR 6 #define RPT_LASTCHNG 7 /* Last change made for each user */ #define RPT_BYHOUR 8 /* hour-of-day */ #define RPT_NONE 0 /* None of the above */ /* ** WEBPAGE: reports ** ** Shows activity reports for the repository. ** |
| ︙ | ︙ | |||
747 748 749 750 751 752 753 754 755 756 757 758 759 760 |
{ "File Changes","byfile", RPT_BYFILE },
{ "Last Change", "lastchng", RPT_LASTCHNG },
{ "By Month", "bymonth", RPT_BYMONTH },
{ "By User", "byuser", RPT_BYUSER },
{ "By Week", "byweek", RPT_BYWEEK },
{ "By Weekday", "byweekday", RPT_BYWEEKDAY },
{ "By Year", "byyear", RPT_BYYEAR },
};
static const char *const azType[] = {
"a", "All Changes",
"ci", "Check-ins",
"f", "Forum Posts",
"g", "Tags",
"e", "Tech Notes",
| > | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
{ "File Changes","byfile", RPT_BYFILE },
{ "Last Change", "lastchng", RPT_LASTCHNG },
{ "By Month", "bymonth", RPT_BYMONTH },
{ "By User", "byuser", RPT_BYUSER },
{ "By Week", "byweek", RPT_BYWEEK },
{ "By Weekday", "byweekday", RPT_BYWEEKDAY },
{ "By Year", "byyear", RPT_BYYEAR },
{ "By Hour", "byhour", RPT_BYHOUR },
};
static const char *const azType[] = {
"a", "All Changes",
"ci", "Check-ins",
"f", "Forum Posts",
"g", "Tags",
"e", "Tech Notes",
|
| ︙ | ︙ | |||
815 816 817 818 819 820 821 822 823 824 825 826 827 |
break;
case RPT_BYWEEKDAY:
stats_report_day_of_week(zUserName);
break;
case RPT_BYFILE:
stats_report_by_file(zUserName);
break;
case RPT_LASTCHNG:
stats_report_last_change();
break;
}
style_finish_page();
}
| > > > | 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 |
break;
case RPT_BYWEEKDAY:
stats_report_day_of_week(zUserName);
break;
case RPT_BYFILE:
stats_report_by_file(zUserName);
break;
case RPT_BYHOUR:
stats_report_hour_of_day(zUserName);
break;
case RPT_LASTCHNG:
stats_report_last_change();
break;
}
style_finish_page();
}
|
Changes to src/sync.c.
| ︙ | ︙ | |||
479 480 481 482 483 484 485 | /* ** COMMAND: remote ** COMMAND: remote-url* ** ** Usage: %fossil remote ?SUBCOMMAND ...? ** ** View or modify the URLs of remote repositories used for syncing. | > | | | | | > > > > > > > > > > | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 | /* ** COMMAND: remote ** COMMAND: remote-url* ** ** Usage: %fossil remote ?SUBCOMMAND ...? ** ** View or modify the URLs of remote repositories used for syncing. ** The "default" remote is specially named by Fossil and corresponds to ** the URL used in the most recent "sync", "push", "pull", "clone", or ** similar command. As such, the default remote can be updated by ** Fossil with each sync command. Other named remotes are persistent. ** ** > fossil remote ** ** With no arguments, this command shows the current default remote ** URL. If there is no default, it shows "off". ** ** > fossil remote add NAME URL ** ** Add a new named URL. Afterwards, NAME can be used as a short ** symbolic name for URL in contexts where a URL is required. The ** URL argument can be "default" or a prior symbolic name to make ** a copy of an existing URL under the new NAME. The "default" ** remote cannot be defined with this subcommand; instead, ** use 'fossil remote REF' as documented below. ** ** > fossil remote config-data ** ** DEBUG USE ONLY - Show the name and value of every CONFIG table ** entry in the repository that is associated with the remote URL store. ** Passwords are obscured in the output. ** ** > fossil remote delete NAME ** ** Delete a named URL previously created by the "add" subcommand. ** ** > fossil remote hyperlink ?FILENAME? ?LINENUM? ?LINENUM? ** ** Print a URL that will access the current checkout on the remote ** repository. Or if the FILENAME argument is included, print the ** URL to access that particular file within the current checkout. ** If one or two linenumber arguments are provided after the filename, ** then the URL is for the line or range of lines specified. ** ** > fossil remote list|ls ** ** Show all remote repository URLs. ** ** > fossil remote off ** ** Forget the default URL. This disables autosync. |
| ︙ | ︙ | |||
530 531 532 533 534 535 536 537 538 539 540 541 542 543 |
**
** > fossil remote scrub
**
** Forget any saved passwords for remote repositories, but continue
** to remember the URLs themselves. You will be prompted for the
** password the next time it is needed.
**
** > fossil remote REF
**
** Make REF the new default URL, replacing the prior default.
** REF may be a URL or a NAME from a prior "add".
*/
void remote_url_cmd(void){
char *zUrl, *zArg;
| > > > > > > > > > | 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
**
** > fossil remote scrub
**
** Forget any saved passwords for remote repositories, but continue
** to remember the URLs themselves. You will be prompted for the
** password the next time it is needed.
**
** > fossil remote ui ?FILENAME? ?LINENUM? ?LINENUM?
**
** Bring up a web browser pointing at the remote repository, and
** specifically to the page that describes the current checkout
** on that remote repository. Or if FILENAME and/or LINENUM arguments
** are provided, to the specific file and range of lines. This
** command is similar to "fossil remote hyperlink" except that instead
** of printing the URL, it passes the URL off to the web browser.
**
** > fossil remote REF
**
** Make REF the new default URL, replacing the prior default.
** REF may be a URL or a NAME from a prior "add".
*/
void remote_url_cmd(void){
char *zUrl, *zArg;
|
| ︙ | ︙ | |||
614 615 616 617 618 619 620 |
char *zName;
char *zUrl;
UrlData x;
if( g.argc!=5 ) usage("add NAME URL");
memset(&x, 0, sizeof(x));
zName = g.argv[3];
zUrl = g.argv[4];
| | > > > | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
char *zName;
char *zUrl;
UrlData x;
if( g.argc!=5 ) usage("add NAME URL");
memset(&x, 0, sizeof(x));
zName = g.argv[3];
zUrl = g.argv[4];
if( strcmp(zName,"default")==0 ){
fossil_fatal("update the \"default\" remote-url with 'fossil remote REF'"
"\nsee 'fossil help remote' for complete usage information");
}
db_begin_write();
if( fossil_strcmp(zUrl,"default")==0 ){
x.canonical = db_get("last-sync-url",0);
x.passwd = unobscure(db_get("last-sync-pw",0));
}else{
url_parse_local(zUrl, URL_PROMPT_PW|URL_USE_CONFIG, &x);
}
|
| ︙ | ︙ | |||
649 650 651 652 653 654 655 656 657 658 659 660 661 662 |
db_begin_write();
db_unprotect(PROTECT_CONFIG);
db_multi_exec("DELETE FROM config WHERE name glob 'sync-url:%q'", zName);
db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:%q'", zName);
db_protect_pop();
db_commit_transaction();
return;
}
if( strncmp(zArg, "scrub", nArg)==0 ){
if( g.argc!=3 ) usage("scrub");
db_begin_write();
db_unprotect(PROTECT_CONFIG);
db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:*'");
db_multi_exec("DELETE FROM config WHERE name = 'last-sync-pw'");
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 |
db_begin_write();
db_unprotect(PROTECT_CONFIG);
db_multi_exec("DELETE FROM config WHERE name glob 'sync-url:%q'", zName);
db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:%q'", zName);
db_protect_pop();
db_commit_transaction();
return;
}
if( strncmp(zArg, "hyperlink", nArg)==0
|| (nArg==2 && strcmp(zArg, "ui")==0)
){
char *zBase;
char *zUuid;
Blob fname;
Blob url;
char *zSubCmd = g.argv[2][0]=='u' ? "ui" : "hyperlink";
if( !db_table_exists("localdb","vvar") ){
fossil_fatal("the \"remote %s\" command only works from "
"within an open check-out", zSubCmd);
}
zUrl = db_get("last-sync-url", 0);
if( zUrl==0 ){
zUrl = "http://localhost:8080/";
}
url_parse(zUrl, 0);
if( g.url.isFile ){
url_parse("http://localhost:8080/", 0);
}
zBase = url_nouser(&g.url);
blob_init(&url, 0, 0);
if( g.argc==3 ){
blob_appendf(&url, "%s/info/%!S",
zBase,
db_text("???",
"SELECT uuid FROM blob, vvar"
" WHERE blob.rid=0+vvar.value"
" AND vvar.name='checkout';"
));
}else{
blob_init(&fname, 0, 0);
file_tree_name(g.argv[3], &fname, 0, 1);
zUuid = db_text(0,
"SELECT uuid FROM files_of_checkin"
" WHERE checkinID=(SELECT value FROM vvar WHERE name='checkout')"
" AND filename=%Q",
blob_str(&fname)
);
if( zUuid==0 ){
fossil_fatal("not a managed file: \"%s\"", g.argv[3]);
}
blob_appendf(&url, "%s/info/%S",zBase,zUuid);
if( g.argc>4 ){
int ln1 = atoi(g.argv[4]);
if( ln1<=0 || sqlite3_strglob("*[^0-9]*",g.argv[4])==0 ){
fossil_fatal("\"%s\" is not a valid line number", g.argv[4]);
}
if( g.argc>5 ){
int ln2 = atoi(g.argv[5]);
if( ln2==0 || sqlite3_strglob("*[^0-9]*",g.argv[5])==0 ){
fossil_fatal("\"%s\" is not a valid line number", g.argv[5]);
}
if( ln2<=ln1 ){
fossil_fatal("second line number should be greater than the first");
}
blob_appendf(&url,"?ln=%d,%d", ln1, ln2);
}else{
blob_appendf(&url,"?ln=%d", ln1);
}
}
if( g.argc>6 ){
usage(mprintf("%s ?FILENAME? ?LINENUMBER? ?LINENUMBER?", zSubCmd));
}
}
if( g.argv[2][0]=='u' ){
char *zCmd;
zCmd = mprintf("%s %!$ &", fossil_web_browser(), blob_str(&url));
fossil_system(zCmd);
}else{
fossil_print("%s\n", blob_str(&url));
}
return;
}
if( strncmp(zArg, "scrub", nArg)==0 ){
if( g.argc!=3 ) usage("scrub");
db_begin_write();
db_unprotect(PROTECT_CONFIG);
db_multi_exec("DELETE FROM config WHERE name glob 'sync-pw:*'");
db_multi_exec("DELETE FROM config WHERE name = 'last-sync-pw'");
|
| ︙ | ︙ | |||
695 696 697 698 699 700 701 |
}
if( sqlite3_strlike("http://%",zArg,0)==0
|| sqlite3_strlike("https://%",zArg,0)==0
|| sqlite3_strlike("ssh:%",zArg,0)==0
|| sqlite3_strlike("file:%",zArg,0)==0
|| db_exists("SELECT 1 FROM config WHERE name='sync-url:%q'",zArg)
){
| < | | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 |
}
if( sqlite3_strlike("http://%",zArg,0)==0
|| sqlite3_strlike("https://%",zArg,0)==0
|| sqlite3_strlike("ssh:%",zArg,0)==0
|| sqlite3_strlike("file:%",zArg,0)==0
|| db_exists("SELECT 1 FROM config WHERE name='sync-url:%q'",zArg)
){
db_unset("last-sync-url", 0);
db_unset("last-sync-pw", 0);
url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|
URL_USE_CONFIG|URL_ASK_REMEMBER_PW);
url_remember();
return;
}
fossil_fatal("unknown command \"%s\" - should be a URL or one of: "
"add delete hyperlink list off scrub", zArg);
}
/*
** COMMAND: backup*
**
** Usage: %fossil backup ?OPTIONS? FILE|DIRECTORY
**
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
1592 1593 1594 1595 1596 1597 1598 | ** to=CHECKIN ... to this ** shortest ... show only the shortest path ** rel ... also show related checkins ** 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 | | | 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 | ** to=CHECKIN ... to this ** shortest ... show only the shortest path ** rel ... also show related checkins ** 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 ** brbg Background color determined by branch name ** ubg Background color determined by user ** deltabg Background color red for delta manifests or green ** for baseline manifests ** namechng Show only check-ins that have filename changes ** forks Show only forks and their children ** cherrypicks Show all cherrypicks |
| ︙ | ︙ |
Changes to src/unversioned.c.
| ︙ | ︙ | |||
216 217 218 219 220 221 222 |
if( fossil_isspace(zName[0]) ) return 1;
zName++;
}
return 0;
}
/*
| | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
if( fossil_isspace(zName[0]) ) return 1;
zName++;
}
return 0;
}
/*
** COMMAND: uv#
** COMMAND: unversioned
**
** Usage: %fossil unversioned SUBCOMMAND ARGS...
** or: %fossil uv SUBCOMMAND ARGS..
**
** Unversioned files (UV-files) are artifacts that are synced and are available
** for download but which do not preserve history. Only the most recent version
|
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
433 434 435 436 437 438 439 |
** but also exists in the target checkout. Use the current version.
*/
fossil_print("CONFLICT %s\n", zName);
nConflict++;
}else if( idt>0 && idv==0 ){
/* File added in the target. */
if( file_isfile_or_link(zFullPath) ){
| > > > > > | > > | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
** but also exists in the target checkout. Use the current version.
*/
fossil_print("CONFLICT %s\n", zName);
nConflict++;
}else if( idt>0 && idv==0 ){
/* File added in the target. */
if( file_isfile_or_link(zFullPath) ){
/* Name of backup file with Original content */
char *zOrig = file_newname(zFullPath, "original", 1);
/* Backup previously unanaged file before to be overwritten */
file_copy(zFullPath, zOrig);
fossil_free(zOrig);
fossil_print("ADD %s - overwrites an unmanaged file", zName);
if( !dryRunFlag ) fossil_print(", original copy backed up locally");
fossil_print("\n");
nOverwrite++;
}else{
fossil_print("ADD %s\n", zName);
}
if( !dryRunFlag && !internalUpdate ) undo_save(zName);
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt>0 && idv>0 && ridt!=ridv && (chnged==0 || deleted) ){
|
| ︙ | ︙ |
Changes to src/xfer.c.
| ︙ | ︙ | |||
2066 2067 2068 2069 2070 2071 2072 |
if( (syncFlags & (SYNC_UNVERSIONED|SYNC_CLONE))!=0 ){
unversioned_schema();
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS uv_tosend("
" name TEXT PRIMARY KEY," /* Name of file to send client->server */
" mtimeOnly BOOLEAN" /* True to only send mtime, not content */
") WITHOUT ROWID;"
| | | 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 |
if( (syncFlags & (SYNC_UNVERSIONED|SYNC_CLONE))!=0 ){
unversioned_schema();
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS uv_tosend("
" name TEXT PRIMARY KEY," /* Name of file to send client->server */
" mtimeOnly BOOLEAN" /* True to only send mtime, not content */
") WITHOUT ROWID;"
"REPLACE INTO uv_tosend(name,mtimeOnly)"
" SELECT name, 0 FROM unversioned WHERE hash IS NOT NULL;"
);
}
/*
** The request from the client always begin with a clone, pull,
** or push message.
|
| ︙ | ︙ | |||
2805 2806 2807 2808 2809 2810 2811 |
/* Set go to 1 if we need to continue the sync/push/pull/clone for
** another round. Set go to 0 if it is time to quit. */
nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
go = 1;
mxPhantomReq = nFileRecv*2;
if( mxPhantomReq<200 ) mxPhantomReq = 200;
| < < > > > > > > < < < < | 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 |
/* Set go to 1 if we need to continue the sync/push/pull/clone for
** another round. Set go to 0 if it is time to quit. */
nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
go = 1;
mxPhantomReq = nFileRecv*2;
if( mxPhantomReq<200 ) mxPhantomReq = 200;
}else if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){
/* Go another round if files are queued to send */
go = 1;
}else if( xfer.nPrivIGot>0 && nCycle==1 ){
go = 1;
}else if( nUvGimmeSent>0 && (nUvFileRcvd>0 || nCycle<3) ){
/* Continue looping as long as new uvfile cards are being received
** and uvgimme cards are being sent. */
go = 1;
}else if( (syncFlags & SYNC_CLONE)!=0 ){
if( nCycle==1 ){
go = 1; /* go at least two rounds on a clone */
}else if( nFileRecv>0 ){
go = 1;
}else if( cloneSeqno>0 && nArtifactRcvd>nPriorArtifact ){
/* Continue the clone until we see the clone_seqno 0" card or
** until we stop receiving artifacts */
go = 1;
}
}
nCardRcvd = 0;
xfer.nFileRcvd = 0;
xfer.nDeltaRcvd = 0;
xfer.nDanglingFile = 0;
db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
|
| ︙ | ︙ |
Changes to tools/fslsrv.
1 | #!/bin/bash | < > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/bin/bash
FOSSIL=fossil
PGARGS="-P 1"
OLDPID=`pgrep -P 1 fossil`
SITE=https://example.com
PORT=12345
if [ "$1" = "-f" ] ; then PGARGS= ; shift ; fi
if [ -n "$OLDPID" ]
then
echo "Killing running Fossil server first..."
pkill $PGARGS fossil
|
| ︙ | ︙ | |||
35 36 37 38 39 40 41 |
then
# We're running from a build tree, so use that version instead
FOSSIL=./fossil
fi
function start_one() {
bn=$1
| < | < | > > > > > | | | > | | > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
then
# We're running from a build tree, so use that version instead
FOSSIL=./fossil
fi
function start_one() {
bn=$1
ln="$2"
$FOSSIL server $extra \
--scgi \
--localhost \
--port $PORT \
--jsmode bundled \
--baseurl ${SITE}/$bn \
--errorlog ~/log/fossil/$bn-errors.log \
~/museum/$bn.fossil > ~/log/fossil/$bn-stdout.log &
echo Started $ln Fossil server, port $PORT, PID $!.
PORT=$(($PORT + 1))
}
start_one first "First Project"
start_one second "Second Project"
start_one third "Third Project"
|
Changes to tools/makemake.tcl.
| ︙ | ︙ | |||
1142 1143 1144 1145 1146 1147 1148 | # SQLITE3_SRC.2 is set by top-level configure/makefile process. SQLITE3_SRC. = $(SRCDIR_extsrc)/sqlite3.c SQLITE3_SRC = $(SQLITE3_SRC.$(SQLITE3_ORIGIN)) SQLITE3_SHELL_SRC.0 = $(SRCDIR_extsrc)/shell.c SQLITE3_SHELL_SRC.1 = $(SRCDIR_extsrc)/shell-see.c # SQLITE3_SHELL_SRC.2 comes from the configure process SQLITE3_SHELL_SRC. = $(SRCDIR_extsrc)/shell.c | | | 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 |
# SQLITE3_SRC.2 is set by top-level configure/makefile process.
SQLITE3_SRC. = $(SRCDIR_extsrc)/sqlite3.c
SQLITE3_SRC = $(SQLITE3_SRC.$(SQLITE3_ORIGIN))
SQLITE3_SHELL_SRC.0 = $(SRCDIR_extsrc)/shell.c
SQLITE3_SHELL_SRC.1 = $(SRCDIR_extsrc)/shell-see.c
# SQLITE3_SHELL_SRC.2 comes from the configure process
SQLITE3_SHELL_SRC. = $(SRCDIR_extsrc)/shell.c
SQLITE3_SHELL_SRC = $(SQLITE3_SHELL_SRC.$(SQLITE3_ORIGIN))
SEE_FLAGS.0 =
SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key
SEE_FLAGS. =
SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE))
}
writeln [string map [list <<<NEXT_LINE>>> \\] {
|
| ︙ | ︙ |
Changes to tools/mkindex.c.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 | ** ones that show up with "fossil help". 2nd-tier are seldom-used and/or ** legacy commands. Test commands are unsupported commands used for testing ** and analysis only. ** ** Commands are 1st-tier by default. If the command name begins with ** "test-" or if the command name has a "test" argument, then it becomes ** a test command. If the command name has a "2nd-tier" argument or ends | | > > > > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | ** ones that show up with "fossil help". 2nd-tier are seldom-used and/or ** legacy commands. Test commands are unsupported commands used for testing ** and analysis only. ** ** Commands are 1st-tier by default. If the command name begins with ** "test-" or if the command name has a "test" argument, then it becomes ** a test command. If the command name has a "2nd-tier" argument or ends ** with a "*" character, it is second tier. If the command name has an "alias" ** argument or ends with a "#" character, it is an alias: another name ** (a one-to-one replacement) for a command. Examples: ** ** COMMAND: abcde* ** COMMAND: fghij 2nd-tier ** COMMAND: mnopq# ** COMMAND: rstuv alias ** COMMAND: test-xyzzy ** COMMAND: xyzzy test ** ** A SETTING: may be followed by arguments that give additional attributes ** to that setting: ** ** SETTING: clean-blob versionable width=40 block-text |
| ︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
#define CMDFLAG_VERSIONABLE 0x0040 /* A versionable setting */
#define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */
#define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */
#define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret webpage content */
#define CMDFLAG_SENSITIVE 0x0400 /* Security-sensitive setting */
#define CMDFLAG_HIDDEN 0x0800 /* Elide from most listings */
#define CMDFLAG_LDAVG_EXEMPT 0x1000 /* Exempt from load_control() */
/**************************************************************************/
/*
** Each entry looks like this:
*/
typedef struct Entry {
int eType; /* CMDFLAG_* values */
| > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
#define CMDFLAG_VERSIONABLE 0x0040 /* A versionable setting */
#define CMDFLAG_BLOCKTEXT 0x0080 /* Multi-line text setting */
#define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */
#define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret webpage content */
#define CMDFLAG_SENSITIVE 0x0400 /* Security-sensitive setting */
#define CMDFLAG_HIDDEN 0x0800 /* Elide from most listings */
#define CMDFLAG_LDAVG_EXEMPT 0x1000 /* Exempt from load_control() */
#define CMDFLAG_ALIAS 0x2000 /* Command aliases */
/**************************************************************************/
/*
** Each entry looks like this:
*/
typedef struct Entry {
int eType; /* CMDFLAG_* values */
|
| ︙ | ︙ | |||
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
/* Commands that start with "test-" are test-commands */
aEntry[nUsed].eType |= CMDFLAG_TEST;
}else if( zLine[i+j-1]=='*' ){
/* If the command name ends in '*', remove the '*' from the name
** but move the command into the second tier */
aEntry[nUsed].zPath[j-1] = 0;
aEntry[nUsed].eType |= CMDFLAG_2ND_TIER;
}else{
/* Otherwise, this is a first-tier command */
aEntry[nUsed].eType |= CMDFLAG_1ST_TIER;
}
}
/* Process additional flags that might follow the command name */
while( zLine[i+j]!=0 ){
i += j;
while( fossil_isspace(zLine[i]) ){ i++; }
if( zLine[i]==0 ) break;
for(j=0; zLine[i+j] && !fossil_isspace(zLine[i+j]); j++){}
if( j==8 && strncmp(&zLine[i], "1st-tier", j)==0 ){
| > > > > > | | | > > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
/* Commands that start with "test-" are test-commands */
aEntry[nUsed].eType |= CMDFLAG_TEST;
}else if( zLine[i+j-1]=='*' ){
/* If the command name ends in '*', remove the '*' from the name
** but move the command into the second tier */
aEntry[nUsed].zPath[j-1] = 0;
aEntry[nUsed].eType |= CMDFLAG_2ND_TIER;
}else if( zLine[i+j-1]=='#' ){
/* If the command name ends in '#', remove the '#' from the name
** but move the command into aliases */
aEntry[nUsed].zPath[j-1] = 0;
aEntry[nUsed].eType |= CMDFLAG_ALIAS;
}else{
/* Otherwise, this is a first-tier command */
aEntry[nUsed].eType |= CMDFLAG_1ST_TIER;
}
}
/* Process additional flags that might follow the command name */
while( zLine[i+j]!=0 ){
i += j;
while( fossil_isspace(zLine[i]) ){ i++; }
if( zLine[i]==0 ) break;
for(j=0; zLine[i+j] && !fossil_isspace(zLine[i+j]); j++){}
if( j==8 && strncmp(&zLine[i], "1st-tier", j)==0 ){
aEntry[nUsed].eType &= ~(CMDFLAG_2ND_TIER|CMDFLAG_TEST|CMDFLAG_ALIAS);
aEntry[nUsed].eType |= CMDFLAG_1ST_TIER;
}else if( j==8 && strncmp(&zLine[i], "2nd-tier", j)==0 ){
aEntry[nUsed].eType &= ~(CMDFLAG_1ST_TIER|CMDFLAG_TEST|CMDFLAG_ALIAS);
aEntry[nUsed].eType |= CMDFLAG_2ND_TIER;
}else if( j==4 && strncmp(&zLine[i], "test", j)==0 ){
aEntry[nUsed].eType &= ~(CMDFLAG_1ST_TIER|CMDFLAG_2ND_TIER|CMDFLAG_ALIAS);
aEntry[nUsed].eType |= CMDFLAG_TEST;
}else if( j==5 && strncmp(&zLine[i], "alias", j)==0 ){
aEntry[nUsed].eType &= ~(CMDFLAG_1ST_TIER|CMDFLAG_2ND_TIER|CMDFLAG_TEST);
aEntry[nUsed].eType |= CMDFLAG_ALIAS;
}else if( j==11 && strncmp(&zLine[i], "raw-content", j)==0 ){
aEntry[nUsed].eType |= CMDFLAG_RAWCONTENT;
}else if( j==7 && strncmp(&zLine[i], "boolean", j)==0 ){
aEntry[nUsed].eType &= ~(CMDFLAG_BLOCKTEXT);
aEntry[nUsed].iWidth = 0;
aEntry[nUsed].eType |= CMDFLAG_BOOLEAN;
}else if( j==10 && strncmp(&zLine[i], "block-text", j)==0 ){
|
| ︙ | ︙ | |||
451 452 453 454 455 456 457 |
int n = strlen(z);
if( n>mxLen ) mxLen = n;
if( aEntry[i].zIf ){
printf("%s", aEntry[i].zIf);
}else if( (aEntry[i].eType & CMDFLAG_WEBPAGE)!=0 ){
nWeb++;
}
| | > > | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
int n = strlen(z);
if( n>mxLen ) mxLen = n;
if( aEntry[i].zIf ){
printf("%s", aEntry[i].zIf);
}else if( (aEntry[i].eType & CMDFLAG_WEBPAGE)!=0 ){
nWeb++;
}
printf(" { \"%.*s\",%*s%s,%*szHelp%03d, %3d, 0x%03x },\n",
n, z,
25-n, "",
aEntry[i].zFunc,
(int)(29-strlen(aEntry[i].zFunc)), "",
aEntry[i].iHelp,
aEntry[i].iHelp,
aEntry[i].eType
);
if( aEntry[i].zIf ) printf("#endif\n");
}
printf("};\n");
printf("#define FOSSIL_FIRST_CMD %d\n", nWeb);
printf("#define FOSSIL_MX_CMDNAME %d /* max length of any command name */\n",
mxLen);
printf("#define FOSSIL_MX_CMDIDX %d /* max index for commands */\n", nFixed);
/* Generate the aSetting[] table */
printf("const Setting aSetting[] = {\n");
for(i=0; i<nFixed; i++){
const char *z;
const char *zVar;
const char *zDef;
|
| ︙ | ︙ |
Changes to tools/skintxt2config.c.
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
zMem = (unsigned char *)malloc((size_t)fpos + 1);
if(!zMem){
err("Malloc failed.");
rc = ENOMEM;
goto end;
}
zMem[fpos] = 0;
| | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
zMem = (unsigned char *)malloc((size_t)fpos + 1);
if(!zMem){
err("Malloc failed.");
rc = ENOMEM;
goto end;
}
zMem[fpos] = 0;
if(fpos && (size_t)1 != fread(zMem, (size_t)fpos, 1, f)){
rc = EIO;
err("Error #%d reading file %s", rc, zFilename);
goto end;
}
end:
fclose(f);
if(rc){
|
| ︙ | ︙ |
Changes to win/Makefile.mingw.
| ︙ | ︙ | |||
1085 1086 1087 1088 1089 1090 1091 | # SQLITE3_SRC.2 is set by top-level configure/makefile process. SQLITE3_SRC. = $(SRCDIR_extsrc)/sqlite3.c SQLITE3_SRC = $(SQLITE3_SRC.$(SQLITE3_ORIGIN)) SQLITE3_SHELL_SRC.0 = $(SRCDIR_extsrc)/shell.c SQLITE3_SHELL_SRC.1 = $(SRCDIR_extsrc)/shell-see.c # SQLITE3_SHELL_SRC.2 comes from the configure process SQLITE3_SHELL_SRC. = $(SRCDIR_extsrc)/shell.c | | | 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 | # SQLITE3_SRC.2 is set by top-level configure/makefile process. SQLITE3_SRC. = $(SRCDIR_extsrc)/sqlite3.c SQLITE3_SRC = $(SQLITE3_SRC.$(SQLITE3_ORIGIN)) SQLITE3_SHELL_SRC.0 = $(SRCDIR_extsrc)/shell.c SQLITE3_SHELL_SRC.1 = $(SRCDIR_extsrc)/shell-see.c # SQLITE3_SHELL_SRC.2 comes from the configure process SQLITE3_SHELL_SRC. = $(SRCDIR_extsrc)/shell.c SQLITE3_SHELL_SRC = $(SQLITE3_SHELL_SRC.$(SQLITE3_ORIGIN)) SEE_FLAGS.0 = SEE_FLAGS.1 = -DSQLITE_HAS_CODEC -DSQLITE_SHELL_DBKEY_PROC=fossil_key SEE_FLAGS. = SEE_FLAGS = $(SEE_FLAGS.$(USE_SEE)) EXTRAOBJ = \ |
| ︙ | ︙ |
Changes to win/Makefile.mingw.mistachkin.
| ︙ | ︙ | |||
52 53 54 55 56 57 58 | # BCC = $(BCCEXE) #### Enable compiling with debug symbols (much larger binary) # # FOSSIL_ENABLE_SYMBOLS = 1 | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | # BCC = $(BCCEXE) #### Enable compiling with debug symbols (much larger binary) # # FOSSIL_ENABLE_SYMBOLS = 1 #### Enable JSON (https://www.json.org) support using "cson" # FOSSIL_ENABLE_JSON = 1 #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) # FOSSIL_ENABLE_SSL = 1 |
| ︙ | ︙ | |||
1067 1068 1069 1070 1071 1072 1073 | # the sqlite3.o object. Instead, the system SQLite will be linked # using -lsqlite3. # # Closely related is SQLITE3_ORIGIN, with the same 0/1 mapping, # plus a value of 2 means that we are building a client-provided # sqlite3.c. SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o | | > | 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 | # the sqlite3.o object. Instead, the system SQLite will be linked # using -lsqlite3. # # Closely related is SQLITE3_ORIGIN, with the same 0/1 mapping, # plus a value of 2 means that we are building a client-provided # sqlite3.c. SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o SQLITE3_OBJ.1 = $(OBJDIR)/sqlite3-see.o # SQLITE3_OBJ.2 is set by the configure process SQLITE3_OBJ. = $(SQLITE3_OBJ.0) SQLITE3_OBJ = $(SQLITE3_OBJ.$(SQLITE3_ORIGIN)) # The USE_SEE variable may be undefined, 0 or 1. If undefined or 0, # in-tree SQLite is used. If 1, then sqlite3-see.c (not part of the # source tree) is used and extra flags are provided to enable the # SQLite Encryption Extension. SQLITE3_SRC.0 = $(SRCDIR_extsrc)/sqlite3.c SQLITE3_SRC.1 = $(SRCDIR_extsrc)/sqlite3-see.c |
| ︙ | ︙ | |||
2565 2566 2567 2568 2569 2570 2571 |
-Daccess=file_access \
-Dsystem=fossil_system \
-Dgetenv=fossil_getenv \
-Dfopen=fossil_fopen
PIKCHR_OPTIONS = -DPIKCHR_TOKEN_LIMIT=10000
| | | 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 |
-Daccess=file_access \
-Dsystem=fossil_system \
-Dgetenv=fossil_getenv \
-Dfopen=fossil_fopen
PIKCHR_OPTIONS = -DPIKCHR_TOKEN_LIMIT=10000
$(SQLITE3_OBJ): $(SQLITE3_SRC) $(SRCDIR)/../win/Makefile.mingw.mistachkin
$(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SEE_FLAGS) \
-c $(SQLITE3_SRC) -o $@
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
|
| ︙ | ︙ |
Changes to www/build.wiki.
| ︙ | ︙ | |||
248 249 250 251 252 253 254 | TCC += -DWITHOUT_ICONV TCC += -Dsocketlen_t=int TCC += -DSQLITE_MAX_MMAP_SIZE=0 </pre></blockquote> </ul> | | < < | < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | TCC += -DWITHOUT_ICONV TCC += -Dsocketlen_t=int TCC += -DSQLITE_MAX_MMAP_SIZE=0 </pre></blockquote> </ul> <h2 id="docker" name="oci">5.0 Building a Docker Container</h2> The information on building Fossil inside an [https://opencontainers.org/ | OCI container] is now in [./containers.md | a separate document]. This includes the instructions on using the OCI container as an expedient intermediary for building a statically-linked Fossil binary on modern Linux platforms, which otherwise make this difficult. <h2>6.0 Building on/for Android</h2> <h3>6.1 Cross-compiling from Linux</h3> The following instructions for building Fossil for Android via Linux, |
| ︙ | ︙ |
Changes to www/changes.wiki.
1 2 3 | <title>Change Log</title> <h2 id='v2_20'>Changes for version 2.20 (pending)</h2> | > > > > > > > > | > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<title>Change Log</title>
<h2 id='v2_20'>Changes for version 2.20 (pending)</h2>
* Added the [/help?cmd=chat-timeline-user|chat-timeline-user setting]. If
it is not an empty string, then any changes that would appear on the timeline
are announced in [./chat.md|the chat room].
* The /unsubscribe page now requests confirmation. [./alerts.md|Email notifications]
now contain only an "Unsubscribe" link, and not a link to subscription management.
* Added the "[/help?cmd=branch|fossil branch lsh]" subcommand to list the
most recently modified branches.
* More elements of the /info page are now inside of an accordion.
* Replace the <tt>--dryrun</tt> flag with <tt>--dry-run</tt> in all
commands which still used the former name, for consistency.
* Rebuilt [/file/Dockerfile | the stock Dockerfile] to create a "from scratch"
Busybox based container image via an Alpine Linux intermediary
* Added [/doc/trunk/www/containers.md | a new document] describing how to
customize, use, and run that container.
* Added "by hour of day" report to [/reports?view=byhour|the /reports page].
* Improved correctness, usability, and efficiency for the case
[/timeline?r=deltify-tkt-blobs|when values in a TICKET's column
tend to be long and volitile].
<h2 id='v2_19'>Changes for version 2.19 (2022-07-21)</h2>
* On file listing pages, sort filenames using the "uintnocase" collating
sequence, so that filenames that contains embedded integers sort in
numeric order even if they contain a different number of digits.
|
| ︙ | ︙ |
Changes to www/chat.md.
| ︙ | ︙ | |||
151 152 153 154 155 156 157 158 159 160 161 162 163 164 | > ~~~~ fossil chat send --remote https://robot:PASSWORD@project.org/fossil \ --message 'MESSAGE TEXT' --file file-to-attach.txt ~~~~ Substitute the appropriate project URL, robot account name and password, message text and file attachment, of course. ## Implementation Details *You do not need to understand how Fossil chat works in order to use it. But many developers prefer to know how their tools work. This section is provided for the benefit of those curious developers.* | > > > > > > > > > > > > | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | > ~~~~ fossil chat send --remote https://robot:PASSWORD@project.org/fossil \ --message 'MESSAGE TEXT' --file file-to-attach.txt ~~~~ Substitute the appropriate project URL, robot account name and password, message text and file attachment, of course. ### <a id="chat-robot"></a> Chat Messages For Timeline Events If the [chat-timeline-user setting](/help?cmd=chat-timeline-user) is not a empty string, then any change to the repository that would normally result in a new timeline entry is announced in the chatroom. The announcement appears to come from a user whose name is given by the chat-timeline-user setting. This mechanism is similar to [email notification](./alerts.md) except that the notification is sent via chat instead of via email. ## Implementation Details *You do not need to understand how Fossil chat works in order to use it. But many developers prefer to know how their tools work. This section is provided for the benefit of those curious developers.* |
| ︙ | ︙ |
Added www/containers.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 |
# OCI Containers
This document shows how to build Fossil into [OCI] compatible containers
and how to use those containers in interesting ways. We start off using
the original and still most popular container development and runtime
platform, [Docker], but since you have more options than that, we will
show some of these options later on.
[Docker]: https://www.docker.com/
[OCI]: https://opencontainers.org/
## 1. Quick Start
Fossil ships a `Dockerfile` at the top of its source tree which you can
build like so:
```
$ docker build -t fossil .
```
If the image built successfully, you can create a container from it and
test that it runs:
```
$ docker run --name fossil -p 9999:8080/tcp fossil
```
This shows us remapping the internal TCP listening port as 9999 on the
host. This feature of OCI runtimes means there’s little point to using
the “`fossil server --port`” feature inside the container. We can let
Fossil default to 8080 internally, then remap it to wherever we want it
on the host instead.
Our stock `Dockerfile` configures Fossil with the default feature set,
so you may wish to modify the `Dockerfile` to add configuration options,
add APK packages to support those options, and so forth. It also strips
out all but the default and darkmode skins to save executable space.
The Fossil `Makefile` provides two convenience targets,
“`make container-image`” and “`make container-run`”. The first creates a
versioned container image, and the second does that and then launches a
fresh container based on that image. You can pass extra arguments to the
first command via the Makefile’s `DBFLAGS` variable and to the second
with the `DRFLAGS` variable. (DB is short for “`docker build`”, and DR
is short for “`docker run`”.) To get the custom port setting as in
second command above, say:
```
$ make container-run DRFLAGS='-p 9999:8080/tcp'
```
Contrast the raw “`docker`” commands above, which create an
_unversioned_ image called `fossil:latest` and from that a container
simply called `fossil`. The unversioned names are more convenient for
interactive use, while the versioned ones are good for CI/CD type
applications since they avoid a conflict with past versions; it lets you
keep old containers around for quick roll-backs while replacing them
with fresh ones.
## 2. <a id="storage"></a>Repository Storage Options
If you want the container to serve an existing repository, there are at
least two right ways to do it.
The wrong way is to use the `Dockerfile COPY` command, because by baking
the repo into the image at build time, it will become one of the image’s
base layers. The end result is that each time you build a container from
that image, the repo will be reset to its build-time state. Worse,
restarting the container will do the same thing, since the base image
layers are immutable in Docker. This is almost certainly not what you
want.
The correct ways put the repo into the _container_ created from the
_image_, not in the image itself.
### <a id="repo-inside"></a> 2.1 Storing the Repo Inside the Container
The simplest method is to stop the container if it was running, then
say:
```
$ docker cp /path/to/my-project.fossil fossil:/jail/museum/repo.fossil
$ docker start fossil
$ docker exec fossil chown -R 499 /jail/museum
```
That copies the local Fossil repo into the container where the server
expects to find it, so that the “start” command causes it to serve from
that copied-in file instead. Since it lives atop the immutable base
layers, it persists as part of the container proper, surviving restarts.
Notice that the copy command changes the name of the repository
database. The container configuration expects it to be called
`repo.fossil`, which it almost certainly was not out on the host system.
This is because there is only one repository inside this container, so
we don’t have to name it after the project it contains, as is
traditional. A generic name lets us hard-code the server start command.
If you skip the “chown” command above and put “`http://localhost:9999/`”
into your browser, expecting to see the copied-in repo’s home page, you
will get an opaque “Not Found” error. This is because the user and group
ID of the file will be that of your local user on the container’s host
machine, which is unlikely to map to anything in the container’s
`/etc/passwd` and `/etc/group` files, effectively preventing the server
from reading the copied-in repository file. 499 is the default “`fossil`”
user ID inside the container, causing Fossil to run with that user’s
privileges after it enters the chroot. (See [below](#args) for how to
change this default.) You don’t have to restart the server after fixing
this with `chmod`: simply reload the browser, and Fossil will try again.
### 2.2 <a id="bind-mount"></a>Storing the Repo Outside the Container
The simple storage method above has a problem: Docker containers are
designed to be killed off at the slightest cause, rebuilt, and
redeployed. If you do that with the repo inside the container, it gets
destroyed, too. The solution is to replace the “run” command above with
the following:
```
$ docker run \
--publish 9999:8080 \
--name fossil-bind-mount \
--volume ~/museum:/jail/museum \
fossil
```
Because this bind mount maps a host-side directory (`~/museum`) into the
container, you don’t need to `docker cp` the repo into the container at
all. It still expects to find the repository as `repo.fossil` under that
directory, but now both the host and the container can see that repo DB.
Instead of a bind mount, you could instead set up a separate [Docker
volume](https://docs.docker.com/storage/volumes/), at which point you
_would_ need to `docker cp` the repo file into the container.
Either way, files in these mounted directories have a lifetime
independent of the container(s) they’re mounted into. When you need to
rebuild the container or its underlying image — such as to upgrade to a
newer version of Fossil — the external directory remains behind and gets
remapped into the new container when you recreate it with `--volume/-v`.
#### 2.2.1 <a id="wal-mode"></a>WAL Mode Interactions
You might be aware that OCI containers allow mapping a single file into
the repository rather than a whole directory. Since Fossil repositories
are specially-formatted SQLite databases, you might be wondering why we
don’t say things like:
```
--volume ~/museum/my-project.fossil:/jail/museum/repo.fossil
```
That lets us have a convenient file name for the project outside the
container while letting the configuration inside the container refer to
the generic “`/museum/repo.fossil`” name. Why should we have to name
the repo generically on the outside merely to placate the container?
The reason is, you might be serving that repo with [WAL mode][wal]
enabled. If you map the repo DB alone into the container, the Fossil
instance inside the container will write the `-journal` and `-wal` files
alongside the mapped-in repository inside the container. That’s fine as
far as it goes, but if you then try using the same repo DB from outside
the container while there’s an active WAL, the Fossil instance outside
won’t know about it. It will think it needs to write *its own*
`-journal` and `-wal` files *outside* the container, creating a high
risk of [database corruption][dbcorr].
If we map a whole directory, both sides see the same set of WAL files.
[Testing](https://tangentsoft.com/sqlite/dir/walbanger?ci=trunk)
gives us a reasonable level of confidence that using WAL across a
container boundary is safe when used in this manner.
[dbcorr]: https://www.sqlite.org/howtocorrupt.html#_deleting_a_hot_journal
[wal]: https://www.sqlite.org/wal.html
## 3. <a id="security"></a>Security
### 3.1 <a id="chroot"></a>Why Chroot?
A potentially surprising feature of this container is that it runs
Fossil as root. Since that causes [the chroot jail feature](./chroot.md)
to kick in, and a Docker container is a type of über-jail already, you
may be wondering why we bother. Instead, why not either:
* run `fossil server --nojail` to skip the internal chroot; or
* set “`USER fossil`” in the `Dockerfile` so it starts Fossil as
that user instead
The reason is, although this container is quite stripped-down by today’s
standards, it’s based on the [surprisingly powerful Busybox
project](https://www.busybox.net/BusyBox.html). (This author made a
living for years in the early 1990s using Unix systems that were less
powerful than this container.) If someone ever figured out how to make a
Fossil binary execute arbitrary commands on the host or to open up a
remote shell, the power available to them at that point would make it
likely that they’d be able to island-hop from there into the rest of
your network. That power is there for you as the system administrator
alone, to let you inspect the container’s runtime behavior, change
things on the fly, and so forth. Fossil proper doesn’t need that power;
if we take it away via this cute double-jail dance, we keep any
potential attacker from making use of it should they ever get in.
Having said this, know that we deem this risk low since a) it’s never
happened, that we know of; and b) we haven’t enabled any of the risky
features of Fossil such as [TH1 docs][th1docrisk]. Nevertheless, we
believe defense-in-depth strategies are wise.
If you say something like “`docker exec fossil ps`” while the system is
idle, it’s likely to report a single `fossil` process running as `root`
even though the chroot feature is documented as causing Fossil to drop
its privileges in favor of the owner of the repository database or its
containing folder. If the repo file is owned by the in-container user
“`fossil`”, why is the server still running as root?
It’s because you’re seeing only the parent process, which assumes it’s
running on bare metal or a VM and thus may need to do rootly things like
listening on port 80 or 443 before forking off any children to handle
HTTP hits. Fossil’s chroot feature only takes effect in these child
processes. This is why you can fix broken permissions with `chown`
after the container is already running, without restarting it: each hit
reevaluates the repository file permissions when deciding what user to
become when dropping root privileges.
[th1docrisk]: https://fossil-scm.org/forum/forumpost/42e0c16544
### 3.2 <a id="caps"></a>Dropping Unnecessary Capabilities
The example commands above create the container with [a default set of
Linux kernel capabilities][defcap]. Although Docker strips away almost
all of the traditional root capabilities by default, and Fossil doesn’t
need any of those it does take away, Docker does leave some enabled that
Fossil doesn’t actually need. You can tighten the scope of capabilities
by adding “`--cap-drop`” options to your container creation commands.
Specifically:
* **`AUDIT_WRITE`**: Fossil doesn’t write to the kernel’s auditing
log, and we can’t see any reason you’d want to be able to do that as
an administrator shelled into the container, either. Auditing is
something done on the host, not from inside each individual
container.
* **`CHOWN`**: The Fossil server never even calls `chown(2)`, and our
image build process sets up all file ownership properly, to the
extent that this is possible under the limitations of our
automation.
Curiously, stripping this capability doesn’t affect your ability to
run commands like “`chown -R fossil:fossil /jail/museum`” when
you’re using bind mounts or external volumes — as we recommend
[above](#bind-mount) — because it’s the host OS’s kernel
capabilities that affect the underlying `chown(2)` call in that
case, not those of the container.
If for some reason you did have to change file ownership of
in-container files, it’s best to do that by changing the
`Dockerfile` to suit, then rebuilding the container, since that
bakes the need for the change into your reproducible build process.
If you had to do it without rebuilding the container, [there’s a
workaround][capchg] for the fact that capabilities are a create-time
change, baked semi-indelibly into the container configuration.
* **`FSETID`**: Fossil doesn’t use the SUID and SGID bits itself, and
our build process doesn’t set those flags on any of the files.
Although the second fact means we can’t see any harm from leaving
this enabled, we also can’t see any good reason to allow it, so we
strip it.
* **`KILL`**: The only place Fossil calls `kill(2)` is in the
[backoffice], and then only for processes it created on earlier
runs; it doesn’t need the ability to kill processes created by other
users. You might wish for this ability as an administrator shelled
into the container, but you can pass the “`docker exec --user`”
option to run commands within your container as the legitimate owner
of the process, removing the need for this capability.
* **`MKNOD`**: All device nodes are created at build time and are
never changed at run time. Realize that the virtualized device nodes
inside the container get mapped onto real devices on the host, so if
an attacker ever got a root shell on the container, they might be
able to do actual damage to the host if we didn’t preemptively strip
this capability away.
* **`NET_BIND_SERVICE`**: With containerized deployment, Fossil never
needs the ability to bind the server to low-numbered TCP ports, not
even if you’re running the server in production with TLS enabled and
want the service bound to port 443. It’s perfectly fine to let the
Fossil instance inside the container bind to its default port (8080)
because you can rebind it on the host with the
“`docker create --publish 443:8080`” option. It’s the container’s
_host_ that needs this ability, not the container itself.
(Even the container runtime might not need that capability if you’re
[terminating TLS with a front-end proxy](./ssl.wiki#server). You’re
more likely to say something like “`-p localhost:12345:8080`” and then
configure the reverse proxy to translate external HTTPS calls into
HTTP directed at this internal port 12345.)
* **`NET_RAW`**: Fossil itself doesn’t use raw sockets, and our build
process leaves out all the Busybox utilities that require them.
Although that set includes common tools like `ping`, we foresee no
compelling reason to use that or any of these other elided utilities
— `ether-wake`, `netstat`, `traceroute`, and `udhcp` — inside the
container. If you need to ping something, do it on the host.
If we did not take this hard-line stance, an attacker that broke
into the container and gained root privileges might use raw sockets
to do a wide array of bad things to any network the container is
bound to.
* **`SETFCAP, SETPCAP`**: There isn’t much call for file permission
granularity beyond the classic Unix ones inside the container, so we
drop root’s ability to change them.
All together, we recommend adding the following options to your
“`docker run`” commands, as well as to any “`docker create`” command
that will be followed by “`docker start`”:
```
--cap-drop AUDIT_WRITE \
--cap-drop CHOWN \
--cap-drop FSETID \
--cap-drop KILL \
--cap-drop MKNOD \
--cap-drop NET_BIND_SERVICE \
--cap-drop NET_RAW \
--cap-drop SETFCAP \
--cap-drop SETPCAP
```
In the next section, we’ll show a case where you create a container
without ever running it, making these options pointless.
[backoffice]: ./backoffice.md
[defcap]: https://docs.docker.com/engine/security/#linux-kernel-capabilities
[capchg]: https://stackoverflow.com/a/45752205/142454
## 4. <a id="static"></a>Extracting a Static Binary
Our 2-stage build process uses Alpine Linux only as a build host. Once
we’ve got everything reduced to the two key static binaries — Fossil and
BusyBox — we throw all the rest of it away.
A secondary benefit falls out of this process for free: it’s arguably
the easiest way to build a purely static Fossil binary for Linux. Most
modern Linux distros make this surprisingly difficult, but Alpine’s
back-to-basics nature makes static builds work the way they used to,
back in the day. If that’s all you’re after, you can do so as easily as
this:
```
$ docker build -t fossil .
$ docker create --name fossil-static-tmp fossil
$ docker cp fossil-static-tmp:/jail/bin/fossil .
$ docker container rm fossil-static-tmp
```
The resulting binary is the single largest file inside that container,
at about 4 MiB. (It’s built stripped and packed with [UPX].)
[UPX]: https://upx.github.io/
## 5. <a id="args"></a>Container Build Arguments
### <a id="pkg-vers"></a> 5.1 Package Versions
You can override the default versions of Fossil and BusyBox that get
fetched in the build step. To get the latest-and-greatest of everything,
you could say:
```
$ docker build -t fossil \
--build-arg FSLVER=trunk \
--build-arg BBXVER=master .
```
(But don’t, for reasons we will get to.)
Because the BusyBox configuration file we ship was created with and
tested against a specific stable release, that’s the version we pull by
default. It does try to merge the defaults for any new configuration
settings into the stock set, but since it’s possible this will fail, we
don’t blindly update the BusyBox version merely because a new release
came out. Someone needs to get around to vetting it against our stock
configuration first.
As for Fossil, it defaults to fetching the same version as the checkout
you’re running the build command from, based on checkin ID. The most
common reason to override this is to get a release version:
```
$ docker build -t fossil \
--build-arg FSLVER=version-2.19 .
```
It’s best to use a specific version number rather than the generic
“`release`” tag because Docker caches downloaded files and tries to
reuse them across builds. If you ask for “`release`” before a new
version is tagged and then immediately after, you might expect to get
two different tarballs, but because the URL hasn’t changed, if you have
an old release tarball in your Docker cache, you’ll get the old version
even if you pass the “`docker build --no-cache`” option.
This is why we default to pulling the Fossil tarball by checkin ID
rather than let it default to the generic “`trunk`” tag: so the URL will
change each time you update your Fossil source tree, forcing Docker to
pull a fresh tarball.
### 5.2 <a id="uids"></a>User & Group IDs
The “`fossil`” user and group IDs inside the container default to 499.
Why? Regular user IDs start at 500 or 1000 on most Unix type systems,
leaving those below it for system users like this Fossil daemon owner.
Since it’s typical for these to start at 0 and go upward, we started at
500 and went *down* one instead to reduce the chance of a conflict to as
close to zero as we can manage.
To change it to something else, say:
```
$ docker build -t fossil --build-arg UID=501 .
```
This is particularly useful if you’re putting your repository on a
Docker volume since the IDs “leak” out into the host environment via
file permissions. You may therefore wish them to mean something on both
sides of the container barrier rather than have “499” appear on the host
in “`ls -l`” output.
## 6. <a id="light"></a>Lightweight Alternatives to Docker
Those afflicted with sticker shock at seeing the size of a [Docker
Desktop][DD] installation — 1.65 GB here — might’ve immediately
“noped” out of the whole concept of containers. The first thing to
realize is that when it comes to actually serving simple containers like
the ones shown above is that [Docker Engine][DE] suffices, at about a
quarter of the size.
Yet on a small server — say, a $4/month 10 GiB Digital Ocean droplet —
that’s still a big chunk of your storage budget. It takes 100:1 overhead
just to run a 4 MiB Fossil server container? Once again, I wouldn’t
blame you if you noped right on out of here, but if you will be patient,
you will find that there are ways to run Fossil inside a container even
on entry-level cloud VPSes. These are well-suited to running Fossil; you
don’t have to resort to [raw Fossil service](./server/) to succeed,
leaving the benefits of containerization to those with bigger budgets.
For the sake of simple examples in this section, we’ll assume you’re
integrating Fossil into a larger web site, such as with our [Debian +
nginx + TLS][DNT] plan. This is why all of the examples below create
the container with this option:
```
--publish 127.0.0.1:9999:8080
```
The assumption is that there’s a reverse proxy running somewhere that
redirects public web hits to localhost port 9999, which in turn goes to
port 8080 inside the container. This use of Docker/Podman port
publishing effectively replaces the use of the
“`fossil server --localhost`” option.
For the nginx case, you need to add `--scgi` to these commands, and you
might also need to specify `--baseurl`.
Containers are a fine addition to such a scheme as they isolate the
Fossil sections of the site from the rest of the back-end resources,
thus greatly reducing the chance that they’ll ever be used to break into
the host as a whole.
(If you wanted to be double-safe, you could put the web server into
another container, restricting it to reading from the static web
site directory and connecting across localhost to back-end dynamic
content servers such as Fossil. That’s way outside the scope of this
document, but you can find ready advice for that elsewhere. Seeing how
we do this with Fossil should help you bridge the gap in extending
this idea to the rest of your site.)
[DD]: https://www.docker.com/products/docker-desktop/
[DE]: https://docs.docker.com/engine/
[DNT]: ./server/debian/nginx.md
### 6.1 <a id="nerdctl" name="containerd"></a>Stripping Docker Engine Down
The core of Docker Engine is its [`containerd`][ctrd] daemon and the
[`runc`][runc] container runner. Add to this the out-of-core CLI program
[`nerdctl`][nerdctl] and you have enough of the engine to run Fossil
containers. The big things you’re missing are:
* **BuildKit**: The container build engine, which doesn’t matter if
you’re building elsewhere and using a container registry as an
intermediary between that build host and the deployment host.
* **SwarmKit**: A powerful yet simple orchestrator for Docker that you
probably aren’t using with Fossil anyway.
In exchange, you get a runtime that’s about half the size of Docker
Engine. The commands are essentially the same as above, but you say
“`nerdctl`” instead of “`docker`”. You might alias one to the other,
because you’re still going to be using Docker to build and ship your
container images.
[ctrd]: https://containerd.io/
[nerdctl]: https://github.com/containerd/nerdctl
[runc]: https://github.com/opencontainers/runc
### 6.2 <a id="podman"></a>Podman
A lighter-weight alternative to either of the prior options that doesn’t
give up the image builder is [Podman]. Initially created by
Red Hat and thus popular on that family of OSes, it will run on
any flavor of Linux. It can even be made to run [on macOS via Homebrew][pmmac]
or [on Windows via WSL2][pmwin].
On Ubuntu 22.04, it’s about a quarter the size of Docker Engine, or half
that of the “full” distribution of `nerdctl` and all its dependencies.
Although Podman [bills itself][whatis] as a drop-in replacement for the
`docker` command and everything that sits behind it, some of the tool’s
design decisions affect how our Fossil containers run, as compared to
using Docker. The most important of these is that, by default, Podman
wants to run your container “rootless,” meaning that it runs as a
regular user. This is generally better for security, but [we dealt with
that risk differently above](#chroot) already. Since neither choice is
unassailably correct in all conditions, we’ll document both options
here.
[pmmac]: https://podman.io/getting-started/installation.html#macos
[pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md
[Podman]: https://podman.io/
[whatis]: https://podman.io/whatis.html
#### 6.2.1 <a id="podman-rootless"></a>Fossil in a Rootless Podman Container
If you build the stock Fossil container under `podman`, it will fail at
two key steps:
1. The `mknod` calls in the second stage, which create the `/jail/dev`
nodes. For a rootless container, we want it to use the “real” `/dev`
tree mounted into the container’s root filesystem instead.
2. Anything that depends on the `/jail` directory and the fact that it
becomes the file system’s root once the Fossil server is up and running.
[The changes to fix this](/file/containers/Dockerfile-nojail.patch)
aren’t complicated. Simply apply that patch to our stock `Dockerfile`
and rebuild:
```
$ patch -p0 < containers/Dockerfile-nojail.patch
$ docker build -t fossil:nojail .
$ docker create \
--name fossil-nojail \
--publish 127.0.0.1:9999:8080 \
--volume ~/museum:/museum \
fossil:nojail
```
Do realize that by doing this, if an attacker ever managed to get shell
access on your container, they’d have a BusyBox installation to play
around in. That shouldn’t be enough to let them break out of the
container entirely, but they’ll have powerful tools like `wget`, and
they’ll be connected to the network the container runs on. Once the bad
guy is inside the house, he doesn’t necessarily have to go after the
residents directly to cause problems for them.
#### 6.2.2 <a id="podman-rootful"></a>Fossil in a Rootful Podman Container
##### Simple Method
Fortunately, it’s easy enough to have it both ways. Simply run your
`podman` commands as root:
```
$ sudo podman build -t fossil --cap-add MKNOD .
$ sudo podman create \
--name fossil \
--cap-drop CHOWN \
--cap-drop FSETID \
--cap-drop KILL \
--cap-drop NET_BIND_SERVICE \
--cap-drop SETFCAP \
--cap-drop SETPCAP \
--publish 127.0.0.1:9999:8080 \
localhost/fossil
$ sudo podman start fossil
```
It’s obvious why we have to start the container as root, but why create
and build it as root, too? Isn’t that a regression from the modern
practice of doing as much as possible with a normal user?
We have to do the build under `sudo` in part because we’re doing rootly
things with the file system image layers we’re building up. Just because
it’s done inside a container runtime’s build environment doesn’t mean we
can get away without root privileges to do things like create the
`/jail/dev/null` node.
The other reason we need “`sudo podman build`” is because it puts the result
into root’s Podman image registry, where the next steps look for it.
That in turn explains why we need “`sudo podman create`:” because it’s
creating a container based on an image that was created by root. If you
ran that step without `sudo`, it wouldn’t be able to find the image.
If Docker is looking better and better to you as a result of all this,
realize that it’s doing the same thing. It just hides it better by
creating the `docker` group, so that when your user gets added to that
group, you get silent root privilege escalation on your build machine.
This is why Podman defaults to rootless containers. If you can get away
with it, it’s a better way to work. We would not be recommending
running `podman` under `sudo` if it didn’t buy us [something we wanted
badly](#chroot).
Notice that we had to add the ability to run `mknod(8)` during the
build. [Podman sensibly denies this by default][nomknod], which lets us
leave off the corresponding `--cap-drop` option. Podman also denies
`CAP_NET_RAW` and `CAP_AUDIT_WRITE` by default, which we don’t need, so
we’ve simply removed them from the `--cap-drop` list relative to the
commands for Docker above.
[nomknod]: https://github.com/containers/podman/issues/15626
##### <a id="pm-root-workaround"></a>Building Under Docker, Running Under Podman
If you have a remote host where the Fossil instance needs to run, it’s
possible to get around this need to build the image as root on the
remote system. You still have to build as root on the local system, but
as I said above, Docker already does this. What we’re doing is shifting
the risk of running as root from the public host to the local one.
Once you have the image built on the local machine, create a “`fossil`”
repository on your container repository of choice such as [Docker
Hub](https://hub.docker.com), then say:
```
$ docker login
$ docker tag fossil:latest mydockername/fossil:latest
$ docker image push mydockername/fossil:latest
```
That will push the image up to your account, so that you can then switch
to the remote machine and say:
```
$ sudo podman create \
--any-options-you-like \
docker.io/mydockername/fossil
```
This round-trip through the public image registry has another side
benefit: your local system might be a lot faster than your remote one,
as when the remote is a small VPS. Even with the overhead of schlepping
container images across the Internet, it can be a net win in terms of
build time.
### 6.3 <a id="barebones"></a>Bare-Bones OCI Bundle Runners
If even the Podman stack is too big for you, you still have options for
running containers that are considerably slimmer, at a high cost to
administration complexity and loss of features.
Part of the OCI standard is the notion of a “bundle,” being a consistent
way to present a pre-built and configured container to the runtime.
Essentially, it consists of a directory containing a `config.json` file
and a `rootfs/` subdirectory containing the root filesystem image. Many
tools can produce these for you. We’ll show only one method in the first
section below, then reuse that in the following sections.
#### 6.3.1 <a id="runc"></a>`runc`
We mentioned `runc` [above](#nerdctl), but it’s possible to use it
standalone, without `containerd` or its CLI frontend `nerdctl`. You also
lose the build engine, intelligent image layer sharing, image registry
connections, and much more. The plus side is that `runc` alone is
18 MiB.
Using it without all the support tooling isn’t complicated, but it *is*
cryptic enough to want a shell script. Let’s say we want to build on our
big desktop machine but ship the resulting container to a small remote
host. This should serve:
----
```shell
#!/bin/bash -ex
c=fossil
b=/var/lib/machines/$c
h=my-host.example.com
m=/run/containerd/io.containerd.runtime.v2.task/moby
t=$(mktemp -d /tmp/$c-bundle.XXXXXX)
if [ -d "$t" ]
then
docker container start $c
docker container export $c > $t/rootfs.tar
id=$(docker inspect --format="{{.Id}}" $c)
sudo cat $m/$id/config.json \
| jq '.root.path = "'$b/rootfs'"'
| jq '.linux.cgroupsPath = ""'
| jq 'del(.linux.sysctl)'
| jq 'del(.linux.namespaces[] | select(.type == "network"))'
| jq 'del(.mounts[] | select(.destination == "/etc/hostname"))'
| jq 'del(.mounts[] | select(.destination == "/etc/resolv.conf"))'
| jq 'del(.mounts[] | select(.destination == "/etc/hosts"))'
| jq 'del(.hooks)' > $t/config.json
scp -r $t $h:tmp
ssh -t $h "{
mv ./$t/config.json $b &&
sudo tar -C $b/rootfs -xf ./$t/rootfs.tar &&
rm -r ./$t
}"
rm -r $t
fi
```
----
The first several lines list configurables:
* **`c`**: the name of the Docker container you’re bundling up for use
with `runc`
* **`b`**: the path of the exported container, called the “bundle” in
OCI jargon; we’re using the [`nspawn`](#nspawn) convention, a
reasonable choice under the [Linux FHS rules][LFHS]
* **`h`**: the remote host name
* **`m`**: the local directory holding the running machines, configurable
because:
* the path name is longer than we want to use inline
* it’s been known to change from one version of Docker to the next
* you might be building and testing with [Podman](#podman), so it
has to be “`/run/user/$UID/crun`” instead
* **`t`**: the temporary bundle directory we populate locally, then
`scp` to the remote machine, where it’s unpacked
[LFHS]: https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
##### Why All That `sudo` Stuff?
This script uses `sudo` for two different purposes:
1. To read the local `config.json` file out of the `containerd` managed
directory, which is owned by `root` on Docker systems. Additionally,
that input file is only available while the container is started, so
we must ensure that before extracting it.
2. To unpack the bundle onto the remote machine. If you try to get
clever and unpack it locally, then `rsync` it to the remote host to
avoid re-copying files that haven’t changed since the last update,
you’ll find that it fails when it tries to copy device nodes, to
create files owned only by the remote root user, and so forth. If the
container bundle is small, it’s simpler to re-copy and unpack it
fresh each time.
I point all this out because it might ask for your password twice: once for
the local sudo command, and once for the remote.
##### Why All That `jq` Stuff?
We’re using [jq] for two separate purposes:
1. To automatically transmogrify Docker’s container configuration so it
will work with `runc`:
* point it where we unpacked the container’s exported rootfs
* accede to its wish to [manage cgroups by itself][ecg]
* remove the `sysctl` calls that will break after…
* …we remove the network namespace to allow Fossil’s TCP listening
port to be available on the host; `runc` doesn’t offer the
equivalent of `docker create --publish`, and we can’t be
bothered to set up a manual mapping from the host port into the
container
* remove file bindings that point into the local runtime managed
directories; one of the things we give up by using a bare
container runner is automatic management of these files
* remove the hooks for essentially the same reason
2. To make the Docker-managed machine-readable `config.json` more
human-readable, in case there are other things you want changed in
this version of the container. Exposing the `config.json` file like
this means you don’t have to rebuild the container merely to change
a value like a mount point, the kernel capability set, and so forth.
##### Running the Bundle
With the container exported to a bundle like this, you can start it as:
```
$ cd /path/to/bundle
$ c=fossil-runc ← …or anything else you prefer
$ sudo runc create $c
$ sudo runc start $c
$ sudo runc exec $c -t sh -l
~ $ ls museum
repo.fossil
~ $ ps -eaf
PID USER TIME COMMAND
1 fossil 0:00 bin/fossil server --create …
~ $ exit
$ sudo runc kill $c
$ sudo runc delete $c
```
If you’re doing this on the export host, the first command is “`cd $b`”
if we’re using the variables from the shell script above. Alternately,
the `runc` subcommands that need to read the bundle files take a
`--bundle/-b` flag to let you avoid switching directories.
The rest should be straightforward: create and start the container as
root so the `chroot(2)` call inside the container will succeed, then get
into it with a login shell and poke around to prove to ourselves that
everything is working properly. It is. Yay!
The remaining commands show shutting the container down and destroying
it, simply to show how these commands change relative to using the
Docker Engine commands. It’s “kill,” not “stop,” and it’s “delete,” not
“rm.”
[ecg]: https://github.com/opencontainers/runc/pull/3131
[jq]: https://stedolan.github.io/jq/
##### Lack of Layer Sharing
The bundle export process collapses Docker’s union filesystem down to a
single layer. Atop that, it makes all files mutable.
All of this is fine for tiny remote hosts with a single container, or at
least one where none of the containers share base layers. Where it
becomes a problem is when you have multiple Fossil containers on a
single host, since they all derive from the same base image.
The full-featured container runtimes above will intelligently share
these immutable base layers among the containers, storing only the
differences in each individual container. More, when pulling images from
a registry host, they’ll transfer only the layers you don’t have copies
of locally, so you don’t have to burn bandwidth sending copies of Alpine
and BusyBox each time, even though they’re unlikely to change from one
build to the next.
#### 6.3.2 <a id="crun"></a>`crun`
In the same way that [Docker Engine is based on `runc`](#runc), Podman’s
engine is based on [`crun`][crun], a lighter-weight alternative to
`runc`. It’s only 1.4 MiB on the system I tested it on, yet it will run
the same container bundles as in my `runc` examples above. We saved
more than that by compressing the container’s Fossil executable with
UPX, making the runtime virtually free in this case. The only question
is whether you can put up with its limitations, which are the same as
for `runc`.
[crun]: https://github.com/containers/crun
#### 6.3.3 <a id="nspawn"></a>`systemd-nspawn`
As of `systemd` version 242, its optional `nspawn` piece
[reportedly](https://www.phoronix.com/news/Systemd-Nspawn-OCI-Runtime)
got the ability to run OCI bundles directly. You might
have it installed already, but if not, it’s only about 2 MiB. It’s
in the `systemd-containers` package as of Ubuntu 22.04 LTS:
```
$ sudo apt install systemd-containers
```
It’s also in CentOS Stream 9, under the same name.
You create the bundles the same way as with [the `runc` method
above](#runc). The only thing that changes are the top-level management
commands:
```
$ sudo systemd-nspawn \
--oci-bundle=/var/lib/machines/fossil \
--machine=fossil \
--network-veth \
--port=127.0.0.1:127.0.0.1:9999:8080
$ sudo machinectl list
No machines.
```
This is why I wrote “reportedly” above: I couldn’t get it to work on two different
Linux distributions, and I can’t see why. I’m leaving this here to give
someone else a leg up, with the hope that they will work out what’s
needed to get the container running and registered with `machinectl`.
As of this writing, the tool expects an OCI container version of
“1.0.0”. I had to edit this at the top of my `config.json` file to get
the first command to read the bundle. The fact that it errored out when
I had “`1.0.2-dev`” in there proves it’s reading the file, but it
doesn’t seem able to make sense of what it finds there, and it doesn’t
give any diagnostics to say why.
<div style="height:50em" id="this-space-intentionally-left-blank"></div>
|
Changes to www/defcsp.md.
| ︙ | ︙ | |||
255 256 257 258 259 260 261 |
Although those files are all outside the Fossil repo at `/code`,
keep in mind that it is the browser’s notion of “self” that matters
here, not Fossil’s. All resources come from the same Internet
domain, so the browser cannot distinguish Fossil-provided content
from static content served directly by the proxy server.
| | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
Although those files are all outside the Fossil repo at `/code`,
keep in mind that it is the browser’s notion of “self” that matters
here, not Fossil’s. All resources come from the same Internet
domain, so the browser cannot distinguish Fossil-provided content
from static content served directly by the proxy server.
This method opens up many other potential benefits, such as
[TLS encryption][tls], high-performance tuning via custom HTTP
headers, integration with other web technologies like PHP, etc.
You might wonder why we rank in-repo content as most preferred above. It
is because the first two options are the only ones that cause such
resources to be included in an initial clone or in subsequent repo
syncs. The methods further down the list have a number of undesirable
properties:
|
| ︙ | ︙ | |||
298 299 300 301 302 303 304 305 306 307 308 309 310 311 | [du]: /help?cmd=/doc [fp]: ./forum.wiki [ru]: /help?cmd=/raw [spof]: https://en.wikipedia.org/wiki/Single_point_of_failure [tkt]: ./tickets.wiki [tn]: ./event.wiki [uu]: /help?cmd=/uv [uv]: ./unvers.wiki [wiki]: ./wikitheory.wiki ## <a id="override"></a>Overriding the Default CSP | > | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | [du]: /help?cmd=/doc [fp]: ./forum.wiki [ru]: /help?cmd=/raw [spof]: https://en.wikipedia.org/wiki/Single_point_of_failure [tkt]: ./tickets.wiki [tn]: ./event.wiki [tls]: ./server/debian/nginx.md [uu]: /help?cmd=/uv [uv]: ./unvers.wiki [wiki]: ./wikitheory.wiki ## <a id="override"></a>Overriding the Default CSP |
| ︙ | ︙ |
Changes to www/encryptedrepos.wiki.
1 2 3 4 5 6 7 8 | <title>How To Use Encrypted Repositories</title> <h2>Introduction</h2><blockquote> Fossil can be compiled so that it works with encrypted repositories using the [https://www.sqlite.org/see/doc/trunk/www/readme.wiki|SQLite Encryption Extension]. This technical note explains the process. </blockquote> <h2>Building An Encryption-Enabled Fossil</h2><blockquote> The SQLite Encryption Extension (SEE) is proprietary software and requires | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <title>How To Use Encrypted Repositories</title> <h2>Introduction</h2><blockquote> Fossil can be compiled so that it works with encrypted repositories using the [https://www.sqlite.org/see/doc/trunk/www/readme.wiki|SQLite Encryption Extension]. This technical note explains the process. </blockquote> <h2>Building An Encryption-Enabled Fossil</h2><blockquote> The SQLite Encryption Extension (SEE) is proprietary software and requires [https://sqlite.org/purchase/see|purchasing a license]. <p> Assuming you have an SEE license, the first step of compiling Fossil to use SEE is to create an SEE-enabled version of the SQLite database source code. This alternative SQLite database source file should be called "sqlite3-see.c" and should be placed in the extsrc/ subfolder of the Fossil sources, right beside the public-domain "sqlite3.c" source file. Also make a copy of the SEE-enabled "shell.c" file, renamed as "shell-see.c", and place it in the extsrc/ subfolder beside the original "shell.c". <p> Add the --with-see command-line option to the configuration script to enable the use of SEE on unix-like systems. <blockquote><pre> ./configure --with-see; make </pre></blockquote> |
| ︙ | ︙ |
Changes to www/foss-cklist.wiki.
1 2 3 4 5 6 | <title>Checklist For Successful Open-Source Projects</title> <nowiki> <p>This checklist is loosely derived from Tom "Spot" Callaway's Fail Score blog post <a href="http://spot.livejournal.com/308370.html"> http://spot.livejournal.com/308370.html</a> (see also | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <title>Checklist For Successful Open-Source Projects</title> <nowiki> <p>This checklist is loosely derived from Tom "Spot" Callaway's Fail Score blog post <a href="http://spot.livejournal.com/308370.html"> http://spot.livejournal.com/308370.html</a> (see also <a href="http://www.theopensourceway.org/book/The_Open_Source_Way-How_to_tell_if_a_FLOSS_project_is_doomed_to_FAIL.html">[1]</a>). Tom's original post assigned point scores to the various elements and by adding together the individual points, the reader is supposed to be able to judge the likelihood that the project will fail. The point scores, and the items on the list, clearly reflect Tom's biases and are not necessarily those of the larger open-source community. Nevertheless, the policy of the Fossil shall be to strive for a perfect score.</p> |
| ︙ | ︙ |
Changes to www/fossil-is-not-relational.md.
| ︙ | ︙ | |||
136 137 138 139 140 141 142 | stores in them an sqlite database, one record per distinct hash, in its `blob` table (which we will cover more very soon). Non-SCM-relevant state includes: - Fossil's list of users and their metadata (permissions, email address, etc.). Artifacts themselves reference users only by their | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | stores in them an sqlite database, one record per distinct hash, in its `blob` table (which we will cover more very soon). Non-SCM-relevant state includes: - Fossil's list of users and their metadata (permissions, email address, etc.). Artifacts themselves reference users only by their user names. Artifacts neither care whether, nor guarantee that, user "drh" in one artifact is in fact the same "drh" referenced in another artifact. - All Fossil UI configuration, e.g. the site's skin, config settings, and project name. - In short, any tables in a Fossil repository file except for the |
| ︙ | ︙ |
Changes to www/fossil-v-git.wiki.
| ︙ | ︙ | |||
205 206 207 208 209 210 211 | Fossil is easy to build from sources. Just run "<tt>./configure && make</tt>" on POSIX systems and "<tt>nmake /f Makefile.msc</tt>" on Windows. Contrast a basic installation of Git, which takes up about 15 MiB on Debian 10 across 230 files, not counting the contents of <tt>/usr/share/doc</tt> or <tt>/usr/share/locale</tt>. If you need to | | | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | Fossil is easy to build from sources. Just run "<tt>./configure && make</tt>" on POSIX systems and "<tt>nmake /f Makefile.msc</tt>" on Windows. Contrast a basic installation of Git, which takes up about 15 MiB on Debian 10 across 230 files, not counting the contents of <tt>/usr/share/doc</tt> or <tt>/usr/share/locale</tt>. If you need to deploy to any platform where you cannot count on facilities like the POSIX shell, Perl interpreter, and Tcl/Tk platform needed to fully use Git as part of the base platform, the full footprint of a Git installation extends to more like 45 MiB and thousands of files. This complicates several common scenarios: Git for Windows, chrooted Git servers, Docker images... Some say that Git more closely adheres to the Unix philosophy, |
| ︙ | ︙ | |||
281 282 283 284 285 286 287 | It is common in Fossil to ask to see [/timeline?df=release&y=ci|all check-ins since the last release]. Git lets you see "what came before". Fossil makes it just as easy to also see "what came after". Leaf check-ins in Git that lack a "ref" become "detached," making them difficult to locate and subject to garbage collection. This | | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | It is common in Fossil to ask to see [/timeline?df=release&y=ci|all check-ins since the last release]. Git lets you see "what came before". Fossil makes it just as easy to also see "what came after". Leaf check-ins in Git that lack a "ref" become "detached," making them difficult to locate and subject to garbage collection. This [http://gitfaq.org/1/01/what-is-a-detached-head/|detached head state] problem has caused grief for [https://www.google.com/search?q=git+detached+head+state | many Git users]. With Fossil, detached heads are simply impossible because we can always find our way back into the Merkle tree using one or more of the relations in the SQL database. |
| ︙ | ︙ | |||
507 508 509 510 511 512 513 | Where Git encourages siloed development, Fossil fights against it. Fossil places a lot of emphasis on synchronizing everyone's work and on reporting on the state of the project and the work of its developers, so that everyone — especially the project leader — can maintain a better mental picture of what is happening, leading to better situational awareness. | | | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | Where Git encourages siloed development, Fossil fights against it. Fossil places a lot of emphasis on synchronizing everyone's work and on reporting on the state of the project and the work of its developers, so that everyone — especially the project leader — can maintain a better mental picture of what is happening, leading to better situational awareness. By contrast, "…[https://docs.github.com/en/get-started/quickstart/contributing-to-projects|forking is at the core of social coding at GitHub]". As of January 2022, [https://github.com/search?q=is:public|Github hosts 47 million distinct software projects], most of which were created by forking a previously-existing project. Since this is [https://evansdata.com/reports/viewRelease.php?reportID=9 | roughly twice the number of developers in the world], it beggars belief that most of these forks are still under active development. The vast bulk |
| ︙ | ︙ |
Changes to www/interwiki.md.
1 2 3 4 5 6 7 | # Interwiki Links Interwiki links are a short-hand notation for links that target external wikis or websites. For example, the following two hyperlinks mean the same thing (assuming an appropriate [intermap](#intermap) configuration): | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # Interwiki Links Interwiki links are a short-hand notation for links that target external wikis or websites. For example, the following two hyperlinks mean the same thing (assuming an appropriate [intermap](#intermap) configuration): * [](wikipedia:MediaWiki#Interwiki_links) * [](https://en.wikipedia.org/wiki/MediaWiki#Interwiki_links) Another example: The Fossil Forum is hosted in a separate repository from the Fossil source code. This page is part of the source code repository. Interwiki links can be used to more easily refer to the forum repository: * [](forum:d5508c3bf44c6393df09c) |
| ︙ | ︙ |
Changes to www/mkindex.tcl.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
childprojects.wiki {Child Projects}
chroot.md {Server Chroot Jail}
ckout-workflows.md {Check-Out Workflows}
co-vs-up.md {Checkout vs Update}
copyright-release.html {Contributor License Agreement}
concepts.wiki {Fossil Core Concepts}
contact.md {Developer Contact Information}
contribute.wiki {Contributing Code or Documentation To The Fossil Project}
css-tricks.md {Fossil CSS Tips and Tricks}
customgraph.md {Theming: Customizing the Timeline Graph}
customskin.md {Theming: Customizing The Appearance of Web Pages}
customskin.md {Custom Skins}
custom_ticket.wiki {Customizing The Ticket System}
defcsp.md {The Default Content Security Policy}
| > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
childprojects.wiki {Child Projects}
chroot.md {Server Chroot Jail}
ckout-workflows.md {Check-Out Workflows}
co-vs-up.md {Checkout vs Update}
copyright-release.html {Contributor License Agreement}
concepts.wiki {Fossil Core Concepts}
contact.md {Developer Contact Information}
containers.md {OCI Containers}
contribute.wiki {Contributing Code or Documentation To The Fossil Project}
css-tricks.md {Fossil CSS Tips and Tricks}
customgraph.md {Theming: Customizing the Timeline Graph}
customskin.md {Theming: Customizing The Appearance of Web Pages}
customskin.md {Custom Skins}
custom_ticket.wiki {Customizing The Ticket System}
defcsp.md {The Default Content Security Policy}
|
| ︙ | ︙ |
Changes to www/permutedindex.html.
| ︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 | <li><a href="fossil-is-not-relational.md">Introduction to the (Non-relational) Fossil Data Model</a></li> <li><a href="blockchain.md">Is Fossil A Blockchain?</a></li> <li><a href="json-api/index.md">JSON API</a></li> <li><a href="mirrorlimitations.md">Limitations On Git Mirrors</a></li> <li><a href="../../../help">Lists of Commands and Webpages</a></li> <li><a href="loadmgmt.md">Managing Server Load</a></li> <li><a href="../../../md_rules">Markdown Formatting Rules</a></li> <li><a href="password.wiki">Password Management And Authentication</a></li> <li><a href="stats.wiki">Performance Statistics</a></li> <li><a href="../test/release-checklist.wiki">Pre-Release Testing Checklist</a></li> <li><a href="pop.wiki">Principles Of Operation</a></li> <li><a href="qandc.wiki">Questions And Criticisms</a></li> <li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li> <li><a href="rebaseharm.md">Rebase Considered Harmful</a></li> | > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | <li><a href="fossil-is-not-relational.md">Introduction to the (Non-relational) Fossil Data Model</a></li> <li><a href="blockchain.md">Is Fossil A Blockchain?</a></li> <li><a href="json-api/index.md">JSON API</a></li> <li><a href="mirrorlimitations.md">Limitations On Git Mirrors</a></li> <li><a href="../../../help">Lists of Commands and Webpages</a></li> <li><a href="loadmgmt.md">Managing Server Load</a></li> <li><a href="../../../md_rules">Markdown Formatting Rules</a></li> <li><a href="containers.md">OCI Containers</a></li> <li><a href="password.wiki">Password Management And Authentication</a></li> <li><a href="stats.wiki">Performance Statistics</a></li> <li><a href="../test/release-checklist.wiki">Pre-Release Testing Checklist</a></li> <li><a href="pop.wiki">Principles Of Operation</a></li> <li><a href="qandc.wiki">Questions And Criticisms</a></li> <li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li> <li><a href="rebaseharm.md">Rebase Considered Harmful</a></li> |
| ︙ | ︙ |
Changes to www/private.wiki.
| ︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | check-in manifest of the resulting merge child would include a <code>+close</code> tag referring to the leaf check-in on the private branch, and generate a missing artifact reference on repository clones without that private branch. It's still possible to close the leaf of the private branch (after committing the merge child) with the <code>fossil amend --close</code> command. <h2>Syncing Private Branches</h2> A private branch normally stays on the one repository where it was originally created. But sometimes you want to share private branches with another repository. For example, you might be building a cross-platform application and have separate repositories on your Windows laptop, your Linux desktop, and your iMac. You can transfer private branches | > > > > > > > > > > > > > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | check-in manifest of the resulting merge child would include a <code>+close</code> tag referring to the leaf check-in on the private branch, and generate a missing artifact reference on repository clones without that private branch. It's still possible to close the leaf of the private branch (after committing the merge child) with the <code>fossil amend --close</code> command. <blockquote><small> Side note: For the same reason, i.e. so as not to generate a missing artifact reference on peer repositories without the private branch, the merge parent is not recorded when merging the private branch into a public branch. As a consequence, the web UI timeline does not draw a merge line from the private merge parent to the public merge child. Moreover, repeat private-to-public merge operations (without the [/help?cmd=merge | --force option]) with files added on the private branch may only work once, but later abort with "WARNING: no common ancestor for FILE", as the parent-child relationship is not recorded (see the [/doc/trunk/www/branching.wiki | Branching, Forking, Merging, and Tagging] document for more information). </small></blockquote> <h2>Syncing Private Branches</h2> A private branch normally stays on the one repository where it was originally created. But sometimes you want to share private branches with another repository. For example, you might be building a cross-platform application and have separate repositories on your Windows laptop, your Linux desktop, and your iMac. You can transfer private branches |
| ︙ | ︙ |
Changes to www/quotes.wiki.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 | <li><nowiki>It's simplest to think of the state of your [git] repository as a point in a high-dimensional "code-space", in which branches are represented as n-dimensional membranes, mapping the spatial loci of successive commits onto the projected manifold of each cloned repository.</nowiki> <blockquote> | | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <li><nowiki>It's simplest to think of the state of your [git] repository as a point in a high-dimensional "code-space", in which branches are represented as n-dimensional membranes, mapping the spatial loci of successive commits onto the projected manifold of each cloned repository.</nowiki> <blockquote> <i>by Jonathan Hartley at [https://www.tartley.com/posts/a-guide-to-git-using-spatial-analogies]; <br>Quoted here: [https://lwn.net/Articles/420152/].</i> </blockquote> <li>Git is not a Prius. Git is a Model T. Its plumbing and wiring sticks out all over the place. You have to be a mechanic to operate it successfully or you'll be stuck on the side of the road when it breaks down. And it <b>will</b> break down. |
| ︙ | ︙ |
Added www/relatedwork.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | # Related Work ## Support Projects * [SQLite]: a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine * [pikchr]: a PIC-like markup language for diagrams in technical documentation * [althttpd]: a simple, secure, and low resource usage webserver that has run the https://sqlite.org/ website since 2004 * [Lemon Parser Generator][lemon]: an LALR(1), re-entrant, and thread-safe parser with a less error-prone grammar syntax than YACC or BISON ## Fossil Inspired Projects * [libfossil]: 3rd party Fossil SCM Library API * [fnc]: an interactive text-based user interface for Fossil * [ChiselApp][chisel]: Free Fossil SCM hosting! * [Fuel][fuel]: a cross-platform GUI front-end for the excellent Fossil SCM ## Editor Plugins * [Emacs-Fossil][emacsfsl]: GNU Emacs VC backend for the Fossil version control system * [VS Code][vscode]: Integrated Fossil source control in Visual Studio Code * [Qt Creator Plugin][qtfsl]: Fossil SCM plugin for the Qt Creator IDE * [Jetbrains IDE Plugin][jetbrains]: Fossil SCM plugin for [CLion], [IntelliJ], [GoLand], and more * [NetBeans Plugin][netbeans]: NetBeans plugin module to use Fossil SCM ## Version Control/Software Configuration Management * [Git]: Free and open source distributed version control system * [Subversion]: Apache's open source version control system * [Mercurial]: free, distributed source control management tool * [Game of Trees][got]: version control which prioritizes ease of use and simplicity over flexibility * [Darcs]: free and open source, cross-platform version control system * [Pijul]: patch-based distributed version control system ## Podcasts * [Corecursive #066][corec66]: The Untold Story of SQLite * [The Changelog #454][changelog454]: Richard Hipp returns * [The Changelog #201][changelog201]: Why SQLite succeeded as a database * [bsdtalk194][bsdtalk]: Interview with D. Richard Hipp * [Two Weeks of Databases][db2w]: Richard Hipp interviewed by Federico Razzoli * [Software Engineering Daily][swed]: SQLite with D. Richard Hipp * [Floss Weekly 26][floss26]: Interview with D. Richard Hipp, creator of SQLite ## Miscellany * [Tcl]: a simple-to-learn yet very powerful programming language [althttpd]: https://sqlite.org/althttpd/doc/trunk/althttpd.md [bsdtalk]: https://bsdtalk.blogspot.com/2010/07/bsdtalk194-fossil-scm-with-d-richard.html [changelog201]: https://changelog.com/podcast/201 [changelog454]: https://changelog.com/podcast/454 [chisel]: https://chiselapp.com/ [CLion]: https://www.jetbrains.com/clion/ [corec66]: https://corecursive.com/066-sqlite-with-richard-hipp/ [Darcs]: http://darcs.net/ [db2w]: https://youtu.be/2eaQzahCeh4 [emacsfsl]: https://chiselapp.com/user/venks/repository/emacs-fossil/doc/tip/README.md [floss26]: https://twit.tv/shows/floss-weekly/episodes/26 [fnc]: https://fnc.bsdbox.org [Fuel]: https://fuel-scm.org/fossil/index [Git]: https://git-scm.com [GoLand]: https://www.jetbrains.com/go/ [got]: https://gameoftrees.org [IntelliJ]: https://www.jetbrains.com/idea/ [jetbrains]: https://plugins.jetbrains.com/plugin/7479-fossil-integration [lemon]: https://www.hwaci.com/sw/lemon/ [libfossil]: https://fossil.wanderinghorse.net/r/libfossil/wiki/home [Mercurial]: https://www.mercurial-scm.org/ [netbeans]: https://chiselapp.com/user/backendzeit/repository/netbeans-fossil-plugin/index [Pijul]: https://pijul.org [pikchr]: https://pikchr.org [qtfsl]: https://code.qt.io/cgit/qt-creator/plugin-fossil-scm.git/ [SQLite]: https://sqlite.org/index.html [Subversion]: https://subversion.apache.org/ [swed]: https://softwareengineeringdaily.com/2015/11/13/sqlite-with-d-richard-hipp/ [Tcl]: https://core.tcl-lang.org/tcl/wiki?name=Index [VSCode]: https://marketplace.visualstudio.com/items?itemName=koog1000.fossil |
Changes to www/reviews.wiki.
1 2 3 | <title>Reviews</title> <b>External links:</b> | | | 1 2 3 4 5 6 7 8 9 10 11 |
<title>Reviews</title>
<b>External links:</b>
* [https://www.nixtu.info/2010/03/fossil-dvcs-on-go-first-impressions.html |
Fossil DVCS on the Go - First Impressions]
<b>See Also:</b>
* [./quotes.wiki | Short Quotes on Fossil, Git, And DVCSes]
<b>Daniel writes on 2009-01-06:</b>
|
| ︙ | ︙ | |||
54 55 56 57 58 59 60 | run standalone servers or add Apache modules.) So I tried it out. The thing which bugged me most about it was having to type "commit" or "com" instead of "ci" for checking in (as is custom in all other systems I've used), despite the fact that fossil uses "ci" as a filter in things like the timeline view. Looking back now, I have used fossil for about about 95% of my work in the past | | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | run standalone servers or add Apache modules.) So I tried it out. The thing which bugged me most about it was having to type "commit" or "com" instead of "ci" for checking in (as is custom in all other systems I've used), despite the fact that fossil uses "ci" as a filter in things like the timeline view. Looking back now, I have used fossil for about about 95% of my work in the past year (<a href="http://blog.s11n.net/?p=71"><i>dead link</i></a>), in over 15 source trees, and I now get tripped up when I have to use svn or cvs. So, having got over typing "fossil com -m ...", here's why I love it so much... Point #1: CGI Again, this sounds archaic, but fossil has allowed me to share source trees which I cannot justifiably host in other projects I work on |
| ︙ | ︙ |
Changes to www/server/any/scgi.md.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 | * [Linux (systemd)](../debian/service.md) * [Windows service](../windows/service.md) * [macOS (launchd)](../macos/service.md) * [xinetd](../any/xinetd.md) * [inetd](../any/inetd.md) We go into more detail on nginx service setup with Fossil in our | | | < | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | * [Linux (systemd)](../debian/service.md) * [Windows service](../windows/service.md) * [macOS (launchd)](../macos/service.md) * [xinetd](../any/xinetd.md) * [inetd](../any/inetd.md) We go into more detail on nginx service setup with Fossil in our [Debian/Ubuntu specific guide](../debian/nginx.md), which also gets you TLS service. Similarly, our [OpenBSD specific guide](../openbsd/fastcgi.md) details how to setup a Fossil server using httpd and FastCGI on OpenBSD. *[Return to the top-level Fossil server article.](../)* [404]: https://en.wikipedia.org/wiki/HTTP_404 |
Changes to www/server/debian/nginx.md.
1 2 3 4 5 6 7 | # Serving via nginx on Debian and Ubuntu This document is an extension of [the platform-independent SCGI instructions][scgii], which may suffice for your purposes if your needs are simple. Here, we add more detailed information on nginx itself, plus details | | > | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # Serving via nginx on Debian and Ubuntu This document is an extension of [the platform-independent SCGI instructions][scgii], which may suffice for your purposes if your needs are simple. Here, we add more detailed information on nginx itself, plus details about running it on Debian type OSes. This document was originally written for and tested on Debian 10 (Buster) and Ubuntu 20.04, which were common Tier 1 OS offerings for [virtual private servers][vps] at the time. The same configuration appears to run on Ubuntu 22.04 LTS without change. This material may not work for older OSes. It is known in particular to not work as given for Debian 9 and older! We also cover [adding TLS](#tls) to the basic configuration, because several details depend on the host OS and web stack details. Besides, TLS is widely considered part of the baseline configuration these days. [scgii]: ../any/scgi.md [vps]: https://en.wikipedia.org/wiki/Virtual_private_server |
| ︙ | ︙ | |||
107 108 109 110 111 112 113 | source to get a more up-to-date version than is shipped with the host OS. ## <a id="scgi"></a>Running Fossil in SCGI Mode For the following nginx configuration to work, it needs to contact a | | | > > | < | > > > | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | source to get a more up-to-date version than is shipped with the host OS. ## <a id="scgi"></a>Running Fossil in SCGI Mode For the following nginx configuration to work, it needs to contact a background Fossil instance speaking the SCGI protocol. There are [many ways](../) to set that up, such as [with `systemd`](./service.md) on mainstream Linux distros. Another way is to [containerize][ctz] your repository servers, then use the [`fslsrv` wrapper for Podman][fspm] to generate `systemd` units for use by the front-end proxy. However you do it, you need to match up the TCP port numbers between it and those in the nginx configuration below. [ctz]: ../../containers.md [fspm]: https://tangentsoft.com/fossil/dir/bin ## <a id="config"></a>Configuration On Debian and Ubuntu systems the primary user-level configuration file for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this file contain only a list of include statements, one for each site that server hosts: |
| ︙ | ︙ | |||
279 280 281 282 283 284 285 | [dof2b]: https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04 ## <a id="tls"></a> Adding TLS (HTTPS) Support | | | < < | < < < < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < | < < | < | < | < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < | < | < < | > > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | < < < < < < < < < < | < < < | < < < < < < < < < | | | | < < < < | < < < < < < | < < | < < < < < | < < | < < < < | < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | < < < | | < < | < < | < < < < < | < < < < < < < < < < < < < < < < < | < < < | < < | < < < | < | < < < < < | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < | | | | | > > | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
[dof2b]: https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04
## <a id="tls"></a> Adding TLS (HTTPS) Support
One of the [many ways](../../ssl.wiki) to provide TLS-encrypted HTTP
access (a.k.a. HTTPS) to Fossil is to run it behind a web proxy that
supports TLS. Because one such option is nginx, it’s best to delegate
TLS to it if you were already using nginx for some other reason, such as
static content serving, with only part of the site being served by
Fossil.
The simplest way by far to do this is to use [Let’s Encrypt][LE]’s
[Certbot][CB], which can configure nginx for you and keep its
certificates up to date. You need but follow their [nginx on Ubuntu 20
guide][CBU]. We had trouble with this in the past, but either Certbot
has gotten smarter or our nginx configurations have gotten simpler, so
we have removed the manual instructions we used to have here.
You may wish to include something like this from each `server { }`
block in your configuration to enable TLS in a common, secure way:
```
# Tell nginx to accept TLS-encrypted HTTPS on the standard TCP port.
listen 443 ssl;
listen [::]:443 ssl;
# Reference the TLS cert files produced by Certbot.
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Load the Let's Encrypt Diffie-Hellman parameters generated for
# this server. Without this, the server is vulnerable to Logjam.
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Tighten things down further, per Qualys’ and Certbot’s advice.
ssl_session_cache shared:le_nginx_SSL:1m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_timeout 1440m;
# Offer OCSP certificate stapling.
ssl_stapling on;
ssl_stapling_verify on;
# Enable HSTS.
include local/enable-hsts;
```
The [HSTS] step is optional and should be applied only after due
consideration, since it has the potential to lock users out of your
site if you later change your mind on the TLS configuration.
The `local/enable-hsts` file it references is simply:
```
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
```
It’s a separate file because nginx requires that headers like this be
applied separately for each `location { }` block. We’ve therefore
factored this out so you can `include` it everywhere you need it.
The [OCSP] step is optional, but recommended.
You may find [Qualys’ SSL Server Test][QSLT] helpful in verifying that
you have set all this up correctly, and that the configuration is
strong. We’ve found their [best practices doc][QSLC] to be helpful. As
of this writing, the above configuration yields an A+ rating when run on
Ubuntu 22.04.01 LTS.
[CB]: https://certbot.eff.org/
[CBU]: https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal
[LE]: https://letsencrypt.org/
[HSTS]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
[OCSP]: https://en.wikipedia.org/wiki/OCSP_stapling
[QSLC]: https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices
[QSLT]: https://www.ssllabs.com/ssltest/
<div style="height:50em" id="this-space-intentionally-left-blank"></div>
*[Return to the top-level Fossil server article.](../)*
|
Changes to www/server/debian/service.md.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 | service’s owner. We’ve told `systemd` that we want automatic service restarts with back-off logic, making this much more robust than the by-hand launches of `fossil` in the platform-independent Fossil server instructions. The service will stay up until we explicitly tell it to shut down. | < < | > > | > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
service’s owner.
We’ve told `systemd` that we want automatic service restarts with
back-off logic, making this much more robust than the by-hand launches
of `fossil` in the platform-independent Fossil server instructions. The
service will stay up until we explicitly tell it to shut down.
This scheme couples well with [the generic SCGI instructions][scgi] as
it requires a way to run the underlying repository server in the
background. Given that its service port is then proxied by SCGI, it
follows that it doesn’t need to run as a system service. A user service
works perfectly well for this.
Because we’ve set this up as a user service, the commands you give to
manipulate the service vary somewhat from the sort you’re more likely to
find online:
$ systemctl --user daemon-reload
$ systemctl --user enable fossil
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
desktop environments, where this is the behavior you often want. To
allow background services to continue to run after logout, say:
$ sudo loginctl enable-linger $USER
You can paste the command just like that into your terminal, since
`$USER` will expand to your login name.
### System Service Alternative
There are a couple of common reasons that you’d have cause to install
Fossil as a system-level service rather than the prior user-level one:
| > > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
desktop environments, where this is the behavior you often want. To
allow background services to continue to run after logout, say:
$ sudo loginctl enable-linger $USER
You can paste the command just like that into your terminal, since
`$USER` will expand to your login name.
[scgi]: ../any/scgi.md
### System Service Alternative
There are a couple of common reasons that you’d have cause to install
Fossil as a system-level service rather than the prior user-level one:
|
| ︙ | ︙ |
Changes to www/ssl.wiki.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | identify spoofing, and more. There are two major aspects to this, both of which have to be addressed in different ways. Those are the subjects of the next two major sections. | | < | | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
identify spoofing, and more.
There are two major aspects to this, both of which have to be addressed
in different ways. Those are the subjects of the next two major
sections.
<h2 id="client">Client-Side Configuration</h2>
You can build Fossil against [https://www.openssl.org/ |
OpenSSL] to allow it to clone and sync with a remote
Fossil repository via <tt>https</tt> URIs.
<h3 id="openssl-bin">Building Against OpenSSL Automatically</h3>
The <tt>configure</tt> script will attempt to find OpenSSL on your
system automatically. It first tries asking the <tt>pkg-config</tt>
system where the OpenSSL development files are, and if that fails, it
falls back to looking through a list of likely directories.
If it can't find the files it needs, the most common solution is to
install the OpenSSL development package on your system via your OS's
package manager. Examples:
* <b>RHEL & Fedora</b>: <tt>sudo dnf install openssl-devel</tt>
* <b>Debian & Ubuntu</b>: <tt>sudo apt install libssl-dev</tt>
* <b>FreeBSD</b>: <tt>su -c 'pkg install openssl'</tt>
* <b>macOS</b>: <tt>sudo brew install openssl</tt>
* <b>Cygwin</b>: Install <tt>openssl-devel</tt> via Cygwin's
<tt>setup-*.exe</tt> program
The macOS case requires explanation. Apple last shipped OpenSSL
|
| ︙ | ︙ | |||
222 223 224 225 226 227 228 | password. If you attempt to connect to a server which requests a client certificate, but don't provide one, fossil will show an error message which explains what to do to authenticate with the server. | | | | | | > | | < | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | password. If you attempt to connect to a server which requests a client certificate, but don't provide one, fossil will show an error message which explains what to do to authenticate with the server. <h2 id="server">Server-Side Configuration</h2> 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: * <a id="stunnel" href="./server/any/stunnel.md">Serving via stunnel</a> * <a id="althttpd" href="./server/any/althttpd.md">Serving via stunnel + althttpd</a> * <a id="nginx" href="./server/debian/nginx.md#tls">Serving via SCGI with nginx on Debian</a> <h2 id="enforcing">Enforcing TLS Access</h2> |
| ︙ | ︙ | |||
285 286 287 288 289 290 291 |
# <p><b>Download, fix, and restore.</b> You can copy the remote
repository file down to a local machine, use <tt>fossil ui</tt> to
fix the setting, and then upload it to the repository server
again.</p>
It's best to enforce TLS-only access at the front-end proxy level
anyway. It not only avoids the problem entirely, it can be significantly
| | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# <p><b>Download, fix, and restore.</b> You can copy the remote
repository file down to a local machine, use <tt>fossil ui</tt> to
fix the setting, and then upload it to the repository server
again.</p>
It's best to enforce TLS-only access at the front-end proxy level
anyway. It not only avoids the problem entirely, it can be significantly
more secure. The [./server/debian/nginx.md#tls | nginx-on-Debian proxy guide] shows one way
to achieve this.</p>
<h2>Terminology Note</h2>
This document is called <tt>ssl.wiki</tt> for historical reasons. The
TLS protocol was originally called SSL, and it went through several
revisions before being replaced by TLS. Years before this writing, SSL
finally became entirely obsolete due to weaknesses in the protocol fixed
in the later TLS series of protocols.
Some people still use the term "SSL" when they actually mean "TLS," but
in the Fossil project, we always use "TLS" except when we must preserve
some sort of historical compatibility, as with this document's name in
order to avoid broken external URLs. The Fossil TLS-related settings
also often use "<tt>ssl</tt>" in their names for the same reason.
This series of protocols is also called "HTTPS" after the URI scheme
used to specify "HTTP over TLS."
|
Changes to www/userlinks.wiki.
1 2 3 4 5 6 7 8 9 |
<title>Links For Fossil Users:</title>
* [./permutedindex.html | Documentation index] with [/search?c=d | full text search].
* [./reviews.wiki | Testimonials] from satisfied Fossil users and
[./quotes.wiki | Quotes] about Fossil and other DVCSes.
* [./faq.wiki | Frequently Asked Questions]
* The [./concepts.wiki | concepts] behind Fossil.
[./glossary.md | Another viewpoint].
* [./quickstart.wiki | Quick Start] guide to using Fossil.
| > > | 1 2 3 4 5 6 7 8 9 10 11 |
<title>Links For Fossil Users:</title>
* [./relatedwork.md | Related Work]: projects and links related to
Fossil and version control.
* [./permutedindex.html | Documentation index] with [/search?c=d | full text search].
* [./reviews.wiki | Testimonials] from satisfied Fossil users and
[./quotes.wiki | Quotes] about Fossil and other DVCSes.
* [./faq.wiki | Frequently Asked Questions]
* The [./concepts.wiki | concepts] behind Fossil.
[./glossary.md | Another viewpoint].
* [./quickstart.wiki | Quick Start] guide to using Fossil.
|
| ︙ | ︙ |