SQLite

Check-in [082fd5f8ac]
Login

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

Overview
Comment:Merge updates from trunk.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | rowvalue
Files: files | file ages | folders
SHA1: 082fd5f8ac227dbb983da0a772485268af40a484
User & Date: drh 2016-08-27 14:13:58.459
Context
2016-09-02
23:56
Merge recent changes from trunk. (check-in: c7271fbde1 user: drh tags: rowvalue)
2016-08-27
14:13
Merge updates from trunk. (check-in: 082fd5f8ac user: drh tags: rowvalue)
14:05
Fix the extra comments (added with -DSQLITE_ENABLE_EXPLAIN_COMMENTS) so that the sense of <, <=, >, and >= tests is correct and so that the SQLITE_STOREP2 version is shown correctly. These changes are already in the rowvalue branch but are added here since they are technically unrelated to rowvalue. (check-in: 4d43c4698e user: drh tags: trunk)
01:41
Fix the "Synopsis" on the OP_Lt, OP_Le, OP_Gt, and OP_Ge opcodes, which has been backwards for time out of mind. (check-in: f51248dcfa user: drh tags: rowvalue)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/insert.c.
1777
1778
1779
1780
1781
1782
1783




1784
1785
1786
1787
1788
1789
1790
1791
1792

1793
1794
1795
1796
1797
1798
1799
  }else{
    sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
  }
  if( piIdxCur ) *piIdxCur = iBase;
  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    int iIdxCur = iBase++;
    assert( pIdx->pSchema==pTab->pSchema );




    if( aToOpen==0 || aToOpen[i+1] ){
      sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
      sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
      VdbeComment((v, "%s", pIdx->zName));
    }
    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
      if( piDataCur ) *piDataCur = iIdxCur;
    }else{
      sqlite3VdbeChangeP5(v, p5);

    }
  }
  if( iBase>pParse->nTab ) pParse->nTab = iBase;
  return i;
}









>
>
>
>



<
<
<
<
<

>







1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790





1791
1792
1793
1794
1795
1796
1797
1798
1799
  }else{
    sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
  }
  if( piIdxCur ) *piIdxCur = iBase;
  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
    int iIdxCur = iBase++;
    assert( pIdx->pSchema==pTab->pSchema );
    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
      if( piDataCur ) *piDataCur = iIdxCur;
      p5 = 0;
    }
    if( aToOpen==0 || aToOpen[i+1] ){
      sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
      sqlite3VdbeSetP4KeyInfo(pParse, pIdx);





      sqlite3VdbeChangeP5(v, p5);
      VdbeComment((v, "%s", pIdx->zName));
    }
  }
  if( iBase>pParse->nTab ) pParse->nTab = iBase;
  return i;
}


Changes to src/test_fs.c.
495
496
497
498
499
500
501




502
503
504
505
506
507
508
509
510
511
  char *zPrefix;
  int nPrefix;
  const char *zDir;
  int nDir;
  char aWild[2] = { '\0', '\0' };

#if SQLITE_OS_WIN




  zRoot = sqlite3_mprintf("%s%c", getenv("SystemDrive"), '/');
  nRoot = sqlite3Strlen30(zRoot);
  zPrefix = sqlite3_mprintf("%s", getenv("SystemDrive"));
  nPrefix = sqlite3Strlen30(zPrefix);
#else
  zRoot = "/";
  nRoot = 1;
  zPrefix = "";
  nPrefix = 0;
#endif







>
>
>
>
|

|







495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  char *zPrefix;
  int nPrefix;
  const char *zDir;
  int nDir;
  char aWild[2] = { '\0', '\0' };

#if SQLITE_OS_WIN
  const char *zDrive = windirent_getenv("fstreeDrive");
  if( zDrive==0 ){
    zDrive = windirent_getenv("SystemDrive");
  }
  zRoot = sqlite3_mprintf("%s%c", zDrive, '/');
  nRoot = sqlite3Strlen30(zRoot);
  zPrefix = sqlite3_mprintf("%s", zDrive);
  nPrefix = sqlite3Strlen30(zPrefix);
#else
  zRoot = "/";
  nRoot = 1;
  zPrefix = "";
  nPrefix = 0;
#endif
Changes to src/test_windirent.c.
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
** This file contains code to implement most of the opendir() family of
** POSIX functions on Win32 using the MSVCRT.
*/

#if defined(_WIN32) && defined(_MSC_VER)

#include "test_windirent.h"





























