/ Check-in [253dd707]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Progress toward getting things to work better on windows.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | quota-stdio
Files: files | file ages | folders
SHA1: 253dd7072ef7f4e8742e5b6430658f8e5102e0bb
User & Date: drh 2011-12-01 22:07:22
Context
2011-12-01
22:12
Run quota-stdio tests in binary mode so that they work on windows. check-in: 71e4e97d user: drh tags: quota-stdio
22:07
Progress toward getting things to work better on windows. check-in: 253dd707 user: drh tags: quota-stdio
20:48
Add test logic and some test cases. check-in: a4730586 user: drh tags: quota-stdio
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/test_quota.c.

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
...
254
255
256
257
258
259
260

261
262
263
264
265
266
267
268
269
...
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
....
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
....
1031
1032
1033
1034
1035
1036
1037

1038
1039
1040
1041
1042
1043
1044
1045

1046
1047
1048
1049
1050
1051
1052
....
1301
1302
1303
1304
1305
1306
1307


1308


1309
1310
1311
1312
1313
1314
1315
1316
1317
....
1532
1533
1534
1535
1536
1537
1538


























1539
1540
1541
1542
1543
1544
1545
....
1556
1557
1558
1559
1560
1561
1562

1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
**
**     [^...]     Matches one character not in the enclosed list.
**
**     /          Matches "/" or "\\"
**
*/
static int quotaStrglob(const char *zGlob, const char *z){
  int c, c2;
  int invert;
  int seen;

  while( (c = (*(zGlob++)))!=0 ){
    if( c=='*' ){
      while( (c=(*(zGlob++))) == '*' || c=='?' ){
        if( c=='?' && (*(z++))==0 ) return 0;
................................................................................
        return 1;
      }else if( c=='[' ){
        while( *z && quotaStrglob(zGlob-1,z)==0 ){
          z++;
        }
        return (*z)!=0;
      }

      while( (c2 = (*(z++)))!=0 ){
        while( c2!=c ){
          c2 = *(z++);
          if( c2==0 ) return 0;
        }
        if( quotaStrglob(zGlob,z) ) return 1;
      }
      return 0;
    }else if( c=='?' ){
................................................................................
}

/*
** Deallocate any memory allocated by quota_utf8_to_mbcs().
*/
static void quota_mbcs_free(char *zOld){
#if SQLITE_OS_WIN
  free(zOld);
#else
  /* No-op on unix */
#endif  
}

/************************* VFS Method Wrappers *****************************/
/*
................................................................................
  sqlite3_int64 iEnd;
  sqlite3_int64 szNew;
  quotaFile *pFile;
  
  iOfst = ftell(p->f);
  iEnd = iOfst + size*nmemb;
  pFile = p->pFile;
  if( pFile->iSize<iEnd ){
    quotaGroup *pGroup = pFile->pGroup;
    quotaEnter();
    szNew = pGroup->iSize - pFile->iSize + iEnd;
    if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
      if( pGroup->xCallback ){
        pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew, 
                          pGroup->pArg);
................................................................................
** Close an open quota_FILE stream.
*/
int sqlite3_quota_fclose(quota_FILE *p){
  int rc;
  quotaFile *pFile;
  rc = fclose(p->f);
  pFile = p->pFile;

  quotaEnter();
  pFile->nRef--;
  if( pFile->nRef==0 ){
    quotaGroup *pGroup = pFile->pGroup;
    if( pFile->deleteOnClose ) quotaRemoveFile(pFile);
    quotaGroupDeref(pGroup);
  }
  quotaLeave();

  sqlite3_free(p);
  return rc;
}

/*
** Seek on a quota_FILE stream.
*/
................................................................................
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewStringObj(pGroup->zPattern, -1));
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewWideIntObj(pGroup->iLimit));
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewWideIntObj(pGroup->iSize));
    for(pFile=pGroup->pFiles; pFile; pFile=pFile->pNext){


      pFileTerm = Tcl_NewObj();


      Tcl_ListObjAppendElement(interp, pFileTerm,
            Tcl_NewStringObj(pFile->zFilename, -1));
      Tcl_ListObjAppendElement(interp, pFileTerm,
            Tcl_NewWideIntObj(pFile->iSize));
      Tcl_ListObjAppendElement(interp, pFileTerm,
            Tcl_NewWideIntObj(pFile->nRef));
      Tcl_ListObjAppendElement(interp, pFileTerm,
            Tcl_NewWideIntObj(pFile->deleteOnClose));
      Tcl_ListObjAppendElement(interp, pGroupTerm, pFileTerm);
................................................................................
    return TCL_ERROR;
  }
  zFilename = Tcl_GetString(objv[1]);
  rc = sqlite3_quota_remove(zFilename);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
  return TCL_OK;
}



























