Login
Changes On Branch feech-versionedsettingsupport
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch feech-versionedsettingsupport Excluding Merge-Ins

This is equivalent to a diff from 4e32063e22 to 201339bcc3

2014-10-24
02:24
integrate feech-versionedsettingsupport. Not strictly fully tested, but I feel pretty good about it, so I'm going to close it out. I'll do any bugfixes here that might show up in the next days of testing. check-in: 03c3149b0e user: dave tags: dave
01:22
added support for 'non-multi-var settings' (most settings, actually), which inhibits list processing (i.e. doing comma/newline normalization). Also made alteration to VC6 project file to suppress warnings about sqlite3.c. Closed-Leaf check-in: 201339bcc3 user: dave tags: feech-versionedsettingsupport
2014-10-23
22:21
bug storing match_or_fail context structure; modded some accept regexes to include the 'empty is OK' metametacharacter check-in: 699fec5042 user: dave tags: feech-versionedsettingsupport
2014-10-20
13:06
I committed into wrong branch, so pulling to the intended one. The changes thus far are benign, so I'm going to leave them there for the moment, and also since ultimately I'll be merging them back. (I'm such a buffoon.) check-in: d9afd076f1 user: dave tags: feech-versionedsettingsupport
13:02
interim; add source for settings vtable and regexp extension functions; not wired it yet. update VC/DS projects. minor mod to auto.def to avoid redefining a define that oftentimes comes from the command line to cl, and would otherwise generate a warning in some projects. check-in: 4e32063e22 user: dave tags: dave
2014-10-19
15:07
(keeping up to date; merge trunk) check-in: 92fd52048b user: dave tags: dave

Changes to include/fossil-scm/fossil-confdb.h.
41
42
43
44
45
46
47
48









49
50
51
52
53
54
55
/**
   Signfies the repository-level configuration area.
*/
FSL_CONFDB_REPO = 2,
/**
   Signfies the checkout-level (a.k.a. "local") configuration area.
*/
FSL_CONFDB_CKOUT = 3









};
typedef enum fsl_confdb_t fsl_confdb_t;

/**
   Returns the name of the db table associated with the given
   mode. Results are undefined if mode is an invalid value. The
   returned bytes are static and constant.







|
>
>
>
>
>
>
>
>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
   Signfies the repository-level configuration area.
*/
FSL_CONFDB_REPO = 2,
/**
   Signfies the checkout-level (a.k.a. "local") configuration area.
*/
FSL_CONFDB_CKOUT = 3,
/**
   Signifies the versioned-level (via ".fossil-settings") configuration area.
*/
FSL_CONFDB_VERSIONED = 4,
/**
   Signifies the default-level (and other settings metadata) configuration area.
   This are is read-only, and only contains the publicly documented settings.
*/
FSL_CONFDB_METADATA = 5
};
typedef enum fsl_confdb_t fsl_confdb_t;

/**
   Returns the name of the db table associated with the given
   mode. Results are undefined if mode is an invalid value. The
   returned bytes are static and constant.
Changes to include/fossil-scm/fossil-core.h.
1297
1298
1299
1300
1301
1302
1303











1304
1305
1306
1307
1308
1309
1310
FSL_EXPORT fsl_db * fsl_needs_repo(fsl_cx * f);

/**
   The checkout-db counterpart of fsl_needs_repo().
*/
FSL_EXPORT fsl_db * fsl_needs_checkout(fsl_cx * f);













/**
   Opens the given database file as f's configuration database. If f
   already has a config database opened, it is closed before opening
   the new one. The database is created and populated with an
   initial schema if needed.








>
>
>
>
>
>
>
>
>
>
>







1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
FSL_EXPORT fsl_db * fsl_needs_repo(fsl_cx * f);

/**
   The checkout-db counterpart of fsl_needs_repo().
*/
FSL_EXPORT fsl_db * fsl_needs_checkout(fsl_cx * f);


/**
   The versioned settings counterpart of fsl_needs_repo().
*/
FSL_EXPORT fsl_db * fsl_cx_db_versioned( fsl_cx * f );

/**
   The settings metadata are read-only aspects of settings.
*/
FSL_EXPORT fsl_db * fsl_cx_db_metadata( fsl_cx * f );


/**
   Opens the given database file as f's configuration database. If f
   already has a config database opened, it is closed before opening
   the new one. The database is created and populated with an
   initial schema if needed.

Changes to include/fossil-scm/fossil-ext_regexp.h.
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
#if !defined NET_FOSSIL_SCM_REGEXP_H_INCLUDED
#define NET_FOSSIL_SCM_REGEXP_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif

#include "sqlite3ext.h"

/*(this file is derived from sqlite3 regexp.c; I wanted to expose
the engine to also be used directly*/

typedef struct ReCompiled ReCompiled;


/*
** Compile a textual regular expression in zIn[] into a compiled regular
** expression suitable for us by re_match() and return a pointer to the
** compiled regular expression in *ppRe.  Return NULL on success or an
** error message if something goes wrong.
*/
const char* sqlite3re_compile ( ReCompiled** ppRe, const char* zIn, int noCase );


/* Free and reclaim all the memory used by a previously compiled
** regular expression.  Applications should invoke this routine once
** for every call to re_compile() to avoid memory leaks.
*/
void sqlite3re_free ( ReCompiled* pRe );


/* Run a compiled regular expression on the zero-terminated input
** string zIn[].  Return true on a match and false if there is no match.
*/
int sqlite3re_match ( ReCompiled* pRe, const unsigned char* zIn, int nIn );



/*registers the REGEXP extension function into a sqlite3 database instance */
int sqlite3_regexp_init ( sqlite3* db, char** pzErrMsg,
    const struct sqlite3_api_routines* pApi );








|




|








|






|





|







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
#if !defined NET_FOSSIL_SCM_REGEXP_H_INCLUDED
#define NET_FOSSIL_SCM_REGEXP_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif

struct sqlite3_api_routines;

/*(this file is derived from sqlite3 regexp.c; I wanted to expose
the engine to also be used directly*/

typedef struct sqlite3_ReCompiled sqlite3_ReCompiled;


/*
** Compile a textual regular expression in zIn[] into a compiled regular
** expression suitable for us by re_match() and return a pointer to the
** compiled regular expression in *ppRe.  Return NULL on success or an
** error message if something goes wrong.
*/
const char* sqlite3re_compile ( sqlite3_ReCompiled** ppRe, const char* zIn, int noCase );


/* Free and reclaim all the memory used by a previously compiled
** regular expression.  Applications should invoke this routine once
** for every call to re_compile() to avoid memory leaks.
*/
void sqlite3re_free ( sqlite3_ReCompiled* pRe );


/* Run a compiled regular expression on the zero-terminated input
** string zIn[].  Return true on a match and false if there is no match.
*/
int sqlite3re_match ( sqlite3_ReCompiled* pRe, const unsigned char* zIn, int nIn );



/*registers the REGEXP extension function into a sqlite3 database instance */
int sqlite3_regexp_init ( sqlite3* db, char** pzErrMsg,
    const struct sqlite3_api_routines* pApi );

Changes to include/fossil-scm/fossil-vtbl_fossil_settings.h.
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
#define NET_FOSSIL_SCM_VTBLFOSSILSETTINGS_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif


#include "sqlite3ext.h"



int sqlite3_vtbl_fossilsettings_init (
    sqlite3* db,
    char** pzErrMsg,
    const struct sqlite3_api_routines* pApi
    );









|


>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#define NET_FOSSIL_SCM_VTBLFOSSILSETTINGS_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif


struct sqlite3_api_routines;


/*registers some sqlite3 extensions for handling versioned settings */
int sqlite3_vtbl_fossilsettings_init (
    sqlite3* db,
    char** pzErrMsg,
    const struct sqlite3_api_routines* pApi
    );


Changes to libfossil_VC6.dsp.
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# Begin Source File

SOURCE=.\src\fsl_zip.c
# End Source File
# Begin Source File

SOURCE=.\src\sqlite3.c
# ADD CPP /W3
# End Source File
# End Group
# Begin Group "Header Files"

# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File








|







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# Begin Source File

SOURCE=.\src\fsl_zip.c
# End Source File
# Begin Source File

SOURCE=.\src\sqlite3.c
# ADD CPP /w /W0
# End Source File
# End Group
# Begin Group "Header Files"

# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File

Changes to src/Makefile.in.
1
2
3
4
5
6
7
8
9
10
11
all:
include ../subdir-inc.make
#$(error $(TOP_SRCDIR))
CPPFLAGS += -DBUILD_libfossil
#CPPFLAGS += -I$(TOP_INCDIR)
#CPPFLAGS += -I$(TOP_SRCDIR)/include
#CPPFLAGS += -I$(TOP_SRCDIR)/src# workaround for in-tree sqlite3.h
EXTRA_LIBS := -lz
EXTRA_LIBS +=  $(LDFLAGS_MODULE_LOADER)

#INCLUDES_PATH ?= $(HOME)/include /usr/local/include /usr/include



|







1
2
3
4
5
6
7
8
9
10
11
all:
include ../subdir-inc.make
#$(error $(TOP_SRCDIR))
CPPFLAGS += -DBUILD_libfossil -DSQLITE_CORE
#CPPFLAGS += -I$(TOP_INCDIR)
#CPPFLAGS += -I$(TOP_SRCDIR)/include
#CPPFLAGS += -I$(TOP_SRCDIR)/src# workaround for in-tree sqlite3.h
EXTRA_LIBS := -lz
EXTRA_LIBS +=  $(LDFLAGS_MODULE_LOADER)

#INCLUDES_PATH ?= $(HOME)/include /usr/local/include /usr/include
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
	fsl_config.c \
	fsl_cx.c \
	fsl_db.c \
	fsl_delta.c \
	fsl_diff.c \
	fsl_encode.c \
	fsl_event.c \

	fsl_fs.c \
	fsl_glob.c \
	fsl_io.c \
	fsl_leaf.c \
	fsl_list.c \
	fsl_md5.c \
	fsl_mf.c \
	fsl_path.c \
	fsl_popen.c \
	fsl_pq.c \
	fsl_repo.c \
	fsl_schema.c \
	fsl_sha1.c \
	fsl_strftime.c \
	fsl_tag.c \
	fsl_ticket.c \
	fsl_utf8.c \
	fsl_vfile.c \

	fsl_wiki.c \
	fsl_zip.c

FSL.SRC := $(FSL.SRC.BASE) \
	fsl_jni.c \
	fsl_tcl.c








>


















>







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
	fsl_config.c \
	fsl_cx.c \
	fsl_db.c \
	fsl_delta.c \
	fsl_diff.c \
	fsl_encode.c \
	fsl_event.c \
	fsl_ext_regexp.c \
	fsl_fs.c \
	fsl_glob.c \
	fsl_io.c \
	fsl_leaf.c \
	fsl_list.c \
	fsl_md5.c \
	fsl_mf.c \
	fsl_path.c \
	fsl_popen.c \
	fsl_pq.c \
	fsl_repo.c \
	fsl_schema.c \
	fsl_sha1.c \
	fsl_strftime.c \
	fsl_tag.c \
	fsl_ticket.c \
	fsl_utf8.c \
	fsl_vfile.c \
	fsl_vtbl_fossil_settings.c \
	fsl_wiki.c \
	fsl_zip.c

FSL.SRC := $(FSL.SRC.BASE) \
	fsl_jni.c \
	fsl_tcl.c

173
174
175
176
177
178
179


180
181
182
183
184
185
186
	$(INCD)/fossil-hash.h \
	$(INCD)/fossil-content.h \
	$(INCD)/fossil-confdb.h \
	$(INCD)/fossil-path.h \
	$(INCD)/fossil-internal.h \
	$(INCD)/fossil-auth.h \
	$(INCD)/fossil-pages.h \


	$(INCD)/fossil-cli.h
$(AMAL_H.SRC):
$(AMAL_C.SRC):
$(AMAL_H): $(MAKEFILE_LIST) $(AMAL_H.SRC) $(AMAL_CONF.H)
$(AMAL_C): $(MAKEFILE_LIST) $(AMAL_H) $(AMAL_C.SRC)
$(AMAL_CONF.H): $(MAIN_MAKEFILES)
	@echo "Generating $@ ..."







>
>







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
	$(INCD)/fossil-hash.h \
	$(INCD)/fossil-content.h \
	$(INCD)/fossil-confdb.h \
	$(INCD)/fossil-path.h \
	$(INCD)/fossil-internal.h \
	$(INCD)/fossil-auth.h \
	$(INCD)/fossil-pages.h \
	$(INCD)/fossil-ext_regexp.h \
	$(INCD)/fossil-vtbl_fossil_settings.h \
	$(INCD)/fossil-cli.h
$(AMAL_H.SRC):
$(AMAL_C.SRC):
$(AMAL_H): $(MAKEFILE_LIST) $(AMAL_H.SRC) $(AMAL_CONF.H)
$(AMAL_C): $(MAKEFILE_LIST) $(AMAL_H) $(AMAL_C.SRC)
$(AMAL_CONF.H): $(MAIN_MAKEFILES)
	@echo "Generating $@ ..."
Changes to src/fsl_config.c.
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
#define SELECT_FROM_CONFIG "SELECT value FROM %s WHERE name=?"

char const * fsl_config_table_for_role(fsl_confdb_t mode){
  switch(mode){
    case FSL_CONFDB_REPO: return "config";
    case FSL_CONFDB_CKOUT: return "vvar";
    case FSL_CONFDB_GLOBAL: return "global_config";


    default:
      assert(!"Invalid fsl_confdb_t value");
      return NULL;
  }
}

fsl_db * fsl_config_for_role(fsl_cx * f, fsl_confdb_t mode){
  switch(mode){
    case FSL_CONFDB_REPO: return fsl_cx_db_repo(f);
    case FSL_CONFDB_CKOUT: return fsl_cx_db_checkout(f);
    case FSL_CONFDB_GLOBAL: return fsl_cx_db_config(f);


    default:
      assert(!"Invalid fsl_confdb_t value");
      return NULL;
  }
}









>
>











>
>







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
#define SELECT_FROM_CONFIG "SELECT value FROM %s WHERE name=?"

char const * fsl_config_table_for_role(fsl_confdb_t mode){
  switch(mode){
    case FSL_CONFDB_REPO: return "config";
    case FSL_CONFDB_CKOUT: return "vvar";
    case FSL_CONFDB_GLOBAL: return "global_config";
    case FSL_CONFDB_VERSIONED: return "versionedsettings";
    case FSL_CONFDB_METADATA: return "settingsmetadata";
    default:
      assert(!"Invalid fsl_confdb_t value");
      return NULL;
  }
}

fsl_db * fsl_config_for_role(fsl_cx * f, fsl_confdb_t mode){
  switch(mode){
    case FSL_CONFDB_REPO: return fsl_cx_db_repo(f);
    case FSL_CONFDB_CKOUT: return fsl_cx_db_checkout(f);
    case FSL_CONFDB_GLOBAL: return fsl_cx_db_config(f);
    case FSL_CONFDB_VERSIONED: return fsl_cx_db_versioned(f);
    case FSL_CONFDB_METADATA: return fsl_cx_db_metadata(f);
    default:
      assert(!"Invalid fsl_confdb_t value");
      return NULL;
  }
}


Changes to src/fsl_cx.c.
16
17
18
19
20
21
22


23
24
25
26
27
28
29
     http://www.hwaci.com/drh/
  
  *****************************************************************************
   This file houses most of the context-related APIs.
*/
#include "fossil-scm/fossil-internal.h"
#include <assert.h>



#if defined(_WIN32)
# include <windows.h>
# define F_OK 0
# define W_OK 2
#else
# include <unistd.h> /* F_OK */







>
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
     http://www.hwaci.com/drh/
  
  *****************************************************************************
   This file houses most of the context-related APIs.
*/
#include "fossil-scm/fossil-internal.h"
#include <assert.h>
#include "fossil-scm/fossil-ext_regexp.h"
#include "fossil-scm/fossil-vtbl_fossil_settings.h"

#if defined(_WIN32)
# include <windows.h>
# define F_OK 0
# define W_OK 2
#else
# include <unistd.h> /* F_OK */
58
59
60
61
62
63
64












65
66
67
68
69
70
71
    f = fsl_cx_malloc();
    if(!f) return FSL_RC_OOM;

    *tgt = f;
  }
  f->output = param->output;
  f->cxConfig = param->config;












  return rc;
}
    
void fsl_cx_reset(fsl_cx * f, char closeDatabases){
  if(!f) return;
  fsl_checkin_discard(f);
#define SFREE(X) fsl_free(X); X = NULL







>
>
>
>
>
>
>
>
>
>
>
>







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
    f = fsl_cx_malloc();
    if(!f) return FSL_RC_OOM;

    *tgt = f;
  }
  f->output = param->output;
  f->cxConfig = param->config;
/*HHH idempotent */
{
  static int bRegistered = 0;
  if ( ! bRegistered )
  {
    /*register our statically linked extensions to be auto-init'ed at the appropriate time*/
    sqlite3_auto_extension((void(*)(void))(sqlite3_vtbl_fossilsettings_init));  /*our settings vtables*/
    sqlite3_auto_extension((void(*)(void))(sqlite3_regexp_init));     /*sqlite regexp extension*/
    bRegistered = 1;
  }
}

  return rc;
}
    
void fsl_cx_reset(fsl_cx * f, char closeDatabases){
  if(!f) return;
  fsl_checkin_discard(f);
#define SFREE(X) fsl_free(X); X = NULL
272
273
274
275
276
277
278










279
280
281
282
283
284
285

fsl_db * fsl_cx_db_checkout( fsl_cx * f ){
  if(!f) return NULL;
  else if(f->ckout.db.dbh) return &f->ckout.db;
  else if(f->dbMain && (FSL_DB_ROLE_CHECKOUT & f->dbMain->role)) return f->dbMain;
  else return NULL;
}











fsl_db * fsl_cx_db( fsl_cx * f ){
  return f ? f->dbMain : NULL;
}










>
>
>
>
>
>
>
>
>
>







286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309

fsl_db * fsl_cx_db_checkout( fsl_cx * f ){
  if(!f) return NULL;
  else if(f->ckout.db.dbh) return &f->ckout.db;
  else if(f->dbMain && (FSL_DB_ROLE_CHECKOUT & f->dbMain->role)) return f->dbMain;
  else return NULL;
}

fsl_db * fsl_cx_db_versioned( fsl_cx * f ){
  /*the 'versioned settings' is a virtual table strapped onto the checkout db*/
  return fsl_cx_db_checkout ( f );
}

fsl_db * fsl_cx_db_metadata( fsl_cx * f ){
  /*the 'settings metadata' is a virtual table strapped onto the main db*/
  return fsl_cx_db ( f );
}

fsl_db * fsl_cx_db( fsl_cx * f ){
  return f ? f->dbMain : NULL;
}



1091
1092
1093
1094
1095
1096
1097





















1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110

1111
1112
1113
1114
1115
1116
1117
    *(end+1) = 0; /* rather than strdup'ing, we'll just lop off the
                 filename part. Keep the '/' for historical
                 conventions purposes. */
    f->ckout.dir = (char *)buf->mem;
    *buf = fsl_buffer_empty /* we took ownership of buf->mem */;
    assert(!f->ckout.dir[f->ckout.dirLen]);
    assert('/' == f->ckout.dir[f->ckout.dirLen-1]);





















    /* why?
       rc = fsl_config_open(f, NULL);
             
       Seems to me we don't need that at the library level. In my
       experience global config options for a lib which is used by
       multiple apps are generally a bad idea, as no single
       setting of any given property will be best for all apps.
       Fossil's global config db assumes that there is only one
       fossil-based app, which is no longer the case.
    */
    f->flags |= FSL_CX_F_IS_OPENING_CKOUT;
    rc = fsl_repo_open_for_checkout(f);
    f->flags &= ~FSL_CX_F_IS_OPENING_CKOUT;

    rc = fsl_cx_after_open(f);
    if(rc){
      /* Is this sane? Is not doing it sane? */
      fsl_checkout_close(f);
    }
    return rc;
  }







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













>







1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
    *(end+1) = 0; /* rather than strdup'ing, we'll just lop off the
                 filename part. Keep the '/' for historical
                 conventions purposes. */
    f->ckout.dir = (char *)buf->mem;
    *buf = fsl_buffer_empty /* we took ownership of buf->mem */;
    assert(!f->ckout.dir[f->ckout.dirLen]);
    assert('/' == f->ckout.dir[f->ckout.dirLen-1]);
    /*defensively drop any existing table definition; there shouldn't be one,
    but maybe could be if the application crashed before closing gracefully*/
    rc = sqlite3_exec ( f->dbMain->dbh, "DROP TABLE versionedsettings;", NULL, NULL, NULL );
    /*now we create our versioned settings table*/
    {
    /*alas, we must coin the name ourselves, because parameters to CREATE
    VIRTUAL TABLE are not processed by sqlite, so we can't use
    FSL_CKOUT_DIR().  Since we go that far, we might as well just add the
    surrounding sql as well.*/
    fsl_buffer strCreateSql;
    strCreateSql = fsl_buffer_empty;
    fsl_buffer_append ( &strCreateSql, "CREATE VIRTUAL TABLE "
        "versionedsettings USING VERSIONED_SETTINGS( '", -1 );
    fsl_buffer_append ( &strCreateSql, f->ckout.dir, -1 );
    fsl_buffer_append ( &strCreateSql, ".fossil-settings", -1 );
    fsl_buffer_append ( &strCreateSql, "', MKDIR );", -1 );
    rc = sqlite3_exec ( f->dbMain->dbh,
        fsl_buffer_cstr ( &strCreateSql ),
        NULL, NULL, NULL );
    fsl_buffer_clear ( &strCreateSql );
    }
    /* why?
       rc = fsl_config_open(f, NULL);
             
       Seems to me we don't need that at the library level. In my
       experience global config options for a lib which is used by
       multiple apps are generally a bad idea, as no single
       setting of any given property will be best for all apps.
       Fossil's global config db assumes that there is only one
       fossil-based app, which is no longer the case.
    */
    f->flags |= FSL_CX_F_IS_OPENING_CKOUT;
    rc = fsl_repo_open_for_checkout(f);
    f->flags &= ~FSL_CX_F_IS_OPENING_CKOUT;
/*HHH this updates some copies of settings!!!*/
    rc = fsl_cx_after_open(f);
    if(rc){
      /* Is this sane? Is not doing it sane? */
      fsl_checkout_close(f);
    }
    return rc;
  }
Changes to src/fsl_db.c.
142
143
144
145
146
147
148




149
150
151
152
153
154
155
      fsl_db_transaction_end(db, 1);
    }
    if(0!=db->openStatementCount){
      MARKER(("WARNING: %d open statement(s) left on db [%s].\n",
              (int)db->openStatementCount, db->filename));
    }
    if(db->dbh){




      sqlite3_close(db->dbh)
        /* ignoring result in the style of
           "destructors may not throw".
        */;
    }
    fsl_db_clear_strings(db, 1);
    fsl_db_cleanup_beforeCommit(db);







>
>
>
>







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
      fsl_db_transaction_end(db, 1);
    }
    if(0!=db->openStatementCount){
      MARKER(("WARNING: %d open statement(s) left on db [%s].\n",
              (int)db->openStatementCount, db->filename));
    }
    if(db->dbh){
      /*drop our virtual tables, if they exist*/
      int rc;
      rc = sqlite3_exec ( db->dbh, "DROP TABLE settingsmetadata;", NULL, NULL, NULL );
      rc = sqlite3_exec ( db->dbh, "DROP TABLE versionedsettings;", NULL, NULL, NULL );
      sqlite3_close(db->dbh)
        /* ignoring result in the style of
           "destructors may not throw".
        */;
    }
    fsl_db_clear_strings(db, 1);
    fsl_db_cleanup_beforeCommit(db);
1470
1471
1472
1473
1474
1475
1476





1477
1478
1479
1480
1481
1482
1483
      /* functions registered in v1 by db.c:db_open(). */
      /* porting cgi() requires access to the HTTP/CGI
         layer. i.e. this belongs downstream. */
      sqlite3_create_function(dbh, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
      sqlite3_create_function(dbh, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
      re_add_sql_func(db) /* Requires the regex bits. */;
#endif





    }/*if(db->f)*/
  }
  end:
  if(rc){
#if 1
    /* This is arguable... */
    if(db->f && db->error.code && !db->f->error.code){







>
>
>
>
>







1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
      /* functions registered in v1 by db.c:db_open(). */
      /* porting cgi() requires access to the HTTP/CGI
         layer. i.e. this belongs downstream. */
      sqlite3_create_function(dbh, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
      sqlite3_create_function(dbh, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
      re_add_sql_func(db) /* Requires the regex bits. */;
#endif
      /*HHH check out the re_add_sql_func; did we already have regex somewhere?*/
      /*create the settingsmetadata virtual table in the db*/
      rc = sqlite3_exec ( dbh, "CREATE VIRTUAL TABLE IF NOT EXISTS "
          "settingsmetadata USING SETTINGS_METADATA();", NULL, NULL, NULL );
      assert(SQLITE_OK==rc);  /*shoud only fails if you haven't registered the extension*/
    }/*if(db->f)*/
  }
  end:
  if(rc){
#if 1
    /* This is arguable... */
    if(db->f && db->error.code && !db->f->error.code){
Changes to src/fsl_ext_regexp.c.
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
** this expansion.
*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif
#ifndef SQLITE_CORE
#include "sqlite3ext.h"
//declares extern the vtable of all the sqlite3 functions (for loadable modules only)
SQLITE_EXTENSION_INIT3
#else
#include "sqlite3.h"
#endif
#include "fossil-scm/fossil-ext_regexp.h"
#include <string.h>
#include <stdlib.h>

/*
** The following #defines change the names of some functions implemented in
** this file to prevent name collisions with C-library functions of the
** same name.
*/
#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.
*/







|








<
<
<
<
<
<
<
<







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74








75
76
77
78
79
80
81
** this expansion.
*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif
#ifndef SQLITE_CORE
#include "sqlite3ext.h"
/*declares extern the vtable of all the sqlite3 functions (for loadable modules only)*/
SQLITE_EXTENSION_INIT3
#else
#include "sqlite3.h"
#endif
#include "fossil-scm/fossil-ext_regexp.h"
#include <string.h>
#include <stdlib.h>










/* 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.
*/
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
#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
** number of actives states is small.
*/
typedef struct ReStateSet {
  unsigned nState;            /* Number of current states */
  ReStateNumber *aState;      /* Current states */
} ReStateSet;

/* An input string read one character at a time.
*/
typedef struct ReInput ReInput;
struct ReInput {
  const unsigned char *z;  /* All text */
  int i;                   /* Next byte to read */
  int mx;                  /* EOF when i>=mx */
};

/* A compiled NFA (or an NFA that is in the process of being compiled) is
** an instance of the following object.
*/

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 characters 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;
  for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return;
  pSet->aState[pSet->nState++] = newState;
}

/* Extract the next unicode character from *pzIn and return it.  Advance
** *pzIn to the first byte past the end of the character returned.  To
** be clear:  this routine converts utf8 to unicode.  This routine is 
** optimized for the common case where the next character is a single byte.
*/
static unsigned re_next_char(ReInput *p){
  unsigned c;
  if( p->i>=p->mx ) return 0;
  c = p->z[p->i++];
  if( c>=0x80 ){
    if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
      c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
      if( c<0x80 ) c = 0xfffd;







|






|

|
|



|
|








>
|
|



|







|










|







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
#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 sqlite3_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
** number of actives states is small.
*/
typedef struct sqlite3_ReStateSet {
  unsigned nState;            /* Number of current states */
  sqlite3_ReStateNumber *aState;      /* Current states */
} sqlite3_ReStateSet;

/* An input string read one character at a time.
*/
typedef struct sqlite3_ReInput sqlite3_ReInput;
struct sqlite3_ReInput {
  const unsigned char *z;  /* All text */
  int i;                   /* Next byte to read */
  int mx;                  /* EOF when i>=mx */
};

/* A compiled NFA (or an NFA that is in the process of being compiled) is
** an instance of the following object.
*/
/*typedef struct sqlite3_ReCompiled sqlite3_ReCompiled;*/
struct sqlite3_ReCompiled {
  sqlite3_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)(sqlite3_ReInput*);  /* Next character function */
  unsigned char zInit[12];    /* Initial text to match */
  int nInit;                  /* Number of characters 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 sqlite3re_add_state(sqlite3_ReStateSet *pSet, int newState){
  unsigned i;
  for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return;
  pSet->aState[pSet->nState++] = newState;
}

/* Extract the next unicode character from *pzIn and return it.  Advance
** *pzIn to the first byte past the end of the character returned.  To
** be clear:  this routine converts utf8 to unicode.  This routine is 
** optimized for the common case where the next character is a single byte.
*/
static unsigned sqlite3re_next_char(sqlite3_ReInput *p){
  unsigned c;
  if( p->i>=p->mx ) return 0;
  c = p->z[p->i++];
  if( c>=0x80 ){
    if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){
      c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f);
      if( c<0x80 ) c = 0xfffd;
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
      if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
    }else{
      c = 0xfffd;
    }
  }
  return c;
}
static unsigned re_next_char_nocase(ReInput *p){
  unsigned c = re_next_char(p);
  if( c>='A' && c<='Z' ) c += 'a' - 'A';
  return c;
}

/* Return true if c is a perl "word" character:  [A-Za-z0-9_] */
static int re_word_char(int c){
  return (c>='0' && c<='9') || (c>='a' && c<='z')
      || (c>='A' && c<='Z') || c=='_';
}

/* Return true if c is a "digit" character:  [0-9] */
static int re_digit_char(int c){
  return (c>='0' && c<='9');
}

/* Return true if c is a perl "space" character:  [ \t\r\n\v\f] */
static int re_space_char(int c){
  return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
}

/* Run a compiled regular expression on the zero-terminated input
** string zIn[].  Return true on a match and false if there is no match.
*/
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_EOF+1;
  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 ){







|
|





|





|




|






|
|
|
|





|







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
      if( c<=0xffff || c>0x10ffff ) c = 0xfffd;
    }else{
      c = 0xfffd;
    }
  }
  return c;
}
static unsigned sqlite3re_next_char_nocase(sqlite3_ReInput *p){
  unsigned c = sqlite3re_next_char(p);
  if( c>='A' && c<='Z' ) c += 'a' - 'A';
  return c;
}

/* Return true if c is a perl "word" character:  [A-Za-z0-9_] */
static int sqlite3re_word_char(int c){
  return (c>='0' && c<='9') || (c>='a' && c<='z')
      || (c>='A' && c<='Z') || c=='_';
}

/* Return true if c is a "digit" character:  [0-9] */
static int sqlite3re_digit_char(int c){
  return (c>='0' && c<='9');
}

/* Return true if c is a perl "space" character:  [ \t\r\n\v\f] */
static int sqlite3re_space_char(int c){
  return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
}

/* Run a compiled regular expression on the zero-terminated input
** string zIn[].  Return true on a match and false if there is no match.
*/
int sqlite3re_match(sqlite3_ReCompiled *pRe, const unsigned char *zIn, int nIn){
  sqlite3_ReStateSet aStateSet[2], *pThis, *pNext;
  sqlite3_ReStateNumber aSpace[100];
  sqlite3_ReStateNumber *pToFree;
  unsigned int i = 0;
  unsigned int iSwap = 0;
  int c = RE_EOF+1;
  int cPrev = 0;
  int rc = 0;
  sqlite3_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 ){
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
    if( in.i+pRe->nInit>in.mx ) return 0;
  }

  if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
    pToFree = 0;
    aStateSet[0].aState = aSpace;
  }else{
    pToFree = sqlite3_malloc( sizeof(ReStateNumber)*2*pRe->nState );
    if( pToFree==0 ) return -1;
    aStateSet[0].aState = pToFree;
  }
  aStateSet[1].aState = &aStateSet[0].aState[pRe->nState];
  pNext = &aStateSet[1];
  pNext->nState = 0;
  re_add_state(pNext, 0);
  while( c!=RE_EOF && pNext->nState>0 ){
    cPrev = c;
    c = pRe->xNextChar(&in);
    pThis = pNext;
    pNext = &aStateSet[iSwap];
    iSwap = 1 - iSwap;
    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: {
          re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_WORD: {
          if( re_word_char(c) ) re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_NOTWORD: {
          if( !re_word_char(c) ) re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_DIGIT: {
          if( re_digit_char(c) ) re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_NOTDIGIT: {
          if( !re_digit_char(c) ) re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_SPACE: {
          if( re_space_char(c) ) re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_NOTSPACE: {
          if( !re_space_char(c) ) re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_BOUNDARY: {
          if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1);
          break;
        }
        case RE_OP_ANYSTAR: {
          re_add_state(pNext, x);
          re_add_state(pThis, x+1);
          break;
        }
        case RE_OP_FORK: {
          re_add_state(pThis, x+pRe->aArg[x]);
          re_add_state(pThis, x+1);
          break;
        }
        case RE_OP_GOTO: {
          re_add_state(pThis, x+pRe->aArg[x]);
          break;
        }
        case RE_OP_ACCEPT: {
          rc = 1;
          goto re_match_end;
        }
        case RE_OP_CC_INC:







|






|











|



|



|



|



|



|



|



|



|



|
|



|
|



|







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
    if( in.i+pRe->nInit>in.mx ) return 0;
  }

  if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
    pToFree = 0;
    aStateSet[0].aState = aSpace;
  }else{
    pToFree = sqlite3_malloc( sizeof(sqlite3_ReStateNumber)*2*pRe->nState );
    if( pToFree==0 ) return -1;
    aStateSet[0].aState = pToFree;
  }
  aStateSet[1].aState = &aStateSet[0].aState[pRe->nState];
  pNext = &aStateSet[1];
  pNext->nState = 0;
  sqlite3re_add_state(pNext, 0);
  while( c!=RE_EOF && pNext->nState>0 ){
    cPrev = c;
    c = pRe->xNextChar(&in);
    pThis = pNext;
    pNext = &aStateSet[iSwap];
    iSwap = 1 - iSwap;
    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 ) sqlite3re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_ANY: {
          sqlite3re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_WORD: {
          if( sqlite3re_word_char(c) ) sqlite3re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_NOTWORD: {
          if( !sqlite3re_word_char(c) ) sqlite3re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_DIGIT: {
          if( sqlite3re_digit_char(c) ) sqlite3re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_NOTDIGIT: {
          if( !sqlite3re_digit_char(c) ) sqlite3re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_SPACE: {
          if( sqlite3re_space_char(c) ) sqlite3re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_NOTSPACE: {
          if( !sqlite3re_space_char(c) ) sqlite3re_add_state(pNext, x+1);
          break;
        }
        case RE_OP_BOUNDARY: {
          if( sqlite3re_word_char(c)!=sqlite3re_word_char(cPrev) ) sqlite3re_add_state(pThis, x+1);
          break;
        }
        case RE_OP_ANYSTAR: {
          sqlite3re_add_state(pNext, x);
          sqlite3re_add_state(pThis, x+1);
          break;
        }
        case RE_OP_FORK: {
          sqlite3re_add_state(pThis, x+pRe->aArg[x]);
          sqlite3re_add_state(pThis, x+1);
          break;
        }
        case RE_OP_GOTO: {
          sqlite3re_add_state(pThis, x+pRe->aArg[x]);
          break;
        }
        case RE_OP_ACCEPT: {
          rc = 1;
          goto re_match_end;
        }
        case RE_OP_CC_INC:
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
                j = -1;
              }else{
                j++;
              }
            }
          }
          if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
          if( hit ) re_add_state(pNext, x+n);
          break;            
        }
      }
    }
  }
  for(i=0; i<pNext->nState; i++){
    if( pRe->aOp[pNext->aState[i]]==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.
*/
static int re_resize(ReCompiled *p, int N){
  char *aOp;
  int *aArg;
  aOp = sqlite3_realloc(p->aOp, N*sizeof(p->aOp[0]));
  if( aOp==0 ) return 1;
  p->aOp = aOp;
  aArg = sqlite3_realloc(p->aArg, N*sizeof(p->aArg[0]));
  if( aArg==0 ) return 1;
  p->aArg = aArg;
  p->nAlloc = N;
  return 0;
}

/* Insert a new opcode and argument into an RE under construction.  The
** insertion point is just prior to existing opcode iBefore.
*/
static int re_insert(ReCompiled *p, int iBefore, int op, int arg){
  int i;
  if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0;
  for(i=p->nState; i>iBefore; i--){
    p->aOp[i] = p->aOp[i-1];
    p->aArg[i] = p->aArg[i-1];
  }
  p->nState++;
  p->aOp[iBefore] = op;
  p->aArg[iBefore] = arg;
  return iBefore;
}

/* Append a new opcode and argument to the end of the RE under construction.
*/
static int re_append(ReCompiled *p, int op, int arg){
  return re_insert(p, p->nState, op, arg);
}

/* Make a copy of N opcodes starting at iStart onto the end of the RE
** under construction.
*/
static void re_copy(ReCompiled *p, int iStart, int N){
  if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return;
  memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0]));
  memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0]));
  p->nState += N;
}

/* Return true if c is a hexadecimal digit character:  [0-9a-fA-F]
** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c).  If
** c is not a hex digit *pV is unchanged.
*/
static int re_hex(int c, int *pV){
  if( c>='0' && c<='9' ){
    c -= '0';
  }else if( c>='a' && c<='f' ){
    c -= 'a' - 10;
  }else if( c>='A' && c<='F' ){
    c -= 'A' - 10;
  }else{
    return 0;
  }
  *pV = (*pV)*16 + (c & 0xff);
  return 1;
}

/* A backslash character has been seen, read the next character and
** return its interpretation.
*/
static unsigned re_esc_char(ReCompiled *p){
  static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
  static const char zTrans[] = "\a\f\n\r\t\v";
  int i, v = 0;
  char c;
  if( p->sIn.i>=p->sIn.mx ) return 0;
  c = p->sIn.z[p->sIn.i];
  if( c=='u' && p->sIn.i+4<p->sIn.mx ){
    const unsigned char *zIn = p->sIn.z + p->sIn.i;
    if( re_hex(zIn[1],&v)
     && re_hex(zIn[2],&v)
     && re_hex(zIn[3],&v)
     && re_hex(zIn[4],&v)
    ){
      p->sIn.i += 5;
      return v;
    }
  }
  if( c=='x' && p->sIn.i+2<p->sIn.mx ){
    const unsigned char *zIn = p->sIn.z + p->sIn.i;
    if( re_hex(zIn[1],&v)
     && re_hex(zIn[2],&v)
    ){
      p->sIn.i += 3;
      return v;
    }
  }
  for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
  if( zEsc[i] ){
    if( i<6 ) c = zTrans[i];
    p->sIn.i++;
  }else{
    p->zErr = "unknown \\ escape";
  }
  return c;
}

/* Forward declaration */
static const char *re_subcompile_string(ReCompiled*);

/* Peek at the next byte of input */
static unsigned char rePeek(ReCompiled *p){
  return p->sIn.i<p->sIn.mx ? p->sIn.z[p->sIn.i] : 0;
}

/* Compile RE text into a sequence of opcodes.  Continue up to the
** first unmatched ")" character, then return.  If an error is found,
** return a pointer to the error message string.
*/
static const char *re_subcompile_re(ReCompiled *p){
  const char *zErr;
  int iStart, iEnd, iGoto;
  iStart = p->nState;
  zErr = re_subcompile_string(p);
  if( zErr ) return zErr;
  while( rePeek(p)=='|' ){
    iEnd = p->nState;
    re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart);
    iGoto = re_append(p, RE_OP_GOTO, 0);
    p->sIn.i++;
    zErr = re_subcompile_string(p);
    if( zErr ) return zErr;
    p->aArg[iGoto] = p->nState - iGoto;
  }
  return 0;
}

/* Compile an element of regular expression text (anything that can be
** an operand to the "|" operator).  Return NULL on success or a pointer
** to the error message if there is a problem.
*/
static const char *re_subcompile_string(ReCompiled *p){
  int iPrev = -1;
  int iStart;
  unsigned c;
  const char *zErr;
  while( (c = p->xNextChar(&p->sIn))!=0 ){
    iStart = p->nState;
    switch( c ){
      case '|':
      case '$': 
      case ')': {
        p->sIn.i--;
        return 0;
      }
      case '(': {
        zErr = re_subcompile_re(p);
        if( zErr ) return zErr;
        if( rePeek(p)!=')' ) return "unmatched '('";
        p->sIn.i++;
        break;
      }
      case '.': {
        if( rePeek(p)=='*' ){
          re_append(p, RE_OP_ANYSTAR, 0);
          p->sIn.i++;
        }else{ 
          re_append(p, RE_OP_ANY, 0);
        }
        break;
      }
      case '*': {
        if( iPrev<0 ) return "'*' without operand";
        re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1);
        re_append(p, RE_OP_FORK, iPrev - p->nState + 1);
        break;
      }
      case '+': {
        if( iPrev<0 ) return "'+' without operand";
        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);
        }
        if( n==0 && m>0 ){
          re_append(p, RE_OP_FORK, -sz);
        }
        break;
      }
      case '[': {
        int iFirst = p->nState;
        if( rePeek(p)=='^' ){
          re_append(p, RE_OP_CC_EXC, 0);
          p->sIn.i++;
        }else{
          re_append(p, RE_OP_CC_INC, 0);
        }
        while( (c = p->xNextChar(&p->sIn))!=0 ){
          if( c=='[' && rePeek(p)==':' ){
            return "POSIX character classes not supported";
          }
          if( c=='\\' ) c = re_esc_char(p);
          if( rePeek(p)=='-' ){
            re_append(p, RE_OP_CC_RANGE, c);
            p->sIn.i++;
            c = p->xNextChar(&p->sIn);
            if( c=='\\' ) c = re_esc_char(p);
            re_append(p, RE_OP_CC_RANGE, c);
          }else{
            re_append(p, RE_OP_CC_VALUE, c);
          }
          if( rePeek(p)==']' ){ p->sIn.i++; break; }
        }
        if( c==0 ) return "unclosed '['";
        p->aArg[iFirst] = p->nState - iFirst;
        break;
      }
      case '\\': {
        int specialOp = 0;
        switch( rePeek(p) ){
          case 'b': specialOp = RE_OP_BOUNDARY;   break;
          case 'd': specialOp = RE_OP_DIGIT;      break;
          case 'D': specialOp = RE_OP_NOTDIGIT;   break;
          case 's': specialOp = RE_OP_SPACE;      break;
          case 'S': specialOp = RE_OP_NOTSPACE;   break;
          case 'w': specialOp = RE_OP_WORD;       break;
          case 'W': specialOp = RE_OP_NOTWORD;    break;
        }
        if( specialOp ){
          p->sIn.i++;
          re_append(p, specialOp, 0);
        }else{
          c = re_esc_char(p);
          re_append(p, RE_OP_MATCH, c);
        }
        break;
      }
      default: {
        re_append(p, RE_OP_MATCH, c);
        break;
      }
    }
    iPrev = iStart;
  }
  return 0;
}

/* Free and reclaim all the memory used by a previously compiled
** regular expression.  Applications should invoke this routine once
** for every call to re_compile() to avoid memory leaks.
*/
void re_free(ReCompiled *pRe){
  if( pRe ){
    sqlite3_free(pRe->aOp);
    sqlite3_free(pRe->aArg);
    sqlite3_free(pRe);
  }
}

/*
** Compile a textual regular expression in zIn[] into a compiled regular
** expression suitable for us by re_match() and return a pointer to the
** compiled regular expression in *ppRe.  Return NULL on success or an
** error message if something goes wrong.
*/
const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
  ReCompiled *pRe;
  const char *zErr;
  int i, j;

  *ppRe = 0;
  pRe = sqlite3_malloc( sizeof(*pRe) );
  if( pRe==0 ){
    return "out of memory";
  }
  memset(pRe, 0, sizeof(*pRe));
  pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char;
  if( re_resize(pRe, 30) ){
    re_free(pRe);
    return "out of memory";
  }
  if( zIn[0]=='^' ){
    zIn++;
  }else{
    re_append(pRe, RE_OP_ANYSTAR, 0);
  }
  pRe->sIn.z = (unsigned char*)zIn;
  pRe->sIn.i = 0;
  pRe->sIn.mx = (int)strlen(zIn);
  zErr = re_subcompile_re(pRe);
  if( zErr ){
    re_free(pRe);
    return zErr;
  }
  if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
    re_append(pRe, RE_OP_MATCH, RE_EOF);
    re_append(pRe, RE_OP_ACCEPT, 0);
    *ppRe = pRe;
  }else if( pRe->sIn.i>=pRe->sIn.mx ){
    re_append(pRe, RE_OP_ACCEPT, 0);
    *ppRe = pRe;
  }else{
    re_free(pRe);
    return "unrecognized character";
  }

  /* The following is a performance optimization.  If the regex begins with
  ** ".*" (if the input regex lacks an initial "^") and afterwards there are
  ** one or more matching characters, enter those matching characters into
  ** zInit[].  The re_match() routine can then search ahead in the input 
  ** string looking for the initial match without having to run the whole
  ** regex engine over the string.  Do not worry able trying to match
  ** unicode characters beyond plane 0 - those are very rare and this is
  ** just an optimization. */
  if( pRe->aOp[0]==RE_OP_ANYSTAR ){
    for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
      unsigned x = pRe->aArg[i];
      if( x<=127 ){
        pRe->zInit[j++] = x;
      }else if( x<=0xfff ){
        pRe->zInit[j++] = 0xc0 | (x>>6);
        pRe->zInit[j++] = 0x80 | (x&0x3f);
      }else if( x<=0xffff ){







|















|















|

|












|
|





|
|









|
















|








|
|
|
|







|
|
















|


|







|



|

|

|
|

|










|














|

|




|
|


|





|
|




|




|






|




|







|


|


|
|


|





|
|


|


|


|
|
|


|
|

|

|







|










|

|
|




|












|













|
|









|
|
|





|




|

|


|
|
|


|


|












|







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
                j = -1;
              }else{
                j++;
              }
            }
          }
          if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
          if( hit ) sqlite3re_add_state(pNext, x+n);
          break;            
        }
      }
    }
  }
  for(i=0; i<pNext->nState; i++){
    if( pRe->aOp[pNext->aState[i]]==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.
*/
static int sqlite3re_resize(sqlite3_ReCompiled *p, int N){
  char *aOp;
  int *aArg;
  aOp = sqlite3_realloc(p->aOp, N*sizeof(p->aOp[0]));
  if( aOp==0 ) return 1;
  p->aOp = aOp;
  aArg = sqlite3_realloc(p->aArg, N*sizeof(p->aArg[0]));
  if( aArg==0 ) return 1;
  p->aArg = aArg;
  p->nAlloc = N;
  return 0;
}

/* Insert a new opcode and argument into an RE under construction.  The
** insertion point is just prior to existing opcode iBefore.
*/
static int sqlite3re_insert(sqlite3_ReCompiled *p, int iBefore, int op, int arg){
  int i;
  if( p->nAlloc<=p->nState && sqlite3re_resize(p, p->nAlloc*2) ) return 0;
  for(i=p->nState; i>iBefore; i--){
    p->aOp[i] = p->aOp[i-1];
    p->aArg[i] = p->aArg[i-1];
  }
  p->nState++;
  p->aOp[iBefore] = op;
  p->aArg[iBefore] = arg;
  return iBefore;
}

/* Append a new opcode and argument to the end of the RE under construction.
*/
static int sqlite3re_append(sqlite3_ReCompiled *p, int op, int arg){
  return sqlite3re_insert(p, p->nState, op, arg);
}

/* Make a copy of N opcodes starting at iStart onto the end of the RE
** under construction.
*/
static void sqlite3re_copy(sqlite3_ReCompiled *p, int iStart, int N){
  if( p->nState+N>=p->nAlloc && sqlite3re_resize(p, p->nAlloc*2+N) ) return;
  memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0]));
  memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0]));
  p->nState += N;
}

/* Return true if c is a hexadecimal digit character:  [0-9a-fA-F]
** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c).  If
** c is not a hex digit *pV is unchanged.
*/
static int sqlite3re_hex(int c, int *pV){
  if( c>='0' && c<='9' ){
    c -= '0';
  }else if( c>='a' && c<='f' ){
    c -= 'a' - 10;
  }else if( c>='A' && c<='F' ){
    c -= 'A' - 10;
  }else{
    return 0;
  }
  *pV = (*pV)*16 + (c & 0xff);
  return 1;
}

/* A backslash character has been seen, read the next character and
** return its interpretation.
*/
static unsigned sqlite3re_esc_char(sqlite3_ReCompiled *p){
  static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]";
  static const char zTrans[] = "\a\f\n\r\t\v";
  int i, v = 0;
  char c;
  if( p->sIn.i>=p->sIn.mx ) return 0;
  c = p->sIn.z[p->sIn.i];
  if( c=='u' && p->sIn.i+4<p->sIn.mx ){
    const unsigned char *zIn = p->sIn.z + p->sIn.i;
    if( sqlite3re_hex(zIn[1],&v)
     && sqlite3re_hex(zIn[2],&v)
     && sqlite3re_hex(zIn[3],&v)
     && sqlite3re_hex(zIn[4],&v)
    ){
      p->sIn.i += 5;
      return v;
    }
  }
  if( c=='x' && p->sIn.i+2<p->sIn.mx ){
    const unsigned char *zIn = p->sIn.z + p->sIn.i;
    if( sqlite3re_hex(zIn[1],&v)
     && sqlite3re_hex(zIn[2],&v)
    ){
      p->sIn.i += 3;
      return v;
    }
  }
  for(i=0; zEsc[i] && zEsc[i]!=c; i++){}
  if( zEsc[i] ){
    if( i<6 ) c = zTrans[i];
    p->sIn.i++;
  }else{
    p->zErr = "unknown \\ escape";
  }
  return c;
}

/* Forward declaration */
static const char* sqlite3re_subcompile_string(sqlite3_ReCompiled*);

/* Peek at the next byte of input */
static unsigned char sqlite3rePeek(sqlite3_ReCompiled *p){
  return p->sIn.i<p->sIn.mx ? p->sIn.z[p->sIn.i] : 0;
}

/* Compile RE text into a sequence of opcodes.  Continue up to the
** first unmatched ")" character, then return.  If an error is found,
** return a pointer to the error message string.
*/
static const char* sqlite3re_subcompile_re(sqlite3_ReCompiled *p){
  const char *zErr;
  int iStart, iEnd, iGoto;
  iStart = p->nState;
  zErr = sqlite3re_subcompile_string(p);
  if( zErr ) return zErr;
  while( sqlite3rePeek(p)=='|' ){
    iEnd = p->nState;
    sqlite3re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart);
    iGoto = sqlite3re_append(p, RE_OP_GOTO, 0);
    p->sIn.i++;
    zErr = sqlite3re_subcompile_string(p);
    if( zErr ) return zErr;
    p->aArg[iGoto] = p->nState - iGoto;
  }
  return 0;
}

/* Compile an element of regular expression text (anything that can be
** an operand to the "|" operator).  Return NULL on success or a pointer
** to the error message if there is a problem.
*/
static const char* sqlite3re_subcompile_string(sqlite3_ReCompiled *p){
  int iPrev = -1;
  int iStart;
  unsigned c;
  const char *zErr;
  while( (c = p->xNextChar(&p->sIn))!=0 ){
    iStart = p->nState;
    switch( c ){
      case '|':
      case '$': 
      case ')': {
        p->sIn.i--;
        return 0;
      }
      case '(': {
        zErr = sqlite3re_subcompile_re(p);
        if( zErr ) return zErr;
        if( sqlite3rePeek(p)!=')' ) return "unmatched '('";
        p->sIn.i++;
        break;
      }
      case '.': {
        if( sqlite3rePeek(p)=='*' ){
          sqlite3re_append(p, RE_OP_ANYSTAR, 0);
          p->sIn.i++;
        }else{ 
          sqlite3re_append(p, RE_OP_ANY, 0);
        }
        break;
      }
      case '*': {
        if( iPrev<0 ) return "'*' without operand";
        sqlite3re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1);
        sqlite3re_append(p, RE_OP_FORK, iPrev - p->nState + 1);
        break;
      }
      case '+': {
        if( iPrev<0 ) return "'+' without operand";
        sqlite3re_append(p, RE_OP_FORK, iPrev - p->nState);
        break;
      }
      case '?': {
        if( iPrev<0 ) return "'?' without operand";
        sqlite3re_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=sqlite3rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; }
        n = m;
        if( c==',' ){
          p->sIn.i++;
          n = 0;
          while( (c=sqlite3rePeek(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}'";
          sqlite3re_insert(p, iPrev, RE_OP_FORK, sz+1);
          n--;
        }else{
          for(j=1; j<m; j++) sqlite3re_copy(p, iPrev, sz);
        }
        for(j=m; j<n; j++){
          sqlite3re_append(p, RE_OP_FORK, sz+1);
          sqlite3re_copy(p, iPrev, sz);
        }
        if( n==0 && m>0 ){
          sqlite3re_append(p, RE_OP_FORK, -sz);
        }
        break;
      }
      case '[': {
        int iFirst = p->nState;
        if( sqlite3rePeek(p)=='^' ){
          sqlite3re_append(p, RE_OP_CC_EXC, 0);
          p->sIn.i++;
        }else{
          sqlite3re_append(p, RE_OP_CC_INC, 0);
        }
        while( (c = p->xNextChar(&p->sIn))!=0 ){
          if( c=='[' && sqlite3rePeek(p)==':' ){
            return "POSIX character classes not supported";
          }
          if( c=='\\' ) c = sqlite3re_esc_char(p);
          if( sqlite3rePeek(p)=='-' ){
            sqlite3re_append(p, RE_OP_CC_RANGE, c);
            p->sIn.i++;
            c = p->xNextChar(&p->sIn);
            if( c=='\\' ) c = sqlite3re_esc_char(p);
            sqlite3re_append(p, RE_OP_CC_RANGE, c);
          }else{
            sqlite3re_append(p, RE_OP_CC_VALUE, c);
          }
          if( sqlite3rePeek(p)==']' ){ p->sIn.i++; break; }
        }
        if( c==0 ) return "unclosed '['";
        p->aArg[iFirst] = p->nState - iFirst;
        break;
      }
      case '\\': {
        int specialOp = 0;
        switch( sqlite3rePeek(p) ){
          case 'b': specialOp = RE_OP_BOUNDARY;   break;
          case 'd': specialOp = RE_OP_DIGIT;      break;
          case 'D': specialOp = RE_OP_NOTDIGIT;   break;
          case 's': specialOp = RE_OP_SPACE;      break;
          case 'S': specialOp = RE_OP_NOTSPACE;   break;
          case 'w': specialOp = RE_OP_WORD;       break;
          case 'W': specialOp = RE_OP_NOTWORD;    break;
        }
        if( specialOp ){
          p->sIn.i++;
          sqlite3re_append(p, specialOp, 0);
        }else{
          c = sqlite3re_esc_char(p);
          sqlite3re_append(p, RE_OP_MATCH, c);
        }
        break;
      }
      default: {
        sqlite3re_append(p, RE_OP_MATCH, c);
        break;
      }
    }
    iPrev = iStart;
  }
  return 0;
}

/* Free and reclaim all the memory used by a previously compiled
** regular expression.  Applications should invoke this routine once
** for every call to re_compile() to avoid memory leaks.
*/
void sqlite3re_free(sqlite3_ReCompiled *pRe){
  if( pRe ){
    sqlite3_free(pRe->aOp);
    sqlite3_free(pRe->aArg);
    sqlite3_free(pRe);
  }
}

/*
** Compile a textual regular expression in zIn[] into a compiled regular
** expression suitable for us by re_match() and return a pointer to the
** compiled regular expression in *ppRe.  Return NULL on success or an
** error message if something goes wrong.
*/
const char* sqlite3re_compile(sqlite3_ReCompiled **ppRe, const char *zIn, int noCase){
  sqlite3_ReCompiled *pRe;
  const char *zErr;
  int i, j;

  *ppRe = 0;
  pRe = sqlite3_malloc( sizeof(*pRe) );
  if( pRe==0 ){
    return "out of memory";
  }
  memset(pRe, 0, sizeof(*pRe));
  pRe->xNextChar = noCase ? sqlite3re_next_char_nocase : sqlite3re_next_char;
  if( sqlite3re_resize(pRe, 30) ){
    sqlite3re_free(pRe);
    return "out of memory";
  }
  if( zIn[0]=='^' ){
    zIn++;
  }else{
    sqlite3re_append(pRe, RE_OP_ANYSTAR, 0);
  }
  pRe->sIn.z = (unsigned char*)zIn;
  pRe->sIn.i = 0;
  pRe->sIn.mx = (int)strlen(zIn);
  zErr = sqlite3re_subcompile_re(pRe);
  if( zErr ){
    sqlite3re_free(pRe);
    return zErr;
  }
  if( sqlite3rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
    sqlite3re_append(pRe, RE_OP_MATCH, RE_EOF);
    sqlite3re_append(pRe, RE_OP_ACCEPT, 0);
    *ppRe = pRe;
  }else if( pRe->sIn.i>=pRe->sIn.mx ){
    sqlite3re_append(pRe, RE_OP_ACCEPT, 0);
    *ppRe = pRe;
  }else{
    sqlite3re_free(pRe);
    return "unrecognized character";
  }

  /* The following is a performance optimization.  If the regex begins with
  ** ".*" (if the input regex lacks an initial "^") and afterwards there are
  ** one or more matching characters, enter those matching characters into
  ** zInit[].  The re_match() routine can then search ahead in the input 
  ** string looking for the initial match without having to run the whole
  ** regex engine over the string.  Do not worry able trying to match
  ** unicode characters beyond plane 0 - those are very rare and this is
  ** just an optimization. */
  if( pRe->aOp[0]==RE_OP_ANYSTAR ){
    for(j=0, i=1; j<(int)sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
      unsigned x = pRe->aArg[i];
      if( x<=127 ){
        pRe->zInit[j++] = x;
      }else if( x<=0xfff ){
        pRe->zInit[j++] = 0xc0 | (x>>6);
        pRe->zInit[j++] = 0x80 | (x&0x3f);
      }else if( x<=0xffff ){
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
** is implemented as regexp(B,A).
*/
static void re_sql_func(
  sqlite3_context *context, 
  int argc, 
  sqlite3_value **argv
){
  ReCompiled *pRe;          /* Compiled regular expression */
  const char *zPattern;     /* The regular expression */
  const unsigned char *zStr;/* String being searched */
  const char *zErr;         /* Compile error message */
  int setAux = 0;           /* True to invoke sqlite3_set_auxdata() */

  pRe = sqlite3_get_auxdata(context, 0);
  if( pRe==0 ){
    zPattern = (const char*)sqlite3_value_text(argv[0]);
    if( zPattern==0 ) return;
    zErr = re_compile(&pRe, zPattern, 0);
    if( zErr ){
      re_free(pRe);
      sqlite3_result_error(context, zErr, -1);
      return;
    }
    if( pRe==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }
    setAux = 1;
  }
  zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
  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.
*/
int sqlite3_regexp_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const struct sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
#ifndef SQLITE_CORE
	SQLITE_EXTENSION_INIT2(pApi)	//sets up the 'vtable' to the host exe sqlite3 impl
#else
#endif
  rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
                                 re_sql_func, 0, 0);
  return rc;
}







|









|

|











|


|














|






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
** is implemented as regexp(B,A).
*/
static void re_sql_func(
  sqlite3_context *context, 
  int argc, 
  sqlite3_value **argv
){
  sqlite3_ReCompiled *pRe;  /* Compiled regular expression */
  const char *zPattern;     /* The regular expression */
  const unsigned char *zStr;/* String being searched */
  const char *zErr;         /* Compile error message */
  int setAux = 0;           /* True to invoke sqlite3_set_auxdata() */

  pRe = sqlite3_get_auxdata(context, 0);
  if( pRe==0 ){
    zPattern = (const char*)sqlite3_value_text(argv[0]);
    if( zPattern==0 ) return;
    zErr = sqlite3re_compile(&pRe, zPattern, 0);
    if( zErr ){
      sqlite3re_free(pRe);
      sqlite3_result_error(context, zErr, -1);
      return;
    }
    if( pRe==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }
    setAux = 1;
  }
  zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
  if( zStr!=0 ){
    sqlite3_result_int(context, sqlite3re_match(pRe, zStr, -1));
  }
  if( setAux ){
    sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))sqlite3re_free);
  }
}

/*
** Invoke this routine to register the regexp() function with the
** SQLite database connection.
*/
int sqlite3_regexp_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const struct sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
#ifndef SQLITE_CORE
	SQLITE_EXTENSION_INIT2(pApi)	/*sets up the 'vtable' to the host exe sqlite3 impl*/
#else
#endif
  rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
                                 re_sql_func, 0, 0);
  return rc;
}
Changes to src/fsl_vtbl_fossil_settings.c.
35
36
37
38
39
40
41

42
43
44
45
46
47
48
#include <direct.h>
#else
#include <unistd.h>
#include <strings.h>
#endif

#include "fossil-scm/fossil-ext_regexp.h"   /*sqlite3's regex engine*/

#include "fossil-scm/fossil-util.h"         /*for some internal class defs*/


#ifndef COUNTOF
#define COUNTOF(arr) (sizeof(arr)/sizeof(*arr))
#endif








>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <direct.h>
#else
#include <unistd.h>
#include <strings.h>
#endif

#include "fossil-scm/fossil-ext_regexp.h"   /*sqlite3's regex engine*/
#include "fossil-scm/fossil-core.h"         /*for some public defs*/
#include "fossil-scm/fossil-util.h"         /*for some internal class defs*/


#ifndef COUNTOF
#define COUNTOF(arr) (sizeof(arr)/sizeof(*arr))
#endif

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
/*descriptor of a well-known (publicly facing) setting in fossil*/
struct tagSettingDesc {
  const char* _pszName;           /*setting name*/
  bool        _bIsVersionable;    /*can it be in .fossil-settings?*/
  const char* _pszDefault;        /*the default value, if any*/
  const char* _pszHelp;           /*Help text, tooltip*/
  int         _nHelpTextID;       /*id of Help text (for eventual i18n)*/

  const char* _pszRegexAccept;    /*regex to validate input value*/
};
typedef struct tagSettingDesc SettingDesc;



/*common validation regexes*/














static const char sg_pszreBoolean[] = "^\\s*(true|false|0|1|on|off|yes|no)\\s*$";


static const char sg_pszreNumber[] = "^\\s*\\d+\\s*$";
static const char sg_pszreDecNumber[] = "^\\s*(\\d+\\.?\\d*)\\s*|\\s*(\\d*\\.?\\d+)\\s*$";




/*Note, these MUST be in alpha order by name, because we do binary searches*/
/*over the collection*/
static const SettingDesc g_asdSettingsDescriptors[] = {
  {
    "access-log",
    false,
    "off",
    "If enabled, record successful and failed login attempts "
    "in the \"accesslog\" table.",
    0,

    sg_pszreBoolean
  },
  {
    "allow-symlinks",
    true,
    "off",
    "If enabled, don't follow symlinks, and instead treat "
    "them as symlinks on Unix. Has no effect on Windows "
    "(existing links in repository created on Unix become "
    "plain-text files with link destination path inside).",
    0,

    sg_pszreBoolean
  },
  {
    "auto-captcha",
    false,
    "on",
    "If enabled, the Login page provides a button to "
    "fill in the captcha password.",
    0,

    sg_pszreBoolean
  },
  {
    "auto-hyperlink",
    false,
    "on",
    "Use javascript to enable hyperlinks on web pages "
    "for all users (regardless of the \"h\" privilege) if the "
    "User-Agent string in the HTTP header look like it came "
    "from real person, not a spider or bot.",
    0,

    sg_pszreBoolean
  },
  {
    "auto-shun",
    false,
    "on",
    "If enabled, automatically pull the shunning list "
    "from a server to which the client autosyncs.",
    0,

    sg_pszreBoolean
  },
  {
    "autosync",
    false,
    "on",
    "If enabled, automatically pull prior to commit "
    "or update and automatically push after commit or "
    "tag or branch creation.  If the value is \"pullonly\" "
    "then only pull operations occur automatically.",
    0,

    sg_pszreBoolean
  },
  {
    "binary-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of "
    "GLOB patterns that should be treated as binary files "
    "for committing and merging purposes.  Example: *.jpg ",
    0,
    ""  /*YYY need regex*/

  },
  {
    "case-sensitive",
    false,
    "false",
    "If TRUE, the files whose names differ only in case "
    "are considered distinct.  If FALSE files whose names "
    "differ only in case are the same file.\r\n"
    "Defaults to TRUE for unix and FALSE for Cygwin, Mac and Windows.",
    0,

    sg_pszreBoolean
  },
  {
    "clean-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of GLOB "
    "patterns specifying files that the \"clean\" command will "
    "delete without prompting even when the -force flag has "
    "not been used.  Example:  *.a *.lib *.o",
    0,
    ""  /*YYY need regex*/

  },
  {
    "clearsign",
    false,
    "off",
    "When enabled, fossil will attempt to sign all commits "
    "with gpg.  When disabled (the default), commits will "
    "be unsigned.",
    0,

    sg_pszreBoolean
  },
  {
    "crnl-glob",
    true,
    "",
    "A comma or newline-separated list of GLOB patterns for "
    "text files in which it is ok to have CR, CR+NL or mixed "
    "line endings. Set to \"*\" to disable CR+NL checking.",
    0,
    ""  /*YYY need regex*/

  },
  {
    "default-perms",
    false,
    "u",
    "Permissions given automatically to new users.  For more "
    "information on permissions see Users page in Server "
    "Administration of the HTTP UI.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "diff-binary",
    false,
    "true",
    "If TRUE (the default), permit files that may be binary "
    "or that match the \"binary-glob\" setting to be used with "
    "external diff programs.  If FALSE, skip these files.",
    0,

    sg_pszreBoolean
  },
  {
    "diff-command",
    false,
    "",
    "External command to run when performing a diff.\r\n"
    "If undefined, the internal text diff will be used.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "dont-push",
    false,
    "false",
    "Prevent this repository from pushing from client to "
    "server.  Useful when setting up a private branch.",
    0,

    sg_pszreBoolean
  },
  {
    "editor",
    false,

    "notepad.exe",





    "Text editor command used for check-in comments.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "empty-dirs",
    true,
    "",
    "A comma or newline-separated list of pathnames. On "
    "update and checkout commands, if no file or directory "
    "exists with that name, an empty directory will be "
    "created.",
    0,
    ""  /*YYY need regex*/

  },
  {
    "encoding-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of GLOB "
    "patterns specifying files that the \"commit\" command will "
    "ignore when issuing warnings about text files that may "
    "use another encoding than ASCII or UTF-8. Set to \"*\" "
    "to disable encoding checking.",
    0,
    ""  /*YYY need regex*/

  },
  {
    "gdiff-command",
    false,

    "WinDiff.exe",





    "External command to run when performing a graphical "
    "diff. If undefined, text diff will be used.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "gmerge-command",
    false,
    "",
    "A graphical merge conflict resolver command operating "
    "on four files.\r\n"
    "Ex: kdiff3 \"%baseline\" \"%original\" \"%merge\" -o \"%output\"\r\n"
    "Ex: xxdiff \"%original\" \"%baseline\" \"%merge\" -M \"%output\"\r\n"
    "Ex: meld \"%baseline\" \"%original\" \"%merge\" \"%output\"",
    0,

    ""  /*YYY need regex*/
  },
  {
    "http-port",
    false,
    "8080",
    "The TCP/IP port number to use by the \"server\""
    "and \"ui\" commands.",
    0,

    sg_pszreNumber
  },
  {
    "https-login",
    false,
    "",
    "Send login credentials using HTTPS instead of HTTP "
    "even if the login page request came via HTTP.",
    0,

    sg_pszreBoolean
  },
  {
    "ignore-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of GLOB "
    "patterns specifying files that the \"add\", \"addremove\", "
    "\"clean\", and \"extra\" commands will ignore.\r\n"
    "Example:  *.log customCode.c notes.txt",
    0,
    ""  /*YYY need regex*/

  },
  {
    "keep-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of GLOB "
    "patterns specifying files that the \"clean\" command will "
    "keep.",
    0,
    ""  /*YYY need regex*/

  },
  {
    "localauth",
    false,
    "false",
    "If enabled, require that HTTP connections from "
    "127.0.0.1 be authenticated by password.  If "
    "false, all HTTP requests from localhost have "
    "unrestricted access to the repository.",
    0,

    sg_pszreBoolean
  },
  {
    "main-branch",
    false,
    "trunk",
    "The primary branch for the project.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "manifest",
    true,
    "off",
    "If enabled, automatically create files \"manifest\" and "
    "\"manifest.uuid\" in every checkout.  The SQLite and "
    "Fossil repositories both require this.",
    0,

    sg_pszreBoolean
  },
  {
    "max-loadavg",
    false,
    "0.0",
    "Some CPU-intensive web pages (ex: /zip, /tarball, /blame) "
    "are disallowed if the system load average goes above this "
    "value.  \"0.0\" means no limit.  This only works on unix.\r\n"
    "Only local settings of this value make a difference since "
    "when running as a web-server, Fossil does not open the "
    "global configuration database.",
    0,

    sg_pszreDecNumber
  },
  {
    "max-upload",
    false,
    "250000",
    "A limit on the size of uplink HTTP requests.  The "
    "default is 250000 bytes.",
    0,

    sg_pszreNumber
  },
  {
    "mtime-changes",
    false,
    "on",
    "Use file modification times (mtimes) to detect when "
    "files have been modified.",
    0,

    sg_pszreBoolean
  },
  {
    "pgp-command",
    false,
    "gpg --clearsign -o ",
    "Command used to clear-sign manifests at check-in.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "proxy",
    false,
    "",
    "URL of the HTTP proxy.  If undefined or \"off\" then "
    "the \"http_proxy\" environment variable is consulted.\r\n"
    "If the http_proxy environment variable is undefined "
    "then a direct HTTP connection is used.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "relative-paths",
    false,
    "on",
    "When showing changes and extras, report paths relative "
    "to the current working directory.",
    0,

    sg_pszreBoolean
  },
  {
    "repo-cksum",
    false,
    "on",
    "Compute checksums over all files in each checkout "
    "as a double-check of correctness.  Defaults to \"on\". "
    "Disable on large repositories for a performance "
    "improvement.",
    0,

    sg_pszreBoolean
  },
  {
    "self-register",
    false,
    "off",
    "Allow users to register themselves through the HTTP UI.\r\n"
    "This is useful if you want to see other names than "
    "\"Anonymous\" in e.g. ticketing system. On the other hand "
    "users can not be deleted.",
    0,

    sg_pszreBoolean
  },
  {
    "ssh-command",
    false,
    "",
    "Command used to talk to a remote machine with "
    "the \"ssh://\" protocol.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "ssl-ca-location",
    false,
    "",
    "The full pathname to a file containing PEM encoded "
    "CA root certificates, or a directory of certificates "
    "with filenames formed from the certificate hashes as "
    "required by OpenSSL.\r\n"
    "If set, this will override the OS default list of "
    "OpenSSL CAs. If unset, the default list will be used.\r\n"
    "Some platforms may add additional certificates.\r\n"
    "Check your platform behaviour is as required if the "
    "exact contents of the CA root is critical for your "
    "application.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "ssl-identity",
    false,
    "",
    "The full pathname to a file containing a certificate "
    "and private key in PEM format. Create by concatenating "
    "the certificate and private key files.\r\n"
    "This identity will be presented to SSL servers to "
    "authenticate this client, in addition to the normal "
    "password authentication.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "tcl",
    false,
    "off",
    "If enabled (and Fossil was compiled with Tcl support), "
    "Tcl integration commands will be added to the TH1 "
    "interpreter, allowing arbitrary Tcl expressions and "
    "scripts to be evaluated from TH1.  Additionally, the Tcl "
    "interpreter will be able to evaluate arbitrary TH1 "
    "expressions and scripts.",
    0,

    sg_pszreBoolean
  },
  {
    "tcl-setup",
    true,
    "",
    "This is the setup script to be evaluated after creating "
    "and initializing the Tcl interpreter.  By default, this "
    "is empty and no extra setup is performed.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "th1-setup",
    true,
    "",
    "This is the setup script to be evaluated after creating "
    "and initializing the TH1 interpreter.  By default, this "
    "is empty and no extra setup is performed.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "th1-uri-regexp",
    true,
    "",
    "Specify which URI's are allowed in HTTP requests from "
    "TH1 scripts.  If empty, no HTTP requests are allowed "
    "whatsoever.  The default is an empty string.",
    0,

    ""  /*YYY need regex*/
  },
  {
    "web-browser",
    false,

    "start",





    "A shell command used to launch your preferred "
    "web browser when given a URL as an argument.\r\n"
    "Defaults to \"start\" on windows, \"open\" on Mac, "
    "and \"firefox\" on Unix.",
    0,

    ""  /*YYY need regex*/
  },
};

const size_t g_asdSettingsDescriptorsCount = COUNTOF(g_asdSettingsDescriptors);




/*===========================================
/ *our objects for settings metadata v-table
*/

struct tagvtblSetMetDat_table {
  sqlite3_vtab    _base;
  /*const sqlite3_module *pModule;    / *The module for this virtual table*/
  /*int nRef;                         / *NO LONGER USED*/
  /*char *zErrMsg;                    / *Error message from sqlite3_mprintf()*/
  /*Virtual table implementations will typically add additional fields*/
};
typedef struct tagvtblSetMetDat_table vtblSetMetDat_table;


vtblSetMetDat_table* vtblSetMetDat_table_new ( void ) {
  vtblSetMetDat_table* pThis = (vtblSetMetDat_table*) malloc ( sizeof(vtblSetMetDat_table) );
  /*any ctor actions...*/
  /*YYY (BBB docs say lib will set these up, but it doesn't.  it does setup pModule, however)*/
  pThis->_base.nRef = 0;          /*unused, but we clear it anyway*/
  pThis->_base.zErrMsg = NULL;    /*ensure null lest there be crashes when lib tries to free*/
  return pThis;
}

void vtblSetMetDat_table_delete ( vtblSetMetDat_table* pThis ) {
  if ( NULL != pThis )
  {
    /*any dtor actions...*/
    free ( pThis );
  }
}



struct tagvtblSetMetDat_cursor {
  sqlite3_vtab_cursor     _base;
  /*sqlite3_vtab *pVtab;      / *Virtual table of this cursor*/
  /*Virtual table implementations will typically add additional fields*/
  size_t _nIdxEntry;
};
typedef struct tagvtblSetMetDat_cursor vtblSetMetDat_cursor;


vtblSetMetDat_cursor* vtblSetMetDat_cursor_new() {
  vtblSetMetDat_cursor* pThis = (vtblSetMetDat_cursor*) malloc ( sizeof(vtblSetMetDat_cursor) );
  /*(any ctor actions...)*/
  pThis->_nIdxEntry = 0;
  return pThis;
}


void vtblSetMetDat_cursor_delete ( vtblSetMetDat_cursor* pThis ) {
  if ( NULL != pThis ) {
    /*(any dtor actions...)*/
    free ( pThis );
  }
}



/*===========================================*/
/*sqlite vtable interface code*/
/*'table' stuff*/



/*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/
int vtblSetMetDat_Create ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) {
  /*argv[0]   / *name of module*/
  /*argv[1]   / *name of database; "main", "temp", ...*/
  /*argv[2]   / *name of the virtual table*/
  /*argv[3...]    / *arguments of the sql create virtual table statement; if present*/
    
  /*first, declare our effective schema*/
  int ret = sqlite3_declare_vtab ( db, "CREATE TABLE [ignored] ( "
      "NAME TEXT,"                /*setting name*/
      "ISVERSIONABLE INTEGER,"    /*can it be in .fossil-settings*/
      "DEFAULT_VALUE TEXT,"       /*the default value, if any*/

      "HELP TEXT,"                /*Help text, tooltip*/
      "HELP_ID INTEGER,"          /*id of Help text (for eventual i18n)*/
      "REGEX_ACCEPT TEXT"         /*regex to validate input value*/
      ")" );
  if ( SQLITE_OK != ret )
    return ret;
    
  /*anything else we need?*/
  *ppVTab = &vtblSetMetDat_table_new()->_base;
    
  return SQLITE_OK;
}



/*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/
/*last connection to this table is going away*/
int vtblSetMetDat_Destroy ( sqlite3_vtab* pVTab ) {
  vtblSetMetDat_table* pThis = DOWNCAST(vtblSetMetDat_table,_base,pVTab);
  vtblSetMetDat_table_delete ( pThis );
  return SQLITE_OK;
}



/*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate   */
/*new connection to existing table; we just treat it the same as 'create'*/
int vtblSetMetDat_Connect ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr )
{ return vtblSetMetDat_Create ( db, pAux, argc, argv, ppVTab, pzErr ); }


/*xDisconnect -- drop virtual table, but not the last one*/
/*table is going away, but not last one*/
/*(BBB actually I have seen the last one go away via this method in the*/
/*case of database closure when there was not an explicit drop table)*/
int vtblSetMetDat_Disconnect ( sqlite3_vtab* pVTab )
{ return vtblSetMetDat_Destroy ( pVTab ); }


/*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/
/*think about what query is being done, and indicate what possible internal*/
/*quasi-index we might have*/
int vtblSetMetDat_BestIndex ( sqlite3_vtab* pVTab, sqlite3_index_info* pIdxInfo ) {
  /*
  vtblSetMetDat_table* pThis = DOWNCAST(vtblSetMetDat_table,_base,pVTab);
  int nIdx;
  / *Inputs* /
  pIdxInfo->nConstraint;                      / *Number of entries in aConstraint* /
  pIdxInfo->aConstraint[0].iColumn;           / *Column on left-hand side of constraint* /
  pIdxInfo->aConstraint[0].op;                / *Constraint operator* /







>







>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
|
>













>











>









>











>









>











>










|
>










>











|
>









>










|
>









>
|









>









>
|








>





>

>
>
>
>
>


>
|










|
>











|
>




>

>
>
>
>
>



>
|











>
|








>









>











|
>









|
>










>








>
|









>













>









>









>








>
|










>
|








>











>











>









>
|
















>
|












>
|












>










>
|









>
|









>
|




>

>
>
>
>
>





>
|



|


















|








|


















|







|















|










>

















|









|







|






|







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
/*descriptor of a well-known (publicly facing) setting in fossil*/
struct tagSettingDesc {
  const char* _pszName;           /*setting name*/
  bool        _bIsVersionable;    /*can it be in .fossil-settings?*/
  const char* _pszDefault;        /*the default value, if any*/
  const char* _pszHelp;           /*Help text, tooltip*/
  int         _nHelpTextID;       /*id of Help text (for eventual i18n)*/
  bool        _bIsMultivalue;     /*should there be list processing?*/
  const char* _pszRegexAccept;    /*regex to validate input value*/
};
typedef struct tagSettingDesc SettingDesc;



/*common validation regexes*/
/*Note: we have created some 'extended' metacharacters beyond those supported
by the regex engine proper:
\$i  regex is case-insensitive
\$m  regex is for a multi-valued setting (e.g. 'ignore-glob')
\$e  regex should match the empty setting as well
these metacharacters must be at the beginning of the regex, because we handle
their processing programattically, and use the rest of the string to compile
as per usual.
These metacharacters are needed principally because MATCH_OR_FAIL doesn't
have context of the setting it is validating, to get to the metadata for that
setting.  I could have made MATCH_OR_FAIL also take the setting name, so that
it can find the metatdata, but this way it is also generally useful for other
non-setting-related data validation purposes.
*/
static const char sg_pszreNonvalidated[] = ".*";
static const char sg_pszreBasicMultivalue[] = "\\$e\\$m^\\s*[^,\n\r]*\\s*$";
static const char sg_pszreBoolean[] = "\\$e\\$i^\\s*(true|false|1|0|on|off|yes|no)\\s*$";
static const char sg_pszreNumber[] = "\\$e^\\s*\\d+\\s*$";
static const char sg_pszreDecNumber[] = "\\$e^\\s*(\\d+\\.?\\d*)\\s*|\\s*(\\d*\\.?\\d+)\\s*$";
static const char sg_pszrePermissions[] = "^[abcdefghijklmnopqrstuvwxz]*$";



/*Note, these MUST be in alpha order by name, because we do binary searches*/
/*over the collection*/
static const SettingDesc g_asdSettingsDescriptors[] = {
  {
    "access-log",
    false,
    "off",
    "If enabled, record successful and failed login attempts "
    "in the \"accesslog\" table.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "allow-symlinks",
    true,
    "off",
    "If enabled, don't follow symlinks, and instead treat "
    "them as symlinks on Unix. Has no effect on Windows "
    "(existing links in repository created on Unix become "
    "plain-text files with link destination path inside).",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "auto-captcha",
    false,
    "on",
    "If enabled, the Login page provides a button to "
    "fill in the captcha password.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "auto-hyperlink",
    false,
    "on",
    "Use javascript to enable hyperlinks on web pages "
    "for all users (regardless of the \"h\" privilege) if the "
    "User-Agent string in the HTTP header look like it came "
    "from real person, not a spider or bot.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "auto-shun",
    false,
    "on",
    "If enabled, automatically pull the shunning list "
    "from a server to which the client autosyncs.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "autosync",
    false,
    "on",
    "If enabled, automatically pull prior to commit "
    "or update and automatically push after commit or "
    "tag or branch creation.  If the value is \"pullonly\" "
    "then only pull operations occur automatically.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "binary-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of "
    "GLOB patterns that should be treated as binary files "
    "for committing and merging purposes.  Example: *.jpg ",
    0,
    true,
    sg_pszreBasicMultivalue
  },
  {
    "case-sensitive",
    false,
    "false",
    "If TRUE, the files whose names differ only in case "
    "are considered distinct.  If FALSE files whose names "
    "differ only in case are the same file.\r\n"
    "Defaults to TRUE for unix and FALSE for Cygwin, Mac and Windows.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "clean-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of GLOB "
    "patterns specifying files that the \"clean\" command will "
    "delete without prompting even when the -force flag has "
    "not been used.  Example:  *.a *.lib *.o",
    0,
    true,
    sg_pszreBasicMultivalue
  },
  {
    "clearsign",
    false,
    "off",
    "When enabled, fossil will attempt to sign all commits "
    "with gpg.  When disabled (the default), commits will "
    "be unsigned.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "crnl-glob",
    true,
    "",
    "A comma or newline-separated list of GLOB patterns for "
    "text files in which it is ok to have CR, CR+NL or mixed "
    "line endings. Set to \"*\" to disable CR+NL checking.",
    0,
    true,
    sg_pszreBasicMultivalue
  },
  {
    "default-perms",
    false,
    "u",
    "Permissions given automatically to new users.  For more "
    "information on permissions see Users page in Server "
    "Administration of the HTTP UI.",
    0,
    false,
    sg_pszrePermissions
  },
  {
    "diff-binary",
    false,
    "true",
    "If TRUE (the default), permit files that may be binary "
    "or that match the \"binary-glob\" setting to be used with "
    "external diff programs.  If FALSE, skip these files.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "diff-command",
    false,
    "",
    "External command to run when performing a diff.\r\n"
    "If undefined, the internal text diff will be used.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "dont-push",
    false,
    "false",
    "Prevent this repository from pushing from client to "
    "server.  Useful when setting up a private branch.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "editor",
    false,
#ifdef WIN32
    "notepad.exe",
#elif defined ( __APPLE__ ) || defined ( __OSX__ )
    "",     /*YYY verify*/
#else
    "",     /*YYY verify*/
#endif
    "Text editor command used for check-in comments.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "empty-dirs",
    true,
    "",
    "A comma or newline-separated list of pathnames. On "
    "update and checkout commands, if no file or directory "
    "exists with that name, an empty directory will be "
    "created.",
    0,
    true,
    sg_pszreBasicMultivalue
  },
  {
    "encoding-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of GLOB "
    "patterns specifying files that the \"commit\" command will "
    "ignore when issuing warnings about text files that may "
    "use another encoding than ASCII or UTF-8. Set to \"*\" "
    "to disable encoding checking.",
    0,
    true,
    sg_pszreBasicMultivalue
  },
  {
    "gdiff-command",
    false,
#ifdef WIN32
    "WinDiff.exe",
#elif defined ( __APPLE__ ) || defined ( __OSX__ )
    "",     /*YYY verify*/
#else
    "",     /*YYY verify*/
#endif
    "External command to run when performing a graphical "
    "diff. If undefined, text diff will be used.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "gmerge-command",
    false,
    "",
    "A graphical merge conflict resolver command operating "
    "on four files.\r\n"
    "Ex: kdiff3 \"%baseline\" \"%original\" \"%merge\" -o \"%output\"\r\n"
    "Ex: xxdiff \"%original\" \"%baseline\" \"%merge\" -M \"%output\"\r\n"
    "Ex: meld \"%baseline\" \"%original\" \"%merge\" \"%output\"",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "http-port",
    false,
    "8080",
    "The TCP/IP port number to use by the \"server\""
    "and \"ui\" commands.",
    0,
    false,
    sg_pszreNumber
  },
  {
    "https-login",
    false,
    "",
    "Send login credentials using HTTPS instead of HTTP "
    "even if the login page request came via HTTP.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "ignore-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of GLOB "
    "patterns specifying files that the \"add\", \"addremove\", "
    "\"clean\", and \"extra\" commands will ignore.\r\n"
    "Example:  *.log customCode.c notes.txt",
    0,
    true,
    sg_pszreBasicMultivalue
  },
  {
    "keep-glob",
    true,
    "",
    "The VALUE is a comma or newline-separated list of GLOB "
    "patterns specifying files that the \"clean\" command will "
    "keep.",
    0,
    true,
    sg_pszreBasicMultivalue
  },
  {
    "localauth",
    false,
    "false",
    "If enabled, require that HTTP connections from "
    "127.0.0.1 be authenticated by password.  If "
    "false, all HTTP requests from localhost have "
    "unrestricted access to the repository.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "main-branch",
    false,
    "trunk",
    "The primary branch for the project.",
    0,
    false,
    sg_pszreNonvalidated  /*YYY need regex*/
  },
  {
    "manifest",
    true,
    "off",
    "If enabled, automatically create files \"manifest\" and "
    "\"manifest.uuid\" in every checkout.  The SQLite and "
    "Fossil repositories both require this.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "max-loadavg",
    false,
    "0.0",
    "Some CPU-intensive web pages (ex: /zip, /tarball, /blame) "
    "are disallowed if the system load average goes above this "
    "value.  \"0.0\" means no limit.  This only works on unix.\r\n"
    "Only local settings of this value make a difference since "
    "when running as a web-server, Fossil does not open the "
    "global configuration database.",
    0,
    false,
    sg_pszreDecNumber
  },
  {
    "max-upload",
    false,
    "250000",
    "A limit on the size of uplink HTTP requests.  The "
    "default is 250000 bytes.",
    0,
    false,
    sg_pszreNumber
  },
  {
    "mtime-changes",
    false,
    "on",
    "Use file modification times (mtimes) to detect when "
    "files have been modified.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "pgp-command",
    false,
    "gpg --clearsign -o ",
    "Command used to clear-sign manifests at check-in.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "proxy",
    false,
    "",
    "URL of the HTTP proxy.  If undefined or \"off\" then "
    "the \"http_proxy\" environment variable is consulted.\r\n"
    "If the http_proxy environment variable is undefined "
    "then a direct HTTP connection is used.",
    0,
    false,
    sg_pszreNonvalidated    /*YYY could/should be better?*/
  },
  {
    "relative-paths",
    false,
    "on",
    "When showing changes and extras, report paths relative "
    "to the current working directory.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "repo-cksum",
    false,
    "on",
    "Compute checksums over all files in each checkout "
    "as a double-check of correctness.  Defaults to \"on\". "
    "Disable on large repositories for a performance "
    "improvement.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "self-register",
    false,
    "off",
    "Allow users to register themselves through the HTTP UI.\r\n"
    "This is useful if you want to see other names than "
    "\"Anonymous\" in e.g. ticketing system. On the other hand "
    "users can not be deleted.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "ssh-command",
    false,
    "",
    "Command used to talk to a remote machine with "
    "the \"ssh://\" protocol.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "ssl-ca-location",
    false,
    "",
    "The full pathname to a file containing PEM encoded "
    "CA root certificates, or a directory of certificates "
    "with filenames formed from the certificate hashes as "
    "required by OpenSSL.\r\n"
    "If set, this will override the OS default list of "
    "OpenSSL CAs. If unset, the default list will be used.\r\n"
    "Some platforms may add additional certificates.\r\n"
    "Check your platform behaviour is as required if the "
    "exact contents of the CA root is critical for your "
    "application.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "ssl-identity",
    false,
    "",
    "The full pathname to a file containing a certificate "
    "and private key in PEM format. Create by concatenating "
    "the certificate and private key files.\r\n"
    "This identity will be presented to SSL servers to "
    "authenticate this client, in addition to the normal "
    "password authentication.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "tcl",
    false,
    "off",
    "If enabled (and Fossil was compiled with Tcl support), "
    "Tcl integration commands will be added to the TH1 "
    "interpreter, allowing arbitrary Tcl expressions and "
    "scripts to be evaluated from TH1.  Additionally, the Tcl "
    "interpreter will be able to evaluate arbitrary TH1 "
    "expressions and scripts.",
    0,
    false,
    sg_pszreBoolean
  },
  {
    "tcl-setup",
    true,
    "",
    "This is the setup script to be evaluated after creating "
    "and initializing the Tcl interpreter.  By default, this "
    "is empty and no extra setup is performed.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "th1-setup",
    true,
    "",
    "This is the setup script to be evaluated after creating "
    "and initializing the TH1 interpreter.  By default, this "
    "is empty and no extra setup is performed.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "th1-uri-regexp",
    true,
    "",
    "Specify which URI's are allowed in HTTP requests from "
    "TH1 scripts.  If empty, no HTTP requests are allowed "
    "whatsoever.  The default is an empty string.",
    0,
    false,
    sg_pszreNonvalidated
  },
  {
    "web-browser",
    false,
#ifdef WIN32
    "start",
#elif defined ( __APPLE__ ) || defined ( __OSX__ )
    "open",
#else
    "firefox",
#endif
    "A shell command used to launch your preferred "
    "web browser when given a URL as an argument.\r\n"
    "Defaults to \"start\" on windows, \"open\" on Mac, "
    "and \"firefox\" on Unix.",
    0,
    false,
    sg_pszreNonvalidated
  },
};

static const size_t g_asdSettingsDescriptorsCount = COUNTOF(g_asdSettingsDescriptors);




/*===========================================
/ *our objects for settings metadata v-table
*/

struct tagvtblSetMetDat_table {
  sqlite3_vtab    _base;
  /*const sqlite3_module *pModule;    / *The module for this virtual table*/
  /*int nRef;                         / *NO LONGER USED*/
  /*char *zErrMsg;                    / *Error message from sqlite3_mprintf()*/
  /*Virtual table implementations will typically add additional fields*/
};
typedef struct tagvtblSetMetDat_table vtblSetMetDat_table;


static vtblSetMetDat_table* vtblSetMetDat_table_new ( void ) {
  vtblSetMetDat_table* pThis = (vtblSetMetDat_table*) malloc ( sizeof(vtblSetMetDat_table) );
  /*any ctor actions...*/
  /*YYY (BBB docs say lib will set these up, but it doesn't.  it does setup pModule, however)*/
  pThis->_base.nRef = 0;          /*unused, but we clear it anyway*/
  pThis->_base.zErrMsg = NULL;    /*ensure null lest there be crashes when lib tries to free*/
  return pThis;
}

static void vtblSetMetDat_table_delete ( vtblSetMetDat_table* pThis ) {
  if ( NULL != pThis )
  {
    /*any dtor actions...*/
    free ( pThis );
  }
}



struct tagvtblSetMetDat_cursor {
  sqlite3_vtab_cursor     _base;
  /*sqlite3_vtab *pVtab;      / *Virtual table of this cursor*/
  /*Virtual table implementations will typically add additional fields*/
  size_t _nIdxEntry;
};
typedef struct tagvtblSetMetDat_cursor vtblSetMetDat_cursor;


static vtblSetMetDat_cursor* vtblSetMetDat_cursor_new() {
  vtblSetMetDat_cursor* pThis = (vtblSetMetDat_cursor*) malloc ( sizeof(vtblSetMetDat_cursor) );
  /*(any ctor actions...)*/
  pThis->_nIdxEntry = 0;
  return pThis;
}


static void vtblSetMetDat_cursor_delete ( vtblSetMetDat_cursor* pThis ) {
  if ( NULL != pThis ) {
    /*(any dtor actions...)*/
    free ( pThis );
  }
}



/*===========================================*/
/*sqlite vtable interface code*/
/*'table' stuff*/



/*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/
static int vtblSetMetDat_Create ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) {
  /*argv[0]   / *name of module*/
  /*argv[1]   / *name of database; "main", "temp", ...*/
  /*argv[2]   / *name of the virtual table*/
  /*argv[3...]    / *arguments of the sql create virtual table statement; if present*/
    
  /*first, declare our effective schema*/
  int ret = sqlite3_declare_vtab ( db, "CREATE TABLE [ignored] ( "
      "NAME TEXT,"                /*setting name*/
      "ISVERSIONABLE INTEGER,"    /*can it be in .fossil-settings*/
      "DEFAULT_VALUE TEXT,"       /*the default value, if any*/
      "VALUE TEXT HIDDEN,"        /*the default value, aliased to 'value'*/
      "HELP TEXT,"                /*Help text, tooltip*/
      "HELP_ID INTEGER,"          /*id of Help text (for eventual i18n)*/
      "REGEX_ACCEPT TEXT"         /*regex to validate input value*/
      ")" );
  if ( SQLITE_OK != ret )
    return ret;
    
  /*anything else we need?*/
  *ppVTab = &vtblSetMetDat_table_new()->_base;
    
  return SQLITE_OK;
}



/*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/
/*last connection to this table is going away*/
static int vtblSetMetDat_Destroy ( sqlite3_vtab* pVTab ) {
  vtblSetMetDat_table* pThis = DOWNCAST(vtblSetMetDat_table,_base,pVTab);
  vtblSetMetDat_table_delete ( pThis );
  return SQLITE_OK;
}



/*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate   */
/*new connection to existing table; we just treat it the same as 'create'*/
static int vtblSetMetDat_Connect ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr )
{ return vtblSetMetDat_Create ( db, pAux, argc, argv, ppVTab, pzErr ); }


/*xDisconnect -- drop virtual table, but not the last one*/
/*table is going away, but not last one*/
/*(BBB actually I have seen the last one go away via this method in the*/
/*case of database closure when there was not an explicit drop table)*/
static int vtblSetMetDat_Disconnect ( sqlite3_vtab* pVTab )
{ return vtblSetMetDat_Destroy ( pVTab ); }


/*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/
/*think about what query is being done, and indicate what possible internal*/
/*quasi-index we might have*/
static int vtblSetMetDat_BestIndex ( sqlite3_vtab* pVTab, sqlite3_index_info* pIdxInfo ) {
  /*
  vtblSetMetDat_table* pThis = DOWNCAST(vtblSetMetDat_table,_base,pVTab);
  int nIdx;
  / *Inputs* /
  pIdxInfo->nConstraint;                      / *Number of entries in aConstraint* /
  pIdxInfo->aConstraint[0].iColumn;           / *Column on left-hand side of constraint* /
  pIdxInfo->aConstraint[0].op;                / *Constraint operator* /
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


/*===========================================*/
/*'cursor' stuff*/


/*xOpen -- open a cursor*/
int vtblSetMetDat_cursor_Open ( sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor ) {
  *ppCursor = &vtblSetMetDat_cursor_new()->_base;
  return SQLITE_OK;
}


/*xClose -- close a cursor*/
int vtblSetMetDat_cursor_Close ( sqlite3_vtab_cursor* pCur ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  vtblSetMetDat_cursor_delete ( pThis );
  return SQLITE_OK;
}



int vtblSetMetDat_cursor_Filter ( sqlite3_vtab_cursor* pCur, int idxNum, const char* idxStr, int argc, sqlite3_value** argv ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  /*position cursor to location based on value arguments and parameters that ultimately came from xBestIndex*/
  /*this will 'rewind' the cursor to the beginning*/
  pThis->_nIdxEntry = 0;
  return SQLITE_OK;
}



/*xNext -- advance a cursor*/
int vtblSetMetDat_cursor_Next ( sqlite3_vtab_cursor* pCur ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  /*advance a cursor*/
  /*we iterate through the list*/
  if ( pThis->_nIdxEntry != g_asdSettingsDescriptorsCount ) {   /*still some left*/
    ++pThis->_nIdxEntry;    /*next*/
    return SQLITE_OK;
  }

  return SQLITE_OK;
}



/*xEof -- check for end of scan*/
int vtblSetMetDat_cursor_Eof ( sqlite3_vtab_cursor* pCur ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  /*check for end of iteration*/
  return ( g_asdSettingsDescriptorsCount == pThis->_nIdxEntry ) ? 1 : 0;
}



/*xColumn -- read data*/
int vtblSetMetDat_cursor_Column ( sqlite3_vtab_cursor* pCur, sqlite3_context* pCtx, int nCol ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  const SettingDesc* psd;
  /*read data*/
    
  if ( g_asdSettingsDescriptorsCount == pThis->_nIdxEntry ) {   /*shouldn't happen; I don't think*/
    sqlite3_result_error ( pCtx, "reading past end vtblSetMetDat_cursor", -1 );
    return SQLITE_ERROR;
  }
    
  psd = &g_asdSettingsDescriptors[pThis->_nIdxEntry];
  switch ( nCol ) {
    /*"NAME TEXT,"              / *setting name*/
    case 0:
      sqlite3_result_text ( pCtx, psd->_pszName, -1, SQLITE_STATIC );
    break;
    /*"ISVERSIONABLE INTEGER,"  / *can it be in .fossil-settings*/
    case 1:
      sqlite3_result_int ( pCtx, psd->_bIsVersionable ? 1 : 0 );
    break;
    /*"DEFAULT TEXT,"               / *the default value, if any*/

    case 2:

      if ( NULL == psd->_pszDefault || '\0' == psd->_pszDefault[0] )
        sqlite3_result_null ( pCtx );
      else
        sqlite3_result_text ( pCtx, psd->_pszDefault, -1, SQLITE_STATIC );
    break;
    /*HELP TEXT,"               / *Help text, tooltip*/
    case 3:
      if ( NULL == psd->_pszHelp || '\0' == psd->_pszHelp[0] )
        sqlite3_result_null ( pCtx );
      else
        sqlite3_result_text ( pCtx, psd->_pszHelp, -1, SQLITE_STATIC );
    break;
    /*"HELP_ID INTEGER,"            / *id of Help text (for eventual i18n)*/
    case 4:
      sqlite3_result_int ( pCtx, psd->_nHelpTextID );
    break;
    /*"REGEX_ACCEPT TEXT"           / *regex to validate input value*/
    case 5:
      if ( NULL == psd->_pszRegexAccept || '\0' == psd->_pszRegexAccept[0] )
        sqlite3_result_null ( pCtx );
      else
        sqlite3_result_text ( pCtx, psd->_pszRegexAccept, -1, SQLITE_STATIC );
    break;
    default:    /*que?*/
      sqlite3_result_null ( pCtx );
    break;
  }
  return SQLITE_OK;
}


/*xRowid -- read data*/
int vtblSetMetDat_cursor_Rowid ( sqlite3_vtab_cursor* pCur, sqlite3_int64* pRowid ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  /*read data*/
  *pRowid = pThis->_nIdxEntry;
  return SQLITE_OK;
}




const sqlite3_module sg_pvtblSettingsMetadata = {
  2,                          /*iVersion -- version of this structure, so sqlite doesn't access past end*/
  vtblSetMetDat_Create,       /*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/
  vtblSetMetDat_Connect,      /*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate*/
  vtblSetMetDat_BestIndex,    /*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/
  vtblSetMetDat_Disconnect,   /*xDisconnect -- drop virtual table, but not the last one*/
  vtblSetMetDat_Destroy,      /*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/
  vtblSetMetDat_cursor_Open,  /*xOpen -- open a cursor*/







|






|







|










|














|








|



















|
>

>






|






|



|














|









|







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
922
923
924
925
926


/*===========================================*/
/*'cursor' stuff*/


/*xOpen -- open a cursor*/
static int vtblSetMetDat_cursor_Open ( sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor ) {
  *ppCursor = &vtblSetMetDat_cursor_new()->_base;
  return SQLITE_OK;
}


/*xClose -- close a cursor*/
static int vtblSetMetDat_cursor_Close ( sqlite3_vtab_cursor* pCur ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  vtblSetMetDat_cursor_delete ( pThis );
  return SQLITE_OK;
}



static int vtblSetMetDat_cursor_Filter ( sqlite3_vtab_cursor* pCur, int idxNum, const char* idxStr, int argc, sqlite3_value** argv ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  /*position cursor to location based on value arguments and parameters that ultimately came from xBestIndex*/
  /*this will 'rewind' the cursor to the beginning*/
  pThis->_nIdxEntry = 0;
  return SQLITE_OK;
}



/*xNext -- advance a cursor*/
static int vtblSetMetDat_cursor_Next ( sqlite3_vtab_cursor* pCur ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  /*advance a cursor*/
  /*we iterate through the list*/
  if ( pThis->_nIdxEntry != g_asdSettingsDescriptorsCount ) {   /*still some left*/
    ++pThis->_nIdxEntry;    /*next*/
    return SQLITE_OK;
  }

  return SQLITE_OK;
}



/*xEof -- check for end of scan*/
static int vtblSetMetDat_cursor_Eof ( sqlite3_vtab_cursor* pCur ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  /*check for end of iteration*/
  return ( g_asdSettingsDescriptorsCount == pThis->_nIdxEntry ) ? 1 : 0;
}



/*xColumn -- read data*/
static int vtblSetMetDat_cursor_Column ( sqlite3_vtab_cursor* pCur, sqlite3_context* pCtx, int nCol ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  const SettingDesc* psd;
  /*read data*/
    
  if ( g_asdSettingsDescriptorsCount == pThis->_nIdxEntry ) {   /*shouldn't happen; I don't think*/
    sqlite3_result_error ( pCtx, "reading past end vtblSetMetDat_cursor", -1 );
    return SQLITE_ERROR;
  }
    
  psd = &g_asdSettingsDescriptors[pThis->_nIdxEntry];
  switch ( nCol ) {
    /*"NAME TEXT,"              / *setting name*/
    case 0:
      sqlite3_result_text ( pCtx, psd->_pszName, -1, SQLITE_STATIC );
    break;
    /*"ISVERSIONABLE INTEGER,"  / *can it be in .fossil-settings*/
    case 1:
      sqlite3_result_int ( pCtx, psd->_bIsVersionable ? 1 : 0 );
    break;
    /*"DEFAULT_VALUE TEXT,"     / *the default value, if any*/
    /*"VALUE TEXT,"             / *the default value, aliased to 'value'*/
    case 2:
    case 3:
      if ( NULL == psd->_pszDefault || '\0' == psd->_pszDefault[0] )
        sqlite3_result_null ( pCtx );
      else
        sqlite3_result_text ( pCtx, psd->_pszDefault, -1, SQLITE_STATIC );
    break;
    /*HELP TEXT,"               / *Help text, tooltip*/
    case 4:
      if ( NULL == psd->_pszHelp || '\0' == psd->_pszHelp[0] )
        sqlite3_result_null ( pCtx );
      else
        sqlite3_result_text ( pCtx, psd->_pszHelp, -1, SQLITE_STATIC );
    break;
    /*"HELP_ID INTEGER,"            / *id of Help text (for eventual i18n)*/
    case 5:
      sqlite3_result_int ( pCtx, psd->_nHelpTextID );
    break;
    /*"REGEX_ACCEPT TEXT"           / *regex to validate input value*/
    case 6:
      if ( NULL == psd->_pszRegexAccept || '\0' == psd->_pszRegexAccept[0] )
        sqlite3_result_null ( pCtx );
      else
        sqlite3_result_text ( pCtx, psd->_pszRegexAccept, -1, SQLITE_STATIC );
    break;
    default:    /*que?*/
      sqlite3_result_null ( pCtx );
    break;
  }
  return SQLITE_OK;
}


/*xRowid -- read data*/
static int vtblSetMetDat_cursor_Rowid ( sqlite3_vtab_cursor* pCur, sqlite3_int64* pRowid ) {
  vtblSetMetDat_cursor* pThis = DOWNCAST(vtblSetMetDat_cursor,_base,pCur);
  /*read data*/
  *pRowid = pThis->_nIdxEntry;
  return SQLITE_OK;
}




static const sqlite3_module sg_pvtblSettingsMetadata = {
  2,                          /*iVersion -- version of this structure, so sqlite doesn't access past end*/
  vtblSetMetDat_Create,       /*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/
  vtblSetMetDat_Connect,      /*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate*/
  vtblSetMetDat_BestIndex,    /*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/
  vtblSetMetDat_Disconnect,   /*xDisconnect -- drop virtual table, but not the last one*/
  vtblSetMetDat_Destroy,      /*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/
  vtblSetMetDat_cursor_Open,  /*xOpen -- open a cursor*/
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
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
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


/*since there are only a handful of 'versioned' settings that are supported,*/
/*and since the ones that are, are small textual values, we will just make*/
/*our life easier here, and read them all into memory at once.*/




typedef enum StyleValueSeparation {
  SEPSTYLE_UNKNOWN = 0,   /*couldn't figure it out; probably because there were no multi-values*/
  SEPSTYLE_NEWLINE = 1,
  SEPSTYLE_COMMA = 2,

} StyleValueSeparation;




typedef enum tagStyleLineEnding {
  NLSTYLE_UNKNOWN = 0,    /*couldn't figure it out; probably because there were no newlines*/
  NLSTYLE_CRLF = 1,   /*DOS/Windows*/
  NLSTYLE_CR = 2,     /*Mac*/
  NLSTYLE_LF = 3,     /*Unices*/
} StyleLineEnding;



#if defined(WIN32) || defined(WINDOWS) || defined(DOS)
const char sg_chPathSep = '\\';
#else
const char sg_chPathSep = '/';
#endif



struct tagSettingInfo {
  fsl_buffer              _strName;           /*name*/
  fsl_buffer              _strValue;          /*value, normalized to CSV*/
  /*We try to figure out the separators from the file itself, so we can*/
  /*preserve those choices when persisting back out.  This is done as a*/
  /*courtesy, to avoid creating unnecessary diffs.*/
  StyleValueSeparation    _esvsSep;           /*what was the original value separation style*/
  StyleLineEnding         _esleNewline;       /*what was the original 'newline' style*/
  fsl_buffer              _strOriginalPath;   /*what file contained this setting*/
  /*synthesized properties*/
  sqlite_int64            _nRowId;            /*sqlite needs this, and it can only be int64*/
};
typedef struct tagSettingInfo SettingInfo;


void SettingInfo_ctor ( SettingInfo* pThis ) {
  pThis->_strName = fsl_buffer_empty;         /*name*/
  pThis->_strValue = fsl_buffer_empty;        /*value, normalized to CSV*/
  /*We try to figure out the separators from the file itself, so we can*/
  /*preserve those choices when persisting back out.  This is done as a*/
  /*courtesy, to avoid creating unnecessary diffs.*/
  pThis->_esvsSep = SEPSTYLE_UNKNOWN;         /*what was the original value separation style*/
  pThis->_esleNewline = NLSTYLE_UNKNOWN;      /*what was the original 'newline' style*/
  pThis->_strOriginalPath = fsl_buffer_empty; /*what file contained this setting*/
  /*synthesized properties*/
  pThis->_nRowId = 0;         /*sqlite needs this, and it can only be int64*/
}


void SettingInfo_dtor ( SettingInfo* pThis ) {
  fsl_buffer_clear( &pThis->_strName );
  fsl_buffer_clear( &pThis->_strValue );
  fsl_buffer_clear( &pThis->_strOriginalPath );
}



SettingInfo* SettingInfo_new ( void ) {
  SettingInfo* pThis = (SettingInfo*) malloc ( sizeof(SettingInfo) );
  SettingInfo_ctor ( pThis );
  return pThis;
}



void SettingInfo_delete ( SettingInfo* pThis ) {
  if ( NULL != pThis ) {
    SettingInfo_dtor ( pThis );
    free ( pThis );
  }
}



int fsl_list_visitor_free ( void* obj, void* visitorState ) {
  free ( obj );
  return 0;
}



SettingInfo* SettingInfo_createFromFile ( const char* pszDir, const char* pszName ) {
  /*Note to self; this impl was originally in C++, where it (maybe) made a*/
  /*little more sense, however a tidier impl comes to mind:*/
  /**  read the whole file into buffer*/
  /**  characterise the styles from that buffer*/
  /**  strpbrk out the comma, cr, lf -> nul*/
  /*      list_append the ptr into the buffer of the start of the value text*/
  /**  finally, transform the value into csv*/
  /*this would avoid a lot of buffer copies and dtor code*/


  StyleValueSeparation esvsSep;
  StyleLineEnding esleNewline;
  fsl_buffer strPath;
  struct _stat buf;
  fsl_buffer strValue;
  SettingInfo* psi;

  strPath = fsl_buffer_empty;
  fsl_buffer_appendf ( &strPath, "%s%c%s", pszDir, sg_chPathSep, pszName );
    
  /*if the file does not exist, we can't try to depersist*/
  if ( 0 != _stat ( fsl_buffer_cstr ( &strPath ), &buf ) ) {
    fsl_buffer_clear ( &strPath );
    return NULL;
  }








|
>




>



>
>




|





|

|



















|













|







|







|








|
|





|








>
>








|







959
960
961
962
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
998
999
1000
1001
1002
1003
1004
1005
1006
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
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082


/*since there are only a handful of 'versioned' settings that are supported,*/
/*and since the ones that are, are small textual values, we will just make*/
/*our life easier here, and read them all into memory at once.*/


/*for multi-valued types (e.g. 'ignore-glob'), we attempt to detect and
preserve the style of the original file to minimize diffs*/
typedef enum StyleValueSeparation {
  SEPSTYLE_UNKNOWN = 0,   /*couldn't figure it out; probably because there were no multi-values*/
  SEPSTYLE_NEWLINE = 1,
  SEPSTYLE_COMMA = 2,
  SEPSTYLE_NONE = 3       /*this type is known to not be multivalue; inhibit list processing*/
} StyleValueSeparation;


/*we attempt to detect and preserve the newline style of the original
file to minimize diffs*/
typedef enum tagStyleLineEnding {
  NLSTYLE_UNKNOWN = 0,    /*couldn't figure it out; probably because there were no newlines*/
  NLSTYLE_CRLF = 1,   /*DOS/Windows*/
  NLSTYLE_CR = 2,     /*Mac*/
  NLSTYLE_LF = 3      /*Unices*/
} StyleLineEnding;



#if defined(WIN32) || defined(WINDOWS) || defined(DOS)
static const char sg_chPathSep = '\\';
#else
static const char sg_chPathSep = '/';
#endif



struct tagSettingInfo {
  fsl_buffer              _strName;           /*name*/
  fsl_buffer              _strValue;          /*value, normalized to CSV*/
  /*We try to figure out the separators from the file itself, so we can*/
  /*preserve those choices when persisting back out.  This is done as a*/
  /*courtesy, to avoid creating unnecessary diffs.*/
  StyleValueSeparation    _esvsSep;           /*what was the original value separation style*/
  StyleLineEnding         _esleNewline;       /*what was the original 'newline' style*/
  fsl_buffer              _strOriginalPath;   /*what file contained this setting*/
  /*synthesized properties*/
  sqlite_int64            _nRowId;            /*sqlite needs this, and it can only be int64*/
};
typedef struct tagSettingInfo SettingInfo;


static void SettingInfo_ctor ( SettingInfo* pThis ) {
  pThis->_strName = fsl_buffer_empty;         /*name*/
  pThis->_strValue = fsl_buffer_empty;        /*value, normalized to CSV*/
  /*We try to figure out the separators from the file itself, so we can*/
  /*preserve those choices when persisting back out.  This is done as a*/
  /*courtesy, to avoid creating unnecessary diffs.*/
  pThis->_esvsSep = SEPSTYLE_UNKNOWN;         /*what was the original value separation style*/
  pThis->_esleNewline = NLSTYLE_UNKNOWN;      /*what was the original 'newline' style*/
  pThis->_strOriginalPath = fsl_buffer_empty; /*what file contained this setting*/
  /*synthesized properties*/
  pThis->_nRowId = 0;         /*sqlite needs this, and it can only be int64*/
}


static void SettingInfo_dtor ( SettingInfo* pThis ) {
  fsl_buffer_clear( &pThis->_strName );
  fsl_buffer_clear( &pThis->_strValue );
  fsl_buffer_clear( &pThis->_strOriginalPath );
}



static SettingInfo* SettingInfo_new ( void ) {
  SettingInfo* pThis = (SettingInfo*) malloc ( sizeof(SettingInfo) );
  SettingInfo_ctor ( pThis );
  return pThis;
}



static void SettingInfo_delete ( SettingInfo* pThis ) {
  if ( NULL != pThis ) {
    SettingInfo_dtor ( pThis );
    free ( pThis );
  }
}



static int fsl_list_visitor_free ( void* obj, void* visitorState ) {
  fsl_free ( obj );
  return 0;
}



static SettingInfo* SettingInfo_createFromFile ( const char* pszDir, const SettingDesc* pdesc ) {
  /*Note to self; this impl was originally in C++, where it (maybe) made a*/
  /*little more sense, however a tidier impl comes to mind:*/
  /**  read the whole file into buffer*/
  /**  characterise the styles from that buffer*/
  /**  strpbrk out the comma, cr, lf -> nul*/
  /*      list_append the ptr into the buffer of the start of the value text*/
  /**  finally, transform the value into csv*/
  /*this would avoid a lot of buffer copies and dtor code*/
	/*YYY Note:  fsl_buffer_fill_from_filename can help*/
	/*YYY Note:  fsl_glob_list_parse/fsl_glob_list_clear can help*/
  StyleValueSeparation esvsSep;
  StyleLineEnding esleNewline;
  fsl_buffer strPath;
  struct _stat buf;
  fsl_buffer strValue;
  SettingInfo* psi;

  strPath = fsl_buffer_empty;
  fsl_buffer_appendf ( &strPath, "%s%c%s", pszDir, sg_chPathSep, pdesc->_pszName );
    
  /*if the file does not exist, we can't try to depersist*/
  if ( 0 != _stat ( fsl_buffer_cstr ( &strPath ), &buf ) ) {
    fsl_buffer_clear ( &strPath );
    return NULL;
  }

1066
1067
1068
1069
1070
1071
1072



1073

1074
1075
1076











1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
            }   /*unknown; impossible*/
          }
        }
      }

    fclose ( f );
  }





  /*now, open file, read lines, parse seps, build string list, then*/
  /*anneal string list into csv*/
  strValue = fsl_buffer_empty; {











      fsl_list lstrValues;
      fsl_buffer strToken;
      char ch;
      size_t nRead;
      bool bEOF;
      FILE* f;
      fsl_size_t nIdx;

    lstrValues = fsl_list_empty;
    strToken = fsl_buffer_empty;

    f = fopen ( fsl_buffer_cstr ( &strPath ), "rb" );
    if ( NULL == f ) {
      /*absurd; we just opened it a moment ago*/
      fsl_buffer_clear ( &strToken );
      fsl_list_reserve ( &lstrValues, 0 );
      fsl_buffer_clear ( &strValue );
      fsl_buffer_clear ( &strPath );
      return NULL;
    }

    while ( 
        nRead = fread ( &ch, sizeof(ch), 1, f ),
        bEOF = ( sizeof(ch) != nRead ),
        ! bEOF
        )
    {
      if ( ',' == ch || '\r' == ch || '\n' == ch ) {
        if ( 0 != fsl_buffer_size ( &strToken ) ) { /*push token*/
          fsl_list_append ( &lstrValues, strdup ( fsl_buffer_cstr ( &strToken ) ) );
          fsl_buffer_reset ( &strToken );
        }
      }
      else    /*build token*/
        fsl_buffer_append ( &strToken, &ch, sizeof(ch) );
    }
    if ( 0 != fsl_buffer_size ( &strToken ) ) { /*a last one? (like if fil ended without final sep)*/
      fsl_list_append ( &lstrValues, strdup ( fsl_buffer_cstr ( &strToken ) ) );
      fsl_buffer_reset ( &strToken );
    }

    fclose ( f );

    /*normalize into CSV*/
    for ( nIdx = 0; nIdx < lstrValues.used; ++nIdx ) {
      char chComma = ',';
      if (  0 != fsl_buffer_size ( &strValue ) )
        fsl_buffer_append ( &strValue, &chComma, sizeof(chComma) );
      fsl_buffer_append ( &strValue, lstrValues.list[nIdx], strlen ( lstrValues.list[nIdx] ) );
    }

    /*dtor*/
    fsl_buffer_clear ( &strToken );
    fsl_list_clear ( &lstrValues, fsl_list_visitor_free, NULL );
  }

  /*OK, now we can get down to business...*/
  psi = SettingInfo_new();
  fsl_buffer_append ( &psi->_strName, pszName, strlen ( pszName ) );
  fsl_buffer_append ( &psi->_strOriginalPath, fsl_buffer_cstr ( &strPath ), fsl_buffer_size ( &strPath ) );
  psi->_esvsSep = esvsSep;
  psi->_esleNewline = esleNewline;
  fsl_buffer_append ( &psi->_strValue, fsl_buffer_cstr ( &strValue ), fsl_buffer_size ( &strValue ) );
  psi->_nRowId = 0;           /*(parent will set this up)*/
    
  fsl_buffer_clear ( &strValue );
  fsl_buffer_clear ( &strPath );
    
  return psi;
}



SettingInfo* SettingInfo_createFromParams ( const char* pszDir, const char* pszName,
      const char* pszValue, StyleValueSeparation esvsSep, StyleLineEnding esleNewline ) {
  fsl_buffer strPath;
  SettingInfo* psi;

  strPath = fsl_buffer_empty;
  fsl_buffer_appendf ( &strPath, "%s%c%s", pszDir, sg_chPathSep, pszName );








>
>
>
|
>


|
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|













|




|
<


|






|
|










|









|














|







1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
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
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
            }   /*unknown; impossible*/
          }
        }
      }

    fclose ( f );
  }
  /*well, OK, if metadata says we're not multivalue, override any inferred sep style*/
  if ( ! pdesc->_bIsMultivalue ) {
    esvsSep = SEPSTYLE_NONE;
  }
  
  /*now, open file, read lines, parse seps, build string list, then*/
  /*anneal string list into csv*/
  strValue = fsl_buffer_empty;
  if ( SEPSTYLE_NONE == esvsSep ) {
    if ( FSL_RC_OK != fsl_buffer_fill_from_filename ( &strValue,
        fsl_buffer_cstr ( &strPath ) ) ) {
      /*absurd; we just opened it a moment ago*/
      fsl_buffer_clear ( &strValue );
      fsl_buffer_clear ( &strPath );
      return NULL;
    }
  }
  else {
    /*YYY reimplement this using the fsl_glob_list_parse()*/
    fsl_list lstrValues;
    fsl_buffer strToken;
    char ch;
    size_t nRead;
    bool bEOF;
    FILE* f;
    fsl_size_t nIdx;

    lstrValues = fsl_list_empty;
    strToken = fsl_buffer_empty;

    f = fopen ( fsl_buffer_cstr ( &strPath ), "rb" );
    if ( NULL == f ) {
      /*absurd; we just opened it a moment ago*/
      fsl_buffer_clear ( &strToken );
      fsl_list_reserve ( &lstrValues, 0 );
      fsl_buffer_clear ( &strValue );
      fsl_buffer_clear ( &strPath );
      return NULL;
    }
    
    while ( 
        nRead = fread ( &ch, sizeof(ch), 1, f ),
        bEOF = ( sizeof(ch) != nRead ),
        ! bEOF
        ) {

      if ( ',' == ch || '\r' == ch || '\n' == ch ) {
        if ( 0 != fsl_buffer_size ( &strToken ) ) { /*push token*/
          fsl_list_append ( &lstrValues, fsl_strdup ( fsl_buffer_cstr ( &strToken ) ) );
          fsl_buffer_reset ( &strToken );
        }
      }
      else    /*build token*/
        fsl_buffer_append ( &strToken, &ch, sizeof(ch) );
    }
    if ( 0 != fsl_buffer_size ( &strToken ) ) { /*a last one? (like if file ended without final sep)*/
      fsl_list_append ( &lstrValues, fsl_strdup ( fsl_buffer_cstr ( &strToken ) ) );
      fsl_buffer_reset ( &strToken );
    }

    fclose ( f );

    /*normalize into CSV*/
    for ( nIdx = 0; nIdx < lstrValues.used; ++nIdx ) {
      char chComma = ',';
      if (  0 != fsl_buffer_size ( &strValue ) )
        fsl_buffer_append ( &strValue, &chComma, sizeof(chComma) );
      fsl_buffer_append ( &strValue, lstrValues.list[nIdx], fsl_strlen ( lstrValues.list[nIdx] ) );
    }

    /*dtor*/
    fsl_buffer_clear ( &strToken );
    fsl_list_clear ( &lstrValues, fsl_list_visitor_free, NULL );
  }

  /*OK, now we can get down to business...*/
  psi = SettingInfo_new();
  fsl_buffer_append ( &psi->_strName, pdesc->_pszName, fsl_strlen ( pdesc->_pszName ) );
  fsl_buffer_append ( &psi->_strOriginalPath, fsl_buffer_cstr ( &strPath ), fsl_buffer_size ( &strPath ) );
  psi->_esvsSep = esvsSep;
  psi->_esleNewline = esleNewline;
  fsl_buffer_append ( &psi->_strValue, fsl_buffer_cstr ( &strValue ), fsl_buffer_size ( &strValue ) );
  psi->_nRowId = 0;           /*(parent will set this up)*/
    
  fsl_buffer_clear ( &strValue );
  fsl_buffer_clear ( &strPath );
    
  return psi;
}



static SettingInfo* SettingInfo_createFromParams ( const char* pszDir, const char* pszName,
      const char* pszValue, StyleValueSeparation esvsSep, StyleLineEnding esleNewline ) {
  fsl_buffer strPath;
  SettingInfo* psi;

  strPath = fsl_buffer_empty;
  fsl_buffer_appendf ( &strPath, "%s%c%s", pszDir, sg_chPathSep, pszName );

1167
1168
1169
1170
1171
1172
1173
1174









1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
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
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240

  fsl_buffer_clear ( &strPath );
  return psi;
}



bool SettingInfo_saveToFile ( const SettingInfo* pThis ) {









  FILE* f;
  size_t nIdx;

  f = fopen ( fsl_buffer_cstr ( &pThis->_strOriginalPath ), "wb" );
  if ( NULL == f ) {
    return false;
  }

  /*emit characters in the string until we hit a ',' which we will*/
  /*translate into separators/newline according to style.*/
  for ( nIdx = 0; nIdx < fsl_buffer_size ( &pThis->_strValue ); ++nIdx ) {
    if ( ',' == pThis->_strValue.mem[nIdx] ) {
      if ( SEPSTYLE_COMMA == pThis->_esvsSep ) {
        char ch = ',';
        fwrite ( &ch, sizeof(ch), 1, f );
      }
      else {
        if ( NLSTYLE_CRLF == pThis->_esleNewline ) {
          char ach[2] = { '\r', '\n' };
          fwrite ( ach, sizeof(ach), 1, f );
        }
        else if ( NLSTYLE_CR == pThis->_esleNewline ) {
          char ch = '\r';
          fwrite ( &ch, sizeof(ch), 1, f );
        }
        else {  /*NLSTYLE_LF*/
          char ch = '\n';
          fwrite ( &ch, sizeof(ch), 1, f );
        }
      }
    }
    else {
      fwrite ( &pThis->_strValue.mem[nIdx], sizeof(pThis->_strValue.mem[nIdx]), 1, f );
    }
  }

  fclose ( f );


  return true;
}



bool SettingInfo_removeFile ( const SettingInfo* pThis ) {
  return 0 == _unlink ( fsl_buffer_cstr ( &pThis->_strOriginalPath ) );
}



/*our setting collection is a map of 'rowid's to settings info*/
/*since we only have a few known 'versioned settings', I am just going to use*/
/*an array, and do a linear search for my finds.*/
struct tagSettingCollTuple {
  sqlite_int64    _nRowId;
  SettingInfo*    _psi;
};
typedef struct tagSettingCollTuple SettingCollTuple;

int fsl_list_visitor_settingtuple_free ( void* obj, void* visitorState ) {
  SettingCollTuple* ptpl = (SettingCollTuple*)obj;
  /*dtor on the tuple members*/
  /*ptpl->_nRowId*/
  SettingInfo_delete ( ptpl->_psi );
  /*delete the tuple*/
  free ( ptpl );
  return 0;







|
>
>
>
>
>
>
>
>
>
|
|

|
|
|
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


>






|














|







1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293

1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352

  fsl_buffer_clear ( &strPath );
  return psi;
}



static bool SettingInfo_saveToFile ( const SettingInfo* pThis ) {

  if ( SEPSTYLE_NONE == pThis->_esvsSep ) {
    /*this is not a multivar; just emit the data verbatim*/
    if ( FSL_RC_OK != fsl_buffer_to_filename( &pThis->_strValue,
        fsl_buffer_cstr ( &pThis->_strOriginalPath ) ) ) {
      return false;
    }
  }
  else {
    FILE* f;
    size_t nIdx;

    f = fopen ( fsl_buffer_cstr ( &pThis->_strOriginalPath ), "wb" );
    if ( NULL == f ) {
      return false;
    }

    /*emit characters in the string until we hit a ',' which we will*/
    /*translate into separators/newline according to style.*/
    for ( nIdx = 0; nIdx < fsl_buffer_size ( &pThis->_strValue ); ++nIdx ) {
      if ( ',' == pThis->_strValue.mem[nIdx] ) {
        if ( SEPSTYLE_COMMA == pThis->_esvsSep ) {
          char ch = ',';
          fwrite ( &ch, sizeof(ch), 1, f );
        }
        else {
          if ( NLSTYLE_CRLF == pThis->_esleNewline ) {
            char ach[2] = { '\r', '\n' };
            fwrite ( ach, sizeof(ach), 1, f );
          }
          else if ( NLSTYLE_CR == pThis->_esleNewline ) {
            char ch = '\r';
            fwrite ( &ch, sizeof(ch), 1, f );
          }
          else {  /*NLSTYLE_LF*/
            char ch = '\n';
            fwrite ( &ch, sizeof(ch), 1, f );
          }
        }
      }
      else {
        fwrite ( &pThis->_strValue.mem[nIdx], sizeof(pThis->_strValue.mem[nIdx]), 1, f );
      }
    }

  fclose ( f );
  }

  return true;
}



static bool SettingInfo_removeFile ( const SettingInfo* pThis ) {
  return 0 == _unlink ( fsl_buffer_cstr ( &pThis->_strOriginalPath ) );
}



/*our setting collection is a map of 'rowid's to settings info*/
/*since we only have a few known 'versioned settings', I am just going to use*/
/*an array, and do a linear search for my finds.*/
struct tagSettingCollTuple {
  sqlite_int64    _nRowId;
  SettingInfo*    _psi;
};
typedef struct tagSettingCollTuple SettingCollTuple;

static int fsl_list_visitor_settingtuple_free ( void* obj, void* visitorState ) {
  SettingCollTuple* ptpl = (SettingCollTuple*)obj;
  /*dtor on the tuple members*/
  /*ptpl->_nRowId*/
  SettingInfo_delete ( ptpl->_psi );
  /*delete the tuple*/
  free ( ptpl );
  return 0;
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
  fsl_list                _settings;          /*the settings, depersisted from files*/

  int     _nCursorsOpen;  /*count of open cursors; some updating cannot happen with > 1*/
};
typedef struct tagvtblVerSet_table vtblVerSet_table;


void vtblVerSet_table_ctor ( vtblVerSet_table* pThis, sqlite3* db, const char* pszVerSettingsPath ) {
  /*YYY (BBB docs say lib will set these up, but it doesn't.  it does setup pModule, however)*/
  pThis->_base.nRef = 0;          /*unused, but we clear it anyway*/
  pThis->_base.zErrMsg = NULL;    /*ensure null lest there be crashes when lib tries to free*/
  pThis->_db = db;  /*we need this from time-to-time*/
  /*platform-specific defaults for multi-value and newline styles.  These*/
  /*are used in cases where we couldn't figure them out, like, if there*/
  /*was only one element*/
  pThis->_esvsSepPlat = SEPSTYLE_NEWLINE;
#if defined(WIN32) || defined(WINDOWS) || defined(DOS)
  pThis->_esleNewlinePlat = NLSTYLE_CRLF; /*use windowsian CRLF*/
#else
  pThis->_esleNewlinePlat = NLSTYLE_LF;   /*fall back to unixian LF*/
#endif
  pThis->_strVerSettingsPath = fsl_buffer_empty;
  fsl_buffer_append ( &pThis->_strVerSettingsPath, pszVerSettingsPath, strlen ( pszVerSettingsPath ) );
  pThis->_nLastRowId = 0;
  pThis->_settings = fsl_list_empty;
  pThis->_nCursorsOpen = 0;
}



void vtblVerSet_table_dtor ( vtblVerSet_table* pThis ) {
  fsl_list_clear ( &pThis->_settings, fsl_list_visitor_settingtuple_free, NULL );
  fsl_buffer_clear( &pThis->_strVerSettingsPath );
}



vtblVerSet_table* vtblVerSet_table_new ( sqlite3* db, const char* pszVerSettingsPath ) {
  vtblVerSet_table* pThis = (vtblVerSet_table*) malloc ( sizeof(vtblVerSet_table) );
  vtblVerSet_table_ctor ( pThis, db, pszVerSettingsPath );
  return pThis;
}



void vtblVerSet_table_delete ( vtblVerSet_table* pThis ) {
  if ( NULL != pThis ) {
    vtblVerSet_table_dtor ( pThis );
    free ( pThis );
  }
}



bool vtblVerSet_table_addExistingSetting ( vtblVerSet_table* pThis, const char* pszName ) {
  /*factory idiom*/
  SettingInfo* psi = SettingInfo_createFromFile ( fsl_buffer_cstr ( &pThis->_strVerSettingsPath ), pszName );
  if ( NULL != psi ) {
    SettingCollTuple* psct;
    if ( psi->_esvsSep == SEPSTYLE_UNKNOWN )
      psi->_esvsSep = pThis->_esvsSepPlat;
    if ( psi->_esleNewline == NLSTYLE_UNKNOWN )
      psi->_esleNewline = pThis->_esleNewlinePlat;
    psi->_nRowId = ++(pThis->_nLastRowId);
    /**/
    psct = (SettingCollTuple*) malloc ( sizeof(SettingCollTuple) );
    psct->_nRowId = psi->_nRowId;
    psct->_psi = psi;
    fsl_list_append ( &pThis->_settings, psct );
  }
  return NULL != psi;
}



bool vtblVerSet_table_populate ( vtblVerSet_table* pThis ) {
  size_t nIdx;
  for ( nIdx = 0; nIdx < g_asdSettingsDescriptorsCount; ++nIdx ) {
    if ( g_asdSettingsDescriptors[nIdx]._bIsVersionable )
      vtblVerSet_table_addExistingSetting ( pThis, g_asdSettingsDescriptors[nIdx]._pszName );
  }
  return true;
}



/*since there are only a few well-known versionable settings, I am simply going*/
/*to do a linear search for 'find' operations.  The 'find' operation will*/
/*return the index into the _settings array (er, 'list').  You may use this*/
/*index to get at the setting object, or use it to erase the setting (and*/
/*manage the list correctly).  Non-found items will return an index of -1.*/
int vtblVerSet_table_find_setting_idx_by_rowid ( vtblVerSet_table* pThis, sqlite3_int64 nRowId ) {
  int nIdx;
  for ( nIdx = 0; nIdx < (int) pThis->_settings.used; ++nIdx ) {
    if ( ((SettingCollTuple*)(pThis->_settings.list[nIdx]))->_nRowId == nRowId )
      return nIdx;
  }
  return -1;
}



int vtblVerSet_table_find_setting_idx_by_name ( vtblVerSet_table* pThis, const char* pszName )
{
  int nIdx;
  for ( nIdx = 0; nIdx < (int) pThis->_settings.used; ++nIdx ) {
    if ( 0 == _stricmp ( fsl_buffer_cstr (
        &((SettingCollTuple*)(pThis->_settings.list[nIdx]))->_psi->_strName ),
        pszName ) )
      return nIdx;
  }
  return -1;
}



void vtblVerSet_table_erase_setting_by_idx ( vtblVerSet_table* pThis, int nIdx ) {
  SettingCollTuple* ptpl;
  if ( nIdx < 0 || nIdx >= pThis->_settings.used )
    return; /*bogus; assert-worthy*/
  /*delete the tuple*/
  ptpl = (SettingCollTuple*)(pThis->_settings.list[nIdx]);
  fsl_list_visitor_settingtuple_free ( ptpl, NULL );
  /*scootch memory and update counts*/
  memmove ( &pThis->_settings.list[nIdx],
      &pThis->_settings.list[nIdx+1],







|














|







|






|







|








|

|


















|



|











|










|













|

|







1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
  fsl_list                _settings;          /*the settings, depersisted from files*/

  int     _nCursorsOpen;  /*count of open cursors; some updating cannot happen with > 1*/
};
typedef struct tagvtblVerSet_table vtblVerSet_table;


static void vtblVerSet_table_ctor ( vtblVerSet_table* pThis, sqlite3* db, const char* pszVerSettingsPath ) {
  /*YYY (BBB docs say lib will set these up, but it doesn't.  it does setup pModule, however)*/
  pThis->_base.nRef = 0;          /*unused, but we clear it anyway*/
  pThis->_base.zErrMsg = NULL;    /*ensure null lest there be crashes when lib tries to free*/
  pThis->_db = db;  /*we need this from time-to-time*/
  /*platform-specific defaults for multi-value and newline styles.  These*/
  /*are used in cases where we couldn't figure them out, like, if there*/
  /*was only one element*/
  pThis->_esvsSepPlat = SEPSTYLE_NEWLINE;
#if defined(WIN32) || defined(WINDOWS) || defined(DOS)
  pThis->_esleNewlinePlat = NLSTYLE_CRLF; /*use windowsian CRLF*/
#else
  pThis->_esleNewlinePlat = NLSTYLE_LF;   /*fall back to unixian LF*/
#endif
  pThis->_strVerSettingsPath = fsl_buffer_empty;
  fsl_buffer_append ( &pThis->_strVerSettingsPath, pszVerSettingsPath, fsl_strlen ( pszVerSettingsPath ) );
  pThis->_nLastRowId = 0;
  pThis->_settings = fsl_list_empty;
  pThis->_nCursorsOpen = 0;
}



static void vtblVerSet_table_dtor ( vtblVerSet_table* pThis ) {
  fsl_list_clear ( &pThis->_settings, fsl_list_visitor_settingtuple_free, NULL );
  fsl_buffer_clear( &pThis->_strVerSettingsPath );
}



static vtblVerSet_table* vtblVerSet_table_new ( sqlite3* db, const char* pszVerSettingsPath ) {
  vtblVerSet_table* pThis = (vtblVerSet_table*) malloc ( sizeof(vtblVerSet_table) );
  vtblVerSet_table_ctor ( pThis, db, pszVerSettingsPath );
  return pThis;
}



static void vtblVerSet_table_delete ( vtblVerSet_table* pThis ) {
  if ( NULL != pThis ) {
    vtblVerSet_table_dtor ( pThis );
    free ( pThis );
  }
}



static bool vtblVerSet_table_addExistingSetting ( vtblVerSet_table* pThis, const SettingDesc* pdesc ) {
  /*factory idiom*/
  SettingInfo* psi = SettingInfo_createFromFile ( fsl_buffer_cstr ( &pThis->_strVerSettingsPath ), pdesc );
  if ( NULL != psi ) {
    SettingCollTuple* psct;
    if ( psi->_esvsSep == SEPSTYLE_UNKNOWN )
      psi->_esvsSep = pThis->_esvsSepPlat;
    if ( psi->_esleNewline == NLSTYLE_UNKNOWN )
      psi->_esleNewline = pThis->_esleNewlinePlat;
    psi->_nRowId = ++(pThis->_nLastRowId);
    /**/
    psct = (SettingCollTuple*) malloc ( sizeof(SettingCollTuple) );
    psct->_nRowId = psi->_nRowId;
    psct->_psi = psi;
    fsl_list_append ( &pThis->_settings, psct );
  }
  return NULL != psi;
}



static bool vtblVerSet_table_populate ( vtblVerSet_table* pThis ) {
  size_t nIdx;
  for ( nIdx = 0; nIdx < g_asdSettingsDescriptorsCount; ++nIdx ) {
    if ( g_asdSettingsDescriptors[nIdx]._bIsVersionable )
      vtblVerSet_table_addExistingSetting ( pThis, &g_asdSettingsDescriptors[nIdx] );
  }
  return true;
}



/*since there are only a few well-known versionable settings, I am simply going*/
/*to do a linear search for 'find' operations.  The 'find' operation will*/
/*return the index into the _settings array (er, 'list').  You may use this*/
/*index to get at the setting object, or use it to erase the setting (and*/
/*manage the list correctly).  Non-found items will return an index of -1.*/
static int vtblVerSet_table_find_setting_idx_by_rowid ( vtblVerSet_table* pThis, sqlite3_int64 nRowId ) {
  int nIdx;
  for ( nIdx = 0; nIdx < (int) pThis->_settings.used; ++nIdx ) {
    if ( ((SettingCollTuple*)(pThis->_settings.list[nIdx]))->_nRowId == nRowId )
      return nIdx;
  }
  return -1;
}



static int vtblVerSet_table_find_setting_idx_by_name ( vtblVerSet_table* pThis, const char* pszName )
{
  int nIdx;
  for ( nIdx = 0; nIdx < (int) pThis->_settings.used; ++nIdx ) {
    if ( 0 == _stricmp ( fsl_buffer_cstr (
        &((SettingCollTuple*)(pThis->_settings.list[nIdx]))->_psi->_strName ),
        pszName ) )
      return nIdx;
  }
  return -1;
}



static void vtblVerSet_table_erase_setting_by_idx ( vtblVerSet_table* pThis, int nIdx ) {
  SettingCollTuple* ptpl;
  if ( nIdx < 0 || nIdx >= (int) pThis->_settings.used )
    return; /*bogus; assert-worthy*/
  /*delete the tuple*/
  ptpl = (SettingCollTuple*)(pThis->_settings.list[nIdx]);
  fsl_list_visitor_settingtuple_free ( ptpl, NULL );
  /*scootch memory and update counts*/
  memmove ( &pThis->_settings.list[nIdx],
      &pThis->_settings.list[nIdx+1],
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
  vtblVerSet_table* _pvst;    /*(strictly, this is redundant with base member pVtab)*/
  /*anything else we need?*/
};
typedef struct tagvtblVerSet_cursor vtblVerSet_cursor;



void vtblVerSet_cursor_ctor ( vtblVerSet_cursor* pThis, vtblVerSet_table* pvst ) {
  pThis->_nIter = 0;
  pThis->_pvst = pvst;
  ++(pThis->_pvst->_nCursorsOpen);
}



void vtblVerSet_cursor_dtor ( vtblVerSet_cursor* pThis ) {
  --(pThis->_pvst->_nCursorsOpen);
}



vtblVerSet_cursor* vtblVerSet_cursor_new ( vtblVerSet_table* pvst ) {
  vtblVerSet_cursor* pThis = (vtblVerSet_cursor*) malloc ( sizeof(vtblVerSet_cursor) );
  vtblVerSet_cursor_ctor ( pThis, pvst );
  return pThis;
}



void vtblVerSet_cursor_delete ( vtblVerSet_cursor* pThis ) {
  if ( NULL != pThis ) {
    vtblVerSet_cursor_dtor ( pThis );
    free ( pThis );
  }
}



/*===========================================*/
/*sqlite vtable interface code*/
/*'table' stuff*/



/*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/
int vtblVerSet_Create ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) {
  int nLen;
  char* pszValue;
  fsl_buffer strVerSettingsPath;
  char ch;
  bool bMkdirOK;
  int nIdx;
  struct _stat buf;







|







|





|







|















|







1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
  vtblVerSet_table* _pvst;    /*(strictly, this is redundant with base member pVtab)*/
  /*anything else we need?*/
};
typedef struct tagvtblVerSet_cursor vtblVerSet_cursor;



static void vtblVerSet_cursor_ctor ( vtblVerSet_cursor* pThis, vtblVerSet_table* pvst ) {
  pThis->_nIter = 0;
  pThis->_pvst = pvst;
  ++(pThis->_pvst->_nCursorsOpen);
}



static void vtblVerSet_cursor_dtor ( vtblVerSet_cursor* pThis ) {
  --(pThis->_pvst->_nCursorsOpen);
}



static vtblVerSet_cursor* vtblVerSet_cursor_new ( vtblVerSet_table* pvst ) {
  vtblVerSet_cursor* pThis = (vtblVerSet_cursor*) malloc ( sizeof(vtblVerSet_cursor) );
  vtblVerSet_cursor_ctor ( pThis, pvst );
  return pThis;
}



static void vtblVerSet_cursor_delete ( vtblVerSet_cursor* pThis ) {
  if ( NULL != pThis ) {
    vtblVerSet_cursor_dtor ( pThis );
    free ( pThis );
  }
}



/*===========================================*/
/*sqlite vtable interface code*/
/*'table' stuff*/



/*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/
static int vtblVerSet_Create ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) {
  int nLen;
  char* pszValue;
  fsl_buffer strVerSettingsPath;
  char ch;
  bool bMkdirOK;
  int nIdx;
  struct _stat buf;
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
    return SQLITE_ERROR;    /*if you return error, you must set pzErr to something or NULL*/
  }

  /*first arg is the fully-qualified path to the .fossil-settings directory*/
  strVerSettingsPath = fsl_buffer_empty;
  /*knock off the SQL quotes*/
  pszValue = (char*) argv[3];
  nLen = strlen ( pszValue );
  if ( 0 != nLen && '\'' == pszValue[0] ) {
    ++pszValue;
    --nLen;
  }
  if ( 0 != nLen && '\'' == pszValue[nLen-1] ) {
    --nLen;
  }







|







1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
    return SQLITE_ERROR;    /*if you return error, you must set pzErr to something or NULL*/
  }

  /*first arg is the fully-qualified path to the .fossil-settings directory*/
  strVerSettingsPath = fsl_buffer_empty;
  /*knock off the SQL quotes*/
  pszValue = (char*) argv[3];
  nLen = fsl_strlen ( pszValue );
  if ( 0 != nLen && '\'' == pszValue[0] ) {
    ++pszValue;
    --nLen;
  }
  if ( 0 != nLen && '\'' == pszValue[nLen-1] ) {
    --nLen;
  }
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
  return SQLITE_OK;
}



/*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/
/*last connection to this table is going away*/
int vtblVerSet_Destroy ( sqlite3_vtab* pVTab ) {
  vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab);
  vtblVerSet_table_delete ( pThis );
  return SQLITE_OK;
}



/*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate*/
/*new connection to existing table; we just treat it the same as 'create'*/
int vtblVerSet_Connect ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) {
  return vtblVerSet_Create ( db, pAux, argc, argv, ppVTab, pzErr );
}



/*xDisconnect -- drop virtual table, but not the last one*/
/*table is going away, but not last one*/
/*(BBB actually I have seen the last one go away via this method in the*/
/*case of database closure when there was not an explicit drop table)*/
int vtblVerSet_Disconnect ( sqlite3_vtab* pVTab ) {
  return vtblVerSet_Destroy ( pVTab );
}


/*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/
/*think about what query is being done, and indicate what possible internal*/
/*quasi-index we might have*/
int vtblVerSet_BestIndex ( sqlite3_vtab* pVTab, sqlite3_index_info* pIdxInfo ) {
  /*vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab);
  int nIdx;
  / *Inputs* /
  pIdxInfo->nConstraint;                      / *Number of entries in aConstraint* /
  pIdxInfo->aConstraint[0].iColumn;           / *Column on left-hand side of constraint* /
  pIdxInfo->aConstraint[0].op;                / *Constraint operator* /
  pIdxInfo->aConstraint[0].usable;            / *True if this constraint is usable* /







|









|









|







|







1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
  return SQLITE_OK;
}



/*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/
/*last connection to this table is going away*/
static int vtblVerSet_Destroy ( sqlite3_vtab* pVTab ) {
  vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab);
  vtblVerSet_table_delete ( pThis );
  return SQLITE_OK;
}



/*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate*/
/*new connection to existing table; we just treat it the same as 'create'*/
static int vtblVerSet_Connect ( sqlite3* db, void* pAux, int argc, const char*const* argv, sqlite3_vtab** ppVTab, char** pzErr ) {
  return vtblVerSet_Create ( db, pAux, argc, argv, ppVTab, pzErr );
}



/*xDisconnect -- drop virtual table, but not the last one*/
/*table is going away, but not last one*/
/*(BBB actually I have seen the last one go away via this method in the*/
/*case of database closure when there was not an explicit drop table)*/
static int vtblVerSet_Disconnect ( sqlite3_vtab* pVTab ) {
  return vtblVerSet_Destroy ( pVTab );
}


/*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/
/*think about what query is being done, and indicate what possible internal*/
/*quasi-index we might have*/
static int vtblVerSet_BestIndex ( sqlite3_vtab* pVTab, sqlite3_index_info* pIdxInfo ) {
  /*vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab);
  int nIdx;
  / *Inputs* /
  pIdxInfo->nConstraint;                      / *Number of entries in aConstraint* /
  pIdxInfo->aConstraint[0].iColumn;           / *Column on left-hand side of constraint* /
  pIdxInfo->aConstraint[0].op;                / *Constraint operator* /
  pIdxInfo->aConstraint[0].usable;            / *True if this constraint is usable* /
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701

/*===========================================*/
/*'cursor' stuff*/



/*xOpen -- open a cursor*/
int vtblVerSet_cursor_Open ( sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor ) {
  vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab);
  *ppCursor = &vtblVerSet_cursor_new ( pThis )->_base;
  return SQLITE_OK;
}



/*xClose -- close a cursor*/
int vtblVerSet_cursor_Close ( sqlite3_vtab_cursor* pCur ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  vtblVerSet_cursor_delete ( pThis );
  return SQLITE_OK;
}


int vtblVerSet_cursor_Filter ( sqlite3_vtab_cursor* pCur, int idxNum, const char* idxStr, int argc, sqlite3_value** argv ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*position cursor to location based on value arguments and parameters that ultimately came from xBestIndex*/
  /*this will 'rewind' the cursor to the beginning*/
  pThis->_nIter = 0;
  return SQLITE_OK;
}



/*xNext -- advance a cursor*/
int vtblVerSet_cursor_Next ( sqlite3_vtab_cursor* pCur ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*advance a cursor*/
  /*we iterate through the list*/
  if ( pThis->_nIter < pThis->_pvst->_settings.used ) {   /*still some left*/
    ++pThis->_nIter;    /*next*/
    return SQLITE_OK;
  }

  return SQLITE_OK;
}



/*xEof -- check for end of scan*/
int vtblVerSet_cursor_Eof ( sqlite3_vtab_cursor* pCur ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*check for end of iteration*/
  return (  pThis->_nIter >= pThis->_pvst->_settings.used  ) ? 1 : 0;
}



/*xColumn -- read data*/
int vtblVerSet_cursor_Column ( sqlite3_vtab_cursor* pCur, sqlite3_context* pCtx, int nCol ) {
  const SettingInfo* psi;
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*read data*/

  psi = ((SettingCollTuple*)pThis->_pvst->_settings.list[pThis->_nIter])->_psi;
  switch ( nCol ) {
    /*"NAME TEXT,"              / *setting name*/







|








|






|










|














|








|







1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813

/*===========================================*/
/*'cursor' stuff*/



/*xOpen -- open a cursor*/
static int vtblVerSet_cursor_Open ( sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor ) {
  vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab);
  *ppCursor = &vtblVerSet_cursor_new ( pThis )->_base;
  return SQLITE_OK;
}



/*xClose -- close a cursor*/
static int vtblVerSet_cursor_Close ( sqlite3_vtab_cursor* pCur ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  vtblVerSet_cursor_delete ( pThis );
  return SQLITE_OK;
}


static int vtblVerSet_cursor_Filter ( sqlite3_vtab_cursor* pCur, int idxNum, const char* idxStr, int argc, sqlite3_value** argv ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*position cursor to location based on value arguments and parameters that ultimately came from xBestIndex*/
  /*this will 'rewind' the cursor to the beginning*/
  pThis->_nIter = 0;
  return SQLITE_OK;
}



/*xNext -- advance a cursor*/
static int vtblVerSet_cursor_Next ( sqlite3_vtab_cursor* pCur ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*advance a cursor*/
  /*we iterate through the list*/
  if ( pThis->_nIter < pThis->_pvst->_settings.used ) {   /*still some left*/
    ++pThis->_nIter;    /*next*/
    return SQLITE_OK;
  }

  return SQLITE_OK;
}



/*xEof -- check for end of scan*/
static int vtblVerSet_cursor_Eof ( sqlite3_vtab_cursor* pCur ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*check for end of iteration*/
  return (  pThis->_nIter >= pThis->_pvst->_settings.used  ) ? 1 : 0;
}



/*xColumn -- read data*/
static int vtblVerSet_cursor_Column ( sqlite3_vtab_cursor* pCur, sqlite3_context* pCtx, int nCol ) {
  const SettingInfo* psi;
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*read data*/

  psi = ((SettingCollTuple*)pThis->_pvst->_settings.list[pThis->_nIter])->_psi;
  switch ( nCol ) {
    /*"NAME TEXT,"              / *setting name*/
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
  }
  return SQLITE_OK;
}



/*xRowid -- read data*/
int vtblVerSet_cursor_Rowid ( sqlite3_vtab_cursor* pCur, sqlite3_int64* pRowid ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*read data*/
  *pRowid = ((SettingCollTuple*)pThis->_pvst->_settings.list[pThis->_nIter])->_nRowId;
  return SQLITE_OK;
}









|







1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
  }
  return SQLITE_OK;
}



/*xRowid -- read data*/
static int vtblVerSet_cursor_Rowid ( sqlite3_vtab_cursor* pCur, sqlite3_int64* pRowid ) {
  vtblVerSet_cursor* pThis = DOWNCAST(vtblVerSet_cursor,_base,pCur);
  /*read data*/
  *pRowid = ((SettingCollTuple*)pThis->_pvst->_settings.list[pThis->_nIter])->_nRowId;
  return SQLITE_OK;
}


1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
        return true;
  }
  return false;
}



int vtblVerSet_Update ( sqlite3_vtab* pVTab, int argc, sqlite3_value** argv, sqlite3_int64* pRowid ) {
  vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab);

  /*All changes to a virtual table are made using the xUpdate method.*/
  /*This one method can be used to insert, delete, or update.*/

  /*The argv[1] parameter is the rowid of a new row to be inserted into*/
  /*the virtual table. If argv[1] is an SQL NULL, then the implementation*/







|







1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
        return true;
  }
  return false;
}



static int vtblVerSet_Update ( sqlite3_vtab* pVTab, int argc, sqlite3_value** argv, sqlite3_int64* pRowid ) {
  vtblVerSet_table* pThis = DOWNCAST(vtblVerSet_table,_base,pVTab);

  /*All changes to a virtual table are made using the xUpdate method.*/
  /*This one method can be used to insert, delete, or update.*/

  /*The argv[1] parameter is the rowid of a new row to be inserted into*/
  /*the virtual table. If argv[1] is an SQL NULL, then the implementation*/
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
    /*explicitly, supplying null for those which the user did not provide.*/
    /*"NAME TEXT,"                      / *setting name*/
    pszName = (const char*) sqlite3_value_text ( argv[2] );
    /*"VALUE TEXT,"                     / *setting value, if any*/
    pszValue = (const char*) sqlite3_value_text ( argv[3] );
    /*"VALUE_SEPARATOR INTEGER HIDDEN," / *style of value separation*/
    nsvs = SQLITE_NULL == sqlite3_value_type ( argv[4] ) ? 
        pThis->_esvsSepPlat : sqlite3_value_int ( argv[4] );
    /*"LINE_ENDINGS INTEGER HIDDEN,"        / *style of line endings*/
    nsle = SQLITE_NULL == sqlite3_value_type ( argv[5] ) ? 
        pThis->_esleNewlinePlat : sqlite3_value_int ( argv[5] );
    /*"ORIGINAL_PATH TEXT HIDDEN"           / *path where this setting came from*/
    /*you're never going to be able to set this, but we'll just ignore it if you try*/
    /*argv[6]*/

    /*first, some sanity checks on the data*/
    if ( SQLITE_NULL != sqlite3_value_type ( argv[1] ) ) {
      pThis->_base.zErrMsg = sqlite3_mprintf ( "you cannot specify the rowid on insert" );







|


|







1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
    /*explicitly, supplying null for those which the user did not provide.*/
    /*"NAME TEXT,"                      / *setting name*/
    pszName = (const char*) sqlite3_value_text ( argv[2] );
    /*"VALUE TEXT,"                     / *setting value, if any*/
    pszValue = (const char*) sqlite3_value_text ( argv[3] );
    /*"VALUE_SEPARATOR INTEGER HIDDEN," / *style of value separation*/
    nsvs = SQLITE_NULL == sqlite3_value_type ( argv[4] ) ? 
        (int) pThis->_esvsSepPlat : sqlite3_value_int ( argv[4] );
    /*"LINE_ENDINGS INTEGER HIDDEN,"        / *style of line endings*/
    nsle = SQLITE_NULL == sqlite3_value_type ( argv[5] ) ? 
        (int) pThis->_esleNewlinePlat : sqlite3_value_int ( argv[5] );
    /*"ORIGINAL_PATH TEXT HIDDEN"           / *path where this setting came from*/
    /*you're never going to be able to set this, but we'll just ignore it if you try*/
    /*argv[6]*/

    /*first, some sanity checks on the data*/
    if ( SQLITE_NULL != sqlite3_value_type ( argv[1] ) ) {
      pThis->_base.zErrMsg = sqlite3_mprintf ( "you cannot specify the rowid on insert" );
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
    /*name cannot change*/
    if ( 0 != _stricmp ( pszName, fsl_buffer_cstr ( &ptpl->_psi->_strName ) ) ) {
      pThis->_base.zErrMsg = sqlite3_mprintf ( "NAME cannot change" );
      return SQLITE_ERROR;
    }
    /*"VALUE_SEPARATOR INTEGER HIDDEN," / *style of value separation*/
    nsvs = SQLITE_NULL == sqlite3_value_type ( argv[4] ) ? 
        pThis->_esvsSepPlat : sqlite3_value_int ( argv[4] );
    /*range check:  nsvs must be a value enum value*/
    if ( nsvs < SEPSTYLE_NEWLINE || nsvs > SEPSTYLE_COMMA ) {
      pThis->_base.zErrMsg = sqlite3_mprintf ( "VALUE_SEPARATOR must be a valid value" );
      return SQLITE_CONSTRAINT;
    }
    /*"LINE_ENDINGS INTEGER HIDDEN,"        / *style of line endings*/
    nsle = SQLITE_NULL == sqlite3_value_type ( argv[5] ) ? 
        pThis->_esvsSepPlat : sqlite3_value_int ( argv[5] );
    /*range check:  nsle must be a value enum value*/
    if ( nsle < NLSTYLE_CRLF || nsvs > NLSTYLE_LF ) {
      pThis->_base.zErrMsg = sqlite3_mprintf ( "LINE_ENDINGS must be a valid value" );
      return SQLITE_CONSTRAINT;
    }
    /*"ORIGINAL_PATH TEXT HIDDEN"           / *path where this setting came from*/
    /*you're never going to be able to change this, but we'll just ignore it if you try*/







|







|







2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
    /*name cannot change*/
    if ( 0 != _stricmp ( pszName, fsl_buffer_cstr ( &ptpl->_psi->_strName ) ) ) {
      pThis->_base.zErrMsg = sqlite3_mprintf ( "NAME cannot change" );
      return SQLITE_ERROR;
    }
    /*"VALUE_SEPARATOR INTEGER HIDDEN," / *style of value separation*/
    nsvs = SQLITE_NULL == sqlite3_value_type ( argv[4] ) ? 
        (int) pThis->_esvsSepPlat : sqlite3_value_int ( argv[4] );
    /*range check:  nsvs must be a value enum value*/
    if ( nsvs < SEPSTYLE_NEWLINE || nsvs > SEPSTYLE_COMMA ) {
      pThis->_base.zErrMsg = sqlite3_mprintf ( "VALUE_SEPARATOR must be a valid value" );
      return SQLITE_CONSTRAINT;
    }
    /*"LINE_ENDINGS INTEGER HIDDEN,"        / *style of line endings*/
    nsle = SQLITE_NULL == sqlite3_value_type ( argv[5] ) ? 
        (int) pThis->_esvsSepPlat : sqlite3_value_int ( argv[5] );
    /*range check:  nsle must be a value enum value*/
    if ( nsle < NLSTYLE_CRLF || nsvs > NLSTYLE_LF ) {
      pThis->_base.zErrMsg = sqlite3_mprintf ( "LINE_ENDINGS must be a valid value" );
      return SQLITE_CONSTRAINT;
    }
    /*"ORIGINAL_PATH TEXT HIDDEN"           / *path where this setting came from*/
    /*you're never going to be able to change this, but we'll just ignore it if you try*/
2060
2061
2062
2063
2064
2065
2066
















































































2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095

2096
2097








2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111

2112

2113
2114
2115
2116
2117
2118
2119
2120
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
/*notification of impending commit/rollback; for realizing two-phase commit*/
/*int vtblVerSet_Sync ( sqlite3_vtab* pVTab );*/

/*end a transaction on a virtual table*/
/*int vtblVerSet_Commit ( sqlite3_vtab* pVTab );*/
/*int vtblVerSet_Rollback ( sqlite3_vtab* pVTab );*/


















































































/*This is a sqlite3 extension function that either matches a text to a regex
  pattern, or fails (with a SQLITE_CONSTRAINT error.  This is intended to be
  used for value validation for INSERTs or UPDATE, and was created for the
  fossil settings vtable, but it may be of general use, since it doesn't have
  any special bindings to that system.
  Some things of note:  NULL pattern yields NULL result.  Empty pattern (non-
  null, zero length) matches everything.
  This implementation uses the sqlite3 sample regexp engine, but it is simple
  enough that you could easily use another, more powerful, engine, like PCRE.
  argv[0] = text to match
  argv[1] = regex
*/
void implMatchOrFail ( sqlite3_context* pctx, int argc, sqlite3_value** argv ) {

  ReCompiled* pRe;          /* Compiled regular expression */
  const char* zPattern;     /* The regular expression */
  const char* zStr;         /* String being searched */
  const char* zErr;         /* Compile error message */
  /*we registered this method explicitly as taking two parameters, so we don't
  need to check that assuption*/

  /*we definitely need the text to test, and do some pre-checks*/
  zStr = (const char*) sqlite3_value_text ( argv[0] );
  if ( NULL == zStr ) {
    sqlite3_result_null ( pctx );
    return;
  }


  pRe = (ReCompiled*)sqlite3_get_auxdata ( pctx, 0 );  /*precompiled?*/
  if ( NULL == pRe ) {  /*no, must compile it now*/








    zPattern = (const char*) sqlite3_value_text ( argv[1] );
    /*null pattern == null return*/
    if ( NULL == zPattern ) {
      sqlite3_result_null ( pctx );
      return;
    }
    /*empty pattern == always match*/
    if ( '\0' == zPattern[0] ) {
      sqlite3_result_text ( pctx, zStr, -1, SQLITE_TRANSIENT );
      return;
    }

    /*XXX maybe empty pattern means 'never match, because .* can always match and ^$ doesn't compile*/
    /*XXX add two new metachars for insensitive and multivar; need to figure out what those can be, because I will have to emulate that here since it's not part of the regex engine*/



    zErr = sqlite3re_compile ( &pRe, zPattern, 0 );
    if ( NULL != zErr ) {
      sqlite3re_free ( pRe );
      sqlite3_result_error ( pctx, zErr, -1 );
      return;
    }
    if ( NULL == pRe ) {
      sqlite3_result_error_nomem ( pctx );
      return;
    }







    sqlite3_set_auxdata ( pctx, 0, pRe, (void(*)(void*))sqlite3re_free );
  }

  /*OK, now, finally we can test*/
  if ( sqlite3re_match ( pRe, (const unsigned char*)zStr, -1 ) ) {
    sqlite3_result_text ( pctx, zStr, -1, SQLITE_TRANSIENT );
  } else {
    sqlite3_result_error_code ( pctx, SQLITE_CONSTRAINT );
  }

}



/*'overloading' functions*/
int vtblVerSet_FindFunction ( sqlite3_vtab* pVtab, int nArg, const char* zName,
    void (**pxFunc) ( sqlite3_context*, int, sqlite3_value** ), void** ppArg ) {
  return 0;   /*do not override*/
}


int vtblVerSet_Rename ( sqlite3_vtab* pVtab, const char* zNew ) {
  return SQLITE_OK;   /*we don't care about being renamed*/
}


const sqlite3_module sg_pvtblVersionedSettings = {
  2,                          /*iVersion -- version of this structure, so sqlite doesn't access past end*/
  vtblVerSet_Create,          /*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/
  vtblVerSet_Connect,         /*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate*/
  vtblVerSet_BestIndex,       /*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/
  vtblVerSet_Disconnect,      /*xDisconnect -- drop virtual table, but not the last one*/
  vtblVerSet_Destroy,         /*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/
  vtblVerSet_cursor_Open,     /*xOpen -- open a cursor*/







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













|
|
<
<

<










>
|
|
>
>
>
>
>
>
>
>






|

|



|
|
>

>
|










>
>
>
>
>
>
|

|

|










|





|




|







2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273


2274

2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
/*notification of impending commit/rollback; for realizing two-phase commit*/
/*int vtblVerSet_Sync ( sqlite3_vtab* pVTab );*/

/*end a transaction on a virtual table*/
/*int vtblVerSet_Commit ( sqlite3_vtab* pVTab );*/
/*int vtblVerSet_Rollback ( sqlite3_vtab* pVTab );*/


/*here, we preprocess a regex for our 'extended' escapes (which must be
at the start of the regex; we just have a couple, and set bools to indicate
whether they were detected.  we return a pointer to the 'rest' of the
regex, which can be processed as per usual.*/
static const char* _implPreprocessRegex ( const char* pszRegex,
    bool* pbInsensitive, bool* pbMultivar, bool* pbEmptyOK ) {
  const char* pszRest = pszRegex;
  *pbInsensitive = false; /*init defaults for params we are parsing*/
  *pbMultivar = false;
  while ( '\0' != *pszRest ) {
    /*must start with our special escape sequence*/
    if ( '\\' != pszRest[0] || '$' != pszRest[1] ) {
      break;
    }
    /*must be one of our known instructions*/
    if ( 'i' == pszRest[2] ) {
      *pbInsensitive = true;
    }
    else if ( 'm' == pszRest[2] ) {
      *pbMultivar = true;
    }
    else if ( 'e' == pszRest[2] ) {
      *pbEmptyOK = true;
    }
    else
      break;
    /*consume*/
    pszRest += 3;
  }
  return pszRest;
}


/*context data stored in 'aux data'*/
typedef struct tagMatchOrFailFxnCtx MatchOrFailFxnCtx;
struct tagMatchOrFailFxnCtx
{
  sqlite3_ReCompiled* pRe;  /* Compiled regular expression */
  bool bInsensitive;  /*and rude*/
  bool bMultivar;     /*must we crack it into several items?*/
  bool bEmptyOK;      /*is empty input text considered a match?*/
};

void MatchOrFailFxnCtx_delete ( MatchOrFailFxnCtx* pThis ) {
  sqlite3re_free ( pThis->pRe );
  free ( pThis );
}

bool MatchOrFailFxnCtx_match ( MatchOrFailFxnCtx* pThis, const char* pszStr ) {
  if ( '\0' == pszStr[0] && pThis->bEmptyOK ) {
    return true;
  }
  else if ( ! pThis->bMultivar ) {
    return sqlite3re_match ( pThis->pRe, (const unsigned char*)pszStr, -1 );
  }
  else {
    /*this is a 'multivar' value, so crack it, and test them all individually*/
    fsl_list lstrValues = fsl_list_empty;
    fsl_size_t nIdx;
    bool bResult;
    /*while it is called a 'glob_list', in fact, it is just a list of strings*/
    if ( 0 != fsl_glob_list_parse ( &lstrValues, pszStr ) ) {
      /*horror*/
      return false;
    }
    /*for each; match.  return logical 'and' over all tests*/
    bResult = true;
    for ( nIdx = 0; bResult && nIdx < lstrValues.used; ++nIdx ) {
      if ( ! sqlite3re_match ( pThis->pRe,
          (const unsigned char*)lstrValues.list[nIdx], -1 ) ) {
        bResult = false;
      }
    }
    fsl_glob_list_clear ( &lstrValues );
    return bResult;
  }
}



/*This is a sqlite3 extension function that either matches a text to a regex
  pattern, or fails (with a SQLITE_CONSTRAINT error.  This is intended to be
  used for value validation for INSERTs or UPDATE, and was created for the
  fossil settings vtable, but it may be of general use, since it doesn't have
  any special bindings to that system.
  Some things of note:  NULL pattern yields NULL result.  Empty pattern (non-
  null, zero length) matches everything.
  This implementation uses the sqlite3 sample regexp engine, but it is simple
  enough that you could easily use another, more powerful, engine, like PCRE.
  argv[0] = text to match
  argv[1] = regex
*/
static void implMatchOrFail ( sqlite3_context* pctx, int argc, sqlite3_value** argv ) {
  MatchOrFailFxnCtx* pCtx;


  const char* zStr;         /* String being searched */

  /*we registered this method explicitly as taking two parameters, so we don't
  need to check that assuption*/

  /*we definitely need the text to test, and do some pre-checks*/
  zStr = (const char*) sqlite3_value_text ( argv[0] );
  if ( NULL == zStr ) {
    sqlite3_result_null ( pctx );
    return;
  }

  /*see if we precomputed this, and compute if needed*/
  pCtx = (MatchOrFailFxnCtx*)sqlite3_get_auxdata ( pctx, 0 ); /*precomputed?*/
  if ( NULL == pCtx ) {  /*no, must compile it now*/
    const char* zErr;         /* Compile error message */
    sqlite3_ReCompiled* pRe;  /* Compiled regular expression */
    const char* zPattern;     /*The regular expression*/
    const char* pszProcessedPattern;  /*the pattern after custom escapes*/
    bool bInsensitive;  /*and rude*/
    bool bMultivar;     /*must we crack it into several items?*/
    bool bEmptyOK;      /*is the empty string OK?*/

    zPattern = (const char*) sqlite3_value_text ( argv[1] );
    /*null pattern == null return*/
    if ( NULL == zPattern ) {
      sqlite3_result_null ( pctx );
      return;
    }
    /*empty pattern == never match*/
    if ( '\0' == zPattern[0] ) {
      sqlite3_result_error_code ( pctx, SQLITE_CONSTRAINT );
      return;
    }

    /*parse off our special metachars, if any*/
    pszProcessedPattern = _implPreprocessRegex ( zPattern,
        &bInsensitive, &bMultivar, &bEmptyOK );

    /*compile regex machine*/
    zErr = sqlite3re_compile ( &pRe, pszProcessedPattern, bInsensitive );
    if ( NULL != zErr ) {
      sqlite3re_free ( pRe );
      sqlite3_result_error ( pctx, zErr, -1 );
      return;
    }
    if ( NULL == pRe ) {
      sqlite3_result_error_nomem ( pctx );
      return;
    }

    /*remember...*/
    pCtx = (MatchOrFailFxnCtx*) malloc ( sizeof(MatchOrFailFxnCtx) );
    pCtx->pRe = pRe;
    pCtx->bInsensitive = bInsensitive;
    pCtx->bMultivar = bMultivar;
    pCtx->bEmptyOK = bEmptyOK;
    sqlite3_set_auxdata ( pctx, 0, pCtx, (void(*)(void*))MatchOrFailFxnCtx_delete );
  }
  
  /*OK, now, finally we can test*/
  if ( MatchOrFailFxnCtx_match ( pCtx, zStr ) ) {
    sqlite3_result_text ( pctx, zStr, -1, SQLITE_TRANSIENT );
  } else {
    sqlite3_result_error_code ( pctx, SQLITE_CONSTRAINT );
  }

}



/*'overloading' functions*/
static int vtblVerSet_FindFunction ( sqlite3_vtab* pVtab, int nArg, const char* zName,
    void (**pxFunc) ( sqlite3_context*, int, sqlite3_value** ), void** ppArg ) {
  return 0;   /*do not override*/
}


static int vtblVerSet_Rename ( sqlite3_vtab* pVtab, const char* zNew ) {
  return SQLITE_OK;   /*we don't care about being renamed*/
}


static const sqlite3_module sg_pvtblVersionedSettings = {
  2,                          /*iVersion -- version of this structure, so sqlite doesn't access past end*/
  vtblVerSet_Create,          /*xCreate -- 'create virtual table' called; make a sqlite3_vtab*/
  vtblVerSet_Connect,         /*xConnect -- connect to an existing vtable; relevant for dealing with idempotently instantiated state, otherwise the same as xCreate*/
  vtblVerSet_BestIndex,       /*xBestIndex -- prepare for query, indicate what filtering we can do efficiently ourselves*/
  vtblVerSet_Disconnect,      /*xDisconnect -- drop virtual table, but not the last one*/
  vtblVerSet_Destroy,         /*xDestroy -- drop virtual table; the last one, so global cleanup can be done*/
  vtblVerSet_cursor_Open,     /*xOpen -- open a cursor*/
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208


int sqlite3_vtbl_fossilsettings_init (
    sqlite3* db,
    char** pzErrMsg,
    const struct sqlite3_api_routines* pApi
    ) {
  int nRet;
#ifndef SQLITE_CORE
  SQLITE_EXTENSION_INIT2(pApi)    /*sets up the 'vtable' to the host exe sqlite3 impl*/
#else
#endif

#ifndef SQLITE_OMIT_VIRTUALTABLE
  nRet = sqlite3_create_module_v2 ( db, "SETTINGS_METADATA", &sg_pvtblSettingsMetadata, NULL, NULL );
  nRet = sqlite3_create_module_v2 ( db, "VERSIONED_SETTINGS", &sg_pvtblVersionedSettings, NULL, NULL );
#endif

  nRet = sqlite3_create_function ( db, "MATCH_OR_FAIL", 2, SQLITE_UTF8, 0, implMatchOrFail, 0, 0 );

  return SQLITE_OK;
}









|






|
|


|





2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414


int sqlite3_vtbl_fossilsettings_init (
    sqlite3* db,
    char** pzErrMsg,
    const struct sqlite3_api_routines* pApi
    ) {
  /* int nRet; */
#ifndef SQLITE_CORE
  SQLITE_EXTENSION_INIT2(pApi)    /*sets up the 'vtable' to the host exe sqlite3 impl*/
#else
#endif

#ifndef SQLITE_OMIT_VIRTUALTABLE
  /* nRet =  */sqlite3_create_module_v2 ( db, "SETTINGS_METADATA", &sg_pvtblSettingsMetadata, NULL, NULL );
  /* nRet =  */sqlite3_create_module_v2 ( db, "VERSIONED_SETTINGS", &sg_pvtblVersionedSettings, NULL, NULL );
#endif

  /* nRet =  */sqlite3_create_function ( db, "MATCH_OR_FAIL", 2, SQLITE_UTF8, 0, implMatchOrFail, 0, 0 );

  return SQLITE_OK;
}


Changes to src/sqlite3.c.
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.8.7"
#define SQLITE_VERSION_NUMBER 3008007
#define SQLITE_SOURCE_ID      "2014-10-01 13:17:34 07c89940c49a5dca3205a4b6fa8290f23bcb6e10"

/*
** 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







|







229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.8.7"
#define SQLITE_VERSION_NUMBER 3008007
#define SQLITE_SOURCE_ID      "2014-10-17 11:24:17 e4ab094f8afce0817f4074e823fabe59fc29ebb4"

/*
** 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
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
** a NULL will be written into *ppDb instead of a pointer to the [sqlite3]
** object.)^ ^(If the database is opened (and/or created) successfully, then
** [SQLITE_OK] is returned.  Otherwise an [error code] is returned.)^ ^The
** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain
** an English language description of the error following a failure of any
** of the sqlite3_open() routines.
**
** ^The default encoding for the database will be UTF-8 if
** sqlite3_open() or sqlite3_open_v2() is called and
** UTF-16 in the native byte order if sqlite3_open16() is used.
**
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
** passing it to [sqlite3_close()] when it is no longer required.
**
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control







|
|
|







2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
** a NULL will be written into *ppDb instead of a pointer to the [sqlite3]
** object.)^ ^(If the database is opened (and/or created) successfully, then
** [SQLITE_OK] is returned.  Otherwise an [error code] is returned.)^ ^The
** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain
** an English language description of the error following a failure of any
** of the sqlite3_open() routines.
**
** ^The default encoding will be UTF-8 for databases created using
** sqlite3_open() or sqlite3_open_v2().  ^The default encoding for databases
** created using sqlite3_open16() will be UTF-16 in the native byte order.
**
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
** passing it to [sqlite3_close()] when it is no longer required.
**
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891

2892
2893
2894
2895
2896
2897
2898
2899
** present, is ignored.
**
** ^SQLite uses the path component of the URI as the name of the disk file
** which contains the database. ^If the path begins with a '/' character, 
** then it is interpreted as an absolute path. ^If the path does not begin 
** with a '/' (meaning that the authority section is omitted from the URI)
** then the path is interpreted as a relative path. 
** ^On windows, the first component of an absolute path 
** is a drive specification (e.g. "C:").
**
** [[core URI query parameters]]
** The query component of a URI may contain parameters that are interpreted
** either by SQLite itself, or by a [VFS | custom VFS implementation].

** SQLite interprets the following three query parameters:
**
** <ul>
**   <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
**     a VFS object that provides the operating system interface that should
**     be used to access the database file on disk. ^If this option is set to
**     an empty string the default VFS object is used. ^Specifying an unknown
**     VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is







|
|




>
|







2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
** present, is ignored.
**
** ^SQLite uses the path component of the URI as the name of the disk file
** which contains the database. ^If the path begins with a '/' character, 
** then it is interpreted as an absolute path. ^If the path does not begin 
** with a '/' (meaning that the authority section is omitted from the URI)
** then the path is interpreted as a relative path. 
** ^(On windows, the first component of an absolute path 
** is a drive specification (e.g. "C:").)^
**
** [[core URI query parameters]]
** The query component of a URI may contain parameters that are interpreted
** either by SQLite itself, or by a [VFS | custom VFS implementation].
** SQLite and its built-in [VFSes] interpret the
** following query parameters:
**
** <ul>
**   <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
**     a VFS object that provides the operating system interface that should
**     be used to access the database file on disk. ^If this option is set to
**     an empty string the default VFS object is used. ^Specifying an unknown
**     VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
**     SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
**     sqlite3_open_v2(). ^Setting the cache parameter to "private" is 
**     equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
**     ^If sqlite3_open_v2() is used and the "cache" parameter is present in
**     a URI filename, its value overrides any behavior requested by setting
**     SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
**
**  <li> <b>psow</b>: ^The psow parameter may be "true" (or "on" or "yes" or
**     "1") or "false" (or "off" or "no" or "0") to indicate that the
**     [powersafe overwrite] property does or does not apply to the
**     storage media on which the database file resides.  ^The psow query
**     parameter only works for the built-in unix and Windows VFSes.
**
**  <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
**     which if set disables file locking in rollback journal modes.  This
**     is useful for accessing a database on a filesystem that does not
**     support locking.  Caution:  Database corruption might result if two
**     or more processes write to the same database and any one of those
**     processes uses nolock=1.







|
<

|
<







2921
2922
2923
2924
2925
2926
2927
2928

2929
2930

2931
2932
2933
2934
2935
2936
2937
**     SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
**     sqlite3_open_v2(). ^Setting the cache parameter to "private" is 
**     equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
**     ^If sqlite3_open_v2() is used and the "cache" parameter is present in
**     a URI filename, its value overrides any behavior requested by setting
**     SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
**
**  <li> <b>psow</b>: ^The psow parameter indicates whether or not the

**     [powersafe overwrite] property does or does not apply to the
**     storage media on which the database file resides.

**
**  <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
**     which if set disables file locking in rollback journal modes.  This
**     is useful for accessing a database on a filesystem that does not
**     support locking.  Caution:  Database corruption might result if two
**     or more processes write to the same database and any one of those
**     processes uses nolock=1.
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
** terminated.  If any NUL characters occur at byte offsets less than 
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs.  The result of expressions involving strings
** with embedded NULs is undefined.
**
** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it.  ^The destructor is called
** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(),
** sqlite3_bind_text(), or sqlite3_bind_text16() fails.  
** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
** SQLite makes its own private copy of the data immediately, before
** the sqlite3_bind_*() routine returns.
**
** ^The sixth argument to sqlite3_bind_text64() must be one of
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
** to specify the encoding of the text in the third parameter.  If
** the sixth argument to sqlite3_bind_text64() is not how of the
** allowed values shown above, or if the text encoding is different
** from the encoding specified by the sixth parameter, then the behavior
** is undefined.
**
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
** is filled with zeroes.  ^A zeroblob uses a fixed amount of memory
** (just an integer to hold its size) while it is being processed.







|
|

|
<










|







3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528

3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
** terminated.  If any NUL characters occur at byte offsets less than 
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs.  The result of expressions involving strings
** with embedded NULs is undefined.
**
** ^The fifth argument to the BLOB and string binding interfaces
** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it.  ^The destructor is called
** to dispose of the BLOB or string even if the call to bind API fails.

** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
** SQLite makes its own private copy of the data immediately, before
** the sqlite3_bind_*() routine returns.
**
** ^The sixth argument to sqlite3_bind_text64() must be one of
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
** to specify the encoding of the text in the third parameter.  If
** the sixth argument to sqlite3_bind_text64() is not one of the
** allowed values shown above, or if the text encoding is different
** from the encoding specified by the sixth parameter, then the behavior
** is undefined.
**
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
** is filled with zeroes.  ^A zeroblob uses a fixed amount of memory
** (just an integer to hold its size) while it is being processed.
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
** of the application-defined function to be the 64-bit signed integer
** value given in the 2nd argument.
**
** ^The sqlite3_result_null() interface sets the return value
** of the application-defined function to be NULL.
**
** ^The sqlite3_result_text(), sqlite3_result_text16(),
** sqlite3_result_text16le(), and sqlite3_result_text16be()
** set the return value of the application-defined function to be
** a text string which is represented as UTF-8, UTF-16 native byte order,
** UTF-16 little endian, or UTF-16 big endian, respectively.
** ^The sqlite3_result_text64() interface sets the return value of an
** application-defined function to be a text string in an encoding
** specified by the fifth (and last) parameter, which must be one
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].







|







4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
** of the application-defined function to be the 64-bit signed integer
** value given in the 2nd argument.
**
** ^The sqlite3_result_null() interface sets the return value
** of the application-defined function to be NULL.
**
** ^The sqlite3_result_text(), sqlite3_result_text16(),
** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces
** set the return value of the application-defined function to be
** a text string which is represented as UTF-8, UTF-16 native byte order,
** UTF-16 little endian, or UTF-16 big endian, respectively.
** ^The sqlite3_result_text64() interface sets the return value of an
** application-defined function to be a text string in an encoding
** specified by the fifth (and last) parameter, which must be one
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
7944
7945
7946
7947
7948
7949
7950
7951
7952
7953
7954
7955
7956
7957
7958

/*
** A macro to hint to the compiler that a function should not be
** inlined.
*/
#if defined(__GNUC__)
#  define SQLITE_NOINLINE  __attribute__((noinline))
#elif defined(_MSC_VER)
#  define SQLITE_NOINLINE  __declspec(noinline)
#else
#  define SQLITE_NOINLINE
#endif

/*
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.







|







7942
7943
7944
7945
7946
7947
7948
7949
7950
7951
7952
7953
7954
7955
7956

/*
** A macro to hint to the compiler that a function should not be
** inlined.
*/
#if defined(__GNUC__)
#  define SQLITE_NOINLINE  __attribute__((noinline))
#elif defined(_MSC_VER) && _MSC_VER>=1310
#  define SQLITE_NOINLINE  __declspec(noinline)
#else
#  define SQLITE_NOINLINE
#endif

/*
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
11322
11323
11324
11325
11326
11327
11328

11329
11330
11331
11332
11333
11334
11335
  unsigned isResized:1;    /* True if resizeIndexObject() has been called */
  unsigned isCovering:1;   /* True if this is a covering index */
#ifdef SQLITE_ENABLE_STAT3_OR_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 */

#endif
};

/*
** Allowed values for Index.idxType
*/
#define SQLITE_IDXTYPE_APPDEF      0   /* Created using CREATE INDEX */







>







11320
11321
11322
11323
11324
11325
11326
11327
11328
11329
11330
11331
11332
11333
11334
  unsigned isResized:1;    /* True if resizeIndexObject() has been called */
  unsigned isCovering:1;   /* True if this is a covering index */
#ifdef SQLITE_ENABLE_STAT3_OR_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 table */
#endif
};

/*
** Allowed values for Index.idxType
*/
#define SQLITE_IDXTYPE_APPDEF      0   /* Created using CREATE INDEX */
12186
12187
12188
12189
12190
12191
12192
12193
12194
12195
12196
12197
12198
12199
12200
*/
#define OPFLAG_NCHANGE       0x01    /* Set to update db->nChange */
#define OPFLAG_EPHEM         0x01    /* OP_Column: Ephemeral output is ok */
#define OPFLAG_LASTROWID     0x02    /* Set to update db->lastRowid */
#define OPFLAG_ISUPDATE      0x04    /* This OP_Insert is an sql UPDATE */
#define OPFLAG_APPEND        0x08    /* This is likely to be an append */
#define OPFLAG_USESEEKRESULT 0x10    /* Try to avoid a seek in BtreeInsert() */
#define OPFLAG_CLEARCACHE    0x20    /* Clear pseudo-table cache in OP_Column */
#define OPFLAG_LENGTHARG     0x40    /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG     0x80    /* OP_Column only used for typeof() */
#define OPFLAG_BULKCSR       0x01    /* OP_Open** used to open bulk cursor */
#define OPFLAG_P2ISREG       0x02    /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE       0x01    /* OP_Compare: use the permutation */

/*







<







12185
12186
12187
12188
12189
12190
12191

12192
12193
12194
12195
12196
12197
12198
*/
#define OPFLAG_NCHANGE       0x01    /* Set to update db->nChange */
#define OPFLAG_EPHEM         0x01    /* OP_Column: Ephemeral output is ok */
#define OPFLAG_LASTROWID     0x02    /* Set to update db->lastRowid */
#define OPFLAG_ISUPDATE      0x04    /* This OP_Insert is an sql UPDATE */
#define OPFLAG_APPEND        0x08    /* This is likely to be an append */
#define OPFLAG_USESEEKRESULT 0x10    /* Try to avoid a seek in BtreeInsert() */

#define OPFLAG_LENGTHARG     0x40    /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG     0x80    /* OP_Column only used for typeof() */
#define OPFLAG_BULKCSR       0x01    /* OP_Open** used to open bulk cursor */
#define OPFLAG_P2ISREG       0x02    /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE       0x01    /* OP_Compare: use the permutation */

/*
13320
13321
13322
13323
13324
13325
13326
13327
13328
13329
13330
13331
13332
13333
13334
13335
13336
13337
SQLITE_PRIVATE   int sqlite3MemdebugNoType(void*,u8);
#else
# define sqlite3MemdebugSetType(X,Y)  /* no-op */
# define sqlite3MemdebugHasType(X,Y)  1
# define sqlite3MemdebugNoType(X,Y)   1
#endif
#define MEMTYPE_HEAP       0x01  /* General heap allocations */
#define MEMTYPE_LOOKASIDE  0x02  /* Might have been lookaside memory */
#define MEMTYPE_SCRATCH    0x04  /* Scratch allocations */
#define MEMTYPE_PCACHE     0x08  /* Page cache allocations */
#define MEMTYPE_DB         0x10  /* Uses sqlite3DbMalloc, not sqlite_malloc */

/*
** Threading interface
*/
#if SQLITE_MAX_WORKER_THREADS>0
SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**);







|


<







13318
13319
13320
13321
13322
13323
13324
13325
13326
13327

13328
13329
13330
13331
13332
13333
13334
SQLITE_PRIVATE   int sqlite3MemdebugNoType(void*,u8);
#else
# define sqlite3MemdebugSetType(X,Y)  /* no-op */
# define sqlite3MemdebugHasType(X,Y)  1
# define sqlite3MemdebugNoType(X,Y)   1
#endif
#define MEMTYPE_HEAP       0x01  /* General heap allocations */
#define MEMTYPE_LOOKASIDE  0x02  /* Heap that might have been lookaside */
#define MEMTYPE_SCRATCH    0x04  /* Scratch allocations */
#define MEMTYPE_PCACHE     0x08  /* Page cache allocations */


/*
** Threading interface
*/
#if SQLITE_MAX_WORKER_THREADS>0
SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**);
13467
13468
13469
13470
13471
13472
13473







13474
13475
13476
13477
13478
13479
13480
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e0..e7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e8..ef    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* f0..f7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};
#endif








#ifndef SQLITE_USE_URI
# define  SQLITE_USE_URI 0
#endif

#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
#endif







>
>
>
>
>
>
>







13464
13465
13466
13467
13468
13469
13470
13471
13472
13473
13474
13475
13476
13477
13478
13479
13480
13481
13482
13483
13484
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e0..e7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e8..ef    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* f0..f7    ........ */
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};
#endif

/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards
** compatibility for legacy applications, the URI filename capability is
** disabled by default.
**
** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled
** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options.
*/
#ifndef SQLITE_USE_URI
# define  SQLITE_USE_URI 0
#endif

#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
#endif
14088
14089
14090
14091
14092
14093
14094
14095
14096
14097
14098
14099
14100
14101
14102
14103
14104
14105
14106
14107
14108
14109
14110
14111
14112
14113
14114
14115
14116
14117
14118
14119
14120
14121

14122
14123
14124
14125
14126
14127
14128
  i16 nField;           /* Number of fields in the header */
  u16 nHdrParsed;       /* Number of header fields parsed so far */
#ifdef SQLITE_DEBUG
  u8 seekOp;            /* Most recent seek operation on this cursor */
#endif
  i8 iDb;               /* Index of cursor database in db->aDb[] (or -1) */
  u8 nullRow;           /* True if pointing to a row with no data */
  u8 rowidIsValid;      /* True if lastRowid is valid */
  u8 deferredMoveto;    /* A call to sqlite3BtreeMoveto() is needed */
  Bool isEphemeral:1;   /* True for an ephemeral table */
  Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
  Bool isTable:1;       /* True if a table requiring integer keys */
  Bool isOrdered:1;     /* True if the underlying table is BTREE_UNORDERED */
  Pgno pgnoRoot;        /* Root page of the open btree cursor */
  sqlite3_vtab_cursor *pVtabCursor;  /* The cursor for a virtual table */
  i64 seqCount;         /* Sequence counter */
  i64 movetoTarget;     /* Argument to the deferred sqlite3BtreeMoveto() */
  i64 lastRowid;        /* Rowid being deleted by OP_Delete */
  VdbeSorter *pSorter;  /* Sorter object for OP_SorterOpen cursors */

  /* Cached information about the header for the data record that the
  ** cursor is currently pointing to.  Only valid if cacheStatus matches
  ** Vdbe.cacheCtr.  Vdbe.cacheCtr will never take on the value of
  ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
  ** the cache is out of date.
  **
  ** aRow might point to (ephemeral) data for the current row, or it might
  ** be NULL.
  */
  u32 cacheStatus;      /* Cache is valid if this matches Vdbe.cacheCtr */
  u32 payloadSize;      /* Total number of bytes in the record */
  u32 szRow;            /* Byte available in aRow */
  u32 iHdrOffset;       /* Offset to next unparsed byte of the header */
  const u8 *aRow;       /* Data for the current row, if all on one page */

  u32 aType[1];         /* Type values for all entries in the record */
  /* 2*nField extra array elements allocated for aType[], beyond the one
  ** static element declared in the structure.  nField total array slots for
  ** aType[] and nField+1 array slots for aOffset[] */
};
typedef struct VdbeCursor VdbeCursor;








<









<
















>







14092
14093
14094
14095
14096
14097
14098

14099
14100
14101
14102
14103
14104
14105
14106
14107

14108
14109
14110
14111
14112
14113
14114
14115
14116
14117
14118
14119
14120
14121
14122
14123
14124
14125
14126
14127
14128
14129
14130
14131
  i16 nField;           /* Number of fields in the header */
  u16 nHdrParsed;       /* Number of header fields parsed so far */
#ifdef SQLITE_DEBUG
  u8 seekOp;            /* Most recent seek operation on this cursor */
#endif
  i8 iDb;               /* Index of cursor database in db->aDb[] (or -1) */
  u8 nullRow;           /* True if pointing to a row with no data */

  u8 deferredMoveto;    /* A call to sqlite3BtreeMoveto() is needed */
  Bool isEphemeral:1;   /* True for an ephemeral table */
  Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
  Bool isTable:1;       /* True if a table requiring integer keys */
  Bool isOrdered:1;     /* True if the underlying table is BTREE_UNORDERED */
  Pgno pgnoRoot;        /* Root page of the open btree cursor */
  sqlite3_vtab_cursor *pVtabCursor;  /* The cursor for a virtual table */
  i64 seqCount;         /* Sequence counter */
  i64 movetoTarget;     /* Argument to the deferred sqlite3BtreeMoveto() */

  VdbeSorter *pSorter;  /* Sorter object for OP_SorterOpen cursors */

  /* Cached information about the header for the data record that the
  ** cursor is currently pointing to.  Only valid if cacheStatus matches
  ** Vdbe.cacheCtr.  Vdbe.cacheCtr will never take on the value of
  ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
  ** the cache is out of date.
  **
  ** aRow might point to (ephemeral) data for the current row, or it might
  ** be NULL.
  */
  u32 cacheStatus;      /* Cache is valid if this matches Vdbe.cacheCtr */
  u32 payloadSize;      /* Total number of bytes in the record */
  u32 szRow;            /* Byte available in aRow */
  u32 iHdrOffset;       /* Offset to next unparsed byte of the header */
  const u8 *aRow;       /* Data for the current row, if all on one page */
  u32 *aOffset;         /* Pointer to aType[nField] */
  u32 aType[1];         /* Type values for all entries in the record */
  /* 2*nField extra array elements allocated for aType[], beyond the one
  ** static element declared in the structure.  nField total array slots for
  ** aType[] and nField+1 array slots for aOffset[] */
};
typedef struct VdbeCursor VdbeCursor;

14191
14192
14193
14194
14195
14196
14197
14198
14199
14200
14201
14202
14203
14204
14205
  u16 flags;          /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
  u8  enc;            /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
  int n;              /* Number of characters in string value, excluding '\0' */
  char *z;            /* String or BLOB value */
  /* ShallowCopy only needs to copy the information above */
  char *zMalloc;      /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
  int szMalloc;       /* Size of the zMalloc allocation */
  int iPadding1;      /* Padding for 8-byte alignment */
  sqlite3 *db;        /* The associated database connection */
  void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
#ifdef SQLITE_DEBUG
  Mem *pScopyFrom;    /* This Mem is a shallow copy of pScopyFrom */
  void *pFiller;      /* So that sizeof(Mem) is a multiple of 8 */
#endif
};







|







14194
14195
14196
14197
14198
14199
14200
14201
14202
14203
14204
14205
14206
14207
14208
  u16 flags;          /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
  u8  enc;            /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
  int n;              /* Number of characters in string value, excluding '\0' */
  char *z;            /* String or BLOB value */
  /* ShallowCopy only needs to copy the information above */
  char *zMalloc;      /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
  int szMalloc;       /* Size of the zMalloc allocation */
  u32 uTemp;          /* Transient storage for serial_type in OP_MakeRecord */
  sqlite3 *db;        /* The associated database connection */
  void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
#ifdef SQLITE_DEBUG
  Mem *pScopyFrom;    /* This Mem is a shallow copy of pScopyFrom */
  void *pFiller;      /* So that sizeof(Mem) is a multiple of 8 */
#endif
};
14399
14400
14401
14402
14403
14404
14405

14406
14407
14408
14409
14410
14411
14412

/*
** Function prototypes
*/
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*);

#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int);
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);







>







14402
14403
14404
14405
14406
14407
14408
14409
14410
14411
14412
14413
14414
14415
14416

/*
** Function prototypes
*/
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*);
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int);
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
14698
14699
14700
14701
14702
14703
14704
14705
14706
14707
14708
14709
14710
14711
14712
      db->pnBytesFreed = &nByte;
      for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
        sqlite3VdbeClearObject(db, pVdbe);
        sqlite3DbFree(db, pVdbe);
      }
      db->pnBytesFreed = 0;

      *pHighwater = 0;
      *pCurrent = nByte;

      break;
    }

    /*
    ** Set *pCurrent to the total cache hits or misses encountered by all







|







14702
14703
14704
14705
14706
14707
14708
14709
14710
14711
14712
14713
14714
14715
14716
      db->pnBytesFreed = &nByte;
      for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
        sqlite3VdbeClearObject(db, pVdbe);
        sqlite3DbFree(db, pVdbe);
      }
      db->pnBytesFreed = 0;

      *pHighwater = 0;  /* IMP: R-64479-57858 */
      *pCurrent = nByte;

      break;
    }

    /*
    ** Set *pCurrent to the total cache hits or misses encountered by all
14723
14724
14725
14726
14727
14728
14729
14730


14731
14732
14733
14734
14735
14736
14737
14738
14739
14740
14741
14742
14743
14744
14745
14746
14747

      for(i=0; i<db->nDb; i++){
        if( db->aDb[i].pBt ){
          Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt);
          sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet);
        }
      }
      *pHighwater = 0;


      *pCurrent = nRet;
      break;
    }

    /* Set *pCurrent to non-zero if there are unresolved deferred foreign
    ** key constraints.  Set *pCurrent to zero if all foreign key constraints
    ** have been satisfied.  The *pHighwater is always set to zero.
    */
    case SQLITE_DBSTATUS_DEFERRED_FKS: {
      *pHighwater = 0;
      *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0;
      break;
    }

    default: {
      rc = SQLITE_ERROR;
    }







|
>
>









|







14727
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

      for(i=0; i<db->nDb; i++){
        if( db->aDb[i].pBt ){
          Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt);
          sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet);
        }
      }
      *pHighwater = 0; /* IMP: R-42420-56072 */
                       /* IMP: R-54100-20147 */
                       /* IMP: R-29431-39229 */
      *pCurrent = nRet;
      break;
    }

    /* Set *pCurrent to non-zero if there are unresolved deferred foreign
    ** key constraints.  Set *pCurrent to zero if all foreign key constraints
    ** have been satisfied.  The *pHighwater is always set to zero.
    */
    case SQLITE_DBSTATUS_DEFERRED_FKS: {
      *pHighwater = 0;  /* IMP: R-11967-56545 */
      *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0;
      break;
    }

    default: {
      rc = SQLITE_ERROR;
    }
17121
17122
17123
17124
17125
17126
17127
17128
17129
17130
17131
17132
17133
17134
17135
/*
** Return TRUE if the mask of type in eType matches the type of the
** allocation p.  Also return true if p==NULL.
**
** This routine is designed for use within an assert() statement, to
** verify the type of an allocation.  For example:
**
**     assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
*/
SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
  int rc = 1;
  if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
    struct MemBlockHdr *pHdr;
    pHdr = sqlite3MemsysGetHeader(p);
    assert( pHdr->iForeGuard==FOREGUARD );         /* Allocation is valid */







|







17127
17128
17129
17130
17131
17132
17133
17134
17135
17136
17137
17138
17139
17140
17141
/*
** Return TRUE if the mask of type in eType matches the type of the
** allocation p.  Also return true if p==NULL.
**
** This routine is designed for use within an assert() statement, to
** verify the type of an allocation.  For example:
**
**     assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
*/
SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
  int rc = 1;
  if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
    struct MemBlockHdr *pHdr;
    pHdr = sqlite3MemsysGetHeader(p);
    assert( pHdr->iForeGuard==FOREGUARD );         /* Allocation is valid */
17143
17144
17145
17146
17147
17148
17149
17150
17151
17152
17153
17154
17155
17156
17157
/*
** Return TRUE if the mask of type in eType matches no bits of the type of the
** allocation p.  Also return true if p==NULL.
**
** This routine is designed for use within an assert() statement, to
** verify the type of an allocation.  For example:
**
**     assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
*/
SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){
  int rc = 1;
  if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
    struct MemBlockHdr *pHdr;
    pHdr = sqlite3MemsysGetHeader(p);
    assert( pHdr->iForeGuard==FOREGUARD );         /* Allocation is valid */







|







17149
17150
17151
17152
17153
17154
17155
17156
17157
17158
17159
17160
17161
17162
17163
/*
** Return TRUE if the mask of type in eType matches no bits of the type of the
** allocation p.  Also return true if p==NULL.
**
** This routine is designed for use within an assert() statement, to
** verify the type of an allocation.  For example:
**
**     assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
*/
SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){
  int rc = 1;
  if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
    struct MemBlockHdr *pHdr;
    pHdr = sqlite3MemsysGetHeader(p);
    assert( pHdr->iForeGuard==FOREGUARD );         /* Allocation is valid */
20218
20219
20220
20221
20222
20223
20224
20225
20226
20227
20228
20229
20230
20231
20232
  }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);
  }
  assert( EIGHT_BYTE_ALIGNMENT(p) );  /* IMP: R-04675-44850 */
  return p;
}

/*
** This version of the memory allocation is for use by the application.
** First make sure the memory subsystem is initialized, then do the
** allocation.







|







20224
20225
20226
20227
20228
20229
20230
20231
20232
20233
20234
20235
20236
20237
20238
  }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);
  }
  assert( EIGHT_BYTE_ALIGNMENT(p) );  /* IMP: R-11148-40995 */
  return p;
}

/*
** This version of the memory allocation is for use by the application.
** First make sure the memory subsystem is initialized, then do the
** allocation.
20355
20356
20357
20358
20359
20360
20361
20362
20363
20364
20365
20366


20367
20368
20369
20370
20371
20372
20373
20374
20375
20376
20377
20378
20379
20380


20381
20382
20383
20384
20385
20386
20387
20388
20389
20390

20391
20392
20393
20394
20395
20396
20397

/*
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
*/
SQLITE_PRIVATE int sqlite3MallocSize(void *p){
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
  return sqlite3GlobalConfig.m.xSize(p);
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
  if( db==0 ){


    return sqlite3MallocSize(p);
  }else{
    assert( sqlite3_mutex_held(db->mutex) );
    if( isLookaside(db, p) ){
      return db->lookaside.sz;
    }else{
      assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
      assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
      assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
      return sqlite3GlobalConfig.m.xSize(p);
    }
  }
}
SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){


  return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p);
}

/*
** Free memory previously obtained from sqlite3Malloc().
*/
SQLITE_API void sqlite3_free(void *p){
  if( p==0 ) return;  /* IMP: R-49053-54554 */
  assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );

  if( sqlite3GlobalConfig.bMemstat ){
    sqlite3_mutex_enter(mem0.mutex);
    sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
    sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
    sqlite3GlobalConfig.m.xFree(p);
    sqlite3_mutex_leave(mem0.mutex);
  }else{







<




>
>






|
|
<





>
>








<

>







20361
20362
20363
20364
20365
20366
20367

20368
20369
20370
20371
20372
20373
20374
20375
20376
20377
20378
20379
20380
20381

20382
20383
20384
20385
20386
20387
20388
20389
20390
20391
20392
20393
20394
20395
20396

20397
20398
20399
20400
20401
20402
20403
20404
20405

/*
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
*/
SQLITE_PRIVATE int sqlite3MallocSize(void *p){
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );

  return sqlite3GlobalConfig.m.xSize(p);
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
  if( db==0 ){
    assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) );
    assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    return sqlite3MallocSize(p);
  }else{
    assert( sqlite3_mutex_held(db->mutex) );
    if( isLookaside(db, p) ){
      return db->lookaside.sz;
    }else{
      assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
      assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );

      return sqlite3GlobalConfig.m.xSize(p);
    }
  }
}
SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
  assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) );
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p);
}

/*
** Free memory previously obtained from sqlite3Malloc().
*/
SQLITE_API void sqlite3_free(void *p){
  if( p==0 ) return;  /* IMP: R-49053-54554 */

  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  assert( sqlite3MemdebugNoType(p, ~MEMTYPE_HEAP) );
  if( sqlite3GlobalConfig.bMemstat ){
    sqlite3_mutex_enter(mem0.mutex);
    sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
    sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
    sqlite3GlobalConfig.m.xFree(p);
    sqlite3_mutex_leave(mem0.mutex);
  }else{
20427
20428
20429
20430
20431
20432
20433
20434
20435
20436
20437
20438
20439
20440
20441
20442
20443
20444
20445
20446


20447
20448
20449
20450
20451
20452
20453
20454
20455
20456
20457
20458
#endif
      pBuf->pNext = db->lookaside.pFree;
      db->lookaside.pFree = pBuf;
      db->lookaside.nOut--;
      return;
    }
  }
  assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
  assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
  assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
  sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
  sqlite3_free(p);
}

/*
** Change the size of an existing memory allocation
*/
SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
  int nOld, nNew, nDiff;
  void *pNew;


  if( pOld==0 ){
    return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
  }
  if( nBytes==0 ){
    sqlite3_free(pOld); /* IMP: R-31593-10574 */
    return 0;
  }
  if( nBytes>=0x7fffff00 ){
    /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */
    return 0;
  }
  nOld = sqlite3MallocSize(pOld);







|
|











>
>

|


|







20435
20436
20437
20438
20439
20440
20441
20442
20443
20444
20445
20446
20447
20448
20449
20450
20451
20452
20453
20454
20455
20456
20457
20458
20459
20460
20461
20462
20463
20464
20465
20466
20467
20468
#endif
      pBuf->pNext = db->lookaside.pFree;
      db->lookaside.pFree = pBuf;
      db->lookaside.nOut--;
      return;
    }
  }
  assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
  assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
  assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
  sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
  sqlite3_free(p);
}

/*
** Change the size of an existing memory allocation
*/
SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
  int nOld, nNew, nDiff;
  void *pNew;
  assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
  assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
  if( pOld==0 ){
    return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */
  }
  if( nBytes==0 ){
    sqlite3_free(pOld); /* IMP: R-26507-47431 */
    return 0;
  }
  if( nBytes>=0x7fffff00 ){
    /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */
    return 0;
  }
  nOld = sqlite3MallocSize(pOld);
20466
20467
20468
20469
20470
20471
20472
20473
20474
20475
20476
20477
20478
20479
20480
20481
20482
20483
20484
20485
20486
20487
20488
20489
20490
20491
20492
20493
20494
20495
20496
20497
20498
20499
20500
20501
20502
20503
20504
20505
20506
20507
    sqlite3_mutex_enter(mem0.mutex);
    sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
    nDiff = nNew - nOld;
    if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= 
          mem0.alarmThreshold-nDiff ){
      sqlite3MallocAlarm(nDiff);
    }
    assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
    assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
    pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
    if( pNew==0 && mem0.alarmCallback ){
      sqlite3MallocAlarm((int)nBytes);
      pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
    }
    if( pNew ){
      nNew = sqlite3MallocSize(pNew);
      sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
    }
    sqlite3_mutex_leave(mem0.mutex);
  }else{
    pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
  }
  assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-04675-44850 */
  return pNew;
}

/*
** The public interface to sqlite3Realloc.  Make sure that the memory
** subsystem is initialized prior to invoking sqliteRealloc.
*/
SQLITE_API void *sqlite3_realloc(void *pOld, int n){
#ifndef SQLITE_OMIT_AUTOINIT
  if( sqlite3_initialize() ) return 0;
#endif
  if( n<0 ) n = 0;
  return sqlite3Realloc(pOld, n);
}
SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
  if( sqlite3_initialize() ) return 0;
#endif
  return sqlite3Realloc(pOld, n);







<
<













|











|







20476
20477
20478
20479
20480
20481
20482


20483
20484
20485
20486
20487
20488
20489
20490
20491
20492
20493
20494
20495
20496
20497
20498
20499
20500
20501
20502
20503
20504
20505
20506
20507
20508
20509
20510
20511
20512
20513
20514
20515
    sqlite3_mutex_enter(mem0.mutex);
    sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
    nDiff = nNew - nOld;
    if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= 
          mem0.alarmThreshold-nDiff ){
      sqlite3MallocAlarm(nDiff);
    }


    pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
    if( pNew==0 && mem0.alarmCallback ){
      sqlite3MallocAlarm((int)nBytes);
      pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
    }
    if( pNew ){
      nNew = sqlite3MallocSize(pNew);
      sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
    }
    sqlite3_mutex_leave(mem0.mutex);
  }else{
    pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
  }
  assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-11148-40995 */
  return pNew;
}

/*
** The public interface to sqlite3Realloc.  Make sure that the memory
** subsystem is initialized prior to invoking sqliteRealloc.
*/
SQLITE_API void *sqlite3_realloc(void *pOld, int n){
#ifndef SQLITE_OMIT_AUTOINIT
  if( sqlite3_initialize() ) return 0;
#endif
  if( n<0 ) n = 0;  /* IMP: R-26507-47431 */
  return sqlite3Realloc(pOld, n);
}
SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
  if( sqlite3_initialize() ) return 0;
#endif
  return sqlite3Realloc(pOld, n);
20580
20581
20582
20583
20584
20585
20586
20587
20588
20589
20590
20591
20592
20593
20594
20595
    return 0;
  }
#endif
  p = sqlite3Malloc(n);
  if( !p && db ){
    db->mallocFailed = 1;
  }
  sqlite3MemdebugSetType(p, MEMTYPE_DB |
         ((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
  return p;
}

/*
** Resize the block of memory pointed to by p to n bytes. If the
** resize fails, set the mallocFailed flag in the connection object.
*/







|
|







20588
20589
20590
20591
20592
20593
20594
20595
20596
20597
20598
20599
20600
20601
20602
20603
    return 0;
  }
#endif
  p = sqlite3Malloc(n);
  if( !p && db ){
    db->mallocFailed = 1;
  }
  sqlite3MemdebugSetType(p, 
         (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
  return p;
}

/*
** Resize the block of memory pointed to by p to n bytes. If the
** resize fails, set the mallocFailed flag in the connection object.
*/
20607
20608
20609
20610
20611
20612
20613
20614
20615
20616
20617
20618
20619
20620
20621
20622
20623
20624
20625
20626
20627
20628
20629
      }
      pNew = sqlite3DbMallocRaw(db, n);
      if( pNew ){
        memcpy(pNew, p, db->lookaside.sz);
        sqlite3DbFree(db, p);
      }
    }else{
      assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
      assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
      sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
      pNew = sqlite3_realloc64(p, n);
      if( !pNew ){
        sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP);
        db->mallocFailed = 1;
      }
      sqlite3MemdebugSetType(pNew, MEMTYPE_DB | 
            (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
    }
  }
  return pNew;
}

/*







|
|



<


|







20615
20616
20617
20618
20619
20620
20621
20622
20623
20624
20625
20626

20627
20628
20629
20630
20631
20632
20633
20634
20635
20636
      }
      pNew = sqlite3DbMallocRaw(db, n);
      if( pNew ){
        memcpy(pNew, p, db->lookaside.sz);
        sqlite3DbFree(db, p);
      }
    }else{
      assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
      assert( sqlite3MemdebugNoType(p, ~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
      sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
      pNew = sqlite3_realloc64(p, n);
      if( !pNew ){

        db->mallocFailed = 1;
      }
      sqlite3MemdebugSetType(pNew,
            (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
    }
  }
  return pNew;
}

/*
22082
22083
22084
22085
22086
22087
22088
22089
22090
22091
22092
22093
22094
22095
22096
22097
22098
22099
22100
22101
22102
22103
}

#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
/******************************** End Unix Pthreads *************************/


/********************************* Win32 Threads ****************************/
#if SQLITE_OS_WIN && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0

#define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */
#include <process.h>

/* A running thread */
struct SQLiteThread {
  uintptr_t tid;           /* The thread handle */
  unsigned id;             /* The thread identifier */
  void *(*xTask)(void*);   /* The routine to run as a thread */
  void *pIn;               /* Argument to xTask */
  void *pResult;           /* Result of xTask */
};

/* Thread procedure Win32 compatibility shim */







|






|







22089
22090
22091
22092
22093
22094
22095
22096
22097
22098
22099
22100
22101
22102
22103
22104
22105
22106
22107
22108
22109
22110
}

#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
/******************************** End Unix Pthreads *************************/


/********************************* Win32 Threads ****************************/
#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0

#define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */
#include <process.h>

/* A running thread */
struct SQLiteThread {
  void *tid;               /* The thread handle */
  unsigned id;             /* The thread identifier */
  void *(*xTask)(void*);   /* The routine to run as a thread */
  void *pIn;               /* Argument to xTask */
  void *pResult;           /* Result of xTask */
};

/* Thread procedure Win32 compatibility shim */
22137
22138
22139
22140
22141
22142
22143
22144
22145
22146
22147
22148
22149
22150
22151
  p = sqlite3Malloc(sizeof(*p));
  if( p==0 ) return SQLITE_NOMEM;
  if( sqlite3GlobalConfig.bCoreMutex==0 ){
    memset(p, 0, sizeof(*p));
  }else{
    p->xTask = xTask;
    p->pIn = pIn;
    p->tid = _beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);
    if( p->tid==0 ){
      memset(p, 0, sizeof(*p));
    }
  }
  if( p->xTask==0 ){
    p->id = GetCurrentThreadId();
    p->pResult = xTask(pIn);







|







22144
22145
22146
22147
22148
22149
22150
22151
22152
22153
22154
22155
22156
22157
22158
  p = sqlite3Malloc(sizeof(*p));
  if( p==0 ) return SQLITE_NOMEM;
  if( sqlite3GlobalConfig.bCoreMutex==0 ){
    memset(p, 0, sizeof(*p));
  }else{
    p->xTask = xTask;
    p->pIn = pIn;
    p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);
    if( p->tid==0 ){
      memset(p, 0, sizeof(*p));
    }
  }
  if( p->xTask==0 ){
    p->id = GetCurrentThreadId();
    p->pResult = xTask(pIn);
22175
22176
22177
22178
22179
22180
22181
22182
22183
22184
22185
22186
22187
22188
22189
    assert( bRc );
  }
  if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
  sqlite3_free(p);
  return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
}

#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINRT */
/******************************** End Win32 Threads *************************/


/********************************* Single-Threaded **************************/
#ifndef SQLITE_THREADS_IMPLEMENTED
/*
** This implementation does not actually create a new thread.  It does the







|







22182
22183
22184
22185
22186
22187
22188
22189
22190
22191
22192
22193
22194
22195
22196
    assert( bRc );
  }
  if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
  sqlite3_free(p);
  return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
}

#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT */
/******************************** End Win32 Threads *************************/


/********************************* Single-Threaded **************************/
#ifndef SQLITE_THREADS_IMPLEMENTED
/*
** This implementation does not actually create a new thread.  It does the
33478
33479
33480
33481
33482
33483
33484

33485



33486
33487
33488
33489
33490
33491
33492
#else
  { "WaitForSingleObject",     (SYSCALL)0,                       0 },
#endif

#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
        DWORD))aSyscall[63].pCurrent)


  { "WaitForSingleObjectEx",   (SYSCALL)WaitForSingleObjectEx,   0 },




#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
        BOOL))aSyscall[64].pCurrent)

#if SQLITE_OS_WINRT
  { "SetFilePointerEx",        (SYSCALL)SetFilePointerEx,        0 },
#else







>

>
>
>







33485
33486
33487
33488
33489
33490
33491
33492
33493
33494
33495
33496
33497
33498
33499
33500
33501
33502
33503
#else
  { "WaitForSingleObject",     (SYSCALL)0,                       0 },
#endif

#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
        DWORD))aSyscall[63].pCurrent)

#if !SQLITE_OS_WINCE
  { "WaitForSingleObjectEx",   (SYSCALL)WaitForSingleObjectEx,   0 },
#else
  { "WaitForSingleObjectEx",   (SYSCALL)0,                       0 },
#endif

#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
        BOOL))aSyscall[64].pCurrent)

#if SQLITE_OS_WINRT
  { "SetFilePointerEx",        (SYSCALL)SetFilePointerEx,        0 },
#else
33821
33822
33823
33824
33825
33826
33827
33828

33829
33830
33831
33832
33833
33834
33835
  assert( sleepObj!=NULL );
  osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE);
#else
  osSleep(milliseconds);
#endif
}

#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0

SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
  DWORD rc;
  while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
                                       TRUE))==WAIT_IO_COMPLETION ){}
  return rc;
}
#endif







|
>







33832
33833
33834
33835
33836
33837
33838
33839
33840
33841
33842
33843
33844
33845
33846
33847
  assert( sleepObj!=NULL );
  osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE);
#else
  osSleep(milliseconds);
#endif
}

#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
        SQLITE_THREADSAFE>0
SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
  DWORD rc;
  while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
                                       TRUE))==WAIT_IO_COMPLETION ){}
  return rc;
}
#endif
37837
37838
37839
37840
37841
37842
37843
37844
37845
37846
37847
37848
37849
37850
37851
37852
37853
37854
37855
37856
37857
37858
37859
37860
37861
37862
37863
37864
37865
37866
37867
37868
37869
37870
37871
37872
37873
37874
37875
static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
  int n = 0;
  UNUSED_PARAMETER(pVfs);
#if defined(SQLITE_TEST)
  n = nBuf;
  memset(zBuf, 0, nBuf);
#else
  if( (int)sizeof(SYSTEMTIME)<=nBuf-n ){
    SYSTEMTIME x;
    osGetSystemTime(&x);
    memcpy(&zBuf[n], &x, sizeof(x));
    n += sizeof(x);
  }
  if( (int)sizeof(DWORD)<=nBuf-n ){
    DWORD pid = osGetCurrentProcessId();
    memcpy(&zBuf[n], &pid, sizeof(pid));
    n += sizeof(pid);
  }
#if SQLITE_OS_WINRT
  if( (int)sizeof(ULONGLONG)<=nBuf-n ){
    ULONGLONG cnt = osGetTickCount64();
    memcpy(&zBuf[n], &cnt, sizeof(cnt));
    n += sizeof(cnt);
  }
#else
  if( (int)sizeof(DWORD)<=nBuf-n ){
    DWORD cnt = osGetTickCount();
    memcpy(&zBuf[n], &cnt, sizeof(cnt));
    n += sizeof(cnt);
  }
#endif
  if( (int)sizeof(LARGE_INTEGER)<=nBuf-n ){
    LARGE_INTEGER i;
    osQueryPerformanceCounter(&i);
    memcpy(&zBuf[n], &i, sizeof(i));
    n += sizeof(i);
  }
#endif
  return n;







|





|





|





|





|







37849
37850
37851
37852
37853
37854
37855
37856
37857
37858
37859
37860
37861
37862
37863
37864
37865
37866
37867
37868
37869
37870
37871
37872
37873
37874
37875
37876
37877
37878
37879
37880
37881
37882
37883
37884
37885
37886
37887
static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
  int n = 0;
  UNUSED_PARAMETER(pVfs);
#if defined(SQLITE_TEST)
  n = nBuf;
  memset(zBuf, 0, nBuf);
#else
  if( sizeof(SYSTEMTIME)<=nBuf-n ){
    SYSTEMTIME x;
    osGetSystemTime(&x);
    memcpy(&zBuf[n], &x, sizeof(x));
    n += sizeof(x);
  }
  if( sizeof(DWORD)<=nBuf-n ){
    DWORD pid = osGetCurrentProcessId();
    memcpy(&zBuf[n], &pid, sizeof(pid));
    n += sizeof(pid);
  }
#if SQLITE_OS_WINRT
  if( sizeof(ULONGLONG)<=nBuf-n ){
    ULONGLONG cnt = osGetTickCount64();
    memcpy(&zBuf[n], &cnt, sizeof(cnt));
    n += sizeof(cnt);
  }
#else
  if( sizeof(DWORD)<=nBuf-n ){
    DWORD cnt = osGetTickCount();
    memcpy(&zBuf[n], &cnt, sizeof(cnt));
    n += sizeof(cnt);
  }
#endif
  if( sizeof(LARGE_INTEGER)<=nBuf-n ){
    LARGE_INTEGER i;
    osQueryPerformanceCounter(&i);
    memcpy(&zBuf[n], &i, sizeof(i));
    n += sizeof(i);
  }
#endif
  return n;
39846
39847
39848
39849
39850
39851
39852
39853
39854
39855
39856
39857
39858
39859
39860
  assert( pCache->nPage >= pCache->nRecyclable );
  nPinned = pCache->nPage - pCache->nRecyclable;
  assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
  assert( pCache->n90pct == pCache->nMax*9/10 );
  if( createFlag==1 && (
        nPinned>=pGroup->mxPinned
     || nPinned>=pCache->n90pct
     || pcache1UnderMemoryPressure(pCache)
  )){
    return 0;
  }

  if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
  assert( pCache->nHash>0 && pCache->apHash );








|







39858
39859
39860
39861
39862
39863
39864
39865
39866
39867
39868
39869
39870
39871
39872
  assert( pCache->nPage >= pCache->nRecyclable );
  nPinned = pCache->nPage - pCache->nRecyclable;
  assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
  assert( pCache->n90pct == pCache->nMax*9/10 );
  if( createFlag==1 && (
        nPinned>=pGroup->mxPinned
     || nPinned>=pCache->n90pct
     || (pcache1UnderMemoryPressure(pCache) && pCache->nRecyclable<nPinned)
  )){
    return 0;
  }

  if( pCache->nPage>=pCache->nHash ) pcache1ResizeHash(pCache);
  assert( pCache->nHash>0 && pCache->apHash );

44467
44468
44469
44470
44471
44472
44473
44474
44475
44476
44477
44478


44479
44480


44481
44482
44483
44484
44485
44486
44487
    if( rc==SQLITE_OK ){
      pNew = (char *)sqlite3PageMalloc(pageSize);
      if( !pNew ) rc = SQLITE_NOMEM;
    }

    if( rc==SQLITE_OK ){
      pager_reset(pPager);
      sqlite3PageFree(pPager->pTmpSpace);
      pPager->pTmpSpace = pNew;
      rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
    }
    if( rc==SQLITE_OK ){


      pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
      pPager->pageSize = pageSize;


    }
  }

  *pPageSize = pPager->pageSize;
  if( rc==SQLITE_OK ){
    if( nReserve<0 ) nReserve = pPager->nReserve;
    assert( nReserve>=0 && nReserve<1000 );







<
<



>
>


>
>







44479
44480
44481
44482
44483
44484
44485


44486
44487
44488
44489
44490
44491
44492
44493
44494
44495
44496
44497
44498
44499
44500
44501
    if( rc==SQLITE_OK ){
      pNew = (char *)sqlite3PageMalloc(pageSize);
      if( !pNew ) rc = SQLITE_NOMEM;
    }

    if( rc==SQLITE_OK ){
      pager_reset(pPager);


      rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
    }
    if( rc==SQLITE_OK ){
      sqlite3PageFree(pPager->pTmpSpace);
      pPager->pTmpSpace = pNew;
      pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
      pPager->pageSize = pageSize;
    }else{
      sqlite3PageFree(pNew);
    }
  }

  *pPageSize = pPager->pageSize;
  if( rc==SQLITE_OK ){
    if( nReserve<0 ) nReserve = pPager->nReserve;
    assert( nReserve>=0 && nReserve<1000 );
51640
51641
51642
51643
51644
51645
51646
51647
51648
51649
51650
51651
51652
51653
51654
  Bitvec *pHasContent;  /* Set of pages moved to free-list this transaction */
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nRef;             /* Number of references to this structure */
  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
  BtLock *pLock;        /* List of locks held on this shared-btree struct */
  Btree *pWriter;       /* Btree with currently open write transaction */
#endif
  u8 *pTmpSpace;        /* BtShared.pageSize bytes of space for tmp use */
};

/*
** Allowed values for BtShared.btsFlags
*/
#define BTS_READ_ONLY        0x0001   /* Underlying file is readonly */
#define BTS_PAGESIZE_FIXED   0x0002   /* Page size can no longer be changed */







|







51654
51655
51656
51657
51658
51659
51660
51661
51662
51663
51664
51665
51666
51667
51668
  Bitvec *pHasContent;  /* Set of pages moved to free-list this transaction */
#ifndef SQLITE_OMIT_SHARED_CACHE
  int nRef;             /* Number of references to this structure */
  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
  BtLock *pLock;        /* List of locks held on this shared-btree struct */
  Btree *pWriter;       /* Btree with currently open write transaction */
#endif
  u8 *pTmpSpace;        /* Temp space sufficient to hold a single cell */
};

/*
** Allowed values for BtShared.btsFlags
*/
#define BTS_READ_ONLY        0x0001   /* Underlying file is readonly */
#define BTS_PAGESIZE_FIXED   0x0002   /* Page size can no longer be changed */
52938
52939
52940
52941
52942
52943
52944
52945
52946
52947
52948
52949
52950
52951
52952
**
** Calling this routine with a NULL cursor pointer returns false.
**
** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor
** back to where it ought to be if this routine returns true.
*/
SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
  return pCur && pCur->eState!=CURSOR_VALID;
}

/*
** This routine restores a cursor back to its original position after it
** has been moved by some outside activity (such as a btree rebalance or
** a row having been deleted out from under the cursor).  
**







|







52952
52953
52954
52955
52956
52957
52958
52959
52960
52961
52962
52963
52964
52965
52966
**
** Calling this routine with a NULL cursor pointer returns false.
**
** Use the separate sqlite3BtreeCursorRestore() routine to restore a cursor
** back to where it ought to be if this routine returns true.
*/
SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
  return pCur->eState!=CURSOR_VALID;
}

/*
** This routine restores a cursor back to its original position after it
** has been moved by some outside activity (such as a btree rebalance or
** a row having been deleted out from under the cursor).  
**
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
54304
54305
54306
54307
54308
54309
#else
  return 1;
#endif
}

/*
** Make sure pBt->pTmpSpace points to an allocation of 
** MX_CELL_SIZE(pBt) bytes.

*/
static void allocateTempSpace(BtShared *pBt){
  if( !pBt->pTmpSpace ){
    pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize );

    /* One of the uses of pBt->pTmpSpace is to format cells before
    ** inserting them into a leaf page (function fillInCell()). If
    ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes
    ** by the various routines that manipulate binary cells. Which
    ** can mean that fillInCell() only initializes the first 2 or 3
    ** bytes of pTmpSpace, but that the first 4 bytes are copied from
    ** it into a database page. This is not actually a problem, but it
    ** does cause a valgrind error when the 1 or 2 bytes of unitialized 
    ** data is passed to system call write(). So to avoid this error,
    ** zero the first 4 bytes of temp space here.  */





    if( pBt->pTmpSpace ) memset(pBt->pTmpSpace, 0, 4);



  }
}

/*
** Free the pBt->pTmpSpace allocation
*/
static void freeTempSpace(BtShared *pBt){
  sqlite3PageFree( pBt->pTmpSpace);


  pBt->pTmpSpace = 0;

}

/*
** Close an open database and invalidate all cursors.
*/
SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
  BtShared *pBt = p->pBt;







|
>














|
>
>
>
>
>
|
>
>
>







|
>
>
|
>







54284
54285
54286
54287
54288
54289
54290
54291
54292
54293
54294
54295
54296
54297
54298
54299
54300
54301
54302
54303
54304
54305
54306
54307
54308
54309
54310
54311
54312
54313
54314
54315
54316
54317
54318
54319
54320
54321
54322
54323
54324
54325
54326
54327
54328
54329
54330
54331
54332
54333
54334
54335
#else
  return 1;
#endif
}

/*
** Make sure pBt->pTmpSpace points to an allocation of 
** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child
** pointer.
*/
static void allocateTempSpace(BtShared *pBt){
  if( !pBt->pTmpSpace ){
    pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize );

    /* One of the uses of pBt->pTmpSpace is to format cells before
    ** inserting them into a leaf page (function fillInCell()). If
    ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes
    ** by the various routines that manipulate binary cells. Which
    ** can mean that fillInCell() only initializes the first 2 or 3
    ** bytes of pTmpSpace, but that the first 4 bytes are copied from
    ** it into a database page. This is not actually a problem, but it
    ** does cause a valgrind error when the 1 or 2 bytes of unitialized 
    ** data is passed to system call write(). So to avoid this error,
    ** zero the first 4 bytes of temp space here.
    **
    ** Also:  Provide four bytes of initialized space before the
    ** beginning of pTmpSpace as an area available to prepend the
    ** left-child pointer to the beginning of a cell.
    */
    if( pBt->pTmpSpace ){
      memset(pBt->pTmpSpace, 0, 8);
      pBt->pTmpSpace += 4;
    }
  }
}

/*
** Free the pBt->pTmpSpace allocation
*/
static void freeTempSpace(BtShared *pBt){
  if( pBt->pTmpSpace ){
    pBt->pTmpSpace -= 4;
    sqlite3PageFree(pBt->pTmpSpace);
    pBt->pTmpSpace = 0;
  }
}

/*
** Close an open database and invalidate all cursors.
*/
SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
  BtShared *pBt = p->pBt;
58007
58008
58009
58010
58011
58012
58013
58014
58015
58016
58017
58018
58019
58020
58021
58022
58023
58024
58025
58026
58027
58028
58029
58030
58031
58032
58033
58034
58035
58036
58037
58038
58039
58040
58041
58042
58043
58044
58045
58046
58047
58048
58049
58050
58051
58052
58053
58054
58055
58056
58057
58058
58059
58060
** If the cell content will fit on the page, then put it there.  If it
** will not fit, then make a copy of the cell content into pTemp if
** pTemp is not null.  Regardless of pTemp, allocate a new entry
** in pPage->apOvfl[] and make it point to the cell content (either
** in pTemp or the original pCell) and also record its index. 
** Allocating a new entry in pPage->aCell[] implies that 
** pPage->nOverflow is incremented.
**
** If nSkip is non-zero, then do not copy the first nSkip bytes of the
** cell. The caller will overwrite them after this function returns. If
** nSkip is non-zero, then pCell may not point to an invalid memory location 
** (but pCell+nSkip is always valid).
*/
static void insertCell(
  MemPage *pPage,   /* Page into which we are copying */
  int i,            /* New cell becomes the i-th cell of the page */
  u8 *pCell,        /* Content of the new cell */
  int sz,           /* Bytes of content in pCell */
  u8 *pTemp,        /* Temp storage space for pCell, if needed */
  Pgno iChild,      /* If non-zero, replace first 4 bytes with this value */
  int *pRC          /* Read and write return code from here */
){
  int idx = 0;      /* Where to write new cell content in data[] */
  int j;            /* Loop counter */
  int end;          /* First byte past the last cell pointer in data[] */
  int ins;          /* Index in data[] where new cell pointer is inserted */
  int cellOffset;   /* Address of first cell pointer in data[] */
  u8 *data;         /* The content of the whole page */
  int nSkip = (iChild ? 4 : 0);

  if( *pRC ) return;

  assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
  assert( MX_CELL(pPage->pBt)<=10921 );
  assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
  assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
  assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
  assert( sqlite3_mutex_held(pPage->pBt->mutex) );
  /* The cell should normally be sized correctly.  However, when moving a
  ** malformed cell from a leaf page to an interior page, if the cell size
  ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size
  ** might be less than 8 (leaf-size + pointer) on the interior node.  Hence
  ** the term after the || in the following assert(). */
  assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) );
  if( pPage->nOverflow || sz+2>pPage->nFree ){
    if( pTemp ){
      memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip);
      pCell = pTemp;
    }
    if( iChild ){
      put4byte(pCell, iChild);
    }
    j = pPage->nOverflow++;
    assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );







<
<
<
<
<
















<

















|







58033
58034
58035
58036
58037
58038
58039





58040
58041
58042
58043
58044
58045
58046
58047
58048
58049
58050
58051
58052
58053
58054
58055

58056
58057
58058
58059
58060
58061
58062
58063
58064
58065
58066
58067
58068
58069
58070
58071
58072
58073
58074
58075
58076
58077
58078
58079
58080
** If the cell content will fit on the page, then put it there.  If it
** will not fit, then make a copy of the cell content into pTemp if
** pTemp is not null.  Regardless of pTemp, allocate a new entry
** in pPage->apOvfl[] and make it point to the cell content (either
** in pTemp or the original pCell) and also record its index. 
** Allocating a new entry in pPage->aCell[] implies that 
** pPage->nOverflow is incremented.





*/
static void insertCell(
  MemPage *pPage,   /* Page into which we are copying */
  int i,            /* New cell becomes the i-th cell of the page */
  u8 *pCell,        /* Content of the new cell */
  int sz,           /* Bytes of content in pCell */
  u8 *pTemp,        /* Temp storage space for pCell, if needed */
  Pgno iChild,      /* If non-zero, replace first 4 bytes with this value */
  int *pRC          /* Read and write return code from here */
){
  int idx = 0;      /* Where to write new cell content in data[] */
  int j;            /* Loop counter */
  int end;          /* First byte past the last cell pointer in data[] */
  int ins;          /* Index in data[] where new cell pointer is inserted */
  int cellOffset;   /* Address of first cell pointer in data[] */
  u8 *data;         /* The content of the whole page */


  if( *pRC ) return;

  assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
  assert( MX_CELL(pPage->pBt)<=10921 );
  assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
  assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
  assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
  assert( sqlite3_mutex_held(pPage->pBt->mutex) );
  /* The cell should normally be sized correctly.  However, when moving a
  ** malformed cell from a leaf page to an interior page, if the cell size
  ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size
  ** might be less than 8 (leaf-size + pointer) on the interior node.  Hence
  ** the term after the || in the following assert(). */
  assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) );
  if( pPage->nOverflow || sz+2>pPage->nFree ){
    if( pTemp ){
      memcpy(pTemp, pCell, sz);
      pCell = pTemp;
    }
    if( iChild ){
      put4byte(pCell, iChild);
    }
    j = pPage->nOverflow++;
    assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );
58075
58076
58077
58078
58079
58080
58081
58082
58083
58084
58085
58086
58087
58088
58089
    if( rc ){ *pRC = rc; return; }
    /* The allocateSpace() routine guarantees the following two properties
    ** if it returns success */
    assert( idx >= end+2 );
    assert( idx+sz <= (int)pPage->pBt->usableSize );
    pPage->nCell++;
    pPage->nFree -= (u16)(2 + sz);
    memcpy(&data[idx+nSkip], pCell+nSkip, sz-nSkip);
    if( iChild ){
      put4byte(&data[idx], iChild);
    }
    memmove(&data[ins+2], &data[ins], end-ins);
    put2byte(&data[ins], idx);
    put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
#ifndef SQLITE_OMIT_AUTOVACUUM







|







58095
58096
58097
58098
58099
58100
58101
58102
58103
58104
58105
58106
58107
58108
58109
    if( rc ){ *pRC = rc; return; }
    /* The allocateSpace() routine guarantees the following two properties
    ** if it returns success */
    assert( idx >= end+2 );
    assert( idx+sz <= (int)pPage->pBt->usableSize );
    pPage->nCell++;
    pPage->nFree -= (u16)(2 + sz);
    memcpy(&data[idx], pCell, sz);
    if( iChild ){
      put4byte(&data[idx], iChild);
    }
    memmove(&data[ins+2], &data[ins], end-ins);
    put2byte(&data[ins], idx);
    put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
#ifndef SQLITE_OMIT_AUTOVACUUM
61621
61622
61623
61624
61625
61626
61627
61628



61629
61630
61631
61632
61633
61634
61635
*/
SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
  /* If MEM_Dyn is set then Mem.xDel!=0.  
  ** Mem.xDel is might not be initialized if MEM_Dyn is clear.
  */
  assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );

  /* MEM_Dyn may only be set if Mem.szMalloc==0 */



  assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 );

  /* Cannot be both MEM_Int and MEM_Real at the same time */
  assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );

  /* The szMalloc field holds the correct memory allocation size */
  assert( p->szMalloc==0







|
>
>
>







61641
61642
61643
61644
61645
61646
61647
61648
61649
61650
61651
61652
61653
61654
61655
61656
61657
61658
*/
SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
  /* If MEM_Dyn is set then Mem.xDel!=0.  
  ** Mem.xDel is might not be initialized if MEM_Dyn is clear.
  */
  assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );

  /* MEM_Dyn may only be set if Mem.szMalloc==0.  In this way we
  ** ensure that if Mem.szMalloc>0 then it is safe to do
  ** Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn.
  ** That saves a few cycles in inner loops. */
  assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 );

  /* Cannot be both MEM_Int and MEM_Real at the same time */
  assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );

  /* The szMalloc field holds the correct memory allocation size */
  assert( p->szMalloc==0
61730
61731
61732
61733
61734
61735
61736
61737
61738
61739
61740
61741
61742
61743
61744
      pMem->szMalloc = 0;
      return SQLITE_NOMEM;
    }else{
      pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
    }
  }

  if( pMem->z && bPreserve && pMem->z!=pMem->zMalloc ){
    memcpy(pMem->zMalloc, pMem->z, pMem->n);
  }
  if( (pMem->flags&MEM_Dyn)!=0 ){
    assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC );
    pMem->xDel((void *)(pMem->z));
  }








|







61753
61754
61755
61756
61757
61758
61759
61760
61761
61762
61763
61764
61765
61766
61767
      pMem->szMalloc = 0;
      return SQLITE_NOMEM;
    }else{
      pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
    }
  }

  if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){
    memcpy(pMem->zMalloc, pMem->z, pMem->n);
  }
  if( (pMem->flags&MEM_Dyn)!=0 ){
    assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC );
    pMem->xDel((void *)(pMem->z));
  }

61757
61758
61759
61760
61761
61762
61763
61764

61765
61766
61767
61768
61769
61770
61771
** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null
** values are preserved.
**
** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM)
** if unable to complete the resizing.
*/
SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
  assert( szNew>=0 );

  if( pMem->szMalloc<szNew ){
    return sqlite3VdbeMemGrow(pMem, szNew, 0);
  }
  assert( (pMem->flags & MEM_Dyn)==0 );
  pMem->z = pMem->zMalloc;
  pMem->flags &= (MEM_Null|MEM_Int|MEM_Real);
  return SQLITE_OK;







|
>







61780
61781
61782
61783
61784
61785
61786
61787
61788
61789
61790
61791
61792
61793
61794
61795
** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null
** values are preserved.
**
** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM)
** if unable to complete the resizing.
*/
SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
  assert( szNew>0 );
  assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 );
  if( pMem->szMalloc<szNew ){
    return sqlite3VdbeMemGrow(pMem, szNew, 0);
  }
  assert( (pMem->flags & MEM_Dyn)==0 );
  pMem->z = pMem->zMalloc;
  pMem->flags &= (MEM_Null|MEM_Int|MEM_Real);
  return SQLITE_OK;
62481
62482
62483
62484
62485
62486
62487



62488
62489
62490
62491
62492
62493
62494
62495
    int nAlloc = nByte;
    if( flags&MEM_Term ){
      nAlloc += (enc==SQLITE_UTF8?1:2);
    }
    if( nByte>iLimit ){
      return SQLITE_TOOBIG;
    }



    if( sqlite3VdbeMemClearAndResize(pMem, nAlloc) ){
      return SQLITE_NOMEM;
    }
    memcpy(pMem->z, z, nAlloc);
  }else if( xDel==SQLITE_DYNAMIC ){
    sqlite3VdbeMemRelease(pMem);
    pMem->zMalloc = pMem->z = (char *)z;
    pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);







>
>
>
|







62505
62506
62507
62508
62509
62510
62511
62512
62513
62514
62515
62516
62517
62518
62519
62520
62521
62522
    int nAlloc = nByte;
    if( flags&MEM_Term ){
      nAlloc += (enc==SQLITE_UTF8?1:2);
    }
    if( nByte>iLimit ){
      return SQLITE_TOOBIG;
    }
    testcase( nAlloc==0 );
    testcase( nAlloc==31 );
    testcase( nAlloc==32 );
    if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){
      return SQLITE_NOMEM;
    }
    memcpy(pMem->z, z, nAlloc);
  }else if( xDel==SQLITE_DYNAMIC ){
    sqlite3VdbeMemRelease(pMem);
    pMem->zMalloc = pMem->z = (char *)z;
    pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
62584
62585
62586
62587
62588
62589
62590
62591
62592
62593
62594
62595
62596
62597
62598
}

/*
** The pVal argument is known to be a value other than NULL.
** Convert it into a string with encoding enc and return a pointer
** to a zero-terminated version of that string.
*/
SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
  assert( pVal!=0 );
  assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
  assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
  assert( (pVal->flags & MEM_RowSet)==0 );
  assert( (pVal->flags & (MEM_Null))==0 );
  if( pVal->flags & (MEM_Blob|MEM_Str) ){
    pVal->flags |= MEM_Str;







|







62611
62612
62613
62614
62615
62616
62617
62618
62619
62620
62621
62622
62623
62624
62625
}

/*
** The pVal argument is known to be a value other than NULL.
** Convert it into a string with encoding enc and return a pointer
** to a zero-terminated version of that string.
*/
static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
  assert( pVal!=0 );
  assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
  assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
  assert( (pVal->flags & MEM_RowSet)==0 );
  assert( (pVal->flags & (MEM_Null))==0 );
  if( pVal->flags & (MEM_Blob|MEM_Str) ){
    pVal->flags |= MEM_Str;
64904
64905
64906
64907
64908
64909
64910
64911
64912
64913
64914
64915
64916
64917
64918
    sqlite3BtreeClose(pCx->pBt);
    /* The pCx->pCursor will be close automatically, if it exists, by
    ** the call above. */
  }else if( pCx->pCursor ){
    sqlite3BtreeCloseCursor(pCx->pCursor);
  }
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( pCx->pVtabCursor ){
    sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
    const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
    p->inVtabMethod = 1;
    pModule->xClose(pVtabCursor);
    p->inVtabMethod = 0;
  }
#endif







|







64931
64932
64933
64934
64935
64936
64937
64938
64939
64940
64941
64942
64943
64944
64945
    sqlite3BtreeClose(pCx->pBt);
    /* The pCx->pCursor will be close automatically, if it exists, by
    ** the call above. */
  }else if( pCx->pCursor ){
    sqlite3BtreeCloseCursor(pCx->pCursor);
  }
#ifndef SQLITE_OMIT_VIRTUALTABLE
  else if( pCx->pVtabCursor ){
    sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
    const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
    p->inVtabMethod = 1;
    pModule->xClose(pVtabCursor);
    p->inVtabMethod = 0;
  }
#endif
64947
64948
64949
64950
64951
64952
64953
64954
64955
64956


64957
64958
64959
64960
64961
64962
64963
** open cursors.
*/
static void closeAllCursors(Vdbe *p){
  if( p->pFrame ){
    VdbeFrame *pFrame;
    for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
    sqlite3VdbeFrameRestore(pFrame);
  }
  p->pFrame = 0;
  p->nFrame = 0;



  if( p->apCsr ){
    int i;
    for(i=0; i<p->nCursor; i++){
      VdbeCursor *pC = p->apCsr[i];
      if( pC ){
        sqlite3VdbeFreeCursor(p, pC);







<
|
|
>
>







64974
64975
64976
64977
64978
64979
64980

64981
64982
64983
64984
64985
64986
64987
64988
64989
64990
64991
** open cursors.
*/
static void closeAllCursors(Vdbe *p){
  if( p->pFrame ){
    VdbeFrame *pFrame;
    for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
    sqlite3VdbeFrameRestore(pFrame);

    p->pFrame = 0;
    p->nFrame = 0;
  }
  assert( p->nFrame==0 );

  if( p->apCsr ){
    int i;
    for(i=0; i<p->nCursor; i++){
      VdbeCursor *pC = p->apCsr[i];
      if( pC ){
        sqlite3VdbeFreeCursor(p, pC);
64971
64972
64973
64974
64975
64976
64977
64978
64979
64980
64981
64982
64983
64984
64985
  while( p->pDelFrame ){
    VdbeFrame *pDel = p->pDelFrame;
    p->pDelFrame = pDel->pParent;
    sqlite3VdbeFrameDelete(pDel);
  }

  /* Delete any auxdata allocations made by the VM */
  sqlite3VdbeDeleteAuxData(p, -1, 0);
  assert( p->pAuxData==0 );
}

/*
** Clean up the VM after a single run.
*/
static void Cleanup(Vdbe *p){







|







64999
65000
65001
65002
65003
65004
65005
65006
65007
65008
65009
65010
65011
65012
65013
  while( p->pDelFrame ){
    VdbeFrame *pDel = p->pDelFrame;
    p->pDelFrame = pDel->pParent;
    sqlite3VdbeFrameDelete(pDel);
  }

  /* Delete any auxdata allocations made by the VM */
  if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0);
  assert( p->pAuxData==0 );
}

/*
** Clean up the VM after a single run.
*/
static void Cleanup(Vdbe *p){
65877
65878
65879
65880
65881
65882
65883
65884
65885
65886
65887
65888
65889
65890
65891
65892
65893
#ifdef SQLITE_TEST
  extern int sqlite3_search_count;
#endif
  assert( p->deferredMoveto );
  assert( p->isTable );
  rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
  if( rc ) return rc;
  p->lastRowid = p->movetoTarget;
  if( res!=0 ) return SQLITE_CORRUPT_BKPT;
  p->rowidIsValid = 1;
#ifdef SQLITE_TEST
  sqlite3_search_count++;
#endif
  p->deferredMoveto = 0;
  p->cacheStatus = CACHE_STALE;
  return SQLITE_OK;
}







<

<







65905
65906
65907
65908
65909
65910
65911

65912

65913
65914
65915
65916
65917
65918
65919
#ifdef SQLITE_TEST
  extern int sqlite3_search_count;
#endif
  assert( p->deferredMoveto );
  assert( p->isTable );
  rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
  if( rc ) return rc;

  if( res!=0 ) return SQLITE_CORRUPT_BKPT;

#ifdef SQLITE_TEST
  sqlite3_search_count++;
#endif
  p->deferredMoveto = 0;
  p->cacheStatus = CACHE_STALE;
  return SQLITE_OK;
}
65904
65905
65906
65907
65908
65909
65910











65911
65912
65913
65914
65915
65916
65917
65918
65919
65920
65921
65922
65923
65924
65925
65926
65927
65928
65929
65930
65931
65932
65933
65934
65935
65936
  assert( p->pCursor!=0 );
  assert( sqlite3BtreeCursorHasMoved(p->pCursor) );
  rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow);
  p->cacheStatus = CACHE_STALE;
  if( isDifferentRow ) p->nullRow = 1;
  return rc;
}












/*
** Make sure the cursor p is ready to read or write the row to which it
** was last positioned.  Return an error code if an OOM fault or I/O error
** prevents us from positioning the cursor to its correct position.
**
** If a MoveTo operation is pending on the given cursor, then do that
** MoveTo now.  If no move is pending, check to see if the row has been
** deleted out from under the cursor and if it has, mark the row as
** a NULL row.
**
** If the cursor is already pointing to the correct row and that row has
** not been deleted out from under the cursor, then this routine is a no-op.
*/
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
  if( p->deferredMoveto ){
    return handleDeferredMoveto(p);
  }
  if( sqlite3BtreeCursorHasMoved(p->pCursor) ){
    return handleMovedCursor(p);
  }
  return SQLITE_OK;
}

/*
** The following functions:







>
>
>
>
>
>
>
>
>
>
>


















|







65930
65931
65932
65933
65934
65935
65936
65937
65938
65939
65940
65941
65942
65943
65944
65945
65946
65947
65948
65949
65950
65951
65952
65953
65954
65955
65956
65957
65958
65959
65960
65961
65962
65963
65964
65965
65966
65967
65968
65969
65970
65971
65972
65973
  assert( p->pCursor!=0 );
  assert( sqlite3BtreeCursorHasMoved(p->pCursor) );
  rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow);
  p->cacheStatus = CACHE_STALE;
  if( isDifferentRow ) p->nullRow = 1;
  return rc;
}

/*
** Check to ensure that the cursor is valid.  Restore the cursor
** if need be.  Return any I/O error from the restore operation.
*/
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
  if( sqlite3BtreeCursorHasMoved(p->pCursor) ){
    return handleMovedCursor(p);
  }
  return SQLITE_OK;
}

/*
** Make sure the cursor p is ready to read or write the row to which it
** was last positioned.  Return an error code if an OOM fault or I/O error
** prevents us from positioning the cursor to its correct position.
**
** If a MoveTo operation is pending on the given cursor, then do that
** MoveTo now.  If no move is pending, check to see if the row has been
** deleted out from under the cursor and if it has, mark the row as
** a NULL row.
**
** If the cursor is already pointing to the correct row and that row has
** not been deleted out from under the cursor, then this routine is a no-op.
*/
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
  if( p->deferredMoveto ){
    return handleDeferredMoveto(p);
  }
  if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){
    return handleMovedCursor(p);
  }
  return SQLITE_OK;
}

/*
** The following functions:
67547
67548
67549
67550
67551
67552
67553

67554
67555
67556
67557
67558
67559
67560
  const char *z, 
  sqlite3_uint64 n,
  void (*xDel)(void *),
  unsigned char enc
){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  assert( xDel!=SQLITE_DYNAMIC );

  if( n>0x7fffffff ){
    (void)invokeValueDestructor(z, xDel, pCtx);
  }else{
    setResultStrOrError(pCtx, z, (int)n, enc, xDel);
  }
}
#ifndef SQLITE_OMIT_UTF16







>







67584
67585
67586
67587
67588
67589
67590
67591
67592
67593
67594
67595
67596
67597
67598
  const char *z, 
  sqlite3_uint64 n,
  void (*xDel)(void *),
  unsigned char enc
){
  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
  assert( xDel!=SQLITE_DYNAMIC );
  if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
  if( n>0x7fffffff ){
    (void)invokeValueDestructor(z, xDel, pCtx);
  }else{
    setResultStrOrError(pCtx, z, (int)n, enc, xDel);
  }
}
#ifndef SQLITE_OMIT_UTF16
69085
69086
69087
69088
69089
69090
69091

69092
69093
69094
69095
69096
69097
69098
    p->apCsr[iCur] = 0;
  }
  if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
    p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
    memset(pCx, 0, sizeof(VdbeCursor));
    pCx->iDb = iDb;
    pCx->nField = nField;

    if( isBtreeCursor ){
      pCx->pCursor = (BtCursor*)
          &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
      sqlite3BtreeCursorZero(pCx->pCursor);
    }
  }
  return pCx;







>







69123
69124
69125
69126
69127
69128
69129
69130
69131
69132
69133
69134
69135
69136
69137
    p->apCsr[iCur] = 0;
  }
  if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
    p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
    memset(pCx, 0, sizeof(VdbeCursor));
    pCx->iDb = iDb;
    pCx->nField = nField;
    pCx->aOffset = &pCx->aType[nField];
    if( isBtreeCursor ){
      pCx->pCursor = (BtCursor*)
          &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
      sqlite3BtreeCursorZero(pCx->pCursor);
    }
  }
  return pCx;
70518
70519
70520
70521
70522
70523
70524
70525
70526
70527
70528
70529
70530
70531
70532

  assert( pOp->p4type==P4_FUNCDEF );
  ctx.pFunc = pOp->p4.pFunc;
  ctx.iOp = pc;
  ctx.pVdbe = p;
  MemSetTypeFlag(ctx.pOut, MEM_Null);
  ctx.fErrorOrAux = 0;
  assert( db->lastRowid==lastRowid );
  (*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */
  lastRowid = db->lastRowid;  /* Remember rowid changes made by xFunc */

  /* If the function returned an error, throw an exception */
  if( ctx.fErrorOrAux ){
    if( ctx.isError ){
      sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut));







|







70557
70558
70559
70560
70561
70562
70563
70564
70565
70566
70567
70568
70569
70570
70571

  assert( pOp->p4type==P4_FUNCDEF );
  ctx.pFunc = pOp->p4.pFunc;
  ctx.iOp = pc;
  ctx.pVdbe = p;
  MemSetTypeFlag(ctx.pOut, MEM_Null);
  ctx.fErrorOrAux = 0;
  db->lastRowid = lastRowid;
  (*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */
  lastRowid = db->lastRowid;  /* Remember rowid changes made by xFunc */

  /* If the function returned an error, throw an exception */
  if( ctx.fErrorOrAux ){
    if( ctx.isError ){
      sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut));
71236
71237
71238
71239
71240
71241
71242
71243
71244
71245
71246
71247
71248
71249
71250
71251
71252
71253
71254
71255
71256
71257
71258
71259
71260
71261
  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
  pDest = &aMem[pOp->p3];
  memAboutToChange(p, pDest);
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( p2<pC->nField );
  aOffset = pC->aType + pC->nField;
#ifndef SQLITE_OMIT_VIRTUALTABLE
  assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
#endif
  pCrsr = pC->pCursor;
  assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
  assert( pCrsr!=0 || pC->nullRow );          /* pC->nullRow on PseudoTables */

  /* If the cursor cache is stale, bring it up-to-date */
  rc = sqlite3VdbeCursorMoveto(pC);
  if( rc ) goto abort_due_to_error;
  if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){
    if( pC->nullRow ){
      if( pCrsr==0 ){
        assert( pC->pseudoTableReg>0 );
        pReg = &aMem[pC->pseudoTableReg];
        assert( pReg->flags & MEM_Blob );
        assert( memIsValid(pReg) );
        pC->payloadSize = pC->szRow = avail = pReg->n;







|










|







71275
71276
71277
71278
71279
71280
71281
71282
71283
71284
71285
71286
71287
71288
71289
71290
71291
71292
71293
71294
71295
71296
71297
71298
71299
71300
  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
  pDest = &aMem[pOp->p3];
  memAboutToChange(p, pDest);
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( p2<pC->nField );
  aOffset = pC->aOffset;
#ifndef SQLITE_OMIT_VIRTUALTABLE
  assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
#endif
  pCrsr = pC->pCursor;
  assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
  assert( pCrsr!=0 || pC->nullRow );          /* pC->nullRow on PseudoTables */

  /* If the cursor cache is stale, bring it up-to-date */
  rc = sqlite3VdbeCursorMoveto(pC);
  if( rc ) goto abort_due_to_error;
  if( pC->cacheStatus!=p->cacheCtr ){
    if( pC->nullRow ){
      if( pCrsr==0 ){
        assert( pC->pseudoTableReg>0 );
        pReg = &aMem[pC->pseudoTableReg];
        assert( pReg->flags & MEM_Blob );
        assert( memIsValid(pReg) );
        pC->payloadSize = pC->szRow = avail = pReg->n;
71292
71293
71294
71295
71296
71297
71298
71299
71300
71301
71302
71303
71304
71305
71306
71307
71308
71309
71310
71311
71312
71313
71314
71315
71316
71317
71318
71319
71320
















71321
71322
71323
71324
71325
71326
71327
71328
71329

71330
71331
71332
71333
71334
71335
71336
        goto too_big;
      }
    }
    pC->cacheStatus = p->cacheCtr;
    pC->iHdrOffset = getVarint32(pC->aRow, offset);
    pC->nHdrParsed = 0;
    aOffset[0] = offset;
    if( avail<offset ){
      /* pC->aRow does not have to hold the entire row, but it does at least
      ** need to cover the header of the record.  If pC->aRow does not contain
      ** the complete header, then set it to zero, forcing the header to be
      ** dynamically allocated. */
      pC->aRow = 0;
      pC->szRow = 0;
    }

    /* Make sure a corrupt database has not given us an oversize header.
    ** Do this now to avoid an oversize memory allocation.
    **
    ** Type entries can be between 1 and 5 bytes each.  But 4 and 5 byte
    ** types use so much data space that there can only be 4096 and 32 of
    ** them, respectively.  So the maximum header length results from a
    ** 3-byte type for each of the maximum of 32768 columns plus three
    ** extra bytes for the header length itself.  32768*3 + 3 = 98307.
    */
    if( offset > 98307 || offset > pC->payloadSize ){
      rc = SQLITE_CORRUPT_BKPT;
      goto op_column_error;
    }
















  }

  /* Make sure at least the first p2+1 entries of the header have been
  ** parsed and valid information is in aOffset[] and pC->aType[].
  */
  if( pC->nHdrParsed<=p2 ){
    /* If there is more header available for parsing in the record, try
    ** to extract additional fields up through the p2+1-th field 
    */

    if( pC->iHdrOffset<aOffset[0] ){
      /* Make sure zData points to enough of the record to cover the header. */
      if( pC->aRow==0 ){
        memset(&sMem, 0, sizeof(sMem));
        rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], 
                                     !pC->isTable, &sMem);
        if( rc!=SQLITE_OK ){







<
<
<
<
<
<
<
<














>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









>







71331
71332
71333
71334
71335
71336
71337








71338
71339
71340
71341
71342
71343
71344
71345
71346
71347
71348
71349
71350
71351
71352
71353
71354
71355
71356
71357
71358
71359
71360
71361
71362
71363
71364
71365
71366
71367
71368
71369
71370
71371
71372
71373
71374
71375
71376
71377
71378
71379
71380
71381
71382
71383
71384
        goto too_big;
      }
    }
    pC->cacheStatus = p->cacheCtr;
    pC->iHdrOffset = getVarint32(pC->aRow, offset);
    pC->nHdrParsed = 0;
    aOffset[0] = offset;









    /* Make sure a corrupt database has not given us an oversize header.
    ** Do this now to avoid an oversize memory allocation.
    **
    ** Type entries can be between 1 and 5 bytes each.  But 4 and 5 byte
    ** types use so much data space that there can only be 4096 and 32 of
    ** them, respectively.  So the maximum header length results from a
    ** 3-byte type for each of the maximum of 32768 columns plus three
    ** extra bytes for the header length itself.  32768*3 + 3 = 98307.
    */
    if( offset > 98307 || offset > pC->payloadSize ){
      rc = SQLITE_CORRUPT_BKPT;
      goto op_column_error;
    }

    if( avail<offset ){
      /* pC->aRow does not have to hold the entire row, but it does at least
      ** need to cover the header of the record.  If pC->aRow does not contain
      ** the complete header, then set it to zero, forcing the header to be
      ** dynamically allocated. */
      pC->aRow = 0;
      pC->szRow = 0;
    }

    /* The following goto is an optimization.  It can be omitted and
    ** everything will still work.  But OP_Column is measurably faster
    ** by skipping the subsequent conditional, which is always true.
    */
    assert( pC->nHdrParsed<=p2 );         /* Conditional skipped */
    goto op_column_read_header;
  }

  /* Make sure at least the first p2+1 entries of the header have been
  ** parsed and valid information is in aOffset[] and pC->aType[].
  */
  if( pC->nHdrParsed<=p2 ){
    /* If there is more header available for parsing in the record, try
    ** to extract additional fields up through the p2+1-th field 
    */
    op_column_read_header:
    if( pC->iHdrOffset<aOffset[0] ){
      /* Make sure zData points to enough of the record to cover the header. */
      if( pC->aRow==0 ){
        memset(&sMem, 0, sizeof(sMem));
        rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], 
                                     !pC->isTable, &sMem);
        if( rc!=SQLITE_OK ){
71367
71368
71369
71370
71371
71372
71373
71374
71375



71376
71377
71378

71379
71380
71381
71382
71383
71384
71385
71386
71387
71388
71389
      pC->nHdrParsed = i;
      pC->iHdrOffset = (u32)(zHdr - zData);
      if( pC->aRow==0 ){
        sqlite3VdbeMemRelease(&sMem);
        sMem.flags = MEM_Null;
      }
  
      /* If we have read more header data than was contained in the header,
      ** or if the end of the last field appears to be past the end of the



      ** record, or if the end of the last field appears to be before the end
      ** of the record (when all fields present), then we must be dealing 
      ** with a corrupt database.

      */
      if( (zHdr > zEndHdr)
       || (offset > pC->payloadSize)
       || (zHdr==zEndHdr && offset!=pC->payloadSize)
      ){
        rc = SQLITE_CORRUPT_BKPT;
        goto op_column_error;
      }
    }

    /* If after trying to extra new entries from the header, nHdrParsed is







|
|
>
>
>
|
<
<
>

|

<







71415
71416
71417
71418
71419
71420
71421
71422
71423
71424
71425
71426
71427


71428
71429
71430
71431

71432
71433
71434
71435
71436
71437
71438
      pC->nHdrParsed = i;
      pC->iHdrOffset = (u32)(zHdr - zData);
      if( pC->aRow==0 ){
        sqlite3VdbeMemRelease(&sMem);
        sMem.flags = MEM_Null;
      }
  
      /* The record is corrupt if any of the following are true:
      ** (1) the bytes of the header extend past the declared header size
      **          (zHdr>zEndHdr)
      ** (2) the entire header was used but not all data was used
      **          (zHdr==zEndHdr && offset!=pC->payloadSize)
      ** (3) the end of the data extends beyond the end of the record.


      **          (offset > pC->payloadSize)
      */
      if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset!=pC->payloadSize))
       || (offset > pC->payloadSize)

      ){
        rc = SQLITE_CORRUPT_BKPT;
        goto op_column_error;
      }
    }

    /* If after trying to extra new entries from the header, nHdrParsed is
71566
71567
71568
71569
71570
71571
71572
71573
71574
71575
71576
71577
71578
71579
71580

  /* Loop through the elements that will make up the record to figure
  ** out how much space is required for the new record.
  */
  pRec = pLast;
  do{
    assert( memIsValid(pRec) );
    serial_type = sqlite3VdbeSerialType(pRec, file_format);
    len = sqlite3VdbeSerialTypeLen(serial_type);
    if( pRec->flags & MEM_Zero ){
      if( nData ){
        sqlite3VdbeMemExpandBlob(pRec);
      }else{
        nZero += pRec->u.nZero;
        len -= pRec->u.nZero;







|







71615
71616
71617
71618
71619
71620
71621
71622
71623
71624
71625
71626
71627
71628
71629

  /* Loop through the elements that will make up the record to figure
  ** out how much space is required for the new record.
  */
  pRec = pLast;
  do{
    assert( memIsValid(pRec) );
    pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format);
    len = sqlite3VdbeSerialTypeLen(serial_type);
    if( pRec->flags & MEM_Zero ){
      if( nData ){
        sqlite3VdbeMemExpandBlob(pRec);
      }else{
        nZero += pRec->u.nZero;
        len -= pRec->u.nZero;
71615
71616
71617
71618
71619
71620
71621
71622
71623
71624
71625
71626
71627
71628
71629

  /* Write the record */
  i = putVarint32(zNewRecord, nHdr);
  j = nHdr;
  assert( pData0<=pLast );
  pRec = pData0;
  do{
    serial_type = sqlite3VdbeSerialType(pRec, file_format);
    i += putVarint32(&zNewRecord[i], serial_type);            /* serial type */
    j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */
  }while( (++pRec)<=pLast );
  assert( i==nHdr );
  assert( j==nByte );

  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );







|







71664
71665
71666
71667
71668
71669
71670
71671
71672
71673
71674
71675
71676
71677
71678

  /* Write the record */
  i = putVarint32(zNewRecord, nHdr);
  j = nHdr;
  assert( pData0<=pLast );
  pRec = pData0;
  do{
    serial_type = pRec->uTemp;
    i += putVarint32(&zNewRecord[i], serial_type);            /* serial type */
    j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */
  }while( (++pRec)<=pLast );
  assert( i==nHdr );
  assert( j==nByte );

  assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
72514
72515
72516
72517
72518
72519
72520
72521
72522
72523
72524
72525
72526
72527
72528
    ** blob, or NULL.  But it needs to be an integer before we can do
    ** the seek, so convert it. */
    pIn3 = &aMem[pOp->p3];
    if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
      applyNumericAffinity(pIn3, 0);
    }
    iKey = sqlite3VdbeIntValue(pIn3);
    pC->rowidIsValid = 0;

    /* If the P3 value could not be converted into an integer without
    ** loss of information, then special processing is required... */
    if( (pIn3->flags & MEM_Int)==0 ){
      if( (pIn3->flags & MEM_Real)==0 ){
        /* If the P3 value cannot be converted into any kind of a number,
        ** then the seek is not possible, so jump to P2 */







<







72563
72564
72565
72566
72567
72568
72569

72570
72571
72572
72573
72574
72575
72576
    ** blob, or NULL.  But it needs to be an integer before we can do
    ** the seek, so convert it. */
    pIn3 = &aMem[pOp->p3];
    if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
      applyNumericAffinity(pIn3, 0);
    }
    iKey = sqlite3VdbeIntValue(pIn3);


    /* If the P3 value could not be converted into an integer without
    ** loss of information, then special processing is required... */
    if( (pIn3->flags & MEM_Int)==0 ){
      if( (pIn3->flags & MEM_Real)==0 ){
        /* If the P3 value cannot be converted into any kind of a number,
        ** then the seek is not possible, so jump to P2 */
72550
72551
72552
72553
72554
72555
72556

72557
72558
72559
72560
72561
72562
72563
72564
72565
72566
72567
72568
72569
72570
        assert( OP_SeekLE==(OP_SeekLT+1) );
        assert( OP_SeekGT==(OP_SeekGE+1) );
        assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) );
        if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
      }
    } 
    rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);

    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }
    if( res==0 ){
      pC->rowidIsValid = 1;
      pC->lastRowid = iKey;
    }
  }else{
    nField = pOp->p4.i;
    assert( pOp->p4type==P4_INT32 );
    assert( nField>0 );
    r.pKeyInfo = pC->pKeyInfo;
    r.nField = (u16)nField;








>



<
<
<
<







72598
72599
72600
72601
72602
72603
72604
72605
72606
72607
72608




72609
72610
72611
72612
72613
72614
72615
        assert( OP_SeekLE==(OP_SeekLT+1) );
        assert( OP_SeekGT==(OP_SeekGE+1) );
        assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) );
        if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
      }
    } 
    rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);
    pC->movetoTarget = iKey;  /* Used by OP_Delete */
    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }




  }else{
    nField = pOp->p4.i;
    assert( pOp->p4type==P4_INT32 );
    assert( nField>0 );
    r.pKeyInfo = pC->pKeyInfo;
    r.nField = (u16)nField;

72586
72587
72588
72589
72590
72591
72592
72593
72594
72595
72596
72597
72598
72599
72600
72601
72602
72603
72604
72605
72606
72607
72608
72609
72610
72611
72612
72613
72614
72615
72616
72617
72618
72619
72620
72621
72622
    { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
#endif
    ExpandBlob(r.aMem);
    rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res);
    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }
    pC->rowidIsValid = 0;
  }
  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;
#ifdef SQLITE_TEST
  sqlite3_search_count++;
#endif
  if( oc>=OP_SeekGE ){  assert( oc==OP_SeekGE || oc==OP_SeekGT );
    if( res<0 || (res==0 && oc==OP_SeekGT) ){
      res = 0;
      rc = sqlite3BtreeNext(pC->pCursor, &res);
      if( rc!=SQLITE_OK ) goto abort_due_to_error;
      pC->rowidIsValid = 0;
    }else{
      res = 0;
    }
  }else{
    assert( oc==OP_SeekLT || oc==OP_SeekLE );
    if( res>0 || (res==0 && oc==OP_SeekLT) ){
      res = 0;
      rc = sqlite3BtreePrevious(pC->pCursor, &res);
      if( rc!=SQLITE_OK ) goto abort_due_to_error;
      pC->rowidIsValid = 0;
    }else{
      /* res might be negative because the table is empty.  Check to
      ** see if this is the case.
      */
      res = sqlite3BtreeEof(pC->pCursor);
    }
  }







<











<









<







72631
72632
72633
72634
72635
72636
72637

72638
72639
72640
72641
72642
72643
72644
72645
72646
72647
72648

72649
72650
72651
72652
72653
72654
72655
72656
72657

72658
72659
72660
72661
72662
72663
72664
    { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
#endif
    ExpandBlob(r.aMem);
    rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res);
    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }

  }
  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;
#ifdef SQLITE_TEST
  sqlite3_search_count++;
#endif
  if( oc>=OP_SeekGE ){  assert( oc==OP_SeekGE || oc==OP_SeekGT );
    if( res<0 || (res==0 && oc==OP_SeekGT) ){
      res = 0;
      rc = sqlite3BtreeNext(pC->pCursor, &res);
      if( rc!=SQLITE_OK ) goto abort_due_to_error;

    }else{
      res = 0;
    }
  }else{
    assert( oc==OP_SeekLT || oc==OP_SeekLE );
    if( res>0 || (res==0 && oc==OP_SeekLT) ){
      res = 0;
      rc = sqlite3BtreePrevious(pC->pCursor, &res);
      if( rc!=SQLITE_OK ) goto abort_due_to_error;

    }else{
      /* res might be negative because the table is empty.  Check to
      ** see if this is the case.
      */
      res = sqlite3BtreeEof(pC->pCursor);
    }
  }
72645
72646
72647
72648
72649
72650
72651
72652
72653
72654
72655
72656
72657
72658
72659
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->pCursor!=0 );
  assert( pC->isTable );
  pC->nullRow = 0;
  pIn2 = &aMem[pOp->p2];
  pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
  pC->rowidIsValid = 0;
  pC->deferredMoveto = 1;
  break;
}
  

/* Opcode: Found P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]







<







72687
72688
72689
72690
72691
72692
72693

72694
72695
72696
72697
72698
72699
72700
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->pCursor!=0 );
  assert( pC->isTable );
  pC->nullRow = 0;
  pIn2 = &aMem[pOp->p2];
  pC->movetoTarget = sqlite3VdbeIntValue(pIn2);

  pC->deferredMoveto = 1;
  break;
}
  

/* Opcode: Found P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
72831
72832
72833
72834
72835
72836
72837
72838
72839
72840
72841
72842
72843
72844
72845
72846
72847
72848
72849
72850
72851
72852
72853
  assert( pC->isTable );
  assert( pC->pseudoTableReg==0 );
  pCrsr = pC->pCursor;
  assert( pCrsr!=0 );
  res = 0;
  iKey = pIn3->u.i;
  rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
  pC->lastRowid = pIn3->u.i;
  pC->rowidIsValid = res==0 ?1:0;
  pC->nullRow = 0;
  pC->cacheStatus = CACHE_STALE;
  pC->deferredMoveto = 0;
  VdbeBranchTaken(res!=0,2);
  if( res!=0 ){
    pc = pOp->p2 - 1;
    assert( pC->rowidIsValid==0 );
  }
  pC->seekResult = res;
  break;
}

/* Opcode: Sequence P1 P2 * * *
** Synopsis: r[P2]=cursor[P1].ctr++







|
<






<







72872
72873
72874
72875
72876
72877
72878
72879

72880
72881
72882
72883
72884
72885

72886
72887
72888
72889
72890
72891
72892
  assert( pC->isTable );
  assert( pC->pseudoTableReg==0 );
  pCrsr = pC->pCursor;
  assert( pCrsr!=0 );
  res = 0;
  iKey = pIn3->u.i;
  rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
  pC->movetoTarget = iKey;  /* Used by OP_Delete */

  pC->nullRow = 0;
  pC->cacheStatus = CACHE_STALE;
  pC->deferredMoveto = 0;
  VdbeBranchTaken(res!=0,2);
  if( res!=0 ){
    pc = pOp->p2 - 1;

  }
  pC->seekResult = res;
  break;
}

/* Opcode: Sequence P1 P2 * * *
** Synopsis: r[P2]=cursor[P1].ctr++
72987
72988
72989
72990
72991
72992
72993
72994
72995
72996
72997
72998
72999
73000
73001
            && (++cnt<100));
      if( rc==SQLITE_OK && res==0 ){
        rc = SQLITE_FULL;   /* IMP: R-38219-53002 */
        goto abort_due_to_error;
      }
      assert( v>0 );  /* EV: R-40812-03570 */
    }
    pC->rowidIsValid = 0;
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
  }
  pOut->u.i = v;
  break;
}








<







73026
73027
73028
73029
73030
73031
73032

73033
73034
73035
73036
73037
73038
73039
            && (++cnt<100));
      if( rc==SQLITE_OK && res==0 ){
        rc = SQLITE_FULL;   /* IMP: R-38219-53002 */
        goto abort_due_to_error;
      }
      assert( v>0 );  /* EV: R-40812-03570 */
    }

    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
  }
  pOut->u.i = v;
  break;
}

73092
73093
73094
73095
73096
73097
73098
73099
73100
73101
73102
73103
73104
73105
73106
  }else{
    nZero = 0;
  }
  rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
                          pData->z, pData->n, nZero,
                          (pOp->p5 & OPFLAG_APPEND)!=0, seekResult
  );
  pC->rowidIsValid = 0;
  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;

  /* Invoke the update-hook if required. */
  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
    zDb = db->aDb[pC->iDb].zName;
    zTbl = pOp->p4.z;







<







73130
73131
73132
73133
73134
73135
73136

73137
73138
73139
73140
73141
73142
73143
  }else{
    nZero = 0;
  }
  rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
                          pData->z, pData->n, nZero,
                          (pOp->p5 & OPFLAG_APPEND)!=0, seekResult
  );

  pC->deferredMoveto = 0;
  pC->cacheStatus = CACHE_STALE;

  /* Invoke the update-hook if required. */
  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
    zDb = db->aDb[pC->iDb].zName;
    zTbl = pOp->p4.z;
73129
73130
73131
73132
73133
73134
73135
73136
73137
73138
73139
73140
73141
73142
73143
73144
73145
73146
73147
73148
73149
73150
73151

73152
73153

73154
73155
73156
73157
73158
73159
73160
73161
73162
73163
73164
73165
73166
73167
73168
73169
**
** If P4 is not NULL, then it is the name of the table that P1 is
** pointing to.  The update hook will be invoked, if it exists.
** If P4 is not NULL then the P1 cursor must have been positioned
** using OP_NotFound prior to invoking this opcode.
*/
case OP_Delete: {
  i64 iKey;
  VdbeCursor *pC;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->pCursor!=0 );  /* Only valid for real tables, no pseudotables */
  iKey = pC->lastRowid;      /* Only used for the update hook */

  /* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
  ** OP_Column on the same table without any intervening operations that
  ** might move or invalidate the cursor.  Hence cursor pC is always pointing
  ** to the row to be deleted and the sqlite3VdbeCursorMoveto() operation
  ** below is always a no-op and cannot fail.  We will run it anyhow, though,
  ** to guard against future changes to the code generator.
  **/

  assert( pC->deferredMoveto==0 );
  rc = sqlite3VdbeCursorMoveto(pC);

  if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;

  rc = sqlite3BtreeDelete(pC->pCursor);
  pC->cacheStatus = CACHE_STALE;

  /* Invoke the update-hook if required. */
  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){
    db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE,
                        db->aDb[pC->iDb].zName, pOp->p4.z, iKey);
    assert( pC->iDb>=0 );
  }
  if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
  break;
}
/* Opcode: ResetCount * * * * *
**







<






|

|
|
|
|
|
|
<
>
|
<
>
|
|






|







73166
73167
73168
73169
73170
73171
73172

73173
73174
73175
73176
73177
73178
73179
73180
73181
73182
73183
73184
73185
73186

73187
73188

73189
73190
73191
73192
73193
73194
73195
73196
73197
73198
73199
73200
73201
73202
73203
73204
73205
**
** If P4 is not NULL, then it is the name of the table that P1 is
** pointing to.  The update hook will be invoked, if it exists.
** If P4 is not NULL then the P1 cursor must have been positioned
** using OP_NotFound prior to invoking this opcode.
*/
case OP_Delete: {

  VdbeCursor *pC;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->pCursor!=0 );  /* Only valid for real tables, no pseudotables */
  assert( pC->deferredMoveto==0 );

#ifdef SQLITE_DEBUG
  /* The seek operation that positioned the cursor prior to OP_Delete will
  ** have also set the pC->movetoTarget field to the rowid of the row that
  ** is being deleted */
  if( pOp->p4.z && pC->isTable ){
    i64 iKey = 0;

    sqlite3BtreeKeySize(pC->pCursor, &iKey);
    assert( pC->movetoTarget==iKey ); 

  }
#endif
 
  rc = sqlite3BtreeDelete(pC->pCursor);
  pC->cacheStatus = CACHE_STALE;

  /* Invoke the update-hook if required. */
  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){
    db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE,
                        db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget);
    assert( pC->iDb>=0 );
  }
  if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
  break;
}
/* Opcode: ResetCount * * * * *
**
73208
73209
73210
73211
73212
73213
73214
73215
73216
73217
73218







73219
73220
73221
73222
73223
73224
73225
73226
73227


73228
73229
73230
73231
73232
73233
73234
  VdbeBranchTaken(res!=0,2);
  if( res ){
    pc = pOp->p2-1;
  }
  break;
};

/* Opcode: SorterData P1 P2 * * *
** Synopsis: r[P2]=data
**
** Write into register P2 the current sorter data for sorter cursor P1.







*/
case OP_SorterData: {
  VdbeCursor *pC;

  pOut = &aMem[pOp->p2];
  pC = p->apCsr[pOp->p1];
  assert( isSorter(pC) );
  rc = sqlite3VdbeSorterRowkey(pC, pOut);
  assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );


  break;
}

/* Opcode: RowData P1 P2 * * *
** Synopsis: r[P2]=data
**
** Write into register P2 the complete row data for cursor P1.







|



>
>
>
>
>
>
>









>
>







73244
73245
73246
73247
73248
73249
73250
73251
73252
73253
73254
73255
73256
73257
73258
73259
73260
73261
73262
73263
73264
73265
73266
73267
73268
73269
73270
73271
73272
73273
73274
73275
73276
73277
73278
73279
  VdbeBranchTaken(res!=0,2);
  if( res ){
    pc = pOp->p2-1;
  }
  break;
};

/* Opcode: SorterData P1 P2 P3 * *
** Synopsis: r[P2]=data
**
** Write into register P2 the current sorter data for sorter cursor P1.
** Then clear the column header cache on cursor P3.
**
** This opcode is normally use to move a record out of the sorter and into
** a register that is the source for a pseudo-table cursor created using
** OpenPseudo.  That pseudo-table cursor is the one that is identified by
** parameter P3.  Clearing the P3 column cache as part of this opcode saves
** us from having to issue a separate NullRow instruction to clear that cache.
*/
case OP_SorterData: {
  VdbeCursor *pC;

  pOut = &aMem[pOp->p2];
  pC = p->apCsr[pOp->p1];
  assert( isSorter(pC) );
  rc = sqlite3VdbeSorterRowkey(pC, pOut);
  assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE;
  break;
}

/* Opcode: RowData P1 P2 * * *
** Synopsis: r[P2]=data
**
** Write into register P2 the complete row data for cursor P1.
73267
73268
73269
73270
73271
73272
73273
73274
73275
73276
73277



73278
73279
73280
73281


73282
73283

73284
73285
73286
73287
73288
73289
73290
73291
73292
73293
73294
73295
73296
73297
73298
73299

73300
73301
73302
73303
73304
73305
73306
73307
  assert( pC->isTable || pOp->opcode!=OP_RowData );
  assert( pC->isTable==0 || pOp->opcode==OP_RowData );
  assert( pC!=0 );
  assert( pC->nullRow==0 );
  assert( pC->pseudoTableReg==0 );
  assert( pC->pCursor!=0 );
  pCrsr = pC->pCursor;
  assert( sqlite3BtreeCursorIsValid(pCrsr) );

  /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
  ** OP_Rewind/Op_Next with no intervening instructions that might invalidate



  ** the cursor.  Hence the following sqlite3VdbeCursorMoveto() call is always
  ** a no-op and can never fail.  But we leave it in place as a safety.
  */
  assert( pC->deferredMoveto==0 );


  rc = sqlite3VdbeCursorMoveto(pC);
  if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;


  if( pC->isTable==0 ){
    assert( !pC->isTable );
    VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
    assert( rc==SQLITE_OK );    /* True because of CursorMoveto() call above */
    if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
      goto too_big;
    }
    n = (u32)n64;
  }else{
    VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n);
    assert( rc==SQLITE_OK );    /* DataSize() cannot fail */
    if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
      goto too_big;
    }
  }

  if( sqlite3VdbeMemClearAndResize(pOut, n) ){
    goto no_mem;
  }
  pOut->n = n;
  MemSetTypeFlag(pOut, MEM_Blob);
  if( pC->isTable==0 ){
    rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
  }else{







<



>
>
>
|
<


>
>

|
>
















>
|







73312
73313
73314
73315
73316
73317
73318

73319
73320
73321
73322
73323
73324
73325

73326
73327
73328
73329
73330
73331
73332
73333
73334
73335
73336
73337
73338
73339
73340
73341
73342
73343
73344
73345
73346
73347
73348
73349
73350
73351
73352
73353
73354
73355
73356
73357
  assert( pC->isTable || pOp->opcode!=OP_RowData );
  assert( pC->isTable==0 || pOp->opcode==OP_RowData );
  assert( pC!=0 );
  assert( pC->nullRow==0 );
  assert( pC->pseudoTableReg==0 );
  assert( pC->pCursor!=0 );
  pCrsr = pC->pCursor;


  /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
  ** OP_Rewind/Op_Next with no intervening instructions that might invalidate
  ** the cursor.  If this where not the case, on of the following assert()s
  ** would fail.  Should this ever change (because of changes in the code
  ** generator) then the fix would be to insert a call to
  ** sqlite3VdbeCursorMoveto().

  */
  assert( pC->deferredMoveto==0 );
  assert( sqlite3BtreeCursorIsValid(pCrsr) );
#if 0  /* Not required due to the previous to assert() statements */
  rc = sqlite3VdbeCursorMoveto(pC);
  if( rc!=SQLITE_OK ) goto abort_due_to_error;
#endif

  if( pC->isTable==0 ){
    assert( !pC->isTable );
    VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
    assert( rc==SQLITE_OK );    /* True because of CursorMoveto() call above */
    if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
      goto too_big;
    }
    n = (u32)n64;
  }else{
    VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n);
    assert( rc==SQLITE_OK );    /* DataSize() cannot fail */
    if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
      goto too_big;
    }
  }
  testcase( n==0 );
  if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){
    goto no_mem;
  }
  pOut->n = n;
  MemSetTypeFlag(pOut, MEM_Blob);
  if( pC->isTable==0 ){
    rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
  }else{
73344
73345
73346
73347
73348
73349
73350
73351
73352
73353
73354
73355
73356
73357
73358
73359
73360
73361
73362
73363
73364
73365
73366
73367
73368
73369
73370
73371
73372
73373
73374
73375
73376
73377
73378
73379
73380
73381
73382
73383
73384
    pModule = pVtab->pModule;
    assert( pModule->xRowid );
    rc = pModule->xRowid(pC->pVtabCursor, &v);
    sqlite3VtabImportErrmsg(p, pVtab);
#endif /* SQLITE_OMIT_VIRTUALTABLE */
  }else{
    assert( pC->pCursor!=0 );
    rc = sqlite3VdbeCursorMoveto(pC);
    if( rc ) goto abort_due_to_error;
    if( pC->rowidIsValid ){
      v = pC->lastRowid;
    }else{
      rc = sqlite3BtreeKeySize(pC->pCursor, &v);
      assert( rc==SQLITE_OK );  /* Always so because of CursorMoveto() above */
    }
  }
  pOut->u.i = v;
  break;
}

/* Opcode: NullRow P1 * * * *
**
** Move the cursor P1 to a null row.  Any OP_Column operations
** that occur while the cursor is on the null row will always
** write a NULL.
*/
case OP_NullRow: {
  VdbeCursor *pC;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  pC->nullRow = 1;
  pC->rowidIsValid = 0;
  pC->cacheStatus = CACHE_STALE;
  if( pC->pCursor ){
    sqlite3BtreeClearCursor(pC->pCursor);
  }
  break;
}








|

<
<
<
|
|
<


















<







73394
73395
73396
73397
73398
73399
73400
73401
73402



73403
73404

73405
73406
73407
73408
73409
73410
73411
73412
73413
73414
73415
73416
73417
73418
73419
73420
73421
73422

73423
73424
73425
73426
73427
73428
73429
    pModule = pVtab->pModule;
    assert( pModule->xRowid );
    rc = pModule->xRowid(pC->pVtabCursor, &v);
    sqlite3VtabImportErrmsg(p, pVtab);
#endif /* SQLITE_OMIT_VIRTUALTABLE */
  }else{
    assert( pC->pCursor!=0 );
    rc = sqlite3VdbeCursorRestore(pC);
    if( rc ) goto abort_due_to_error;



    rc = sqlite3BtreeKeySize(pC->pCursor, &v);
    assert( rc==SQLITE_OK );  /* Always so because of CursorRestore() above */

  }
  pOut->u.i = v;
  break;
}

/* Opcode: NullRow P1 * * * *
**
** Move the cursor P1 to a null row.  Any OP_Column operations
** that occur while the cursor is on the null row will always
** write a NULL.
*/
case OP_NullRow: {
  VdbeCursor *pC;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  pC->nullRow = 1;

  pC->cacheStatus = CACHE_STALE;
  if( pC->pCursor ){
    sqlite3BtreeClearCursor(pC->pCursor);
  }
  break;
}

73404
73405
73406
73407
73408
73409
73410
73411
73412
73413
73414
73415
73416
73417
73418
  assert( pC!=0 );
  pCrsr = pC->pCursor;
  res = 0;
  assert( pCrsr!=0 );
  rc = sqlite3BtreeLast(pCrsr, &res);
  pC->nullRow = (u8)res;
  pC->deferredMoveto = 0;
  pC->rowidIsValid = 0;
  pC->cacheStatus = CACHE_STALE;
#ifdef SQLITE_DEBUG
  pC->seekOp = OP_Last;
#endif
  if( pOp->p2>0 ){
    VdbeBranchTaken(res!=0,2);
    if( res ) pc = pOp->p2 - 1;







<







73449
73450
73451
73452
73453
73454
73455

73456
73457
73458
73459
73460
73461
73462
  assert( pC!=0 );
  pCrsr = pC->pCursor;
  res = 0;
  assert( pCrsr!=0 );
  rc = sqlite3BtreeLast(pCrsr, &res);
  pC->nullRow = (u8)res;
  pC->deferredMoveto = 0;

  pC->cacheStatus = CACHE_STALE;
#ifdef SQLITE_DEBUG
  pC->seekOp = OP_Last;
#endif
  if( pOp->p2>0 ){
    VdbeBranchTaken(res!=0,2);
    if( res ) pc = pOp->p2 - 1;
73471
73472
73473
73474
73475
73476
73477
73478
73479
73480
73481
73482
73483
73484
73485
    rc = sqlite3VdbeSorterRewind(pC, &res);
  }else{
    pCrsr = pC->pCursor;
    assert( pCrsr );
    rc = sqlite3BtreeFirst(pCrsr, &res);
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;
    pC->rowidIsValid = 0;
  }
  pC->nullRow = (u8)res;
  assert( pOp->p2>0 && pOp->p2<p->nOp );
  VdbeBranchTaken(res!=0,2);
  if( res ){
    pc = pOp->p2 - 1;
  }







<







73515
73516
73517
73518
73519
73520
73521

73522
73523
73524
73525
73526
73527
73528
    rc = sqlite3VdbeSorterRewind(pC, &res);
  }else{
    pCrsr = pC->pCursor;
    assert( pCrsr );
    rc = sqlite3BtreeFirst(pCrsr, &res);
    pC->deferredMoveto = 0;
    pC->cacheStatus = CACHE_STALE;

  }
  pC->nullRow = (u8)res;
  assert( pOp->p2>0 && pOp->p2<p->nOp );
  VdbeBranchTaken(res!=0,2);
  if( res ){
    pc = pOp->p2 - 1;
  }
73597
73598
73599
73600
73601
73602
73603
73604
73605
73606
73607
73608
73609
73610
73611
    p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
    sqlite3_search_count++;
#endif
  }else{
    pC->nullRow = 1;
  }
  pC->rowidIsValid = 0;
  goto check_for_interrupt;
}

/* Opcode: IdxInsert P1 P2 P3 * P5
** Synopsis: key=r[P2]
**
** Register P2 holds an SQL index key made using the







<







73640
73641
73642
73643
73644
73645
73646

73647
73648
73649
73650
73651
73652
73653
    p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
    sqlite3_search_count++;
#endif
  }else{
    pC->nullRow = 1;
  }

  goto check_for_interrupt;
}

/* Opcode: IdxInsert P1 P2 P3 * P5
** Synopsis: key=r[P2]
**
** Register P2 holds an SQL index key made using the
73713
73714
73715
73716
73717
73718
73719







73720
73721
73722
73723
73724
73725
73726
73727
73728
73729
73730

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  pCrsr = pC->pCursor;
  assert( pCrsr!=0 );
  pOut->flags = MEM_Null;







  rc = sqlite3VdbeCursorMoveto(pC);
  if( NEVER(rc) ) goto abort_due_to_error;
  assert( pC->deferredMoveto==0 );
  assert( pC->isTable==0 );
  if( !pC->nullRow ){
    rowid = 0;  /* Not needed.  Only used to silence a warning. */
    rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid);
    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }
    pOut->u.i = rowid;







>
>
>
>
>
>
>
|
|
|
<







73755
73756
73757
73758
73759
73760
73761
73762
73763
73764
73765
73766
73767
73768
73769
73770
73771

73772
73773
73774
73775
73776
73777
73778

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  pCrsr = pC->pCursor;
  assert( pCrsr!=0 );
  pOut->flags = MEM_Null;
  assert( pC->isTable==0 );
  assert( pC->deferredMoveto==0 );

  /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
  ** out from under the cursor.  That will never happend for an IdxRowid
  ** opcode, hence the NEVER() arround the check of the return value.
  */
  rc = sqlite3VdbeCursorRestore(pC);
  if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;


  if( !pC->nullRow ){
    rowid = 0;  /* Not needed.  Only used to silence a warning. */
    rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid);
    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }
    pOut->u.i = rowid;
78177
78178
78179
78180
78181
78182
78183
78184
78185
78186
78187
78188
78189
78190
78191

  rc = vdbeSorterMergeTreeBuild(pSorter, &pMain);
  if( rc==SQLITE_OK ){
#if SQLITE_MAX_WORKER_THREADS
    assert( pSorter->bUseThreads==0 || pSorter->nTask>1 );
    if( pSorter->bUseThreads ){
      int iTask;
      PmaReader *pReadr;
      SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1];
      rc = vdbeSortAllocUnpacked(pLast);
      if( rc==SQLITE_OK ){
        pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
        pSorter->pReader = pReadr;
        if( pReadr==0 ) rc = SQLITE_NOMEM;
      }







|







78225
78226
78227
78228
78229
78230
78231
78232
78233
78234
78235
78236
78237
78238
78239

  rc = vdbeSorterMergeTreeBuild(pSorter, &pMain);
  if( rc==SQLITE_OK ){
#if SQLITE_MAX_WORKER_THREADS
    assert( pSorter->bUseThreads==0 || pSorter->nTask>1 );
    if( pSorter->bUseThreads ){
      int iTask;
      PmaReader *pReadr = 0;
      SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1];
      rc = vdbeSortAllocUnpacked(pLast);
      if( rc==SQLITE_OK ){
        pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
        pSorter->pReader = pReadr;
        if( pReadr==0 ) rc = SQLITE_NOMEM;
      }
87158
87159
87160
87161
87162
87163
87164
87165
87166
87167
87168
87169
87170
87171
87172
87173
87174
87175
87176
87177
87178
87179
87180
87181
87182
87183

87184
87185
87186
87187
87188
87189
87190
  int c;
  int i;
  tRowcnt v;

#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  if( z==0 ) z = "";
#else
  if( NEVER(z==0) ) z = "";
#endif
  for(i=0; *z && i<nOut; i++){
    v = 0;
    while( (c=z[0])>='0' && c<='9' ){
      v = v*10 + c - '0';
      z++;
    }
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    if( aOut ){
      aOut[i] = v;
    }else
#else
    assert( aOut==0 );
    UNUSED_PARAMETER(aOut);
#endif
    {
      aLog[i] = sqlite3LogEst(v);
    }

    if( *z==' ' ) z++;
  }
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
  assert( pIndex!=0 );
#else
  if( pIndex )
#endif







|








|
|
<



|
<
|
<
>







87206
87207
87208
87209
87210
87211
87212
87213
87214
87215
87216
87217
87218
87219
87220
87221
87222
87223

87224
87225
87226
87227

87228

87229
87230
87231
87232
87233
87234
87235
87236
  int c;
  int i;
  tRowcnt v;

#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  if( z==0 ) z = "";
#else
  assert( z!=0 );
#endif
  for(i=0; *z && i<nOut; i++){
    v = 0;
    while( (c=z[0])>='0' && c<='9' ){
      v = v*10 + c - '0';
      z++;
    }
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    if( aOut ) aOut[i] = v;
    if( aLog ) aLog[i] = sqlite3LogEst(v);

#else
    assert( aOut==0 );
    UNUSED_PARAMETER(aOut);
    assert( aLog!=0 );

    aLog[i] = sqlite3LogEst(v);

#endif
    if( *z==' ' ) z++;
  }
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
  assert( pIndex!=0 );
#else
  if( pIndex )
#endif
87237
87238
87239
87240
87241
87242
87243









87244
87245
87246
87247
87248
87249
87250
87251
87252
    pIndex = sqlite3PrimaryKeyIndex(pTable);
  }else{
    pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
  }
  z = argv[2];

  if( pIndex ){









    pIndex->bUnordered = 0;
    decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex);
    if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
  }else{
    Index fakeIdx;
    fakeIdx.szIdxRow = pTable->szTabRow;
#ifdef SQLITE_ENABLE_COSTMULT
    fakeIdx.pTable = pTable;
#endif







>
>
>
>
>
>
>
>
>

|







87283
87284
87285
87286
87287
87288
87289
87290
87291
87292
87293
87294
87295
87296
87297
87298
87299
87300
87301
87302
87303
87304
87305
87306
87307
    pIndex = sqlite3PrimaryKeyIndex(pTable);
  }else{
    pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
  }
  z = argv[2];

  if( pIndex ){
    int nCol = pIndex->nKeyCol+1;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
    tRowcnt * const aiRowEst = pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(
        sizeof(tRowcnt) * nCol
    );
    if( aiRowEst==0 ) pInfo->db->mallocFailed = 1;
#else
    tRowcnt * const aiRowEst = 0;
#endif
    pIndex->bUnordered = 0;
    decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex);
    if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
  }else{
    Index fakeIdx;
    fakeIdx.szIdxRow = pTable->szTabRow;
#ifdef SQLITE_ENABLE_COSTMULT
    fakeIdx.pTable = pTable;
#endif
87297
87298
87299
87300
87301
87302
87303

87304
87305
87306
87307






87308




87309

87310
87311
87312
87313
87314

87315
87316

87317
87318
87319
87320
87321

87322
87323
87324
87325
87326
87327
87328
87329
      ** sample columns except the last. The last is always set to 1, as
      ** once the trailing PK fields are considered all index keys are
      ** unique.  */
      nCol = pIdx->nSampleCol-1;
      pIdx->aAvgEq[nCol] = 1;
    }
    for(iCol=0; iCol<nCol; iCol++){

      int i;                    /* Used to iterate through samples */
      tRowcnt sumEq = 0;        /* Sum of the nEq values */
      tRowcnt nSum = 0;         /* Number of terms contributing to sumEq */
      tRowcnt avgEq = 0;






      tRowcnt nDLt = pFinal->anDLt[iCol];






      /* Set nSum to the number of distinct (iCol+1) field prefixes that
      ** occur in the stat4 table for this index before pFinal. Set
      ** sumEq to the sum of the nEq values for column iCol for the same
      ** set (adding the value only once where there exist duplicate 
      ** prefixes).  */

      for(i=0; i<(pIdx->nSample-1); i++){
        if( aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){

          sumEq += aSample[i].anEq[iCol];
          nSum++;
        }
      }
      if( nDLt>nSum ){

        avgEq = (pFinal->anLt[iCol] - sumEq)/(nDLt - nSum);
      }
      if( avgEq==0 ) avgEq = 1;
      pIdx->aAvgEq[iCol] = avgEq;
    }
  }
}








>


<

>
>
>
>
>
>
|
>
>
>
>
|
>

|
|
|
<
>
|
|
>

|


|
>
|







87352
87353
87354
87355
87356
87357
87358
87359
87360
87361

87362
87363
87364
87365
87366
87367
87368
87369
87370
87371
87372
87373
87374
87375
87376
87377
87378
87379

87380
87381
87382
87383
87384
87385
87386
87387
87388
87389
87390
87391
87392
87393
87394
87395
87396
87397
      ** sample columns except the last. The last is always set to 1, as
      ** once the trailing PK fields are considered all index keys are
      ** unique.  */
      nCol = pIdx->nSampleCol-1;
      pIdx->aAvgEq[nCol] = 1;
    }
    for(iCol=0; iCol<nCol; iCol++){
      int nSample = pIdx->nSample;
      int i;                    /* Used to iterate through samples */
      tRowcnt sumEq = 0;        /* Sum of the nEq values */

      tRowcnt avgEq = 0;
      tRowcnt nRow;             /* Number of rows in index */
      i64 nSum100 = 0;          /* Number of terms contributing to sumEq */
      i64 nDist100;             /* Number of distinct values in index */

      if( pIdx->aiRowEst==0 || pIdx->aiRowEst[iCol+1]==0 ){
        nRow = pFinal->anLt[iCol];
        nDist100 = (i64)100 * pFinal->anDLt[iCol];
        nSample--;
      }else{
        nRow = pIdx->aiRowEst[0];
        nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1];
      }

      /* Set nSum to the number of distinct (iCol+1) field prefixes that
      ** occur in the stat4 table for this index. Set sumEq to the sum of 
      ** the nEq values for column iCol for the same set (adding the value 
      ** only once where there exist duplicate prefixes).  */

      for(i=0; i<nSample; i++){
        if( i==(pIdx->nSample-1)
         || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] 
        ){
          sumEq += aSample[i].anEq[iCol];
          nSum100 += 100;
        }
      }

      if( nDist100>nSum100 ){
        avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100);
      }
      if( avgEq==0 ) avgEq = 1;
      pIdx->aAvgEq[iCol] = avgEq;
    }
  }
}

87566
87567
87568
87569
87570
87571
87572





87573
87574
87575
87576
87577
87578
87579
  /* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  if( rc==SQLITE_OK ){
    int lookasideEnabled = db->lookaside.bEnabled;
    db->lookaside.bEnabled = 0;
    rc = loadStat4(db, sInfo.zDatabase);
    db->lookaside.bEnabled = lookasideEnabled;





  }
#endif

  if( rc==SQLITE_NOMEM ){
    db->mallocFailed = 1;
  }
  return rc;







>
>
>
>
>







87634
87635
87636
87637
87638
87639
87640
87641
87642
87643
87644
87645
87646
87647
87648
87649
87650
87651
87652
  /* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  if( rc==SQLITE_OK ){
    int lookasideEnabled = db->lookaside.bEnabled;
    db->lookaside.bEnabled = 0;
    rc = loadStat4(db, sInfo.zDatabase);
    db->lookaside.bEnabled = lookasideEnabled;
  }
  for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
    Index *pIdx = sqliteHashData(i);
    sqlite3_free(pIdx->aiRowEst);
    pIdx->aiRowEst = 0;
  }
#endif

  if( rc==SQLITE_NOMEM ){
    db->mallocFailed = 1;
  }
  return rc;
88860
88861
88862
88863
88864
88865
88866



88867
88868
88869
88870
88871
88872
88873
#ifndef SQLITE_OMIT_ANALYZE
  sqlite3DeleteIndexSamples(db, p);
#endif
  if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo);
  sqlite3ExprDelete(db, p->pPartIdxWhere);
  sqlite3DbFree(db, p->zColAff);
  if( p->isResized ) sqlite3DbFree(db, p->azColl);



  sqlite3DbFree(db, p);
}

/*
** For the index called zIdxName which is found in the database iDb,
** unlike that index from its Table then remove the index from
** the index hash table and free all memory structures associated







>
>
>







88933
88934
88935
88936
88937
88938
88939
88940
88941
88942
88943
88944
88945
88946
88947
88948
88949
#ifndef SQLITE_OMIT_ANALYZE
  sqlite3DeleteIndexSamples(db, p);
#endif
  if( db==0 || db->pnBytesFreed==0 ) sqlite3KeyInfoUnref(p->pKeyInfo);
  sqlite3ExprDelete(db, p->pPartIdxWhere);
  sqlite3DbFree(db, p->zColAff);
  if( p->isResized ) sqlite3DbFree(db, p->azColl);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  sqlite3_free(p->aiRowEst);
#endif
  sqlite3DbFree(db, p);
}

/*
** For the index called zIdxName which is found in the database iDb,
** unlike that index from its Table then remove the index from
** the index hash table and free all memory structures associated
91169
91170
91171
91172
91173
91174
91175
91176
91177
91178
91179
91180
91181
91182
91183
    addr2 = sqlite3VdbeCurrentAddr(v);
    sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
                         pIndex->nKeyCol); VdbeCoverage(v);
    sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
  }else{
    addr2 = sqlite3VdbeCurrentAddr(v);
  }
  sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord);
  sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
  sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
  sqlite3ReleaseTempReg(pParse, regRecord);
  sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
  sqlite3VdbeJumpHere(v, addr1);

  sqlite3VdbeAddOp1(v, OP_Close, iTab);







|







91245
91246
91247
91248
91249
91250
91251
91252
91253
91254
91255
91256
91257
91258
91259
    addr2 = sqlite3VdbeCurrentAddr(v);
    sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
                         pIndex->nKeyCol); VdbeCoverage(v);
    sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
  }else{
    addr2 = sqlite3VdbeCurrentAddr(v);
  }
  sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
  sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
  sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
  sqlite3ReleaseTempReg(pParse, regRecord);
  sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
  sqlite3VdbeJumpHere(v, addr1);

  sqlite3VdbeAddOp1(v, OP_Close, iTab);
105112
105113
105114
105115
105116
105117
105118
105119
105120
105121
105122
105123
105124
105125
105126
  int eDest = pDest->eDest;
  int iParm = pDest->iSDParm;
  int regRow;
  int regRowid;
  int nKey;
  int iSortTab;                   /* Sorter cursor to read from */
  int nSortData;                  /* Trailing values to read from sorter */
  u8 p5;                          /* p5 parameter for 1st OP_Column */
  int i;
  int bSeq;                       /* True if sorter record includes seq. no. */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
  struct ExprList_item *aOutEx = p->pEList->a;
#endif

  if( pSort->labelBkOut ){







<







105188
105189
105190
105191
105192
105193
105194

105195
105196
105197
105198
105199
105200
105201
  int eDest = pDest->eDest;
  int iParm = pDest->iSDParm;
  int regRow;
  int regRowid;
  int nKey;
  int iSortTab;                   /* Sorter cursor to read from */
  int nSortData;                  /* Trailing values to read from sorter */

  int i;
  int bSeq;                       /* True if sorter record includes seq. no. */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
  struct ExprList_item *aOutEx = p->pEList->a;
#endif

  if( pSort->labelBkOut ){
105146
105147
105148
105149
105150
105151
105152
105153
105154
105155
105156
105157
105158
105159
105160
105161
105162
105163
105164
105165
105166
105167
105168
105169
105170
105171
105172
      addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    }
    sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
    if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
    addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
    VdbeCoverage(v);
    codeOffset(v, p->iOffset, addrContinue);
    sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
    p5 = OPFLAG_CLEARCACHE;
    bSeq = 0;
  }else{
    addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
    codeOffset(v, p->iOffset, addrContinue);
    iSortTab = iTab;
    p5 = 0;
    bSeq = 1;
  }
  for(i=0; i<nSortData; i++){
    sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
    if( i==0 ) sqlite3VdbeChangeP5(v, p5);
    VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
  }
  switch( eDest ){
    case SRT_Table:
    case SRT_EphemTab: {
      testcase( eDest==SRT_Table );
      testcase( eDest==SRT_EphemTab );







|
<





<




<







105221
105222
105223
105224
105225
105226
105227
105228

105229
105230
105231
105232
105233

105234
105235
105236
105237

105238
105239
105240
105241
105242
105243
105244
      addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
    }
    sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
    if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
    addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
    VdbeCoverage(v);
    codeOffset(v, p->iOffset, addrContinue);
    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;
  }
  for(i=0; i<nSortData; i++){
    sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);

    VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
  }
  switch( eDest ){
    case SRT_Table:
    case SRT_EphemTab: {
      testcase( eDest==SRT_Table );
      testcase( eDest==SRT_EphemTab );
109087
109088
109089
109090
109091
109092
109093
109094
109095
109096
109097
109098
109099
109100
109101
109102
109103
109104
109105
109106
      ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth)
      ** Then compare the current GROUP BY terms against the GROUP BY terms
      ** from the previous row currently stored in a0, a1, a2...
      */
      addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
      sqlite3ExprCacheClear(pParse);
      if( groupBySort ){
        sqlite3VdbeAddOp2(v, OP_SorterData, sAggInfo.sortingIdx, sortOut);
      }
      for(j=0; j<pGroupBy->nExpr; j++){
        if( groupBySort ){
          sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
          if( j==0 ) sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
        }else{
          sAggInfo.directMode = 1;
          sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
        }
      }
      sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
                          (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);







|




<







109159
109160
109161
109162
109163
109164
109165
109166
109167
109168
109169
109170

109171
109172
109173
109174
109175
109176
109177
      ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth)
      ** Then compare the current GROUP BY terms against the GROUP BY terms
      ** from the previous row currently stored in a0, a1, a2...
      */
      addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
      sqlite3ExprCacheClear(pParse);
      if( groupBySort ){
        sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut,sortPTab);
      }
      for(j=0; j<pGroupBy->nExpr; j++){
        if( groupBySort ){
          sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);

        }else{
          sAggInfo.directMode = 1;
          sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
        }
      }
      sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
                          (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
112440
112441
112442
112443
112444
112445
112446

112447
112448
112449
112450
112451
112452
112453
      *pzErr = sqlite3MPrintf(db, "%s", zErr);
      sqlite3_free(zErr);
    }
    sqlite3DbFree(db, pVTable);
  }else if( ALWAYS(pVTable->pVtab) ){
    /* Justification of ALWAYS():  A correct vtab constructor must allocate
    ** the sqlite3_vtab object if successful.  */

    pVTable->pVtab->pModule = pMod->pModule;
    pVTable->nRef = 1;
    if( sCtx.pTab ){
      const char *zFormat = "vtable constructor did not declare schema: %s";
      *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
      sqlite3VtabUnlock(pVTable);
      rc = SQLITE_ERROR;







>







112511
112512
112513
112514
112515
112516
112517
112518
112519
112520
112521
112522
112523
112524
112525
      *pzErr = sqlite3MPrintf(db, "%s", zErr);
      sqlite3_free(zErr);
    }
    sqlite3DbFree(db, pVTable);
  }else if( ALWAYS(pVTable->pVtab) ){
    /* Justification of ALWAYS():  A correct vtab constructor must allocate
    ** the sqlite3_vtab object if successful.  */
    memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
    pVTable->pVtab->pModule = pMod->pModule;
    pVTable->nRef = 1;
    if( sCtx.pTab ){
      const char *zFormat = "vtable constructor did not declare schema: %s";
      *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
      sqlite3VtabUnlock(pVTable);
      rc = SQLITE_ERROR;
115690
115691
115692
115693
115694
115695
115696








115697
115698
115699
115700
115701
115702
115703
115704
115705
115706
115707
115708
115709
115710
115711
115712
115713
115714
115715
115716
115717
115718
115719
115720
115721
115722
115723
115724
115725
115726
115727
115728
115729
115730
      }else{
        /* Note: this call could be optimized away - since the same values must 
        ** have been requested when testing key $P in whereEqualScanEst().  */
        whereKeyStats(pParse, p, pRec, 0, a);
        iLower = a[0];
        iUpper = a[0] + a[1];
      }









      /* If possible, improve on the iLower estimate using ($P:$L). */
      if( pLower ){
        int bOk;                    /* True if value is extracted from pExpr */
        Expr *pExpr = pLower->pExpr->pRight;
        assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
        if( rc==SQLITE_OK && bOk ){
          tRowcnt iNew;
          whereKeyStats(pParse, p, pRec, 0, a);
          iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
          if( iNew>iLower ) iLower = iNew;
          nOut--;
          pLower = 0;
        }
      }

      /* If possible, improve on the iUpper estimate using ($P:$U). */
      if( pUpper ){
        int bOk;                    /* True if value is extracted from pExpr */
        Expr *pExpr = pUpper->pExpr->pRight;
        assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
        if( rc==SQLITE_OK && bOk ){
          tRowcnt iNew;
          whereKeyStats(pParse, p, pRec, 1, a);
          iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
          if( iNew<iUpper ) iUpper = iNew;
          nOut--;
          pUpper = 0;
        }
      }

      pBuilder->pRec = pRec;







>
>
>
>
>
>
>
>





<




|










<




|







115762
115763
115764
115765
115766
115767
115768
115769
115770
115771
115772
115773
115774
115775
115776
115777
115778
115779
115780
115781

115782
115783
115784
115785
115786
115787
115788
115789
115790
115791
115792
115793
115794
115795
115796

115797
115798
115799
115800
115801
115802
115803
115804
115805
115806
115807
115808
      }else{
        /* Note: this call could be optimized away - since the same values must 
        ** have been requested when testing key $P in whereEqualScanEst().  */
        whereKeyStats(pParse, p, pRec, 0, a);
        iLower = a[0];
        iUpper = a[0] + a[1];
      }

      assert( pLower==0 || (pLower->eOperator & (WO_GT|WO_GE))!=0 );
      assert( pUpper==0 || (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
      assert( p->aSortOrder!=0 );
      if( p->aSortOrder[nEq] ){
        /* The roles of pLower and pUpper are swapped for a DESC index */
        SWAP(WhereTerm*, pLower, pUpper);
      }

      /* If possible, improve on the iLower estimate using ($P:$L). */
      if( pLower ){
        int bOk;                    /* True if value is extracted from pExpr */
        Expr *pExpr = pLower->pExpr->pRight;

        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
        if( rc==SQLITE_OK && bOk ){
          tRowcnt iNew;
          whereKeyStats(pParse, p, pRec, 0, a);
          iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
          if( iNew>iLower ) iLower = iNew;
          nOut--;
          pLower = 0;
        }
      }

      /* If possible, improve on the iUpper estimate using ($P:$U). */
      if( pUpper ){
        int bOk;                    /* True if value is extracted from pExpr */
        Expr *pExpr = pUpper->pExpr->pRight;

        rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
        if( rc==SQLITE_OK && bOk ){
          tRowcnt iNew;
          whereKeyStats(pParse, p, pRec, 1, a);
          iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
          if( iNew<iUpper ) iUpper = iNew;
          nOut--;
          pUpper = 0;
        }
      }

      pBuilder->pRec = pRec;
116215
116216
116217
116218
116219
116220
116221
116222
116223
116224
116225
116226
116227
116228
116229
116230
116231
116232
116233
116234
116235
116236
116237
116238
116239
116240
116241
116242
116243
116244
116245
116246
116247
116248
116249
116250
116251
116252
116253
116254
116255
116256
116257
116258
116259
116260
116261
116262
116263
116264
116265
116266
116267
116268
116269
116270
116271
116272
116273
116274
116275
116276
116277
116278
116279
116280
116281
116282
116283
  sqlite3StrAccumAppendAll(pStr, zColumn);
  sqlite3StrAccumAppend(pStr, zOp, 1);
  sqlite3StrAccumAppend(pStr, "?", 1);
}

/*
** Argument pLevel describes a strategy for scanning table pTab. This 
** function returns a pointer to a string buffer containing a description
** of the subset of table rows scanned by the strategy in the form of an
** SQL expression. Or, if all rows are scanned, NULL is returned.
**
** For example, if the query:
**
**   SELECT * FROM t1 WHERE a=1 AND b>2;
**
** is run and there is an index on (a, b), then this function returns a
** string similar to:
**
**   "a=? AND b>?"
**
** The returned pointer points to memory obtained from sqlite3DbMalloc().
** It is the responsibility of the caller to free the buffer when it is
** no longer required.
*/
static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){
  Index *pIndex = pLoop->u.btree.pIndex;
  u16 nEq = pLoop->u.btree.nEq;
  u16 nSkip = pLoop->u.btree.nSkip;
  int i, j;
  Column *aCol = pTab->aCol;
  i16 *aiColumn = pIndex->aiColumn;
  StrAccum txt;

  if( nEq==0 && (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){
    return 0;
  }
  sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH);
  txt.db = db;
  sqlite3StrAccumAppend(&txt, " (", 2);
  for(i=0; i<nEq; i++){
    char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName;
    if( i>=nSkip ){
      explainAppendTerm(&txt, i, z, "=");
    }else{
      if( i ) sqlite3StrAccumAppend(&txt, " AND ", 5);
      sqlite3StrAccumAppend(&txt, "ANY(", 4);
      sqlite3StrAccumAppendAll(&txt, z);
      sqlite3StrAccumAppend(&txt, ")", 1);
    }
  }

  j = i;
  if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
    char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
    explainAppendTerm(&txt, i++, z, ">");
  }
  if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
    char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
    explainAppendTerm(&txt, i, z, "<");
  }
  sqlite3StrAccumAppend(&txt, ")", 1);
  return sqlite3StrAccumFinish(&txt);
}

/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single
** record is added to the output to describe the table scan strategy in 
** pLevel.







|
|
<









<
<
<
<

|






<

|
<
<
<
<
|



|

|
<
|
<






|



|

|
<







116293
116294
116295
116296
116297
116298
116299
116300
116301

116302
116303
116304
116305
116306
116307
116308
116309
116310




116311
116312
116313
116314
116315
116316
116317
116318

116319
116320




116321
116322
116323
116324
116325
116326
116327

116328

116329
116330
116331
116332
116333
116334
116335
116336
116337
116338
116339
116340
116341

116342
116343
116344
116345
116346
116347
116348
  sqlite3StrAccumAppendAll(pStr, zColumn);
  sqlite3StrAccumAppend(pStr, zOp, 1);
  sqlite3StrAccumAppend(pStr, "?", 1);
}

/*
** Argument pLevel describes a strategy for scanning table pTab. This 
** function appends text to pStr that describes the subset of table
** rows scanned by the strategy in the form of an SQL expression.

**
** For example, if the query:
**
**   SELECT * FROM t1 WHERE a=1 AND b>2;
**
** is run and there is an index on (a, b), then this function returns a
** string similar to:
**
**   "a=? AND b>?"




*/
static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
  Index *pIndex = pLoop->u.btree.pIndex;
  u16 nEq = pLoop->u.btree.nEq;
  u16 nSkip = pLoop->u.btree.nSkip;
  int i, j;
  Column *aCol = pTab->aCol;
  i16 *aiColumn = pIndex->aiColumn;


  if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;




  sqlite3StrAccumAppend(pStr, " (", 2);
  for(i=0; i<nEq; i++){
    char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName;
    if( i>=nSkip ){
      explainAppendTerm(pStr, i, z, "=");
    }else{
      if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);

      sqlite3XPrintf(pStr, 0, "ANY(%s)", z);

    }
  }

  j = i;
  if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
    char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
    explainAppendTerm(pStr, i++, z, ">");
  }
  if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
    char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
    explainAppendTerm(pStr, i, z, "<");
  }
  sqlite3StrAccumAppend(pStr, ")", 1);

}

/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single
** record is added to the output to describe the table scan strategy in 
** pLevel.
116293
116294
116295
116296
116297
116298
116299
116300
116301
116302
116303
116304



116305
116306
116307
116308
116309
116310
116311
116312
116313


116314
116315
116316
116317
116318
116319
116320
116321
116322
116323
116324
116325
116326
116327
116328
116329


116330
116331

116332

116333
116334
116335
116336
116337
116338
116339
116340
116341



116342
116343
116344
116345
116346
116347
116348
116349
116350

116351
116352
116353


116354
116355
116356
116357
116358
116359
116360







116361
116362
116363
116364
116365
116366
116367
116368
#ifndef SQLITE_DEBUG
  if( pParse->explain==2 )
#endif
  {
    struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
    Vdbe *v = pParse->pVdbe;      /* VM being constructed */
    sqlite3 *db = pParse->db;     /* Database handle */
    char *zMsg;                   /* Text to add to EQP output */
    int iId = pParse->iSelectId;  /* Select id (left-most output column) */
    int isSearch;                 /* True for a SEARCH. False for SCAN. */
    WhereLoop *pLoop;             /* The controlling WhereLoop object */
    u32 flags;                    /* Flags that describe this loop */




    pLoop = pLevel->pWLoop;
    flags = pLoop->wsFlags;
    if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return;

    isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
            || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
            || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));



    zMsg = sqlite3MPrintf(db, "%s", isSearch?"SEARCH":"SCAN");
    if( pItem->pSelect ){
      zMsg = sqlite3MAppendf(db, zMsg, "%s SUBQUERY %d", zMsg,pItem->iSelectId);
    }else{
      zMsg = sqlite3MAppendf(db, zMsg, "%s TABLE %s", zMsg, pItem->zName);
    }

    if( pItem->zAlias ){
      zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
    }
    if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0
     && ALWAYS(pLoop->u.btree.pIndex!=0)
    ){
      const char *zFmt;
      Index *pIdx = pLoop->u.btree.pIndex;
      char *zWhere = explainIndexRange(db, pLoop, pItem->pTab);


      assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
      if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){

        zFmt = zWhere ? "%s USING PRIMARY KEY%.0s%s" : "%s%.0s%s";

      }else if( flags & WHERE_AUTO_INDEX ){
        zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s";
      }else if( flags & WHERE_IDX_ONLY ){
        zFmt = "%s USING COVERING INDEX %s%s";
      }else{
        zFmt = "%s USING INDEX %s%s";
      }
      zMsg = sqlite3MAppendf(db, zMsg, zFmt, zMsg, pIdx->zName, zWhere);
      sqlite3DbFree(db, zWhere);



    }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
      zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg);

      if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
        zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg);
      }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
        zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid<?)", zMsg);
      }else if( flags&WHERE_BTM_LIMIT ){
        zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>?)", zMsg);

      }else if( ALWAYS(flags&WHERE_TOP_LIMIT) ){
        zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid<?)", zMsg);
      }


    }
#ifndef SQLITE_OMIT_VIRTUALTABLE
    else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
      zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
                  pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
    }
#endif







    zMsg = sqlite3MAppendf(db, zMsg, "%s", zMsg);
    sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC);
  }
}
#else
# define explainOneScan(u,v,w,x,y,z)
#endif /* SQLITE_OMIT_EXPLAIN */








<




>
>
>









>
>
|

|

|



|

|
<
<
|
|
|
>
>


>
|
>

|

|

|

|
|
>
>
>

<
|

|

|

|
>
|
|

>
>



|



>
>
>
>
>
>
>
|







116358
116359
116360
116361
116362
116363
116364

116365
116366
116367
116368
116369
116370
116371
116372
116373
116374
116375
116376
116377
116378
116379
116380
116381
116382
116383
116384
116385
116386
116387
116388
116389
116390
116391
116392
116393


116394
116395
116396
116397
116398
116399
116400
116401
116402
116403
116404
116405
116406
116407
116408
116409
116410
116411
116412
116413
116414
116415
116416

116417
116418
116419
116420
116421
116422
116423
116424
116425
116426
116427
116428
116429
116430
116431
116432
116433
116434
116435
116436
116437
116438
116439
116440
116441
116442
116443
116444
116445
116446
116447
116448
116449
116450
116451
#ifndef SQLITE_DEBUG
  if( pParse->explain==2 )
#endif
  {
    struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
    Vdbe *v = pParse->pVdbe;      /* VM being constructed */
    sqlite3 *db = pParse->db;     /* Database handle */

    int iId = pParse->iSelectId;  /* Select id (left-most output column) */
    int isSearch;                 /* True for a SEARCH. False for SCAN. */
    WhereLoop *pLoop;             /* The controlling WhereLoop object */
    u32 flags;                    /* Flags that describe this loop */
    char *zMsg;                   /* Text to add to EQP output */
    StrAccum str;                 /* EQP output string */
    char zBuf[100];               /* Initial space for EQP output string */

    pLoop = pLevel->pWLoop;
    flags = pLoop->wsFlags;
    if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return;

    isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
            || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
            || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));

    sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
    str.db = db;
    sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
    if( pItem->pSelect ){
      sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
    }else{
      sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName);
    }

    if( pItem->zAlias ){
      sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias);
    }
    if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){


      const char *zFmt = 0;
      Index *pIdx;

      assert( pLoop->u.btree.pIndex!=0 );
      pIdx = pLoop->u.btree.pIndex;
      assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
      if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
        if( isSearch ){
          zFmt = "PRIMARY KEY";
        }
      }else if( flags & WHERE_AUTO_INDEX ){
        zFmt = "AUTOMATIC COVERING INDEX";
      }else if( flags & WHERE_IDX_ONLY ){
        zFmt = "COVERING INDEX %s";
      }else{
        zFmt = "INDEX %s";
      }
      if( zFmt ){
        sqlite3StrAccumAppend(&str, " USING ", 7);
        sqlite3XPrintf(&str, 0, zFmt, pIdx->zName);
        explainIndexRange(&str, pLoop, pItem->pTab);
      }
    }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){

      const char *zRange;
      if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
        zRange = "(rowid=?)";
      }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
        zRange = "(rowid>? AND rowid<?)";
      }else if( flags&WHERE_BTM_LIMIT ){
        zRange = "(rowid>?)";
      }else{
        assert( flags&WHERE_TOP_LIMIT);
        zRange = "(rowid<?)";
      }
      sqlite3StrAccumAppendAll(&str, " USING INTEGER PRIMARY KEY ");
      sqlite3StrAccumAppendAll(&str, zRange);
    }
#ifndef SQLITE_OMIT_VIRTUALTABLE
    else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
      sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s",
                  pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
    }
#endif
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
    if( pLoop->nOut>=10 ){
      sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
    }else{
      sqlite3StrAccumAppend(&str, " (~1 row)", 9);
    }
#endif
    zMsg = sqlite3StrAccumFinish(&str);
    sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC);
  }
}
#else
# define explainOneScan(u,v,w,x,y,z)
#endif /* SQLITE_OMIT_EXPLAIN */

117623
117624
117625
117626
117627
117628
117629
117630
117631
117632
117633
117634
117635
117636
117637
117638
117639
117640
117641
117642
117643
117644
117645
117646
117647
117648
117649
117650
117651
117652
117653
117654
117655
117656
  ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);

  if( ppPrev==0 ){
    /* There already exists a WhereLoop on the list that is better
    ** than pTemplate, so just ignore pTemplate */
#if WHERETRACE_ENABLED /* 0x8 */
    if( sqlite3WhereTrace & 0x8 ){
      sqlite3DebugPrintf("ins-noop: ");
      whereLoopPrint(pTemplate, pBuilder->pWC);
    }
#endif
    return SQLITE_OK;  
  }else{
    p = *ppPrev;
  }

  /* If we reach this point it means that either p[] should be overwritten
  ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new
  ** WhereLoop and insert it.
  */
#if WHERETRACE_ENABLED /* 0x8 */
  if( sqlite3WhereTrace & 0x8 ){
    if( p!=0 ){
      sqlite3DebugPrintf("ins-del:  ");
      whereLoopPrint(p, pBuilder->pWC);
    }
    sqlite3DebugPrintf("ins-new:  ");
    whereLoopPrint(pTemplate, pBuilder->pWC);
  }
#endif
  if( p==0 ){
    /* Allocate a new WhereLoop to add to the end of the list */
    *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
    if( p==0 ) return SQLITE_NOMEM;







|















|


|







117706
117707
117708
117709
117710
117711
117712
117713
117714
117715
117716
117717
117718
117719
117720
117721
117722
117723
117724
117725
117726
117727
117728
117729
117730
117731
117732
117733
117734
117735
117736
117737
117738
117739
  ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);

  if( ppPrev==0 ){
    /* There already exists a WhereLoop on the list that is better
    ** than pTemplate, so just ignore pTemplate */
#if WHERETRACE_ENABLED /* 0x8 */
    if( sqlite3WhereTrace & 0x8 ){
      sqlite3DebugPrintf("   skip: ");
      whereLoopPrint(pTemplate, pBuilder->pWC);
    }
#endif
    return SQLITE_OK;  
  }else{
    p = *ppPrev;
  }

  /* If we reach this point it means that either p[] should be overwritten
  ** with pTemplate[] if p[] exists, or if p==NULL then allocate a new
  ** WhereLoop and insert it.
  */
#if WHERETRACE_ENABLED /* 0x8 */
  if( sqlite3WhereTrace & 0x8 ){
    if( p!=0 ){
      sqlite3DebugPrintf("replace: ");
      whereLoopPrint(p, pBuilder->pWC);
    }
    sqlite3DebugPrintf("    add: ");
    whereLoopPrint(pTemplate, pBuilder->pWC);
  }
#endif
  if( p==0 ){
    /* Allocate a new WhereLoop to add to the end of the list */
    *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
    if( p==0 ) return SQLITE_NOMEM;
117666
117667
117668
117669
117670
117671
117672
117673
117674
117675
117676
117677
117678
117679
117680
      ppTail = whereLoopFindLesser(ppTail, pTemplate);
      if( ppTail==0 ) break;
      pToDel = *ppTail;
      if( pToDel==0 ) break;
      *ppTail = pToDel->pNextLoop;
#if WHERETRACE_ENABLED /* 0x8 */
      if( sqlite3WhereTrace & 0x8 ){
        sqlite3DebugPrintf("ins-del:  ");
        whereLoopPrint(pToDel, pBuilder->pWC);
      }
#endif
      whereLoopDelete(db, pToDel);
    }
  }
  whereLoopXfer(db, p, pTemplate);







|







117749
117750
117751
117752
117753
117754
117755
117756
117757
117758
117759
117760
117761
117762
117763
      ppTail = whereLoopFindLesser(ppTail, pTemplate);
      if( ppTail==0 ) break;
      pToDel = *ppTail;
      if( pToDel==0 ) break;
      *ppTail = pToDel->pNextLoop;
#if WHERETRACE_ENABLED /* 0x8 */
      if( sqlite3WhereTrace & 0x8 ){
        sqlite3DebugPrintf(" delete: ");
        whereLoopPrint(pToDel, pBuilder->pWC);
      }
#endif
      whereLoopDelete(db, pToDel);
    }
  }
  whereLoopXfer(db, p, pTemplate);
118833
118834
118835
118836
118837
118838
118839
118840
118841
118842
118843
118844
118845
118846
118847
            pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
            if( !pColl ) pColl = db->pDfltColl;
            if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
          }
          isMatch = 1;
          break;
        }
        if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
          /* Make sure the sort order is compatible in an ORDER BY clause.
          ** Sort order is irrelevant for a GROUP BY clause. */
          if( revSet ){
            if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0;
          }else{
            rev = revIdx ^ pOrderBy->a[i].sortOrder;
            if( rev ) *pRevMask |= MASKBIT(iLoop);







|







118916
118917
118918
118919
118920
118921
118922
118923
118924
118925
118926
118927
118928
118929
118930
            pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
            if( !pColl ) pColl = db->pDfltColl;
            if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
          }
          isMatch = 1;
          break;
        }
        if( isMatch && (wctrlFlags & WHERE_GROUPBY)==0 ){
          /* Make sure the sort order is compatible in an ORDER BY clause.
          ** Sort order is irrelevant for a GROUP BY clause. */
          if( revSet ){
            if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0;
          }else{
            rev = revIdx ^ pOrderBy->a[i].sortOrder;
            if( rev ) *pRevMask |= MASKBIT(iLoop);
119298
119299
119300
119301
119302
119303
119304
119305
119306
119307
119308
119309

119310


119311
119312
119313
119314
119315
119316
119317
      pWInfo->nOBSat = pFrom->isOrdered;
      if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
      pWInfo->revMask = pFrom->revLoop;
    }
    if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
        && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr
    ){
      Bitmask notUsed = 0;
      int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, 
          pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &notUsed
      );
      assert( pWInfo->sorted==0 );

      pWInfo->sorted = (nOrder==pWInfo->pOrderBy->nExpr);


    }
  }


  pWInfo->nRowOut = pFrom->nRow;

  /* Free temporary memory and return success */







|

|


>
|
>
>







119381
119382
119383
119384
119385
119386
119387
119388
119389
119390
119391
119392
119393
119394
119395
119396
119397
119398
119399
119400
119401
119402
119403
      pWInfo->nOBSat = pFrom->isOrdered;
      if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
      pWInfo->revMask = pFrom->revLoop;
    }
    if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
        && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr
    ){
      Bitmask revMask = 0;
      int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, 
          pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask
      );
      assert( pWInfo->sorted==0 );
      if( nOrder==pWInfo->pOrderBy->nExpr ){
        pWInfo->sorted = 1;
        pWInfo->revMask = revMask;
      }
    }
  }


  pWInfo->nRowOut = pFrom->nRow;

  /* Free temporary memory and return success */
120192
120193
120194
120195
120196
120197
120198
120199
120200
120201
120202
120203
120204
120205
120206
    pOut->zEnd = &pPostOp->z[pPostOp->n];
  }                           

  /* A routine to convert a binary TK_IS or TK_ISNOT expression into a
  ** unary TK_ISNULL or TK_NOTNULL expression. */
  static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
    sqlite3 *db = pParse->db;
    if( db->mallocFailed==0 && pY->op==TK_NULL ){
      pA->op = (u8)op;
      sqlite3ExprDelete(db, pA->pRight);
      pA->pRight = 0;
    }
  }

  /* Construct an expression node for a unary prefix operator







|







120278
120279
120280
120281
120282
120283
120284
120285
120286
120287
120288
120289
120290
120291
120292
    pOut->zEnd = &pPostOp->z[pPostOp->n];
  }                           

  /* A routine to convert a binary TK_IS or TK_ISNOT expression into a
  ** unary TK_ISNULL or TK_NOTNULL expression. */
  static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
    sqlite3 *db = pParse->db;
    if( pY && pA && pY->op==TK_NULL ){
      pA->op = (u8)op;
      sqlite3ExprDelete(db, pA->pRight);
      pA->pRight = 0;
    }
  }

  /* Construct an expression node for a unary prefix operator
125293
125294
125295
125296
125297
125298
125299





125300
125301
125302
125303
125304
125305
125306
      */
      typedef void(*LOGFUNC_t)(void*,int,const char*);
      sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t);
      sqlite3GlobalConfig.pLogArg = va_arg(ap, void*);
      break;
    }






    case SQLITE_CONFIG_URI: {
      sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
      break;
    }

    case SQLITE_CONFIG_COVERING_INDEX_SCAN: {
      sqlite3GlobalConfig.bUseCis = va_arg(ap, int);







>
>
>
>
>







125379
125380
125381
125382
125383
125384
125385
125386
125387
125388
125389
125390
125391
125392
125393
125394
125395
125396
125397
      */
      typedef void(*LOGFUNC_t)(void*,int,const char*);
      sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t);
      sqlite3GlobalConfig.pLogArg = va_arg(ap, void*);
      break;
    }

    /* EVIDENCE-OF: R-55548-33817 The compile-time setting for URI filenames
    ** can be changed at start-time using the
    ** sqlite3_config(SQLITE_CONFIG_URI,1) or
    ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls.
    */
    case SQLITE_CONFIG_URI: {
      sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
      break;
    }

    case SQLITE_CONFIG_COVERING_INDEX_SCAN: {
      sqlite3GlobalConfig.bUseCis = va_arg(ap, int);
127030
127031
127032
127033
127034
127035
127036
127037
127038
127039
127040
127041
127042
127043
127044
  char *zFile;
  char c;
  int nUri = sqlite3Strlen30(zUri);

  assert( *pzErrMsg==0 );

  if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) 
   && nUri>=5 && memcmp(zUri, "file:", 5)==0 
  ){
    char *zOpt;
    int eState;                   /* Parser state when parsing URI */
    int iIn;                      /* Input character index */
    int iOut = 0;                 /* Output character index */
    int nByte = nUri+2;           /* Bytes of space to allocate */








|







127121
127122
127123
127124
127125
127126
127127
127128
127129
127130
127131
127132
127133
127134
127135
  char *zFile;
  char c;
  int nUri = sqlite3Strlen30(zUri);

  assert( *pzErrMsg==0 );

  if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) 
   && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
  ){
    char *zOpt;
    int eState;                   /* Parser state when parsing URI */
    int iIn;                      /* Input character index */
    int iOut = 0;                 /* Output character index */
    int nByte = nUri+2;           /* Bytes of space to allocate */

127260
127261
127262
127263
127264
127265
127266
127267


127268
127269
127270
127271
127272
127273
127274
  */
  assert( SQLITE_OPEN_READONLY  == 0x01 );
  assert( SQLITE_OPEN_READWRITE == 0x02 );
  assert( SQLITE_OPEN_CREATE    == 0x04 );
  testcase( (1<<(flags&7))==0x02 ); /* READONLY */
  testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
  testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
  if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE_BKPT;



  if( sqlite3GlobalConfig.bCoreMutex==0 ){
    isThreadsafe = 0;
  }else if( flags & SQLITE_OPEN_NOMUTEX ){
    isThreadsafe = 0;
  }else if( flags & SQLITE_OPEN_FULLMUTEX ){
    isThreadsafe = 1;







|
>
>







127351
127352
127353
127354
127355
127356
127357
127358
127359
127360
127361
127362
127363
127364
127365
127366
127367
  */
  assert( SQLITE_OPEN_READONLY  == 0x01 );
  assert( SQLITE_OPEN_READWRITE == 0x02 );
  assert( SQLITE_OPEN_CREATE    == 0x04 );
  testcase( (1<<(flags&7))==0x02 ); /* READONLY */
  testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
  testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
  if( ((1<<(flags&7)) & 0x46)==0 ){
    return SQLITE_MISUSE_BKPT;  /* IMP: R-65497-44594 */
  }

  if( sqlite3GlobalConfig.bCoreMutex==0 ){
    isThreadsafe = 0;
  }else if( flags & SQLITE_OPEN_NOMUTEX ){
    isThreadsafe = 0;
  }else if( flags & SQLITE_OPEN_FULLMUTEX ){
    isThreadsafe = 1;
132603
132604
132605
132606
132607
132608
132609

132610
132611
132612
132613
132614
132615
132616
  if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++];
  if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++];
  assert( iIdx==nVal );

  /* In case the cursor has been used before, clear it now. */
  sqlite3_finalize(pCsr->pStmt);
  sqlite3_free(pCsr->aDoclist);

  sqlite3Fts3ExprFree(pCsr->pExpr);
  memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));

  /* Set the lower and upper bounds on docids to return */
  pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64);
  pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64);








>







132696
132697
132698
132699
132700
132701
132702
132703
132704
132705
132706
132707
132708
132709
132710
  if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++];
  if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++];
  assert( iIdx==nVal );

  /* In case the cursor has been used before, clear it now. */
  sqlite3_finalize(pCsr->pStmt);
  sqlite3_free(pCsr->aDoclist);
  sqlite3_free(pCsr->aMatchinfo);
  sqlite3Fts3ExprFree(pCsr->pExpr);
  memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));

  /* Set the lower and upper bounds on docids to return */
  pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64);
  pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64);

133913
133914
133915
133916
133917
133918
133919
133920
133921
133922
133923
133924
133925
133926
133927
      for(i=0; rc==SQLITE_OK && i<p->nToken && bEof==0; i++){
        rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
        if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){
          iMax = a[i].iDocid;
          bMaxSet = 1;
        }
      }
      assert( rc!=SQLITE_OK || a[p->nToken-1].bIgnore==0 );
      assert( rc!=SQLITE_OK || bMaxSet );

      /* Keep advancing iterators until they all point to the same document */
      for(i=0; i<p->nToken; i++){
        while( rc==SQLITE_OK && bEof==0 
            && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0 
        ){







|







134007
134008
134009
134010
134011
134012
134013
134014
134015
134016
134017
134018
134019
134020
134021
      for(i=0; rc==SQLITE_OK && i<p->nToken && bEof==0; i++){
        rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
        if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){
          iMax = a[i].iDocid;
          bMaxSet = 1;
        }
      }
      assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) );
      assert( rc!=SQLITE_OK || bMaxSet );

      /* Keep advancing iterators until they all point to the same document */
      for(i=0; i<p->nToken; i++){
        while( rc==SQLITE_OK && bEof==0 
            && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0 
        ){
136030
136031
136032
136033
136034
136035
136036
136037
136038
136039
136040
136041
136042
136043
136044
  sqlite3_tokenizer_cursor *pCursor;
  Fts3Expr *pRet = 0;
  int i = 0;

  /* Set variable i to the maximum number of bytes of input to tokenize. */
  for(i=0; i<n; i++){
    if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break;
    if( z[i]=='*' || z[i]=='"' ) break;
  }

  *pnConsumed = i;
  rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor);
  if( rc==SQLITE_OK ){
    const char *zToken;
    int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;







|







136124
136125
136126
136127
136128
136129
136130
136131
136132
136133
136134
136135
136136
136137
136138
  sqlite3_tokenizer_cursor *pCursor;
  Fts3Expr *pRet = 0;
  int i = 0;

  /* Set variable i to the maximum number of bytes of input to tokenize. */
  for(i=0; i<n; i++){
    if( sqlite3_fts3_enable_parentheses && (z[i]=='(' || z[i]==')') ) break;
    if( z[i]=='"' ) break;
  }

  *pnConsumed = i;
  rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor);
  if( rc==SQLITE_OK ){
    const char *zToken;
    int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
Changes to src/sqlite3.h.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.8.7"
#define SQLITE_VERSION_NUMBER 3008007
#define SQLITE_SOURCE_ID      "2014-10-01 13:17:34 07c89940c49a5dca3205a4b6fa8290f23bcb6e10"

/*
** 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







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.8.7"
#define SQLITE_VERSION_NUMBER 3008007
#define SQLITE_SOURCE_ID      "2014-10-17 11:24:17 e4ab094f8afce0817f4074e823fabe59fc29ebb4"

/*
** 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
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
** a NULL will be written into *ppDb instead of a pointer to the [sqlite3]
** object.)^ ^(If the database is opened (and/or created) successfully, then
** [SQLITE_OK] is returned.  Otherwise an [error code] is returned.)^ ^The
** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain
** an English language description of the error following a failure of any
** of the sqlite3_open() routines.
**
** ^The default encoding for the database will be UTF-8 if
** sqlite3_open() or sqlite3_open_v2() is called and
** UTF-16 in the native byte order if sqlite3_open16() is used.
**
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
** passing it to [sqlite3_close()] when it is no longer required.
**
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control







|
|
|







2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
** a NULL will be written into *ppDb instead of a pointer to the [sqlite3]
** object.)^ ^(If the database is opened (and/or created) successfully, then
** [SQLITE_OK] is returned.  Otherwise an [error code] is returned.)^ ^The
** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain
** an English language description of the error following a failure of any
** of the sqlite3_open() routines.
**
** ^The default encoding will be UTF-8 for databases created using
** sqlite3_open() or sqlite3_open_v2().  ^The default encoding for databases
** created using sqlite3_open16() will be UTF-16 in the native byte order.
**
** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by
** passing it to [sqlite3_close()] when it is no longer required.
**
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767

2768
2769
2770
2771
2772
2773
2774
2775
** present, is ignored.
**
** ^SQLite uses the path component of the URI as the name of the disk file
** which contains the database. ^If the path begins with a '/' character, 
** then it is interpreted as an absolute path. ^If the path does not begin 
** with a '/' (meaning that the authority section is omitted from the URI)
** then the path is interpreted as a relative path. 
** ^On windows, the first component of an absolute path 
** is a drive specification (e.g. "C:").
**
** [[core URI query parameters]]
** The query component of a URI may contain parameters that are interpreted
** either by SQLite itself, or by a [VFS | custom VFS implementation].

** SQLite interprets the following three query parameters:
**
** <ul>
**   <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
**     a VFS object that provides the operating system interface that should
**     be used to access the database file on disk. ^If this option is set to
**     an empty string the default VFS object is used. ^Specifying an unknown
**     VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is







|
|




>
|







2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
** present, is ignored.
**
** ^SQLite uses the path component of the URI as the name of the disk file
** which contains the database. ^If the path begins with a '/' character, 
** then it is interpreted as an absolute path. ^If the path does not begin 
** with a '/' (meaning that the authority section is omitted from the URI)
** then the path is interpreted as a relative path. 
** ^(On windows, the first component of an absolute path 
** is a drive specification (e.g. "C:").)^
**
** [[core URI query parameters]]
** The query component of a URI may contain parameters that are interpreted
** either by SQLite itself, or by a [VFS | custom VFS implementation].
** SQLite and its built-in [VFSes] interpret the
** following query parameters:
**
** <ul>
**   <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
**     a VFS object that provides the operating system interface that should
**     be used to access the database file on disk. ^If this option is set to
**     an empty string the default VFS object is used. ^Specifying an unknown
**     VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
**     SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
**     sqlite3_open_v2(). ^Setting the cache parameter to "private" is 
**     equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
**     ^If sqlite3_open_v2() is used and the "cache" parameter is present in
**     a URI filename, its value overrides any behavior requested by setting
**     SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
**
**  <li> <b>psow</b>: ^The psow parameter may be "true" (or "on" or "yes" or
**     "1") or "false" (or "off" or "no" or "0") to indicate that the
**     [powersafe overwrite] property does or does not apply to the
**     storage media on which the database file resides.  ^The psow query
**     parameter only works for the built-in unix and Windows VFSes.
**
**  <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
**     which if set disables file locking in rollback journal modes.  This
**     is useful for accessing a database on a filesystem that does not
**     support locking.  Caution:  Database corruption might result if two
**     or more processes write to the same database and any one of those
**     processes uses nolock=1.







|
<

|
<







2797
2798
2799
2800
2801
2802
2803
2804

2805
2806

2807
2808
2809
2810
2811
2812
2813
**     SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
**     sqlite3_open_v2(). ^Setting the cache parameter to "private" is 
**     equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
**     ^If sqlite3_open_v2() is used and the "cache" parameter is present in
**     a URI filename, its value overrides any behavior requested by setting
**     SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
**
**  <li> <b>psow</b>: ^The psow parameter indicates whether or not the

**     [powersafe overwrite] property does or does not apply to the
**     storage media on which the database file resides.

**
**  <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
**     which if set disables file locking in rollback journal modes.  This
**     is useful for accessing a database on a filesystem that does not
**     support locking.  Caution:  Database corruption might result if two
**     or more processes write to the same database and any one of those
**     processes uses nolock=1.
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
** terminated.  If any NUL characters occur at byte offsets less than 
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs.  The result of expressions involving strings
** with embedded NULs is undefined.
**
** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it.  ^The destructor is called
** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(),
** sqlite3_bind_text(), or sqlite3_bind_text16() fails.  
** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
** SQLite makes its own private copy of the data immediately, before
** the sqlite3_bind_*() routine returns.
**
** ^The sixth argument to sqlite3_bind_text64() must be one of
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
** to specify the encoding of the text in the third parameter.  If
** the sixth argument to sqlite3_bind_text64() is not how of the
** allowed values shown above, or if the text encoding is different
** from the encoding specified by the sixth parameter, then the behavior
** is undefined.
**
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
** is filled with zeroes.  ^A zeroblob uses a fixed amount of memory
** (just an integer to hold its size) while it is being processed.







|
|

|
<










|







3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404

3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
** terminated.  If any NUL characters occur at byte offsets less than 
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs.  The result of expressions involving strings
** with embedded NULs is undefined.
**
** ^The fifth argument to the BLOB and string binding interfaces
** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it.  ^The destructor is called
** to dispose of the BLOB or string even if the call to bind API fails.

** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
** SQLite makes its own private copy of the data immediately, before
** the sqlite3_bind_*() routine returns.
**
** ^The sixth argument to sqlite3_bind_text64() must be one of
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
** to specify the encoding of the text in the third parameter.  If
** the sixth argument to sqlite3_bind_text64() is not one of the
** allowed values shown above, or if the text encoding is different
** from the encoding specified by the sixth parameter, then the behavior
** is undefined.
**
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
** is filled with zeroes.  ^A zeroblob uses a fixed amount of memory
** (just an integer to hold its size) while it is being processed.
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
** of the application-defined function to be the 64-bit signed integer
** value given in the 2nd argument.
**
** ^The sqlite3_result_null() interface sets the return value
** of the application-defined function to be NULL.
**
** ^The sqlite3_result_text(), sqlite3_result_text16(),
** sqlite3_result_text16le(), and sqlite3_result_text16be()
** set the return value of the application-defined function to be
** a text string which is represented as UTF-8, UTF-16 native byte order,
** UTF-16 little endian, or UTF-16 big endian, respectively.
** ^The sqlite3_result_text64() interface sets the return value of an
** application-defined function to be a text string in an encoding
** specified by the fifth (and last) parameter, which must be one
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].







|







4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
** of the application-defined function to be the 64-bit signed integer
** value given in the 2nd argument.
**
** ^The sqlite3_result_null() interface sets the return value
** of the application-defined function to be NULL.
**
** ^The sqlite3_result_text(), sqlite3_result_text16(),
** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces
** set the return value of the application-defined function to be
** a text string which is represented as UTF-8, UTF-16 native byte order,
** UTF-16 little endian, or UTF-16 big endian, respectively.
** ^The sqlite3_result_text64() interface sets the return value of an
** application-defined function to be a text string in an encoding
** specified by the fifth (and last) parameter, which must be one
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
Added src/sqlite3ext.h.










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
** 2006 June 7
**
** 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 defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance.  Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of 
** sqlite3.h.
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
#include "sqlite3.h"

typedef struct sqlite3_api_routines sqlite3_api_routines;

/*
** The following structure holds pointers to all of the SQLite API
** routines.
**
** WARNING:  In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only.  If you insert new
** interfaces in the middle of this structure, then older different
** versions of SQLite will not be able to load each other's shared
** libraries!
*/
struct sqlite3_api_routines {
  void * (*aggregate_context)(sqlite3_context*,int nBytes);
  int  (*aggregate_count)(sqlite3_context*);
  int  (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
  int  (*bind_double)(sqlite3_stmt*,int,double);
  int  (*bind_int)(sqlite3_stmt*,int,int);
  int  (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
  int  (*bind_null)(sqlite3_stmt*,int);
  int  (*bind_parameter_count)(sqlite3_stmt*);
  int  (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
  const char * (*bind_parameter_name)(sqlite3_stmt*,int);
  int  (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
  int  (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
  int  (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
  int  (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
  int  (*busy_timeout)(sqlite3*,int ms);
  int  (*changes)(sqlite3*);
  int  (*close)(sqlite3*);
  int  (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
                           int eTextRep,const char*));
  int  (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
                             int eTextRep,const void*));
  const void * (*column_blob)(sqlite3_stmt*,int iCol);
  int  (*column_bytes)(sqlite3_stmt*,int iCol);
  int  (*column_bytes16)(sqlite3_stmt*,int iCol);
  int  (*column_count)(sqlite3_stmt*pStmt);
  const char * (*column_database_name)(sqlite3_stmt*,int);
  const void * (*column_database_name16)(sqlite3_stmt*,int);
  const char * (*column_decltype)(sqlite3_stmt*,int i);
  const void * (*column_decltype16)(sqlite3_stmt*,int);
  double  (*column_double)(sqlite3_stmt*,int iCol);
  int  (*column_int)(sqlite3_stmt*,int iCol);
  sqlite_int64  (*column_int64)(sqlite3_stmt*,int iCol);
  const char * (*column_name)(sqlite3_stmt*,int);
  const void * (*column_name16)(sqlite3_stmt*,int);
  const char * (*column_origin_name)(sqlite3_stmt*,int);
  const void * (*column_origin_name16)(sqlite3_stmt*,int);
  const char * (*column_table_name)(sqlite3_stmt*,int);
  const void * (*column_table_name16)(sqlite3_stmt*,int);
  const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
  const void * (*column_text16)(sqlite3_stmt*,int iCol);
  int  (*column_type)(sqlite3_stmt*,int iCol);
  sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
  void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
  int  (*complete)(const char*sql);
  int  (*complete16)(const void*sql);
  int  (*create_collation)(sqlite3*,const char*,int,void*,
                           int(*)(void*,int,const void*,int,const void*));
  int  (*create_collation16)(sqlite3*,const void*,int,void*,
                             int(*)(void*,int,const void*,int,const void*));
  int  (*create_function)(sqlite3*,const char*,int,int,void*,
                          void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
                          void (*xStep)(sqlite3_context*,int,sqlite3_value**),
                          void (*xFinal)(sqlite3_context*));
  int  (*create_function16)(sqlite3*,const void*,int,int,void*,
                            void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
                            void (*xStep)(sqlite3_context*,int,sqlite3_value**),
                            void (*xFinal)(sqlite3_context*));
  int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
  int  (*data_count)(sqlite3_stmt*pStmt);
  sqlite3 * (*db_handle)(sqlite3_stmt*);
  int (*declare_vtab)(sqlite3*,const char*);
  int  (*enable_shared_cache)(int);
  int  (*errcode)(sqlite3*db);
  const char * (*errmsg)(sqlite3*);
  const void * (*errmsg16)(sqlite3*);
  int  (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
  int  (*expired)(sqlite3_stmt*);
  int  (*finalize)(sqlite3_stmt*pStmt);
  void  (*free)(void*);
  void  (*free_table)(char**result);
  int  (*get_autocommit)(sqlite3*);
  void * (*get_auxdata)(sqlite3_context*,int);
  int  (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
  int  (*global_recover)(void);
  void  (*interruptx)(sqlite3*);
  sqlite_int64  (*last_insert_rowid)(sqlite3*);
  const char * (*libversion)(void);
  int  (*libversion_number)(void);
  void *(*malloc)(int);
  char * (*mprintf)(const char*,...);
  int  (*open)(const char*,sqlite3**);
  int  (*open16)(const void*,sqlite3**);
  int  (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
  int  (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
  void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
  void  (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
  void *(*realloc)(void*,int);
  int  (*reset)(sqlite3_stmt*pStmt);
  void  (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
  void  (*result_double)(sqlite3_context*,double);
  void  (*result_error)(sqlite3_context*,const char*,int);
  void  (*result_error16)(sqlite3_context*,const void*,int);
  void  (*result_int)(sqlite3_context*,int);
  void  (*result_int64)(sqlite3_context*,sqlite_int64);
  void  (*result_null)(sqlite3_context*);
  void  (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
  void  (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
  void  (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
  void  (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
  void  (*result_value)(sqlite3_context*,sqlite3_value*);
  void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
  int  (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
                         const char*,const char*),void*);
  void  (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
  char * (*snprintf)(int,char*,const char*,...);
  int  (*step)(sqlite3_stmt*);
  int  (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
                                char const**,char const**,int*,int*,int*);
  void  (*thread_cleanup)(void);
  int  (*total_changes)(sqlite3*);
  void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
  int  (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
  void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
                                         sqlite_int64),void*);
  void * (*user_data)(sqlite3_context*);
  const void * (*value_blob)(sqlite3_value*);
  int  (*value_bytes)(sqlite3_value*);
  int  (*value_bytes16)(sqlite3_value*);
  double  (*value_double)(sqlite3_value*);
  int  (*value_int)(sqlite3_value*);
  sqlite_int64  (*value_int64)(sqlite3_value*);
  int  (*value_numeric_type)(sqlite3_value*);
  const unsigned char * (*value_text)(sqlite3_value*);
  const void * (*value_text16)(sqlite3_value*);
  const void * (*value_text16be)(sqlite3_value*);
  const void * (*value_text16le)(sqlite3_value*);
  int  (*value_type)(sqlite3_value*);
  char *(*vmprintf)(const char*,va_list);
  /* Added ??? */
  int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
  /* Added by 3.3.13 */
  int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
  int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
  int (*clear_bindings)(sqlite3_stmt*);
  /* Added by 3.4.1 */
  int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
                          void (*xDestroy)(void *));
  /* Added by 3.5.0 */
  int (*bind_zeroblob)(sqlite3_stmt*,int,int);
  int (*blob_bytes)(sqlite3_blob*);
  int (*blob_close)(sqlite3_blob*);
  int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
                   int,sqlite3_blob**);
  int (*blob_read)(sqlite3_blob*,void*,int,int);
  int (*blob_write)(sqlite3_blob*,const void*,int,int);
  int (*create_collation_v2)(sqlite3*,const char*,int,void*,
                             int(*)(void*,int,const void*,int,const void*),
                             void(*)(void*));
  int (*file_control)(sqlite3*,const char*,int,void*);
  sqlite3_int64 (*memory_highwater)(int);
  sqlite3_int64 (*memory_used)(void);
  sqlite3_mutex *(*mutex_alloc)(int);
  void (*mutex_enter)(sqlite3_mutex*);
  void (*mutex_free)(sqlite3_mutex*);
  void (*mutex_leave)(sqlite3_mutex*);
  int (*mutex_try)(sqlite3_mutex*);
  int (*open_v2)(const char*,sqlite3**,int,const char*);
  int (*release_memory)(int);
  void (*result_error_nomem)(sqlite3_context*);
  void (*result_error_toobig)(sqlite3_context*);
  int (*sleep)(int);
  void (*soft_heap_limit)(int);
  sqlite3_vfs *(*vfs_find)(const char*);
  int (*vfs_register)(sqlite3_vfs*,int);
  int (*vfs_unregister)(sqlite3_vfs*);
  int (*xthreadsafe)(void);
  void (*result_zeroblob)(sqlite3_context*,int);
  void (*result_error_code)(sqlite3_context*,int);
  int (*test_control)(int, ...);
  void (*randomness)(int,void*);
  sqlite3 *(*context_db_handle)(sqlite3_context*);
  int (*extended_result_codes)(sqlite3*,int);
  int (*limit)(sqlite3*,int,int);
  sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
  const char *(*sql)(sqlite3_stmt*);
  int (*status)(int,int*,int*,int);
  int (*backup_finish)(sqlite3_backup*);
  sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
  int (*backup_pagecount)(sqlite3_backup*);
  int (*backup_remaining)(sqlite3_backup*);
  int (*backup_step)(sqlite3_backup*,int);
  const char *(*compileoption_get)(int);
  int (*compileoption_used)(const char*);
  int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
                            void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
                            void (*xStep)(sqlite3_context*,int,sqlite3_value**),
                            void (*xFinal)(sqlite3_context*),
                            void(*xDestroy)(void*));
  int (*db_config)(sqlite3*,int,...);
  sqlite3_mutex *(*db_mutex)(sqlite3*);
  int (*db_status)(sqlite3*,int,int*,int*,int);
  int (*extended_errcode)(sqlite3*);
  void (*log)(int,const char*,...);
  sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
  const char *(*sourceid)(void);
  int (*stmt_status)(sqlite3_stmt*,int,int);
  int (*strnicmp)(const char*,const char*,int);
  int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
  int (*wal_autocheckpoint)(sqlite3*,int);
  int (*wal_checkpoint)(sqlite3*,const char*);
  void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
  int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
  int (*vtab_config)(sqlite3*,int op,...);
  int (*vtab_on_conflict)(sqlite3*);
  /* Version 3.7.16 and later */
  int (*close_v2)(sqlite3*);
  const char *(*db_filename)(sqlite3*,const char*);
  int (*db_readonly)(sqlite3*,const char*);
  int (*db_release_memory)(sqlite3*);
  const char *(*errstr)(int);
  int (*stmt_busy)(sqlite3_stmt*);
  int (*stmt_readonly)(sqlite3_stmt*);
  int (*stricmp)(const char*,const char*);
  int (*uri_boolean)(const char*,const char*,int);
  sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
  const char *(*uri_parameter)(const char*,const char*);
  char *(*vsnprintf)(int,char*,const char*,va_list);
  int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
  /* Version 3.8.7 and later */
  int (*auto_extension)(void(*)(void));
  int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
                     void(*)(void*));
  int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
                      void(*)(void*),unsigned char);
  int (*cancel_auto_extension)(void(*)(void));
  int (*load_extension)(sqlite3*,const char*,const char*,char**);
  void *(*malloc64)(sqlite3_uint64);
  sqlite3_uint64 (*msize)(void*);
  void *(*realloc64)(void*,sqlite3_uint64);
  void (*reset_auto_extension)(void);
  void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
                        void(*)(void*));
  void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
                         void(*)(void*), unsigned char);
  int (*strglob)(const char*,const char*);
};

/*
** The following macros redefine the API routines so that they are
** redirected through the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
** it can get access to the sqlite3_api_routines structure
** definition.  But the main library does not want to redefine
** the API.  So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#ifndef SQLITE_CORE
#define sqlite3_aggregate_context      sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count        sqlite3_api->aggregate_count
#endif
#define sqlite3_bind_blob              sqlite3_api->bind_blob
#define sqlite3_bind_double            sqlite3_api->bind_double
#define sqlite3_bind_int               sqlite3_api->bind_int
#define sqlite3_bind_int64             sqlite3_api->bind_int64
#define sqlite3_bind_null              sqlite3_api->bind_null
#define sqlite3_bind_parameter_count   sqlite3_api->bind_parameter_count
#define sqlite3_bind_parameter_index   sqlite3_api->bind_parameter_index
#define sqlite3_bind_parameter_name    sqlite3_api->bind_parameter_name
#define sqlite3_bind_text              sqlite3_api->bind_text
#define sqlite3_bind_text16            sqlite3_api->bind_text16
#define sqlite3_bind_value             sqlite3_api->bind_value
#define sqlite3_busy_handler           sqlite3_api->busy_handler
#define sqlite3_busy_timeout           sqlite3_api->busy_timeout
#define sqlite3_changes                sqlite3_api->changes
#define sqlite3_close                  sqlite3_api->close
#define sqlite3_collation_needed       sqlite3_api->collation_needed
#define sqlite3_collation_needed16     sqlite3_api->collation_needed16
#define sqlite3_column_blob            sqlite3_api->column_blob
#define sqlite3_column_bytes           sqlite3_api->column_bytes
#define sqlite3_column_bytes16         sqlite3_api->column_bytes16
#define sqlite3_column_count           sqlite3_api->column_count
#define sqlite3_column_database_name   sqlite3_api->column_database_name
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
#define sqlite3_column_decltype        sqlite3_api->column_decltype
#define sqlite3_column_decltype16      sqlite3_api->column_decltype16
#define sqlite3_column_double          sqlite3_api->column_double
#define sqlite3_column_int             sqlite3_api->column_int
#define sqlite3_column_int64           sqlite3_api->column_int64
#define sqlite3_column_name            sqlite3_api->column_name
#define sqlite3_column_name16          sqlite3_api->column_name16
#define sqlite3_column_origin_name     sqlite3_api->column_origin_name
#define sqlite3_column_origin_name16   sqlite3_api->column_origin_name16
#define sqlite3_column_table_name      sqlite3_api->column_table_name
#define sqlite3_column_table_name16    sqlite3_api->column_table_name16
#define sqlite3_column_text            sqlite3_api->column_text
#define sqlite3_column_text16          sqlite3_api->column_text16
#define sqlite3_column_type            sqlite3_api->column_type
#define sqlite3_column_value           sqlite3_api->column_value
#define sqlite3_commit_hook            sqlite3_api->commit_hook
#define sqlite3_complete               sqlite3_api->complete
#define sqlite3_complete16             sqlite3_api->complete16
#define sqlite3_create_collation       sqlite3_api->create_collation
#define sqlite3_create_collation16     sqlite3_api->create_collation16
#define sqlite3_create_function        sqlite3_api->create_function
#define sqlite3_create_function16      sqlite3_api->create_function16
#define sqlite3_create_module          sqlite3_api->create_module
#define sqlite3_create_module_v2       sqlite3_api->create_module_v2
#define sqlite3_data_count             sqlite3_api->data_count
#define sqlite3_db_handle              sqlite3_api->db_handle
#define sqlite3_declare_vtab           sqlite3_api->declare_vtab
#define sqlite3_enable_shared_cache    sqlite3_api->enable_shared_cache
#define sqlite3_errcode                sqlite3_api->errcode
#define sqlite3_errmsg                 sqlite3_api->errmsg
#define sqlite3_errmsg16               sqlite3_api->errmsg16
#define sqlite3_exec                   sqlite3_api->exec
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_expired                sqlite3_api->expired
#endif
#define sqlite3_finalize               sqlite3_api->finalize
#define sqlite3_free                   sqlite3_api->free
#define sqlite3_free_table             sqlite3_api->free_table
#define sqlite3_get_autocommit         sqlite3_api->get_autocommit
#define sqlite3_get_auxdata            sqlite3_api->get_auxdata
#define sqlite3_get_table              sqlite3_api->get_table
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_global_recover         sqlite3_api->global_recover
#endif
#define sqlite3_interrupt              sqlite3_api->interruptx
#define sqlite3_last_insert_rowid      sqlite3_api->last_insert_rowid
#define sqlite3_libversion             sqlite3_api->libversion
#define sqlite3_libversion_number      sqlite3_api->libversion_number
#define sqlite3_malloc                 sqlite3_api->malloc
#define sqlite3_mprintf                sqlite3_api->mprintf
#define sqlite3_open                   sqlite3_api->open
#define sqlite3_open16                 sqlite3_api->open16
#define sqlite3_prepare                sqlite3_api->prepare
#define sqlite3_prepare16              sqlite3_api->prepare16
#define sqlite3_prepare_v2             sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2           sqlite3_api->prepare16_v2
#define sqlite3_profile                sqlite3_api->profile
#define sqlite3_progress_handler       sqlite3_api->progress_handler
#define sqlite3_realloc                sqlite3_api->realloc
#define sqlite3_reset                  sqlite3_api->reset
#define sqlite3_result_blob            sqlite3_api->result_blob
#define sqlite3_result_double          sqlite3_api->result_double
#define sqlite3_result_error           sqlite3_api->result_error
#define sqlite3_result_error16         sqlite3_api->result_error16
#define sqlite3_result_int             sqlite3_api->result_int
#define sqlite3_result_int64           sqlite3_api->result_int64
#define sqlite3_result_null            sqlite3_api->result_null
#define sqlite3_result_text            sqlite3_api->result_text
#define sqlite3_result_text16          sqlite3_api->result_text16
#define sqlite3_result_text16be        sqlite3_api->result_text16be
#define sqlite3_result_text16le        sqlite3_api->result_text16le
#define sqlite3_result_value           sqlite3_api->result_value
#define sqlite3_rollback_hook          sqlite3_api->rollback_hook
#define sqlite3_set_authorizer         sqlite3_api->set_authorizer
#define sqlite3_set_auxdata            sqlite3_api->set_auxdata
#define sqlite3_snprintf               sqlite3_api->snprintf
#define sqlite3_step                   sqlite3_api->step
#define sqlite3_table_column_metadata  sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup         sqlite3_api->thread_cleanup
#define sqlite3_total_changes          sqlite3_api->total_changes
#define sqlite3_trace                  sqlite3_api->trace
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_transfer_bindings      sqlite3_api->transfer_bindings
#endif
#define sqlite3_update_hook            sqlite3_api->update_hook
#define sqlite3_user_data              sqlite3_api->user_data
#define sqlite3_value_blob             sqlite3_api->value_blob
#define sqlite3_value_bytes            sqlite3_api->value_bytes
#define sqlite3_value_bytes16          sqlite3_api->value_bytes16
#define sqlite3_value_double           sqlite3_api->value_double
#define sqlite3_value_int              sqlite3_api->value_int
#define sqlite3_value_int64            sqlite3_api->value_int64
#define sqlite3_value_numeric_type     sqlite3_api->value_numeric_type
#define sqlite3_value_text             sqlite3_api->value_text
#define sqlite3_value_text16           sqlite3_api->value_text16
#define sqlite3_value_text16be         sqlite3_api->value_text16be
#define sqlite3_value_text16le         sqlite3_api->value_text16le
#define sqlite3_value_type             sqlite3_api->value_type
#define sqlite3_vmprintf               sqlite3_api->vmprintf
#define sqlite3_overload_function      sqlite3_api->overload_function
#define sqlite3_prepare_v2             sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2           sqlite3_api->prepare16_v2
#define sqlite3_clear_bindings         sqlite3_api->clear_bindings
#define sqlite3_bind_zeroblob          sqlite3_api->bind_zeroblob
#define sqlite3_blob_bytes             sqlite3_api->blob_bytes
#define sqlite3_blob_close             sqlite3_api->blob_close
#define sqlite3_blob_open              sqlite3_api->blob_open
#define sqlite3_blob_read              sqlite3_api->blob_read
#define sqlite3_blob_write             sqlite3_api->blob_write
#define sqlite3_create_collation_v2    sqlite3_api->create_collation_v2
#define sqlite3_file_control           sqlite3_api->file_control
#define sqlite3_memory_highwater       sqlite3_api->memory_highwater
#define sqlite3_memory_used            sqlite3_api->memory_used
#define sqlite3_mutex_alloc            sqlite3_api->mutex_alloc
#define sqlite3_mutex_enter            sqlite3_api->mutex_enter
#define sqlite3_mutex_free             sqlite3_api->mutex_free
#define sqlite3_mutex_leave            sqlite3_api->mutex_leave
#define sqlite3_mutex_try              sqlite3_api->mutex_try
#define sqlite3_open_v2                sqlite3_api->open_v2
#define sqlite3_release_memory         sqlite3_api->release_memory
#define sqlite3_result_error_nomem     sqlite3_api->result_error_nomem
#define sqlite3_result_error_toobig    sqlite3_api->result_error_toobig
#define sqlite3_sleep                  sqlite3_api->sleep
#define sqlite3_soft_heap_limit        sqlite3_api->soft_heap_limit
#define sqlite3_vfs_find               sqlite3_api->vfs_find
#define sqlite3_vfs_register           sqlite3_api->vfs_register
#define sqlite3_vfs_unregister         sqlite3_api->vfs_unregister
#define sqlite3_threadsafe             sqlite3_api->xthreadsafe
#define sqlite3_result_zeroblob        sqlite3_api->result_zeroblob
#define sqlite3_result_error_code      sqlite3_api->result_error_code
#define sqlite3_test_control           sqlite3_api->test_control
#define sqlite3_randomness             sqlite3_api->randomness
#define sqlite3_context_db_handle      sqlite3_api->context_db_handle
#define sqlite3_extended_result_codes  sqlite3_api->extended_result_codes
#define sqlite3_limit                  sqlite3_api->limit
#define sqlite3_next_stmt              sqlite3_api->next_stmt
#define sqlite3_sql                    sqlite3_api->sql
#define sqlite3_status                 sqlite3_api->status
#define sqlite3_backup_finish          sqlite3_api->backup_finish
#define sqlite3_backup_init            sqlite3_api->backup_init
#define sqlite3_backup_pagecount       sqlite3_api->backup_pagecount
#define sqlite3_backup_remaining       sqlite3_api->backup_remaining
#define sqlite3_backup_step            sqlite3_api->backup_step
#define sqlite3_compileoption_get      sqlite3_api->compileoption_get
#define sqlite3_compileoption_used     sqlite3_api->compileoption_used
#define sqlite3_create_function_v2     sqlite3_api->create_function_v2
#define sqlite3_db_config              sqlite3_api->db_config
#define sqlite3_db_mutex               sqlite3_api->db_mutex
#define sqlite3_db_status              sqlite3_api->db_status
#define sqlite3_extended_errcode       sqlite3_api->extended_errcode
#define sqlite3_log                    sqlite3_api->log
#define sqlite3_soft_heap_limit64      sqlite3_api->soft_heap_limit64
#define sqlite3_sourceid               sqlite3_api->sourceid
#define sqlite3_stmt_status            sqlite3_api->stmt_status
#define sqlite3_strnicmp               sqlite3_api->strnicmp
#define sqlite3_unlock_notify          sqlite3_api->unlock_notify
#define sqlite3_wal_autocheckpoint     sqlite3_api->wal_autocheckpoint
#define sqlite3_wal_checkpoint         sqlite3_api->wal_checkpoint
#define sqlite3_wal_hook               sqlite3_api->wal_hook
#define sqlite3_blob_reopen            sqlite3_api->blob_reopen
#define sqlite3_vtab_config            sqlite3_api->vtab_config
#define sqlite3_vtab_on_conflict       sqlite3_api->vtab_on_conflict
/* Version 3.7.16 and later */
#define sqlite3_close_v2               sqlite3_api->close_v2
#define sqlite3_db_filename            sqlite3_api->db_filename
#define sqlite3_db_readonly            sqlite3_api->db_readonly
#define sqlite3_db_release_memory      sqlite3_api->db_release_memory
#define sqlite3_errstr                 sqlite3_api->errstr
#define sqlite3_stmt_busy              sqlite3_api->stmt_busy
#define sqlite3_stmt_readonly          sqlite3_api->stmt_readonly
#define sqlite3_stricmp                sqlite3_api->stricmp
#define sqlite3_uri_boolean            sqlite3_api->uri_boolean
#define sqlite3_uri_int64              sqlite3_api->uri_int64
#define sqlite3_uri_parameter          sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf          sqlite3_api->vsnprintf
#define sqlite3_wal_checkpoint_v2      sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension         sqlite3_api->auto_extension
#define sqlite3_bind_blob64            sqlite3_api->bind_blob64
#define sqlite3_bind_text64            sqlite3_api->bind_text64
#define sqlite3_cancel_auto_extension  sqlite3_api->cancel_auto_extension
#define sqlite3_load_extension         sqlite3_api->load_extension
#define sqlite3_malloc64               sqlite3_api->malloc64
#define sqlite3_msize                  sqlite3_api->msize
#define sqlite3_realloc64              sqlite3_api->realloc64
#define sqlite3_reset_auto_extension   sqlite3_api->reset_auto_extension
#define sqlite3_result_blob64          sqlite3_api->result_blob64
#define sqlite3_result_text64          sqlite3_api->result_text64
#define sqlite3_strglob                sqlite3_api->strglob
#endif /* SQLITE_CORE */

#ifndef SQLITE_CORE
  /* 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;
# define SQLITE_EXTENSION_INIT3     \
    extern const sqlite3_api_routines *sqlite3_api;
#else
  /* This case when the file is being statically linked into the 
  ** application */
# define SQLITE_EXTENSION_INIT1     /*no-op*/
# define SQLITE_EXTENSION_INIT2(v)  (void)v; /* unused parameter */
# define SQLITE_EXTENSION_INIT3     /*no-op*/
#endif

#endif /* _SQLITE3EXT_H_ */