/*
** Implementation of the POSIX opendir() function using the MSVCRT.
*/
LPDIR opendir(
  const char *dirname
){
  struct _finddata_t data;
  LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR));
  SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]);

  if( dirp==NULL ) return NULL;
  memset(dirp, 0, sizeof(DIR));

  /* TODO: Remove this if Unix-style root paths are not used. */
  if( sqlite3_stricmp(dirname, "/")==0 ){
    dirname = getenv("SystemDrive");
  }

  _snprintf(data.name, namesize, "%s\\*", dirname);
  dirp->d_handle = _findfirst(data.name, &data);

  if( dirp->d_handle==BAD_INTPTR_T ){
    closedir(dirp);







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
















|







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
** This file contains code to implement most of the opendir() family of
** POSIX functions on Win32 using the MSVCRT.
*/

#if defined(_WIN32) && defined(_MSC_VER)

#include "test_windirent.h"

/*
** Implementation of the POSIX getenv() function using the Win32 API.
** This function is not thread-safe.
*/
const char *windirent_getenv(
  const char *name
){
  static char value[32768]; /* Maximum length, per MSDN */
  DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */
  DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */

  memset(value, 0, sizeof(value));
  dwRet = GetEnvironmentVariableA(name, value, dwSize);
  if( dwRet==0 || dwRet>dwSize ){
    /*
    ** The function call to GetEnvironmentVariableA() failed -OR-
    ** the buffer is not large enough.  Either way, return NULL.
    */
    return 0;
  }else{
    /*
    ** The function call to GetEnvironmentVariableA() succeeded
    ** -AND- the buffer contains the entire value.
    */
    return value;
  }
}

/*
** Implementation of the POSIX opendir() function using the MSVCRT.
*/
LPDIR opendir(
  const char *dirname
){
  struct _finddata_t data;
  LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR));
  SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]);

  if( dirp==NULL ) return NULL;
  memset(dirp, 0, sizeof(DIR));

  /* TODO: Remove this if Unix-style root paths are not used. */
  if( sqlite3_stricmp(dirname, "/")==0 ){
    dirname = windirent_getenv("SystemDrive");
  }

  _snprintf(data.name, namesize, "%s\\*", dirname);
  dirp->d_handle = _findfirst(data.name, &data);

  if( dirp->d_handle==BAD_INTPTR_T ){
    closedir(dirp);
Changes to src/test_windirent.h.
88
89
90
91
92
93
94







95
96
97
98
99
100
101

struct DIR {
  intptr_t d_handle; /* Value returned by "_findfirst". */
  DIRENT d_first;    /* DIRENT constructed based on "_findfirst". */
  DIRENT d_next;     /* DIRENT constructed based on "_findnext". */
};








/*
** Finally, we can provide the function prototypes for the opendir(),
** readdir(), readdir_r(), and closedir() POSIX functions.
*/

extern LPDIR opendir(const char *dirname);
extern LPDIRENT readdir(LPDIR dirp);







>
>
>
>
>
>
>







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

struct DIR {
  intptr_t d_handle; /* Value returned by "_findfirst". */
  DIRENT d_first;    /* DIRENT constructed based on "_findfirst". */
  DIRENT d_next;     /* DIRENT constructed based on "_findnext". */
};

/*
** Provide the function prototype for the POSIX compatiable getenv()
** function.  This function is not thread-safe.
*/

extern const char *windirent_getenv(const char *name);

/*
** Finally, we can provide the function prototypes for the opendir(),
** readdir(), readdir_r(), and closedir() POSIX functions.
*/

extern LPDIR opendir(const char *dirname);
extern LPDIRENT readdir(LPDIR dirp);
Changes to test/delete.test.
384
385
386
387
388
389
390














391
392
393
  set res [list]
  db eval { SELECT t5.rowid AS r, c, d FROM t5, t6 ORDER BY a } {
    if {$r==2} { db eval { DELETE FROM t5 WHERE rowid = 3 } }
    lappend res $r $c $d
  }
  set res
} {1 a b 1 c d 2 a b 2 c d}
















finish_test







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



384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  set res [list]
  db eval { SELECT t5.rowid AS r, c, d FROM t5, t6 ORDER BY a } {
    if {$r==2} { db eval { DELETE FROM t5 WHERE rowid = 3 } }
    lappend res $r $c $d
  }
  set res
} {1 a b 1 c d 2 a b 2 c d}

do_execsql_test delete-10.0 {
  CREATE TABLE t1(a INT UNIQUE, b INT);
  INSERT INTO t1(a,b) VALUES('1','2');
  SELECT * FROM t1 WHERE a='1' AND b='2';
} {1 2}