/*
** This routine registers the custom TCL commands defined in this
** module.  This should be the only procedure visible from outside
** of this module.
*/
int Sqlitequota_Init(Tcl_Interp *interp){
................................................................................
    { "sqlite3_quota_fread",      test_quota_fread },
    { "sqlite3_quota_fwrite",     test_quota_fwrite },
    { "sqlite3_quota_fclose",     test_quota_fclose },
    { "sqlite3_quota_fseek",      test_quota_fseek },
    { "sqlite3_quota_rewind",     test_quota_rewind },
    { "sqlite3_quota_ftell",      test_quota_ftell },
    { "sqlite3_quota_remove",     test_quota_remove },

  };
  int i;

  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
    Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  }

  return TCL_OK;
}
#endif







|







 







>

|







 







|







 







|







 







>
|
|
|
|
|
|
|
|
>







 







>
>

>
>

|







 







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







 







>










237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
...
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
...
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
....
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
....
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
....
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
....
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
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
....
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
**
**     [^...]     Matches one character not in the enclosed list.
**
**     /          Matches "/" or "\\"
**
*/
static int quotaStrglob(const char *zGlob, const char *z){
  int c, c2, cx;
  int invert;
  int seen;

  while( (c = (*(zGlob++)))!=0 ){
    if( c=='*' ){
      while( (c=(*(zGlob++))) == '*' || c=='?' ){
        if( c=='?' && (*(z++))==0 ) return 0;
................................................................................
        return 1;
      }else if( c=='[' ){
        while( *z && quotaStrglob(zGlob-1,z)==0 ){
          z++;
        }
        return (*z)!=0;
      }
      cx = (c=='/') ? '\\' : c;
      while( (c2 = (*(z++)))!=0 ){
        while( c2!=c && c2!=cx ){
          c2 = *(z++);
          if( c2==0 ) return 0;
        }
        if( quotaStrglob(zGlob,z) ) return 1;
      }
      return 0;
    }else if( c=='?' ){
................................................................................
}

/*
** Deallocate any memory allocated by quota_utf8_to_mbcs().
*/
static void quota_mbcs_free(char *zOld){
#if SQLITE_OS_WIN
  sqlite3_free(zOld);
#else
  /* No-op on unix */
#endif  
}

/************************* VFS Method Wrappers *****************************/
/*
................................................................................
  sqlite3_int64 iEnd;
  sqlite3_int64 szNew;
  quotaFile *pFile;
  
  iOfst = ftell(p->f);
  iEnd = iOfst + size*nmemb;
  pFile = p->pFile;
  if( pFile && pFile->iSize<iEnd ){
    quotaGroup *pGroup = pFile->pGroup;
    quotaEnter();
    szNew = pGroup->iSize - pFile->iSize + iEnd;
    if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
      if( pGroup->xCallback ){
        pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew, 
                          pGroup->pArg);
................................................................................
** Close an open quota_FILE stream.
*/
int sqlite3_quota_fclose(quota_FILE *p){
  int rc;
  quotaFile *pFile;
  rc = fclose(p->f);
  pFile = p->pFile;
  if( pFile ){
    quotaEnter();
    pFile->nRef--;
    if( pFile->nRef==0 ){
      quotaGroup *pGroup = pFile->pGroup;
      if( pFile->deleteOnClose ) quotaRemoveFile(pFile);
      quotaGroupDeref(pGroup);
    }
    quotaLeave();
  }
  sqlite3_free(p);
  return rc;
}

/*
** Seek on a quota_FILE stream.
*/
................................................................................
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewStringObj(pGroup->zPattern, -1));
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewWideIntObj(pGroup->iLimit));
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewWideIntObj(pGroup->iSize));
    for(pFile=pGroup->pFiles; pFile; pFile=pFile->pNext){
      int i;
      char zTemp[1000];
      pFileTerm = Tcl_NewObj();
      sqlite3_snprintf(sizeof(zTemp), zTemp, "%s", pFile->zFilename);
      for(i=0; zTemp[i]; i++){ if( zTemp[i]=='\\' ) zTemp[i] = '/'; }
      Tcl_ListObjAppendElement(interp, pFileTerm,
            Tcl_NewStringObj(zTemp, -1));
      Tcl_ListObjAppendElement(interp, pFileTerm,
            Tcl_NewWideIntObj(pFile->iSize));
      Tcl_ListObjAppendElement(interp, pFileTerm,
            Tcl_NewWideIntObj(pFile->nRef));
      Tcl_ListObjAppendElement(interp, pFileTerm,
            Tcl_NewWideIntObj(pFile->deleteOnClose));
      Tcl_ListObjAppendElement(interp, pGroupTerm, pFileTerm);
................................................................................
    return TCL_ERROR;
  }
  zFilename = Tcl_GetString(objv[1]);
  rc = sqlite3_quota_remove(zFilename);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
  return TCL_OK;
}