do_execsql_test delete-10.1 {
  DELETE FROM t1 WHERE a='1' AND b='2';
}

do_execsql_test delete-10.2 {
  SELECT * FROM t1 WHERE a='1' AND b='2';
}


finish_test
Changes to test/speed3.test.
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
  db_leave db
# puts "1: [array get stats1]"
# puts "2: [array get stats2]"
  puts "Incrvacuum: Read $stats1(read), wrote $stats1(write)"
  puts "Normal    : Read $stats2(read), wrote $stats2(write)"
}

proc reset_db {} {
  db close
  sqlite3 db test.db
  db eval { 
    PRAGMA main.cache_size = 200000;
    PRAGMA main.auto_vacuum = 'incremental';
    ATTACH 'test2.db' AS 'aux'; 
    PRAGMA aux.auto_vacuum = 'none';
  }
}

forcedelete test2.db test2.db-journal
reset_db

# Set up a database in auto-vacuum mode and create a database schema.
#
do_test speed3-0.1 {
  execsql {
    CREATE TABLE main.t1(a INTEGER, b TEXT, c INTEGER);
  }







|











|







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
  db_leave db
# puts "1: [array get stats1]"
# puts "2: [array get stats2]"
  puts "Incrvacuum: Read $stats1(read), wrote $stats1(write)"
  puts "Normal    : Read $stats2(read), wrote $stats2(write)"
}

proc speed3_reset_db {} {
  db close
  sqlite3 db test.db
  db eval { 
    PRAGMA main.cache_size = 200000;
    PRAGMA main.auto_vacuum = 'incremental';
    ATTACH 'test2.db' AS 'aux'; 
    PRAGMA aux.auto_vacuum = 'none';
  }
}

forcedelete test2.db test2.db-journal
speed3_reset_db

# Set up a database in auto-vacuum mode and create a database schema.
#
do_test speed3-0.1 {
  execsql {
    CREATE TABLE main.t1(a INTEGER, b TEXT, c INTEGER);
  }
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
    PRAGMA aux.auto_vacuum;
  }
} {2 0}

# Delete all content in a table, one row at a time.
#
#io_log db
reset_db
speed_trial speed3-1.incrvacuum $::NROW row {DELETE FROM main.t1 WHERE 1}
speed_trial speed3-1.normal     $::NROW row {DELETE FROM aux.t1 WHERE 1}
io_log db

# Select the "C" column (located at the far end of the overflow 
# chain) from each table row.
#
#db eval {PRAGMA incremental_vacuum(500000)}
populate_t1 db
reset_db
speed_trial speed3-2.incrvacuum $::NROW row {SELECT c FROM main.t1}
speed_trial speed3-2.normal     $::NROW row {SELECT c FROM aux.t1}
io_log db

finish_test







|









|





150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
    PRAGMA aux.auto_vacuum;
  }
} {2 0}

# Delete all content in a table, one row at a time.
#
#io_log db
speed3_reset_db
speed_trial speed3-1.incrvacuum $::NROW row {DELETE FROM main.t1 WHERE 1}
speed_trial speed3-1.normal     $::NROW row {DELETE FROM aux.t1 WHERE 1}
io_log db

# Select the "C" column (located at the far end of the overflow 
# chain) from each table row.
#
#db eval {PRAGMA incremental_vacuum(500000)}
populate_t1 db
speed3_reset_db
speed_trial speed3-2.incrvacuum $::NROW row {SELECT c FROM main.t1}
speed_trial speed3-2.normal     $::NROW row {SELECT c FROM aux.t1}
io_log db

finish_test
Changes to test/vtabF.test.
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
source $testdir/tester.tcl

ifcapable !vtab||!schema_pragmas { finish_test ; return }

# Register the echo module
register_echo_module [sqlite3_connection_pointer db]

do_test vtabE-1.1 {
  execsql {
    CREATE TABLE t1(a, b);
    CREATE INDEX i1 ON t1(a);
    CREATE INDEX i2 ON t1(b);
    INSERT INTO t1 VALUES(10,110);
    INSERT INTO t1 VALUES(11,111);
    INSERT INTO t1 SELECT a+2, b+2 FROM t1;
    INSERT INTO t1 SELECT null, b+4 FROM t1;
    INSERT INTO t1 SELECT null, b+8 FROM t1;
    INSERT INTO t1 SELECT null, b+16 FROM t1;
    ANALYZE;
    CREATE VIRTUAL TABLE tv1 USING echo(t1);
    SELECT b FROM t1 WHERE a IS NOT NULL;
  }
} {110 111 112 113}
do_test vtabE-1.2 {
  execsql {SELECT b FROM tv1 WHERE a IS NOT NULL}
} {110 111 112 113}


finish_test







|















|





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
source $testdir/tester.tcl

ifcapable !vtab||!schema_pragmas { finish_test ; return }

# Register the echo module
register_echo_module [sqlite3_connection_pointer db]

do_test vtabF-1.1 {
  execsql {
    CREATE TABLE t1(a, b);
    CREATE INDEX i1 ON t1(a);
    CREATE INDEX i2 ON t1(b);
    INSERT INTO t1 VALUES(10,110);
    INSERT INTO t1 VALUES(11,111);
    INSERT INTO t1 SELECT a+2, b+2 FROM t1;
    INSERT INTO t1 SELECT null, b+4 FROM t1;
    INSERT INTO t1 SELECT null, b+8 FROM t1;
    INSERT INTO t1 SELECT null, b+16 FROM t1;
    ANALYZE;
    CREATE VIRTUAL TABLE tv1 USING echo(t1);
    SELECT b FROM t1 WHERE a IS NOT NULL;
  }
} {110 111 112 113}
do_test vtabF-1.2 {
  execsql {SELECT b FROM tv1 WHERE a IS NOT NULL}
} {110 111 112 113}


finish_test
Changes to test/vtabH.test.
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
      set ::gfunc
    } $cnt
  }
}

#-------------------------------------------------------------------------
#
if {1} {





  reset_db
  register_fs_module db
  do_execsql_test 3.0 {
    SELECT name FROM fsdir WHERE dir = '.' AND name = 'test.db';
    SELECT name FROM fsdir WHERE dir = '.' AND name = '.'
  } {test.db .}

  proc list_root_files {} {
    if {$::tcl_platform(platform) eq "windows"} {
      set res [list]
      foreach name [glob -directory $::env(SystemDrive)/ -- *] {
        if {[string index [file tail $name] 0] eq "."} continue
        lappend res $name
      }
      return $res
    } else {
      return [string map {/ {}} [glob /*]]
    }







|
>
>
>
>
>










|







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
      set ::gfunc
    } $cnt
  }
}

#-------------------------------------------------------------------------
#
if {$tcl_platform(platform)=="windows"} {
  set drive [string range [pwd] 0 1]
  set ::env(fstreeDrive) $drive
}
if {$tcl_platform(platform)!="windows" || \
    [regexp -nocase -- {^[A-Z]:} $drive]} {
  reset_db
  register_fs_module db
  do_execsql_test 3.0 {
    SELECT name FROM fsdir WHERE dir = '.' AND name = 'test.db';
    SELECT name FROM fsdir WHERE dir = '.' AND name = '.'
  } {test.db .}

  proc list_root_files {} {
    if {$::tcl_platform(platform) eq "windows"} {
      set res [list]
      foreach name [glob -directory $::env(fstreeDrive)/ -- *] {
        if {[string index [file tail $name] 0] eq "."} continue
        lappend res $name
      }
      return $res
    } else {
      return [string map {/ {}} [glob /*]]
    }
137
138
139
140
141
142
143



















144
145
146
147
148
149
150
        lappend res $name
      }
      return $res
    } else {
      return [glob -nocomplain $pattern]
    }
  }




















  # Read all entries in the current directory.
  #
  proc contents {pattern} {
    set res [list]
    foreach f [list_files $pattern] {
      lappend res $f







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







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
        lappend res $name
      }
      return $res
    } else {
      return [glob -nocomplain $pattern]
    }
  }

  # Read the first 5 entries from the root directory.  Except, ignore
  # files that contain the "$" character in their names as these are
  # special files on some Windows platforms.
  #
  set res [list]
  set root_files [list_root_files]
  set num_root_files [llength $root_files]
  set lim_root_files [expr {$num_root_files > 5 ? 5 : $num_root_files}]
  foreach p [lrange $root_files 0 [expr {$lim_root_files - 1}]] {
    if {$::tcl_platform(platform) eq "windows"} {
      if {[regexp {\$} $p]} {incr lim_root_files -1} else {lappend res $p}
    } else {
      lappend res "/$p"
    }
  }
  do_execsql_test 3.1 [subst {
    SELECT path FROM fstree WHERE path NOT GLOB '*\$*' LIMIT $lim_root_files;
  }] $res

  # Read all entries in the current directory.
  #
  proc contents {pattern} {
    set res [list]
    foreach f [list_files $pattern] {
      lappend res $f