/*
** tclcmd: sqlite3_quota_glob PATTERN TEXT
**
** Test the glob pattern matching.  Return 1 if TEXT matches PATTERN
** and return 0 if it does not.
*/
static int test_quota_glob(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  const char *zPattern;          /* The glob pattern */
  const char *zText;             /* Text to compare agains the pattern */
  int rc;
  if( objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "PATTERN TEXT");
    return TCL_ERROR;
  }
  zPattern = Tcl_GetString(objv[1]);
  zText = Tcl_GetString(objv[2]);
  rc = quotaStrglob(zPattern, zText);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
  return TCL_OK;
}

/*
** This routine registers the custom TCL commands defined in this
** module.  This should be the only procedure visible from outside
** of this module.
*/
int Sqlitequota_Init(Tcl_Interp *interp){
................................................................................
    { "sqlite3_quota_fread",      test_quota_fread },
    { "sqlite3_quota_fwrite",     test_quota_fwrite },
    { "sqlite3_quota_fclose",     test_quota_fclose },
    { "sqlite3_quota_fseek",      test_quota_fseek },
    { "sqlite3_quota_rewind",     test_quota_rewind },
    { "sqlite3_quota_ftell",      test_quota_ftell },
    { "sqlite3_quota_remove",     test_quota_remove },
    { "sqlite3_quota_glob",       test_quota_glob },
  };
  int i;

  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
    Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  }

  return TCL_OK;
}
#endif

Added test/quota-glob.test.





































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# 2011 December 1
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests for the glob-style string compare operator embedded in the
# quota shim.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

catch { unset testnum }
catch { unset pattern }
catch { unset text }
catch { unset ans }

foreach {testnum pattern text ans} {
   1  abcdefg   abcdefg   1
   2  abcdefG   abcdefg   0
   3  abcdef    abcdefg   0
   4  abcdefgh  abcdefg   0
   5  abcdef?   abcdefg   1
   6  abcdef?   abcdef    0
   7  abcdef?   abcdefgh  0
   8  abcdefg   abcdef?   0
   9  abcdef?   abcdef?   1
  10  abc/def   abc/def   1
  11  abc/def   abc\\def  1
  12  */abc/*   x/abc/y   1
  13  */abc/*   /abc/     1
  16  */abc/*   x///a/ab/abc   0
  17  */abc/*   x//a/ab/abc/   1
  16  */abc/*   x///a/ab/abc   0
  17  */abc/*   x//a/ab/abc/   1
} {
  do_test quota-glob-$testnum.1 {
    sqlite3_quota_glob $::pattern $::text
  } $::ans
  do_test quota-glob-$testnum.2 {
    sqlite3_quota_glob $::pattern [string map {/ \\} $::text]
  } $::ans
}
finish_test

Changes to test/quota2.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
46
47
48
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
db close
sqlite3_quota_initialize "" 1

file delete -force quota2a
file delete -force quota2b
file mkdir quota2a
file mkdir quota2b












# The quota_check procedure is a callback from the quota handler.
# It has three arguments which are (1) the full pathname of the file
# that has gone over quota, (2) the quota limit, (3) the requested
# new quota size to cover the last write.  These three values are
# appended to the global variable $::quota.  The filename is processed
# to convert every \ character into / and to change the name of the
................................................................................
# working directory to PWD.  
#
# The quota is increased to the request if the ::quota_request_ok 
# global variable is true.
#
set ::quota {}
set ::quota_request_ok 0

proc quota_check {filename limitvar size} {
  upvar $limitvar limit
  set filename [string map [list [pwd] PWD \\ /] $filename]
  lappend ::quota $filename [set limit] $size
  if {$::quota_request_ok} {set limit $size}
}

sqlite3_quota_set */quota2a/* 4000 quota_check
sqlite3_quota_set */quota2b/* 5000 quota_check

unset -nocomplain bigtext
................................................................................
  sqlite3_quota_ftell $::h1
} {50}
do_test quota2-1.10 {
  sqlite3_quota_rewind $::h1
  sqlite3_quota_ftell $::h1
} {0}
do_test quota2-1.11 {
  string map [list [pwd] PWD \\ /] [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}}
do_test quota1-1.12 {
  sqlite3_quota_fclose $::h1
  string map [list [pwd] PWD \\ /] [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 0 0}}}
do_test quota1-1.13 {
  sqlite3_quota_remove quota2a/xyz.txt
  string map [list [pwd] PWD \\ /] [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}}



catch { sqlite3_quota_shutdown }
catch { unset quota_request_ok }
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
46
47
48
49
50
51

52
53
54
55
56
57
58
59
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
db close
sqlite3_quota_initialize "" 1

file delete -force quota2a
file delete -force quota2b
file mkdir quota2a
file mkdir quota2b

# The standard_path procedure converts a pathname into a standard format
# that is the same across platforms.
#
unset -nocomplain ::quota_pwd ::quota_mapping
set ::quota_pwd [string map {\\ /} [pwd]]
set ::quota_mapping [list $::quota_pwd PWD]
proc standard_path {x} {
  set x [string map {\\ /} $x]
  return [string map $::quota_mapping $x]
}

# The quota_check procedure is a callback from the quota handler.
# It has three arguments which are (1) the full pathname of the file
# that has gone over quota, (2) the quota limit, (3) the requested
# new quota size to cover the last write.  These three values are
# appended to the global variable $::quota.  The filename is processed
# to convert every \ character into / and to change the name of the
................................................................................
# working directory to PWD.  
#
# The quota is increased to the request if the ::quota_request_ok 
# global variable is true.
#
set ::quota {}
set ::quota_request_ok 0

proc quota_check {filename limitvar size} {
  upvar $limitvar limit

  lappend ::quota [standard_path $filename] [set limit] $size
  if {$::quota_request_ok} {set limit $size}
}

sqlite3_quota_set */quota2a/* 4000 quota_check
sqlite3_quota_set */quota2b/* 5000 quota_check

unset -nocomplain bigtext
................................................................................
  sqlite3_quota_ftell $::h1
} {50}
do_test quota2-1.10 {
  sqlite3_quota_rewind $::h1
  sqlite3_quota_ftell $::h1
} {0}
do_test quota2-1.11 {
  standard_path [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}}
do_test quota1-1.12 {
  sqlite3_quota_fclose $::h1
  standard_path [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 0 0}}}
do_test quota1-1.13 {
  sqlite3_quota_remove quota2a/xyz.txt
  standard_path [sqlite3_quota_dump]
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}}



catch { sqlite3_quota_shutdown }
catch { unset quota_request_ok }
finish_test