/ Check-in [b91b4c31]
Login

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

Overview
Comment:Merge trunk changes into sessions branch.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1:b91b4c31fe311b292044c9c747feba294ffce25c
User & Date: dan 2011-04-18 17:30:56
Context
2011-05-05
15:46
Merge the latest trunk changes into the sessions branch. check-in: 6883580e user: drh tags: sessions
2011-04-18
17:30
Merge trunk changes into sessions branch. check-in: b91b4c31 user: dan tags: sessions
15:47
Fix further missing comments and other minor issues in the session module code. check-in: 99f0f350 user: dan tags: sessions
2011-04-17
17:09
Change the prototype for the open() system call to agree with Posix. Though a faulty function prototype in a pointer cast is a seemingly innocuous error, the correct prototype is necessary for pthreads to work correctly on NetBSD. check-in: 3e135748 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to VERSION.

1
3.7.6
|
1
3.7.6.1

Changes to configure.

1
2
3
4
5
6
7
8
9
10
...
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
....
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
....
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
....
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
.....
13938
13939
13940
13941
13942
13943
13944
13945
13946
13947
13948
13949
13950
13951
13952
.....
13991
13992
13993
13994
13995
13996
13997
13998
13999
14000
14001
14002
14003
14004
14005
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.62 for sqlite 3.7.6.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
## --------------------- ##
## M4sh Initialization.  ##
................................................................................
MFLAGS=
MAKEFLAGS=
SHELL=${CONFIG_SHELL-/bin/sh}

# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.7.6'
PACKAGE_STRING='sqlite 3.7.6'
PACKAGE_BUGREPORT=''

# Factoring default headers for most tests.
ac_includes_default="\
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
................................................................................
#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures sqlite 3.7.6 to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.
................................................................................
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
_ACEOF
fi

if test -n "$ac_init_help"; then
  case $ac_init_help in
     short | recursive ) echo "Configuration of sqlite 3.7.6:";;
   esac
  cat <<\_ACEOF

Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
................................................................................
    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
sqlite configure 3.7.6
generated by GNU Autoconf 2.62

Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit
fi
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by sqlite $as_me 3.7.6, which was
generated by GNU Autoconf 2.62.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{
................................................................................

exec 6>&1

# Save the log message, to keep $[0] and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.7.6, which was
generated by GNU Autoconf 2.62.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@
................................................................................
$config_commands

Report bugs to <bug-autoconf@gnu.org>."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
sqlite config.status 3.7.6
configured by $0, generated by GNU Autoconf 2.62,
  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

Copyright (C) 2008 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."



|







 







|
|







 







|







 







|







 







|













|







 







|







 







|







1
2
3
4
5
6
7
8
9
10
...
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
....
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
....
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
....
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
.....
13938
13939
13940
13941
13942
13943
13944
13945
13946
13947
13948
13949
13950
13951
13952
.....
13991
13992
13993
13994
13995
13996
13997
13998
13999
14000
14001
14002
14003
14004
14005
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.62 for sqlite 3.7.6.1.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
## --------------------- ##
## M4sh Initialization.  ##
................................................................................
MFLAGS=
MAKEFLAGS=
SHELL=${CONFIG_SHELL-/bin/sh}

# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.7.6.1'
PACKAGE_STRING='sqlite 3.7.6.1'
PACKAGE_BUGREPORT=''

# Factoring default headers for most tests.
ac_includes_default="\
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
................................................................................
#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures sqlite 3.7.6.1 to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.
................................................................................
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
_ACEOF
fi

if test -n "$ac_init_help"; then
  case $ac_init_help in
     short | recursive ) echo "Configuration of sqlite 3.7.6.1:";;
   esac
  cat <<\_ACEOF

Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
................................................................................
    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
sqlite configure 3.7.6.1
generated by GNU Autoconf 2.62

Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit
fi
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by sqlite $as_me 3.7.6.1, which was
generated by GNU Autoconf 2.62.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{
................................................................................

exec 6>&1

# Save the log message, to keep $[0] and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.7.6.1, which was
generated by GNU Autoconf 2.62.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@
................................................................................
$config_commands

Report bugs to <bug-autoconf@gnu.org>."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
sqlite config.status 3.7.6.1
configured by $0, generated by GNU Autoconf 2.62,
  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

Copyright (C) 2008 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."

Changes to src/malloc.c.

262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
...
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
  int nFull;
  void *p;
  assert( sqlite3_mutex_held(mem0.mutex) );
  nFull = sqlite3GlobalConfig.m.xRoundup(n);
  sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
  if( mem0.alarmCallback!=0 ){
    int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
    if( nUsed+nFull >= mem0.alarmThreshold ){
      mem0.nearlyFull = 1;
      sqlite3MallocAlarm(nFull);
    }else{
      mem0.nearlyFull = 0;
    }
  }
  p = sqlite3GlobalConfig.m.xMalloc(nFull);
................................................................................
  sqlite3_free(p);
}

/*
** Change the size of an existing memory allocation
*/
void *sqlite3Realloc(void *pOld, int nBytes){
  int nOld, nNew;
  void *pNew;
  if( pOld==0 ){
    return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
  }
  if( nBytes<=0 ){
    sqlite3_free(pOld); /* IMP: R-31593-10574 */
    return 0;
................................................................................
  ** xRoundup. */
  nNew = sqlite3GlobalConfig.m.xRoundup(nBytes);
  if( nOld==nNew ){
    pNew = pOld;
  }else if( sqlite3GlobalConfig.bMemstat ){
    sqlite3_mutex_enter(mem0.mutex);
    sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes);

    if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >= 
          mem0.alarmThreshold ){
      sqlite3MallocAlarm(nNew-nOld);
    }
    assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
    assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
    pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
    if( pNew==0 && mem0.alarmCallback ){
      sqlite3MallocAlarm(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;







|







 







|







 







>
|
|











|







262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
...
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
  int nFull;
  void *p;
  assert( sqlite3_mutex_held(mem0.mutex) );
  nFull = sqlite3GlobalConfig.m.xRoundup(n);
  sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
  if( mem0.alarmCallback!=0 ){
    int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
    if( nUsed >= mem0.alarmThreshold - nFull ){
      mem0.nearlyFull = 1;
      sqlite3MallocAlarm(nFull);
    }else{
      mem0.nearlyFull = 0;
    }
  }
  p = sqlite3GlobalConfig.m.xMalloc(nFull);
................................................................................
  sqlite3_free(p);
}

/*
** Change the size of an existing memory allocation
*/
void *sqlite3Realloc(void *pOld, int 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;
................................................................................
  ** xRoundup. */
  nNew = sqlite3GlobalConfig.m.xRoundup(nBytes);
  if( nOld==nNew ){
    pNew = pOld;
  }else if( sqlite3GlobalConfig.bMemstat ){
    sqlite3_mutex_enter(mem0.mutex);
    sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes);
    nDiff = nNew - nOld;
    if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= 
          mem0.alarmThreshold-nDiff ){
      sqlite3MallocAlarm(nNew-nOld);
    }
    assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
    assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
    pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
    if( pNew==0 && mem0.alarmCallback ){
      sqlite3MallocAlarm(nBytes);
      pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
    }
    if( pNew ){
      nNew = sqlite3MallocSize(pNew);
      sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nDiff);
    }
    sqlite3_mutex_leave(mem0.mutex);
  }else{
    pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
  }
  assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-04675-44850 */
  return pNew;

Changes to src/mutex_os2.c.

247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  assert( os2MutexHeld(p) );
  DosReleaseMutexSem(p->mutex);
#ifdef SQLITE_DEBUG
  if( p->trace ) os2MutexTrace(p, "leave");
#endif
}

SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
  static const sqlite3_mutex_methods sMutex = {
    os2MutexInit,
    os2MutexEnd,
    os2MutexAlloc,
    os2MutexFree,
    os2MutexEnter,
    os2MutexTry,







|







247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  assert( os2MutexHeld(p) );
  DosReleaseMutexSem(p->mutex);
#ifdef SQLITE_DEBUG
  if( p->trace ) os2MutexTrace(p, "leave");
#endif
}

sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
  static const sqlite3_mutex_methods sMutex = {
    os2MutexInit,
    os2MutexEnd,
    os2MutexAlloc,
    os2MutexFree,
    os2MutexEnter,
    os2MutexTry,

Changes to src/os_os2.c.

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
...
161
162
163
164
165
166
167
168
169

170
171










172
173
174
175
176
177
178
...
528
529
530
531
532
533
534














535
536
537
538
539
540
541
...
543
544
545
546
547
548
549

550
551
552
553
554
555
556
557

558
559
560
561
562
563
564
...
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
...
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
...
766
767
768
769
770
771
772
773
774
775
776

777
778
779
780
781
782
783
...
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
...
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
...
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
...
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
994
995
996
997
998
999
1000
1001
1002
1003
....
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
....
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
1158
1159
....
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186

1187
1188
1189
1190
1191
1192
1193
1194
#endif

/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"






/*
** The os2File structure is subclass of sqlite3_file specific for the OS/2
** protability layer.
*/
typedef struct os2File os2File;
struct os2File {
  const sqlite3_io_methods *pMethod;  /* Always the first entry */
  HFILE h;                  /* Handle for accessing the file */
  char* pathToDel;          /* Name of file to delete on close, NULL if not */
  unsigned char locktype;   /* Type of lock currently held on this file */



};

#define LOCK_TIMEOUT 10L /* the default locking timeout */









/*****************************************************************************
** The next group of routines implement the I/O methods specified
** by the sqlite3_io_methods object.
******************************************************************************/

/*
** Close a file.
*/
static int os2Close( sqlite3_file *id ){
  APIRET rc = NO_ERROR;
  os2File *pFile;
  if( id && (pFile = (os2File*)id) != 0 ){
    OSTRACE(( "CLOSE %d\n", pFile->h ));
    rc = DosClose( pFile->h );
    pFile->locktype = NO_LOCK;
    if( pFile->pathToDel != NULL ){
      rc = DosForceDelete( (PSZ)pFile->pathToDel );
      free( pFile->pathToDel );
      pFile->pathToDel = NULL;
    }
    id = 0;
    OpenCounter( -1 );
  }




  return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
}

/*
** Read data from a file into a buffer.  Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
................................................................................
  return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK;
}

/*
** Truncate an open file to a specified size
*/
static int os2Truncate( sqlite3_file *id, i64 nByte ){
  APIRET rc = NO_ERROR;
  os2File *pFile = (os2File*)id;

  OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte ));
  SimulateIOError( return SQLITE_IOERR_TRUNCATE );










  rc = DosSetFileSize( pFile->h, nByte );
  return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
}

#ifdef SQLITE_TEST
/*
** Count the number of fullsyncs and normal syncs.  This is used to test
................................................................................
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((os2File*)id)->locktype;
      OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n",
                ((os2File*)id)->h, ((os2File*)id)->locktype ));
      return SQLITE_OK;
    }














  }
  return SQLITE_NOTFOUND;
}

/*
** Return the sector size in bytes of the underlying block device for
** the specified file. This is almost always 512 bytes, but may be
................................................................................
**
** SQLite code assumes this function cannot fail. It also assumes that
** if two files are created in the same file-system directory (i.e.
** a database and its journal file) that the sector size will be the
** same for both.
*/
static int os2SectorSize(sqlite3_file *id){

  return SQLITE_DEFAULT_SECTOR_SIZE;
}

/*
** Return a vector of device characteristics.
*/
static int os2DeviceCharacteristics(sqlite3_file *id){
  return 0;

}


/*
** Character set conversion objects used by conversion routines.
*/
static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */
................................................................................
    return out; /* if conversion fails, return the empty string */

  /* determine string for the conversion of UTF-8 which is CP1208 */
  UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH );

  return out;
}




/*








































































































































































































































































































































































































































































































































































































































































** This vector defines all the methods that can operate on an
** sqlite3_file for os2.
*/
static const sqlite3_io_methods os2IoMethod = {
  1,                              /* iVersion */
  os2Close,                       /* xClose */
  os2Read,                        /* xRead */
  os2Write,                       /* xWrite */
  os2Truncate,                    /* xTruncate */
  os2Sync,                        /* xSync */
  os2FileSize,                    /* xFileSize */
  os2Lock,                        /* xLock */
  os2Unlock,                      /* xUnlock */
  os2CheckReservedLock,           /* xCheckReservedLock */
  os2FileControl,                 /* xFileControl */
  os2SectorSize,                  /* xSectorSize */
  os2DeviceCharacteristics,       /* xDeviceCharacteristics */
  0,                              /* xShmMap */
  0,                              /* xShmLock */
  0,                              /* xShmBarrier */
  0                               /* xShmUnmap */
};


/***************************************************************************
** Here ends the I/O methods that form the sqlite3_io_methods object.
**
** The next block of code implements the VFS methods.
****************************************************************************/

/*
** Create a temporary file name in zBuf.  zBuf must be big enough to
** hold at pVfs->mxPathname characters.
*/
static int getTempname(int nBuf, char *zBuf ){
  static const unsigned char zChars[] =
    "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "0123456789";
  int i, j;
  char zTempPathBuf[3];
  PSZ zTempPath = (PSZ)&zTempPathBuf;








  if( sqlite3_temp_directory ){
    zTempPath = sqlite3_temp_directory;
  }else{

    if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){
      if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){
        if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){
           ULONG ulDriveNum = 0, ulDriveMap = 0;



           DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap );
           sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) );




        }
      }
    }
  }
  /* Strip off a trailing slashes or backslashes, otherwise we would get *
   * multiple (back)slashes which causes DosOpen() to fail.              *
   * Trailing spaces are not allowed, either.                            */
  j = sqlite3Strlen30(zTempPath);
  while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/'
                    || zTempPath[j-1] == ' ' ) ){
    j--;
  }
  zTempPath[j] = '\0';
  if( !sqlite3_temp_directory ){

    char *zTempPathUTF = convertCpPathToUtf8( zTempPath );
    sqlite3_snprintf( nBuf-30, zBuf,
                      "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF );
    free( zTempPathUTF );
  }else{
    sqlite3_snprintf( nBuf-30, zBuf,
                      "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath );
  }
  j = sqlite3Strlen30( zBuf );
  sqlite3_randomness( 20, &zBuf[j] );
  for( i = 0; i < 20; i++, j++ ){
    zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
  }
  zBuf[j] = 0;

  OSTRACE(( "TEMP FILENAME: %s\n", zBuf ));
  return SQLITE_OK;
}


/*
** Turn a relative pathname into a full pathname.  Write the full
................................................................................
  const char *zRelative,      /* Possibly relative input path */
  int nFull,                  /* Size of output buffer in bytes */
  char *zFull                 /* Output buffer */
){
  char *zRelativeCp = convertUtf8PathToCp( zRelative );
  char zFullCp[CCHMAXPATH] = "\0";
  char *zFullUTF;
  APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp,
                                CCHMAXPATH );
  free( zRelativeCp );
  zFullUTF = convertCpPathToUtf8( zFullCp );
  sqlite3_snprintf( nFull, zFull, zFullUTF );
  free( zFullUTF );
  return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
}

................................................................................
  ULONG rc;
  os2File *pFile = (os2File*)id;
  const char *zUtf8Name = zName;
  char *zNameCp;
  char  zTmpname[CCHMAXPATH];

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
  int isCreate     = (flags & SQLITE_OPEN_CREATE);
  int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);
#ifndef NDEBUG

  int isReadonly   = (flags & SQLITE_OPEN_READONLY);
  int eType        = (flags & 0xFFFFFF00);
  int isOpenJournal = (isCreate && (
        eType==SQLITE_OPEN_MASTER_JOURNAL 
     || eType==SQLITE_OPEN_MAIN_JOURNAL 
     || eType==SQLITE_OPEN_WAL
  ));
................................................................................
  assert( eType==SQLITE_OPEN_MAIN_DB      || eType==SQLITE_OPEN_TEMP_DB 
       || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL 
       || eType==SQLITE_OPEN_SUBJOURNAL   || eType==SQLITE_OPEN_MASTER_JOURNAL 
       || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
  );

  memset( pFile, 0, sizeof(*pFile) );
  pFile->pMethod = &os2IoMethod;

  /* If the second argument to this function is NULL, generate a 
  ** temporary file name to use 
  */
  if( !zUtf8Name ){
    assert(isDelete && !isOpenJournal);
    rc = getTempname(CCHMAXPATH, zTmpname);
................................................................................
    ulOpenMode |= OPEN_ACCESS_READWRITE;
  }else{
    ulOpenMode |= OPEN_ACCESS_READONLY;
  }

  /* Open in random access mode for possibly better speed.  Allow full
  ** sharing because file locks will provide exclusive access when needed.
  */
  ulOpenMode |= OPEN_FLAGS_RANDOM;
  ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR;
  ulOpenMode |= OPEN_FLAGS_NOINHERIT;
  ulOpenMode |= OPEN_SHARE_DENYNONE;

  /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is 
  ** created. SQLite doesn't use it to indicate "exclusive access" 
  ** as it is usually understood.
  */
  if( isExclusive ){
    /* Creates a new file, only if it does not already exist. */
................................................................................
    /* Open existing file, or create if it doesn't exist */
    ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
  }else{
    /* Opens a file, only if it exists. */
    ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
  }

  /* For DELETEONCLOSE, save a pointer to the converted filename */
  if( isDelete ){
    char pathUtf8[CCHMAXPATH];
    os2FullPathname( pVfs, zUtf8Name, CCHMAXPATH, pathUtf8 );
    pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
  }

  zNameCp = convertUtf8PathToCp( zUtf8Name );
  rc = DosOpen( (PSZ)zNameCp,
                &h,
                &ulAction,
                0L,
                FILE_NORMAL,
                ulOpenFlags,
................................................................................
                ulOpenMode,
                (PEAOP2)NULL );
  free( zNameCp );

  if( rc != NO_ERROR ){
    OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
              rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode ));
    if( pFile->pathToDel )
      free( pFile->pathToDel );
    pFile->pathToDel = NULL;

    if( isReadWrite ){
      return os2Open( pVfs, zName, id,
                      ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
                      pOutFlags );
    }else{
      return SQLITE_CANTOPEN;
................................................................................
    }
  }

  if( pOutFlags ){
    *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
  }





  pFile->h = h;

  OpenCounter(+1);
  OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
  return SQLITE_OK;
}

/*
** Delete the named file.
................................................................................
*/
static int os2Access(
  sqlite3_vfs *pVfs,        /* Not used on os2 */
  const char *zFilename,    /* Name of file to check */
  int flags,                /* Type of test to make on this file */
  int *pOut                 /* Write results here */
){

  FILESTATUS3 fsts3ConfigInfo;
  APIRET rc = NO_ERROR;
  char *zFilenameCp = convertUtf8PathToCp( zFilename );

  memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) );



  rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
                         &fsts3ConfigInfo, sizeof(FILESTATUS3) );
  free( zFilenameCp );
  OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
            fsts3ConfigInfo.attrFile, flags, rc ));

  switch( flags ){
    case SQLITE_ACCESS_READ:






    case SQLITE_ACCESS_EXISTS:
      rc = (rc == NO_ERROR);
      OSTRACE(( "ACCESS %s access of read and exists  rc=%d\n", zFilename, rc));
      break;
    case SQLITE_ACCESS_READWRITE:
      rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 );
      OSTRACE(( "ACCESS %s access of read/write  rc=%d\n", zFilename, rc ));

      break;
    default:

      assert( !"Invalid flags argument" );
  }

  *pOut = rc;


  return SQLITE_OK;
}


#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
................................................................................
** within the shared library, and closing the shared library.
*/
/*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){
  UCHAR loadErr[256];
  HMODULE hmod;
  APIRET rc;
  char *zFilenameCp = convertUtf8PathToCp(zFilename);
  rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod);
  free(zFilenameCp);
  return rc != NO_ERROR ? 0 : (void*)hmod;
}
/*
** A no-op since the error code is returned on the DosLoadModule call.
** os2Dlopen returns zero if DosLoadModule is not successful.
*/
static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
/* no-op */
}
static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
  PFN pfn;
  APIRET rc;
  rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn);
  if( rc != NO_ERROR ){
    /* if the symbol itself was not found, search again for the same
     * symbol with an extra underscore, that might be needed depending
     * on the calling convention */
    char _zSymbol[256] = "_";
    strncat(_zSymbol, zSymbol, 255);
    rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn);
  }
  return rc != NO_ERROR ? 0 : (void(*)(void))pfn;
}
static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
  DosFreeModule((HMODULE)pHandle);
}
#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
................................................................................
*/
static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){
  int n = 0;
#if defined(SQLITE_TEST)
  n = nBuf;
  memset(zBuf, 0, nBuf);
#else
  int sizeofULong = sizeof(ULONG);
  if( (int)sizeof(DATETIME) <= nBuf - n ){

    DATETIME x;
    DosGetDateTime(&x);
    memcpy(&zBuf[n], &x, sizeof(x));
    n += sizeof(x);



  }


  if( sizeofULong <= nBuf - n ){
    PPIB ppib;
    DosGetInfoBlocks(NULL, &ppib);



    memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong);
    n += sizeofULong;
  }


  if( sizeofULong <= nBuf - n ){
    PTIB ptib;
    DosGetInfoBlocks(&ptib, NULL);

    memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong);
    n += sizeofULong;
  }

  /* if we still haven't filled the buffer yet the following will */
  /* grab everything once instead of making several calls for a single item */
  if( sizeofULong <= nBuf - n ){
    ULONG ulSysInfo[QSV_MAX];
    DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX);


    memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong);
    n += sizeofULong;

    if( sizeofULong <= nBuf - n ){
      memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong);

      n += sizeofULong;
    }
    if( sizeofULong <= nBuf - n ){
      memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong);
      n += sizeofULong;
    }
    if( sizeofULong <= nBuf - n ){
      memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong);
      n += sizeofULong;
    }
    if( sizeofULong <= nBuf - n ){
      memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong);
      n += sizeofULong;
    }
  }
#endif

  return n;
}

/*
** Sleep for a little while.  Return the amount of time slept.
................................................................................
** The following variable, if set to a non-zero value, becomes the result
** returned from sqlite3OsCurrentTime().  This is used for testing.
*/
#ifdef SQLITE_TEST
int sqlite3_current_time = 0;
#endif

/*
** Find the current time (in Universal Coordinated Time).  Write the
** current time and date as a Julian Day number into *prNow and
** return 0.  Return 1 if the time and date cannot be found.
*/
int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
  double now;
  SHORT minute; /* needs to be able to cope with negative timezone offset */
  USHORT hundredths, second, hour,
         day, month, year;
  DATETIME dt;
  DosGetDateTime( &dt );
  hundredths = (USHORT)dt.hundredths;
  second = (USHORT)dt.seconds;
  minute = (SHORT)dt.minutes + dt.timezone;
  hour = (USHORT)dt.hours;
  day = (USHORT)dt.day;
  month = (USHORT)dt.month;
  year = (USHORT)dt.year;

  /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
     http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */
  /* Calculate the Julian days */
  now = day - 32076 +
    1461*(year + 4800 + (month - 14)/12)/4 +
    367*(month - 2 - (month - 14)/12*12)/12 -
    3*((year + 4900 + (month - 14)/12)/100)/4;

  /* Add the fractional hours, mins and seconds */
  now += (hour + 12.0)/24.0;
  now += minute/1440.0;
  now += second/86400.0;
  now += hundredths/8640000.0;
  *prNow = now;
#ifdef SQLITE_TEST
  if( sqlite3_current_time ){
    *prNow = sqlite3_current_time/86400.0 + 2440587.5;
  }
#endif
  return 0;
}

/*
** Find the current time (in Universal Coordinated Time).  Write into *piNow
** the current time and date as a Julian Day number times 86_400_000.  In
** other words, write into *piNow the number of milliseconds since the Julian
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
** proleptic Gregorian calendar.
**
** On success, return 0.  Return 1 if the time and date cannot be found.
*/
static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
  double now;











































  os2CurrentTime(pVfs, &now);
  *piNow = now * 86400000;



  return 0;
}































static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){

  return 0;
}

/*
** Initialize and deinitialize the operating system interface.
*/
int sqlite3_os_init(void){
................................................................................
    os2DlError,        /* xDlError */
    os2DlSym,          /* xDlSym */
    os2DlClose,        /* xDlClose */
    os2Randomness,     /* xRandomness */
    os2Sleep,          /* xSleep */
    os2CurrentTime,    /* xCurrentTime */
    os2GetLastError,   /* xGetLastError */
    os2CurrentTimeInt64 /* xCurrentTimeInt64 */
    0,                 /* xSetSystemCall */
    0,                 /* xGetSystemCall */
    0,                 /* xNextSystemCall */
  };
  sqlite3_vfs_register(&os2Vfs, 1);
  initUconvObjects();

  return SQLITE_OK;
}
int sqlite3_os_end(void){
  freeUconvObjects();
  return SQLITE_OK;
}

#endif /* SQLITE_OS_OS2 */







>
>
>
>
>




<



|
|
>
>
>




>
>
>
>
>
>
>
>









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







 







|

>


>
>
>
>
>
>
>
>
>
>







 







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







 







>







|
>







 








>
>
>

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




|












|
|
|
|

>












|




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




|
|



<
>
|
|
<
<
<
<
|
<
|


|


>







 







|
|







 







<



>







 







|







 







|
|
|
|
|







 







<
<
<
<
<
<
<







 







<
<
<







 







>
>
>
>

>







 







>

<
|

|
>
>
>





>

|
>
>
>
>
>
>
|
<
<


|
<
>


>


>
|
>
>







 







<



|













|





|
|







 







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


>
|
<
|
>
|
|


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







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










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


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

>







 







|


|



>








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
...
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
...
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
...
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
...
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
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
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
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
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
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
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
....
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
....
1470
1471
1472
1473
1474
1475
1476

1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
....
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
....
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
....
1557
1558
1559
1560
1561
1562
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
....
1625
1626
1627
1628
1629
1630
1631
1632
1633

1634
1635
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
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
....
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733

1734
1735
1736
1737
1738
1739

1740
1741


1742
1743
1744
1745
1746
1747
1748
1749
1750

1751
1752
1753
1754
1755
1756






1757
1758
1759



1760
1761
1762













1763
1764
1765
1766
1767
1768
1769
....
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
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843

1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
....
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
#endif

/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"

/* Forward references */
typedef struct os2File os2File;         /* The file structure */
typedef struct os2ShmNode os2ShmNode;   /* A shared descritive memory node */
typedef struct os2ShmLink os2ShmLink;   /* A connection to shared-memory */

/*
** The os2File structure is subclass of sqlite3_file specific for the OS/2
** protability layer.
*/

struct os2File {
  const sqlite3_io_methods *pMethod;  /* Always the first entry */
  HFILE h;                  /* Handle for accessing the file */
  int flags;                /* Flags provided to os2Open() */
  int locktype;             /* Type of lock currently held on this file */
  int szChunk;              /* Chunk size configured by FCNTL_CHUNK_SIZE */
  char *zFullPathCp;        /* Full path name of this file */
  os2ShmLink *pShmLink;     /* Instance of shared memory on this file */
};

#define LOCK_TIMEOUT 10L /* the default locking timeout */

/*
** Missing from some versions of the OS/2 toolkit -
** used to allocate from high memory if possible
*/
#ifndef OBJ_ANY
# define OBJ_ANY 0x00000400
#endif

/*****************************************************************************
** The next group of routines implement the I/O methods specified
** by the sqlite3_io_methods object.
******************************************************************************/

/*
** Close a file.
*/
static int os2Close( sqlite3_file *id ){
  APIRET rc;
  os2File *pFile = (os2File*)id;

  assert( id!=0 );
  OSTRACE(( "CLOSE %d (%s)\n", pFile->h, pFile->zFullPathCp ));

  rc = DosClose( pFile->h );

  if( pFile->flags & SQLITE_OPEN_DELETEONCLOSE )
    DosForceDelete( (PSZ)pFile->zFullPathCp );

  free( pFile->zFullPathCp );
  pFile->zFullPathCp = NULL;
  pFile->locktype = NO_LOCK;
  pFile->h = (HFILE)-1;
  pFile->flags = 0;

  OpenCounter( -1 );
  return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
}

/*
** Read data from a file into a buffer.  Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
................................................................................
  return ( rc != NO_ERROR || amt > (int)wrote ) ? SQLITE_FULL : SQLITE_OK;
}

/*
** Truncate an open file to a specified size
*/
static int os2Truncate( sqlite3_file *id, i64 nByte ){
  APIRET rc;
  os2File *pFile = (os2File*)id;
  assert( id!=0 );
  OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte ));
  SimulateIOError( return SQLITE_IOERR_TRUNCATE );

  /* If the user has configured a chunk-size for this file, truncate the
  ** file so that it consists of an integer number of chunks (i.e. the
  ** actual file size after the operation may be larger than the requested
  ** size).
  */
  if( pFile->szChunk ){
    nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
  }
  
  rc = DosSetFileSize( pFile->h, nByte );
  return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
}

#ifdef SQLITE_TEST
/*
** Count the number of fullsyncs and normal syncs.  This is used to test
................................................................................
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
      *(int*)pArg = ((os2File*)id)->locktype;
      OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n",
                ((os2File*)id)->h, ((os2File*)id)->locktype ));
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_CHUNK_SIZE: {
      ((os2File*)id)->szChunk = *(int*)pArg;
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SIZE_HINT: {
      sqlite3_int64 sz = *(sqlite3_int64*)pArg;
      SimulateIOErrorBenign(1);
      os2Truncate(id, sz);
      SimulateIOErrorBenign(0);
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;
    }
  }
  return SQLITE_NOTFOUND;
}

/*
** Return the sector size in bytes of the underlying block device for
** the specified file. This is almost always 512 bytes, but may be
................................................................................
**
** SQLite code assumes this function cannot fail. It also assumes that
** if two files are created in the same file-system directory (i.e.
** a database and its journal file) that the sector size will be the
** same for both.
*/
static int os2SectorSize(sqlite3_file *id){
  UNUSED_PARAMETER(id);
  return SQLITE_DEFAULT_SECTOR_SIZE;
}

/*
** Return a vector of device characteristics.
*/
static int os2DeviceCharacteristics(sqlite3_file *id){
  UNUSED_PARAMETER(id);
  return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
}


/*
** Character set conversion objects used by conversion routines.
*/
static UconvObject ucUtf8 = NULL; /* convert between UTF-8 and UCS-2 */
................................................................................
    return out; /* if conversion fails, return the empty string */

  /* determine string for the conversion of UTF-8 which is CP1208 */
  UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH );

  return out;
}


#ifndef SQLITE_OMIT_WAL

/*
** Use main database file for interprocess locking. If un-defined
** a separate file is created for this purpose. The file will be
** used only to set file locks. There will be no data written to it.
*/
#define SQLITE_OS2_NO_WAL_LOCK_FILE     

#if 0
static void _ERR_TRACE( const char *fmt, ... ) {
  va_list  ap;
  va_start(ap, fmt);
  vfprintf(stderr, fmt, ap);
  fflush(stderr);
}
#define ERR_TRACE(rc, msg)        \
        if( (rc) != SQLITE_OK ) _ERR_TRACE msg;
#else
#define ERR_TRACE(rc, msg)
#endif

/*
** Helper functions to obtain and relinquish the global mutex. The
** global mutex is used to protect os2ShmNodeList.
**
** Function os2ShmMutexHeld() is used to assert() that the global mutex 
** is held when required. This function is only used as part of assert() 
** statements. e.g.
**
**   os2ShmEnterMutex()
**     assert( os2ShmMutexHeld() );
**   os2ShmLeaveMutex()
*/
static void os2ShmEnterMutex(void){
  sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
static void os2ShmLeaveMutex(void){
  sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
#ifdef SQLITE_DEBUG
static int os2ShmMutexHeld(void) {
  return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
int GetCurrentProcessId(void) {
  PPIB pib;
  DosGetInfoBlocks(NULL, &pib);
  return (int)pib->pib_ulpid;
}
#endif

/*
** Object used to represent a the shared memory area for a single log file.
** When multiple threads all reference the same log-summary, each thread has
** its own os2File object, but they all point to a single instance of this 
** object.  In other words, each log-summary is opened only once per process.
**
** os2ShmMutexHeld() must be true when creating or destroying
** this object or while reading or writing the following fields:
**
**      nRef
**      pNext 
**
** The following fields are read-only after the object is created:
** 
**      szRegion
**      hLockFile
**      shmBaseName
**
** Either os2ShmNode.mutex must be held or os2ShmNode.nRef==0 and
** os2ShmMutexHeld() is true when reading or writing any other field
** in this structure.
**
*/
struct os2ShmNode {
  sqlite3_mutex *mutex;      /* Mutex to access this object */
  os2ShmNode *pNext;         /* Next in list of all os2ShmNode objects */

  int szRegion;              /* Size of shared-memory regions */

  int nRegion;               /* Size of array apRegion */
  void **apRegion;           /* Array of pointers to shared-memory regions */

  int nRef;                  /* Number of os2ShmLink objects pointing to this */
  os2ShmLink *pFirst;        /* First os2ShmLink object pointing to this */

  HFILE hLockFile;           /* File used for inter-process memory locking */
  char shmBaseName[1];       /* Name of the memory object !!! must last !!! */
};


/*
** Structure used internally by this VFS to record the state of an
** open shared memory connection.
**
** The following fields are initialized when this object is created and
** are read-only thereafter:
**
**    os2Shm.pShmNode
**    os2Shm.id
**
** All other fields are read/write.  The os2Shm.pShmNode->mutex must be held
** while accessing any read/write fields.
*/
struct os2ShmLink {
  os2ShmNode *pShmNode;      /* The underlying os2ShmNode object */
  os2ShmLink *pNext;         /* Next os2Shm with the same os2ShmNode */
  u32 sharedMask;            /* Mask of shared locks held */
  u32 exclMask;              /* Mask of exclusive locks held */
#ifdef SQLITE_DEBUG
  u8 id;                     /* Id of this connection with its os2ShmNode */
#endif
};


/*
** A global list of all os2ShmNode objects.
**
** The os2ShmMutexHeld() must be true while reading or writing this list.
*/
static os2ShmNode *os2ShmNodeList = NULL;

/*
** Constants used for locking
*/
#ifdef  SQLITE_OS2_NO_WAL_LOCK_FILE
#define OS2_SHM_BASE   (PENDING_BYTE + 0x10000)         /* first lock byte */
#else
#define OS2_SHM_BASE   ((22+SQLITE_SHM_NLOCK)*4)        /* first lock byte */
#endif

#define OS2_SHM_DMS    (OS2_SHM_BASE+SQLITE_SHM_NLOCK)  /* deadman switch */

/*
** Apply advisory locks for all n bytes beginning at ofst.
*/
#define _SHM_UNLCK  1   /* no lock */
#define _SHM_RDLCK  2   /* shared lock, no wait */
#define _SHM_WRLCK  3   /* exlusive lock, no wait */
#define _SHM_WRLCK_WAIT 4 /* exclusive lock, wait */
static int os2ShmSystemLock(
  os2ShmNode *pNode,    /* Apply locks to this open shared-memory segment */
  int lockType,         /* _SHM_UNLCK, _SHM_RDLCK, _SHM_WRLCK or _SHM_WRLCK_WAIT */
  int ofst,             /* Offset to first byte to be locked/unlocked */
  int nByte             /* Number of bytes to lock or unlock */
){
  APIRET rc;
  FILELOCK area;
  ULONG mode, timeout;

  /* Access to the os2ShmNode object is serialized by the caller */
  assert( sqlite3_mutex_held(pNode->mutex) || pNode->nRef==0 );

  mode = 1;     /* shared lock */
  timeout = 0;  /* no wait */
  area.lOffset = ofst;
  area.lRange = nByte;

  switch( lockType ) {
    case _SHM_WRLCK_WAIT:
      timeout = (ULONG)-1;      /* wait forever */
    case _SHM_WRLCK:
      mode = 0;                 /* exclusive lock */
    case _SHM_RDLCK:
      rc = DosSetFileLocks(pNode->hLockFile, 
                           NULL, &area, timeout, mode);
      break;
    /* case _SHM_UNLCK: */
    default:
      rc = DosSetFileLocks(pNode->hLockFile, 
                           &area, NULL, 0, 0);
      break;
  }
                          
  OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n", 
           pNode->hLockFile,
           rc==SQLITE_OK ? "ok" : "failed",
           lockType==_SHM_UNLCK ? "Unlock" : "Lock",
           rc));

  ERR_TRACE(rc, ("os2ShmSystemLock: %d %s\n", rc, pNode->shmBaseName))

  return ( rc == 0 ) ?  SQLITE_OK : SQLITE_BUSY;
}

/*
** Find an os2ShmNode in global list or allocate a new one, if not found.
**
** This is not a VFS shared-memory method; it is a utility function called
** by VFS shared-memory methods.
*/
static int os2OpenSharedMemory( os2File *fd, int szRegion ) {
  os2ShmLink *pLink;
  os2ShmNode *pNode;
  int cbShmName, rc = SQLITE_OK;
  char shmName[CCHMAXPATH + 30];
#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE
  ULONG action;
#endif
  
  /* We need some additional space at the end to append the region number */
  cbShmName = sprintf(shmName, "\\SHAREMEM\\%s", fd->zFullPathCp );
  if( cbShmName >= CCHMAXPATH-8 )
    return SQLITE_IOERR_SHMOPEN; 

  /* Replace colon in file name to form a valid shared memory name */
  shmName[10+1] = '!';

  /* Allocate link object (we free it later in case of failure) */
  pLink = sqlite3_malloc( sizeof(*pLink) );
  if( !pLink )
    return SQLITE_NOMEM;

  /* Access node list */
  os2ShmEnterMutex();

  /* Find node by it's shared memory base name */
  for( pNode = os2ShmNodeList; 
       pNode && stricmp(shmName, pNode->shmBaseName) != 0; 
       pNode = pNode->pNext )   ;

  /* Not found: allocate a new node */
  if( !pNode ) {
    pNode = sqlite3_malloc( sizeof(*pNode) + cbShmName );
    if( pNode ) {
      memset(pNode, 0, sizeof(*pNode) );
      pNode->szRegion = szRegion;
      pNode->hLockFile = (HFILE)-1;      
      strcpy(pNode->shmBaseName, shmName);

#ifdef SQLITE_OS2_NO_WAL_LOCK_FILE
      if( DosDupHandle(fd->h, &pNode->hLockFile) != 0 ) {
#else
      sprintf(shmName, "%s-lck", fd->zFullPathCp);
      if( DosOpen((PSZ)shmName, &pNode->hLockFile, &action, 0, FILE_NORMAL, 
                  OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
                  OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE | 
                  OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR,
                  NULL) != 0 ) {
#endif
        sqlite3_free(pNode);  
        rc = SQLITE_IOERR;
      } else {
        pNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
        if( !pNode->mutex ) {
          sqlite3_free(pNode);  
          rc = SQLITE_NOMEM;
        }
      }   
    } else {
      rc = SQLITE_NOMEM;
    }
    
    if( rc == SQLITE_OK ) {
      pNode->pNext = os2ShmNodeList;
      os2ShmNodeList = pNode;
    } else {
      pNode = NULL;
    }
  } else if( pNode->szRegion != szRegion ) {
    rc = SQLITE_IOERR_SHMSIZE;
    pNode = NULL;
  }

  if( pNode ) {
    sqlite3_mutex_enter(pNode->mutex);

    memset(pLink, 0, sizeof(*pLink));

    pLink->pShmNode = pNode;
    pLink->pNext = pNode->pFirst;
    pNode->pFirst = pLink;
    pNode->nRef++;

    fd->pShmLink = pLink;

    sqlite3_mutex_leave(pNode->mutex);
    
  } else {
    /* Error occured. Free our link object. */
    sqlite3_free(pLink);  
  }

  os2ShmLeaveMutex();

  ERR_TRACE(rc, ("os2OpenSharedMemory: %d  %s\n", rc, fd->zFullPathCp))  
  
  return rc;
}

/*
** Purge the os2ShmNodeList list of all entries with nRef==0.
**
** This is not a VFS shared-memory method; it is a utility function called
** by VFS shared-memory methods.
*/
static void os2PurgeShmNodes( int deleteFlag ) {
  os2ShmNode *pNode;
  os2ShmNode **ppNode;

  os2ShmEnterMutex();
  
  ppNode = &os2ShmNodeList;

  while( *ppNode ) {
    pNode = *ppNode;

    if( pNode->nRef == 0 ) {
      *ppNode = pNode->pNext;   
     
      if( pNode->apRegion ) {
        /* Prevent other processes from resizing the shared memory */
        os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1);

        while( pNode->nRegion-- ) {
#ifdef SQLITE_DEBUG
          int rc = 
#endif          
          DosFreeMem(pNode->apRegion[pNode->nRegion]);

          OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
                  (int)GetCurrentProcessId(), pNode->nRegion,
                  rc == 0 ? "ok" : "failed"));
        }

        /* Allow other processes to resize the shared memory */
        os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1);

        sqlite3_free(pNode->apRegion);
      }  

      DosClose(pNode->hLockFile);
      
#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE
      if( deleteFlag ) {
         char fileName[CCHMAXPATH];
         /* Skip "\\SHAREMEM\\" */
         sprintf(fileName, "%s-lck", pNode->shmBaseName + 10);
         /* restore colon */
         fileName[1] = ':';
         
         DosForceDelete(fileName); 
      }
#endif

      sqlite3_mutex_free(pNode->mutex);

      sqlite3_free(pNode);
      
    } else {
      ppNode = &pNode->pNext;
    }
  } 

  os2ShmLeaveMutex();
}

/*
** This function is called to obtain a pointer to region iRegion of the
** shared-memory associated with the database file id. Shared-memory regions
** are numbered starting from zero. Each shared-memory region is szRegion
** bytes in size.
**
** If an error occurs, an error code is returned and *pp is set to NULL.
**
** Otherwise, if the bExtend parameter is 0 and the requested shared-memory
** region has not been allocated (by any client, including one running in a
** separate process), then *pp is set to NULL and SQLITE_OK returned. If
** bExtend is non-zero and the requested shared-memory region has not yet
** been allocated, it is allocated by this function.
**
** If the shared-memory region has already been allocated or is allocated by
** this call as described above, then it is mapped into this processes
** address space (if it is not already), *pp is set to point to the mapped
** memory and SQLITE_OK returned.
*/
static int os2ShmMap(
  sqlite3_file *id,               /* Handle open on database file */
  int iRegion,                    /* Region to retrieve */
  int szRegion,                   /* Size of regions */
  int bExtend,                    /* True to extend block if necessary */
  void volatile **pp              /* OUT: Mapped memory */
){
  PVOID pvTemp;
  void **apRegion;
  os2ShmNode *pNode;
  int n, rc = SQLITE_OK;
  char shmName[CCHMAXPATH];
  os2File *pFile = (os2File*)id;
  
  *pp = NULL;

  if( !pFile->pShmLink )
    rc = os2OpenSharedMemory( pFile, szRegion );
  
  if( rc == SQLITE_OK ) {
    pNode = pFile->pShmLink->pShmNode ;
    
    sqlite3_mutex_enter(pNode->mutex);
    
    assert( szRegion==pNode->szRegion );

    /* Unmapped region ? */
    if( iRegion >= pNode->nRegion ) {
      /* Prevent other processes from resizing the shared memory */
      os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1);

      apRegion = sqlite3_realloc(
        pNode->apRegion, (iRegion + 1) * sizeof(apRegion[0]));

      if( apRegion ) {
        pNode->apRegion = apRegion;

        while( pNode->nRegion <= iRegion ) {
          sprintf(shmName, "%s-%u", 
                  pNode->shmBaseName, pNode->nRegion);

          if( DosGetNamedSharedMem(&pvTemp, (PSZ)shmName, 
                PAG_READ | PAG_WRITE) != NO_ERROR ) {
            if( !bExtend )
              break;

            if( DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion,
                  PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_ANY) != NO_ERROR && 
                DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion,
                  PAG_READ | PAG_WRITE | PAG_COMMIT) != NO_ERROR ) { 
              rc = SQLITE_NOMEM;
              break;
            }
          }

          apRegion[pNode->nRegion++] = pvTemp;
        }

        /* zero out remaining entries */ 
        for( n = pNode->nRegion; n <= iRegion; n++ )
          pNode->apRegion[n] = NULL;

        /* Return this region (maybe zero) */
        *pp = pNode->apRegion[iRegion];
      } else {
        rc = SQLITE_NOMEM;
      }

      /* Allow other processes to resize the shared memory */
      os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1);
      
    } else {
      /* Region has been mapped previously */
      *pp = pNode->apRegion[iRegion];
    }

    sqlite3_mutex_leave(pNode->mutex);
  } 

  ERR_TRACE(rc, ("os2ShmMap: %s iRgn = %d, szRgn = %d, bExt = %d : %d\n", 
                 pFile->zFullPathCp, iRegion, szRegion, bExtend, rc))
          
  return rc;
}

/*
** Close a connection to shared-memory.  Delete the underlying
** storage if deleteFlag is true.
**
** If there is no shared memory associated with the connection then this
** routine is a harmless no-op.
*/
static int os2ShmUnmap(
  sqlite3_file *id,               /* The underlying database file */
  int deleteFlag                  /* Delete shared-memory if true */
){
  os2File *pFile = (os2File*)id;
  os2ShmLink *pLink = pFile->pShmLink;
  
  if( pLink ) {
    int nRef = -1;
    os2ShmLink **ppLink;
    os2ShmNode *pNode = pLink->pShmNode;

    sqlite3_mutex_enter(pNode->mutex);
    
    for( ppLink = &pNode->pFirst;
         *ppLink && *ppLink != pLink;
         ppLink = &(*ppLink)->pNext )   ;
         
    assert(*ppLink);

    if( *ppLink ) {
      *ppLink = pLink->pNext;
      nRef = --pNode->nRef;
    } else {
      ERR_TRACE(1, ("os2ShmUnmap: link not found ! %s\n", 
                    pNode->shmBaseName))
    }
    
    pFile->pShmLink = NULL;
    sqlite3_free(pLink);

    sqlite3_mutex_leave(pNode->mutex);
    
    if( nRef == 0 )
      os2PurgeShmNodes( deleteFlag );
  }

  return SQLITE_OK;
}

/*
** Change the lock state for a shared-memory segment.
**
** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
** different here than in posix.  In xShmLock(), one can go from unlocked
** to shared and back or from unlocked to exclusive and back.  But one may
** not go from shared to exclusive or from exclusive to shared.
*/
static int os2ShmLock(
  sqlite3_file *id,          /* Database file holding the shared memory */
  int ofst,                  /* First lock to acquire or release */
  int n,                     /* Number of locks to acquire or release */
  int flags                  /* What to do with the lock */
){
  u32 mask;                             /* Mask of locks to take or release */
  int rc = SQLITE_OK;                   /* Result code */
  os2File *pFile = (os2File*)id;
  os2ShmLink *p = pFile->pShmLink;      /* The shared memory being locked */
  os2ShmLink *pX;                       /* For looping over all siblings */
  os2ShmNode *pShmNode = p->pShmNode;   /* Our node */
  
  assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
  assert( n>=1 );
  assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
       || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
       || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
       || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
  assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );

  mask = (u32)((1U<<(ofst+n)) - (1U<<ofst));
  assert( n>1 || mask==(1<<ofst) );


  sqlite3_mutex_enter(pShmNode->mutex);

  if( flags & SQLITE_SHM_UNLOCK ){
    u32 allMask = 0; /* Mask of locks held by siblings */

    /* See if any siblings hold this same lock */
    for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
      if( pX==p ) continue;
      assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
      allMask |= pX->sharedMask;
    }

    /* Unlock the system-level locks */
    if( (mask & allMask)==0 ){
      rc = os2ShmSystemLock(pShmNode, _SHM_UNLCK, ofst+OS2_SHM_BASE, n);
    }else{
      rc = SQLITE_OK;
    }

    /* Undo the local locks */
    if( rc==SQLITE_OK ){
      p->exclMask &= ~mask;
      p->sharedMask &= ~mask;
    } 
  }else if( flags & SQLITE_SHM_SHARED ){
    u32 allShared = 0;  /* Union of locks held by connections other than "p" */

    /* Find out which shared locks are already held by sibling connections.
    ** If any sibling already holds an exclusive lock, go ahead and return
    ** SQLITE_BUSY.
    */
    for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
      if( (pX->exclMask & mask)!=0 ){
        rc = SQLITE_BUSY;
        break;
      }
      allShared |= pX->sharedMask;
    }

    /* Get shared locks at the system level, if necessary */
    if( rc==SQLITE_OK ){
      if( (allShared & mask)==0 ){
        rc = os2ShmSystemLock(pShmNode, _SHM_RDLCK, ofst+OS2_SHM_BASE, n);
      }else{
        rc = SQLITE_OK;
      }
    }

    /* Get the local shared locks */
    if( rc==SQLITE_OK ){
      p->sharedMask |= mask;
    }
  }else{
    /* Make sure no sibling connections hold locks that will block this
    ** lock.  If any do, return SQLITE_BUSY right away.
    */
    for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
      if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
        rc = SQLITE_BUSY;
        break;
      }
    }
  
    /* Get the exclusive locks at the system level.  Then if successful
    ** also mark the local connection as being locked.
    */
    if( rc==SQLITE_OK ){
      rc = os2ShmSystemLock(pShmNode, _SHM_WRLCK, ofst+OS2_SHM_BASE, n);
      if( rc==SQLITE_OK ){
        assert( (p->sharedMask & mask)==0 );
        p->exclMask |= mask;
      }
    }
  }

  sqlite3_mutex_leave(pShmNode->mutex);
  
  OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
           p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask,
           rc ? "failed" : "ok"));

  ERR_TRACE(rc, ("os2ShmLock: ofst = %d, n = %d, flags = 0x%x -> %d \n", 
                 ofst, n, flags, rc))
                  
  return rc; 
}

/*
** Implement a memory barrier or memory fence on shared memory.
**
** All loads and stores begun before the barrier must complete before
** any load or store begun after the barrier.
*/
static void os2ShmBarrier(
  sqlite3_file *id                /* Database file holding the shared memory */
){
  UNUSED_PARAMETER(id);
  os2ShmEnterMutex();
  os2ShmLeaveMutex();
}

#else
# define os2ShmMap     0
# define os2ShmLock    0
# define os2ShmBarrier 0
# define os2ShmUnmap   0
#endif /* #ifndef SQLITE_OMIT_WAL */


/*
** This vector defines all the methods that can operate on an
** sqlite3_file for os2.
*/
static const sqlite3_io_methods os2IoMethod = {
  2,                              /* iVersion */
  os2Close,                       /* xClose */
  os2Read,                        /* xRead */
  os2Write,                       /* xWrite */
  os2Truncate,                    /* xTruncate */
  os2Sync,                        /* xSync */
  os2FileSize,                    /* xFileSize */
  os2Lock,                        /* xLock */
  os2Unlock,                      /* xUnlock */
  os2CheckReservedLock,           /* xCheckReservedLock */
  os2FileControl,                 /* xFileControl */
  os2SectorSize,                  /* xSectorSize */
  os2DeviceCharacteristics,       /* xDeviceCharacteristics */
  os2ShmMap,                      /* xShmMap */
  os2ShmLock,                     /* xShmLock */
  os2ShmBarrier,                  /* xShmBarrier */
  os2ShmUnmap                     /* xShmUnmap */
};


/***************************************************************************
** Here ends the I/O methods that form the sqlite3_io_methods object.
**
** The next block of code implements the VFS methods.
****************************************************************************/

/*
** Create a temporary file name in zBuf.  zBuf must be big enough to
** hold at pVfs->mxPathname characters.
*/
static int getTempname(int nBuf, char *zBuf ){
  static const char zChars[] =
    "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "0123456789";
  int i, j;
  PSZ zTempPathCp;      
  char zTempPath[CCHMAXPATH];
  ULONG ulDriveNum, ulDriveMap;
  
  /* It's odd to simulate an io-error here, but really this is just
  ** using the io-error infrastructure to test that SQLite handles this
  ** function failing. 
  */
  SimulateIOError( return SQLITE_IOERR );

  if( sqlite3_temp_directory ) {


    sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", sqlite3_temp_directory);
  } else if( DosScanEnv( (PSZ)"TEMP",   &zTempPathCp ) == NO_ERROR ||
             DosScanEnv( (PSZ)"TMP",    &zTempPathCp ) == NO_ERROR ||
             DosScanEnv( (PSZ)"TMPDIR", &zTempPathCp ) == NO_ERROR ) {

    char *zTempPathUTF = convertCpPathToUtf8( (char *)zTempPathCp );
    sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", zTempPathUTF);
    free( zTempPathUTF );
  } else if( DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ) == NO_ERROR ) {
    zTempPath[0] = (char)('A' + ulDriveNum - 1);
    zTempPath[1] = ':'; 
    zTempPath[2] = '\0'; 
  } else {
    zTempPath[0] = '\0'; 
  }
  


  /* Strip off a trailing slashes or backslashes, otherwise we would get *
   * multiple (back)slashes which causes DosOpen() to fail.              *
   * Trailing spaces are not allowed, either.                            */
  j = sqlite3Strlen30(zTempPath);
  while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' || 
                    zTempPath[j-1] == ' ' ) ){
    j--;
  }
  zTempPath[j] = '\0';

  
  /* We use 20 bytes to randomize the name */
  sqlite3_snprintf(nBuf-22, zBuf,




                   "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);

  j = sqlite3Strlen30(zBuf);
  sqlite3_randomness( 20, &zBuf[j] );
  for( i = 0; i < 20; i++, j++ ){
    zBuf[j] = zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
  }
  zBuf[j] = 0;

  OSTRACE(( "TEMP FILENAME: %s\n", zBuf ));
  return SQLITE_OK;
}


/*
** Turn a relative pathname into a full pathname.  Write the full
................................................................................
  const char *zRelative,      /* Possibly relative input path */
  int nFull,                  /* Size of output buffer in bytes */
  char *zFull                 /* Output buffer */
){
  char *zRelativeCp = convertUtf8PathToCp( zRelative );
  char zFullCp[CCHMAXPATH] = "\0";
  char *zFullUTF;
  APIRET rc = DosQueryPathInfo( (PSZ)zRelativeCp, FIL_QUERYFULLNAME, 
                                zFullCp, CCHMAXPATH );
  free( zRelativeCp );
  zFullUTF = convertCpPathToUtf8( zFullCp );
  sqlite3_snprintf( nFull, zFull, zFullUTF );
  free( zFullUTF );
  return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
}

................................................................................
  ULONG rc;
  os2File *pFile = (os2File*)id;
  const char *zUtf8Name = zName;
  char *zNameCp;
  char  zTmpname[CCHMAXPATH];

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);

  int isCreate     = (flags & SQLITE_OPEN_CREATE);
  int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);
#ifndef NDEBUG
  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
  int isReadonly   = (flags & SQLITE_OPEN_READONLY);
  int eType        = (flags & 0xFFFFFF00);
  int isOpenJournal = (isCreate && (
        eType==SQLITE_OPEN_MASTER_JOURNAL 
     || eType==SQLITE_OPEN_MAIN_JOURNAL 
     || eType==SQLITE_OPEN_WAL
  ));
................................................................................
  assert( eType==SQLITE_OPEN_MAIN_DB      || eType==SQLITE_OPEN_TEMP_DB 
       || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL 
       || eType==SQLITE_OPEN_SUBJOURNAL   || eType==SQLITE_OPEN_MASTER_JOURNAL 
       || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
  );

  memset( pFile, 0, sizeof(*pFile) );
  pFile->h = (HFILE)-1;

  /* If the second argument to this function is NULL, generate a 
  ** temporary file name to use 
  */
  if( !zUtf8Name ){
    assert(isDelete && !isOpenJournal);
    rc = getTempname(CCHMAXPATH, zTmpname);
................................................................................
    ulOpenMode |= OPEN_ACCESS_READWRITE;
  }else{
    ulOpenMode |= OPEN_ACCESS_READONLY;
  }

  /* Open in random access mode for possibly better speed.  Allow full
  ** sharing because file locks will provide exclusive access when needed.
  ** The handle should not be inherited by child processes and we don't 
  ** want popups from the critical error handler.
  */
  ulOpenMode |= OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE | 
                OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR;

  /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is 
  ** created. SQLite doesn't use it to indicate "exclusive access" 
  ** as it is usually understood.
  */
  if( isExclusive ){
    /* Creates a new file, only if it does not already exist. */
................................................................................
    /* Open existing file, or create if it doesn't exist */
    ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
  }else{
    /* Opens a file, only if it exists. */
    ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
  }








  zNameCp = convertUtf8PathToCp( zUtf8Name );
  rc = DosOpen( (PSZ)zNameCp,
                &h,
                &ulAction,
                0L,
                FILE_NORMAL,
                ulOpenFlags,
................................................................................
                ulOpenMode,
                (PEAOP2)NULL );
  free( zNameCp );

  if( rc != NO_ERROR ){
    OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
              rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode ));




    if( isReadWrite ){
      return os2Open( pVfs, zName, id,
                      ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
                      pOutFlags );
    }else{
      return SQLITE_CANTOPEN;
................................................................................
    }
  }

  if( pOutFlags ){
    *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
  }

  os2FullPathname( pVfs, zUtf8Name, sizeof( zTmpname ), zTmpname );
  pFile->zFullPathCp = convertUtf8PathToCp( zTmpname );
  pFile->pMethod = &os2IoMethod;
  pFile->flags = flags;
  pFile->h = h;

  OpenCounter(+1);
  OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
  return SQLITE_OK;
}

/*
** Delete the named file.
................................................................................
*/
static int os2Access(
  sqlite3_vfs *pVfs,        /* Not used on os2 */
  const char *zFilename,    /* Name of file to check */
  int flags,                /* Type of test to make on this file */
  int *pOut                 /* Write results here */
){
  APIRET rc;
  FILESTATUS3 fsts3ConfigInfo;

  char *zFilenameCp;

  UNUSED_PARAMETER(pVfs);
  SimulateIOError( return SQLITE_IOERR_ACCESS; );
  
  zFilenameCp = convertUtf8PathToCp( zFilename );
  rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
                         &fsts3ConfigInfo, sizeof(FILESTATUS3) );
  free( zFilenameCp );
  OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
            fsts3ConfigInfo.attrFile, flags, rc ));

  switch( flags ){
    case SQLITE_ACCESS_EXISTS:
      /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
      ** as if it does not exist.
      */
      if( fsts3ConfigInfo.cbFile == 0 ) 
        rc = ERROR_FILE_NOT_FOUND;
      break;
    case SQLITE_ACCESS_READ:


      break;
    case SQLITE_ACCESS_READWRITE:
      if( fsts3ConfigInfo.attrFile & FILE_READONLY )

        rc = ERROR_ACCESS_DENIED;
      break;
    default:
      rc = ERROR_FILE_NOT_FOUND;
      assert( !"Invalid flags argument" );
  }

  *pOut = (rc == NO_ERROR);
  OSTRACE(( "ACCESS %s flags %d: rc=%d\n", zFilename, flags, *pOut ));

  return SQLITE_OK;
}


#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Interfaces for opening a shared library, finding entry points
................................................................................
** within the shared library, and closing the shared library.
*/
/*
** Interfaces for opening a shared library, finding entry points
** within the shared library, and closing the shared library.
*/
static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){

  HMODULE hmod;
  APIRET rc;
  char *zFilenameCp = convertUtf8PathToCp(zFilename);
  rc = DosLoadModule(NULL, 0, (PSZ)zFilenameCp, &hmod);
  free(zFilenameCp);
  return rc != NO_ERROR ? 0 : (void*)hmod;
}
/*
** A no-op since the error code is returned on the DosLoadModule call.
** os2Dlopen returns zero if DosLoadModule is not successful.
*/
static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
/* no-op */
}
static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
  PFN pfn;
  APIRET rc;
  rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)zSymbol, &pfn);
  if( rc != NO_ERROR ){
    /* if the symbol itself was not found, search again for the same
     * symbol with an extra underscore, that might be needed depending
     * on the calling convention */
    char _zSymbol[256] = "_";
    strncat(_zSymbol, zSymbol, 254);
    rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)_zSymbol, &pfn);
  }
  return rc != NO_ERROR ? 0 : (void(*)(void))pfn;
}
static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
  DosFreeModule((HMODULE)pHandle);
}
#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */
................................................................................
*/
static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){
  int n = 0;
#if defined(SQLITE_TEST)
  n = nBuf;
  memset(zBuf, 0, nBuf);
#else
  int i;                           
  PPIB ppib;
  PTIB ptib;
  DATETIME dt; 

  static unsigned c = 0;
  /* Ordered by variation probability */
  static ULONG svIdx[6] = { QSV_MS_COUNT, QSV_TIME_LOW,
                            QSV_MAXPRMEM, QSV_MAXSHMEM,
                            QSV_TOTAVAILMEM, QSV_TOTRESMEM };


  /* 8 bytes; timezone and weekday don't increase the randomness much */
  if( (int)sizeof(dt)-3 <= nBuf - n ){


    c += 0x0100;
    DosGetDateTime(&dt);
    dt.year = (USHORT)((dt.year - 1900) | c);
    memcpy(&zBuf[n], &dt, sizeof(dt)-3);
    n += sizeof(dt)-3;
  }

  /* 4 bytes; PIDs and TIDs are 16 bit internally, so combine them */
  if( (int)sizeof(ULONG) <= nBuf - n ){

    DosGetInfoBlocks(&ptib, &ppib);
    *(PULONG)&zBuf[n] = MAKELONG(ppib->pib_ulpid,
                                 ptib->tib_ptib2->tib2_ultid);
    n += sizeof(ULONG);
  }







  /* Up to 6 * 4 bytes; variables depend on the system state */
  for( i = 0; i < 6 && (int)sizeof(ULONG) <= nBuf - n; i++ ){
    DosQuerySysInfo(svIdx[i], svIdx[i], 



                    (PULONG)&zBuf[n], sizeof(ULONG));
    n += sizeof(ULONG);
  } 













#endif

  return n;
}

/*
** Sleep for a little while.  Return the amount of time slept.
................................................................................
** The following variable, if set to a non-zero value, becomes the result
** returned from sqlite3OsCurrentTime().  This is used for testing.
*/
#ifdef SQLITE_TEST
int sqlite3_current_time = 0;
#endif











































/*
** Find the current time (in Universal Coordinated Time).  Write into *piNow
** the current time and date as a Julian Day number times 86_400_000.  In
** other words, write into *piNow the number of milliseconds since the Julian
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
** proleptic Gregorian calendar.
**
** On success, return 0.  Return 1 if the time and date cannot be found.
*/
static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
#ifdef SQLITE_TEST
  static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
#endif
  int year, month, datepart, timepart;
 
  DATETIME dt;
  DosGetDateTime( &dt );

  year = dt.year;
  month = dt.month;

  /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
  ** http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c
  ** Calculate the Julian days
  */
  datepart = (int)dt.day - 32076 +
    1461*(year + 4800 + (month - 14)/12)/4 +
    367*(month - 2 - (month - 14)/12*12)/12 -
    3*((year + 4900 + (month - 14)/12)/100)/4;

  /* Time in milliseconds, hours to noon added */
  timepart = 12*3600*1000 + dt.hundredths*10 + dt.seconds*1000 +
    ((int)dt.minutes + dt.timezone)*60*1000 + dt.hours*3600*1000;

  *piNow = (sqlite3_int64)datepart*86400*1000 + timepart;
   
#ifdef SQLITE_TEST
  if( sqlite3_current_time ){
    *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
  }
#endif

  UNUSED_PARAMETER(pVfs);
  return 0;
}

/*
** Find the current time (in Universal Coordinated Time).  Write the
** current time and date as a Julian Day number into *prNow and
** return 0.  Return 1 if the time and date cannot be found.
*/
static int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
  int rc;
  sqlite3_int64 i;
  rc = os2CurrentTimeInt64(pVfs, &i);

  if( !rc ){
    *prNow = i/86400000.0;
  }
  return rc;
}

/*
** The idea is that this function works like a combination of
** GetLastError() and FormatMessage() on windows (or errno and
** strerror_r() on unix). After an error is returned by an OS
** function, SQLite calls this function with zBuf pointing to
** a buffer of nBuf bytes. The OS layer should populate the
** buffer with a nul-terminated UTF-8 encoded error message
** describing the last IO error to have occurred within the calling
** thread.
**
** If the error message is too large for the supplied buffer,
** it should be truncated. The return value of xGetLastError
** is zero if the error message fits in the buffer, or non-zero
** otherwise (if the message was truncated). If non-zero is returned,
** then it is not necessary to include the nul-terminator character
** in the output buffer.
**
** Not supplying an error message will have no adverse effect
** on SQLite. It is fine to have an implementation that never
** returns an error message:
**
**   int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
**     assert(zBuf[0]=='\0');
**     return 0;
**   }
**
** However if an error message is supplied, it will be incorporated
** by sqlite into the error message available to the user using
** sqlite3_errmsg(), possibly making IO errors easier to debug.
*/
static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
  assert(zBuf[0]=='\0');
  return 0;
}

/*
** Initialize and deinitialize the operating system interface.
*/
int sqlite3_os_init(void){
................................................................................
    os2DlError,        /* xDlError */
    os2DlSym,          /* xDlSym */
    os2DlClose,        /* xDlClose */
    os2Randomness,     /* xRandomness */
    os2Sleep,          /* xSleep */
    os2CurrentTime,    /* xCurrentTime */
    os2GetLastError,   /* xGetLastError */
    os2CurrentTimeInt64, /* xCurrentTimeInt64 */
    0,                 /* xSetSystemCall */
    0,                 /* xGetSystemCall */
    0                  /* xNextSystemCall */
  };
  sqlite3_vfs_register(&os2Vfs, 1);
  initUconvObjects();
/*  sqlite3OSTrace = 1; */
  return SQLITE_OK;
}
int sqlite3_os_end(void){
  freeUconvObjects();
  return SQLITE_OK;
}

#endif /* SQLITE_OS_OS2 */

Changes to src/os_unix.c.

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
...
359
360
361
362
363
364
365

366



367
368
369
370
371
372
373
...
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
....
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
....
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
....
6677
6678
6679
6680
6681
6682
6683




6684
6685
6686
6687
6688
6689
6690
*/
static struct unix_syscall {
  const char *zName;            /* Name of the sytem call */
  sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
  sqlite3_syscall_ptr pDefault; /* Default value */
} aSyscall[] = {
  { "open",         (sqlite3_syscall_ptr)open,       0  },
#define osOpen      ((int(*)(const char*,int,int))aSyscall[0].pCurrent)

  { "close",        (sqlite3_syscall_ptr)close,      0  },
#define osClose     ((int(*)(int))aSyscall[1].pCurrent)

  { "access",       (sqlite3_syscall_ptr)access,     0  },
#define osAccess    ((int(*)(const char*,int))aSyscall[2].pCurrent)

................................................................................

  { "fcntl",        (sqlite3_syscall_ptr)fcntl,      0  },
#define osFcntl     ((int(*)(int,int,...))aSyscall[7].pCurrent)

  { "read",         (sqlite3_syscall_ptr)read,       0  },
#define osRead      ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)

#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
  { "pread",        (sqlite3_syscall_ptr)pread,      0  },
#else
  { "pread",        (sqlite3_syscall_ptr)0,          0  },
#endif
#define osPread     ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)

#if defined(USE_PREAD64)
................................................................................
  { "pread64",      (sqlite3_syscall_ptr)0,          0  },
#endif
#define osPread64   ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)

  { "write",        (sqlite3_syscall_ptr)write,      0  },
#define osWrite     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)

#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
  { "pwrite",       (sqlite3_syscall_ptr)pwrite,     0  },
#else
  { "pwrite",       (sqlite3_syscall_ptr)0,          0  },
#endif
#define osPwrite    ((ssize_t(*)(int,const void*,size_t,off_t))\
                    aSyscall[12].pCurrent)

................................................................................
  { "pwrite64",     (sqlite3_syscall_ptr)pwrite64,   0  },
#else
  { "pwrite64",     (sqlite3_syscall_ptr)0,          0  },
#endif
#define osPwrite64  ((ssize_t(*)(int,const void*,size_t,off_t))\
                    aSyscall[13].pCurrent)


  { "fchmod",       (sqlite3_syscall_ptr)fchmod,     0  },



#define osFchmod    ((int(*)(int,mode_t))aSyscall[14].pCurrent)

#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
  { "fallocate",    (sqlite3_syscall_ptr)posix_fallocate,  0 },
#else
  { "fallocate",    (sqlite3_syscall_ptr)0,                0 },
#endif
................................................................................
  unsigned char bProcessLock;     /* An exclusive process lock is held */
  int nRef;                       /* Number of pointers to this structure */
  unixShmNode *pShmNode;          /* Shared memory associated with this inode */
  int nLock;                      /* Number of outstanding file locks */
  UnixUnusedFd *pUnused;          /* Unused file descriptors to close */
  unixInodeInfo *pNext;           /* List of all unixInodeInfo objects */
  unixInodeInfo *pPrev;           /*    .... doubly linked */
#if defined(SQLITE_ENABLE_LOCKING_STYLE)
  unsigned long long sharedByte;  /* for AFP simulated shared lock */
#endif
#if OS_VXWORKS
  sem_t *pSem;                    /* Named POSIX semaphore */
  char aSemName[MAX_PATHNAME+2];  /* Name of that semaphore */
#endif
};
................................................................................
    offset += wrote;
    pBuf = &((char*)pBuf)[wrote];
  }
  SimulateIOError(( wrote=(-1), amt=1 ));
  SimulateDiskfullError(( wrote=0, amt=1 ));

  if( amt>0 ){
    if( wrote<0 ){
      /* lastErrno set by seekAndWrite */
      return SQLITE_IOERR_WRITE;
    }else{
      pFile->lastErrno = 0; /* not a system error */
      return SQLITE_FULL;
    }
  }
................................................................................
    while(pShmNode->nRegion<=iRegion){
      void *pMem;
      if( pShmNode->h>=0 ){
        pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE, 
            MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
        );
        if( pMem==MAP_FAILED ){
          rc = SQLITE_IOERR;
          goto shmpage_out;
        }
      }else{
        pMem = sqlite3_malloc(szRegion);
        if( pMem==0 ){
          rc = SQLITE_NOMEM;
          goto shmpage_out;
................................................................................
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
    UNIXVFS("unix-afp",      afpIoFinder ),
    UNIXVFS("unix-nfs",      nfsIoFinder ),
    UNIXVFS("unix-proxy",    proxyIoFinder ),
#endif
  };
  unsigned int i;          /* Loop counter */





  /* Register all VFSes defined in the aVfs[] array */
  for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
    sqlite3_vfs_register(&aVfs[i], i==0);
  }
  return SQLITE_OK; 
}







|







 







|







 







|







 







>

>
>
>







 







|







 







|







 







|







 







>
>
>
>







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
...
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
....
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
....
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
....
6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
*/
static struct unix_syscall {
  const char *zName;            /* Name of the sytem call */
  sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
  sqlite3_syscall_ptr pDefault; /* Default value */
} aSyscall[] = {
  { "open",         (sqlite3_syscall_ptr)open,       0  },
#define osOpen      ((int(*)(const char*,int,...))aSyscall[0].pCurrent)

  { "close",        (sqlite3_syscall_ptr)close,      0  },
#define osClose     ((int(*)(int))aSyscall[1].pCurrent)

  { "access",       (sqlite3_syscall_ptr)access,     0  },
#define osAccess    ((int(*)(const char*,int))aSyscall[2].pCurrent)

................................................................................

  { "fcntl",        (sqlite3_syscall_ptr)fcntl,      0  },
#define osFcntl     ((int(*)(int,int,...))aSyscall[7].pCurrent)

  { "read",         (sqlite3_syscall_ptr)read,       0  },
#define osRead      ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)

#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
  { "pread",        (sqlite3_syscall_ptr)pread,      0  },
#else
  { "pread",        (sqlite3_syscall_ptr)0,          0  },
#endif
#define osPread     ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent)

#if defined(USE_PREAD64)
................................................................................
  { "pread64",      (sqlite3_syscall_ptr)0,          0  },
#endif
#define osPread64   ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)

  { "write",        (sqlite3_syscall_ptr)write,      0  },
#define osWrite     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)

#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
  { "pwrite",       (sqlite3_syscall_ptr)pwrite,     0  },
#else
  { "pwrite",       (sqlite3_syscall_ptr)0,          0  },
#endif
#define osPwrite    ((ssize_t(*)(int,const void*,size_t,off_t))\
                    aSyscall[12].pCurrent)

................................................................................
  { "pwrite64",     (sqlite3_syscall_ptr)pwrite64,   0  },
#else
  { "pwrite64",     (sqlite3_syscall_ptr)0,          0  },
#endif
#define osPwrite64  ((ssize_t(*)(int,const void*,size_t,off_t))\
                    aSyscall[13].pCurrent)

#if SQLITE_ENABLE_LOCKING_STYLE
  { "fchmod",       (sqlite3_syscall_ptr)fchmod,     0  },
#else
  { "fchmod",       (sqlite3_syscall_ptr)0,          0  },
#endif
#define osFchmod    ((int(*)(int,mode_t))aSyscall[14].pCurrent)

#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
  { "fallocate",    (sqlite3_syscall_ptr)posix_fallocate,  0 },
#else
  { "fallocate",    (sqlite3_syscall_ptr)0,                0 },
#endif
................................................................................
  unsigned char bProcessLock;     /* An exclusive process lock is held */
  int nRef;                       /* Number of pointers to this structure */
  unixShmNode *pShmNode;          /* Shared memory associated with this inode */
  int nLock;                      /* Number of outstanding file locks */
  UnixUnusedFd *pUnused;          /* Unused file descriptors to close */
  unixInodeInfo *pNext;           /* List of all unixInodeInfo objects */
  unixInodeInfo *pPrev;           /*    .... doubly linked */
#if SQLITE_ENABLE_LOCKING_STYLE
  unsigned long long sharedByte;  /* for AFP simulated shared lock */
#endif
#if OS_VXWORKS
  sem_t *pSem;                    /* Named POSIX semaphore */
  char aSemName[MAX_PATHNAME+2];  /* Name of that semaphore */
#endif
};
................................................................................
    offset += wrote;
    pBuf = &((char*)pBuf)[wrote];
  }
  SimulateIOError(( wrote=(-1), amt=1 ));
  SimulateDiskfullError(( wrote=0, amt=1 ));

  if( amt>0 ){
    if( wrote<0 && pFile->lastErrno!=ENOSPC ){
      /* lastErrno set by seekAndWrite */
      return SQLITE_IOERR_WRITE;
    }else{
      pFile->lastErrno = 0; /* not a system error */
      return SQLITE_FULL;
    }
  }
................................................................................
    while(pShmNode->nRegion<=iRegion){
      void *pMem;
      if( pShmNode->h>=0 ){
        pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE, 
            MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
        );
        if( pMem==MAP_FAILED ){
          rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
          goto shmpage_out;
        }
      }else{
        pMem = sqlite3_malloc(szRegion);
        if( pMem==0 ){
          rc = SQLITE_NOMEM;
          goto shmpage_out;
................................................................................
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
    UNIXVFS("unix-afp",      afpIoFinder ),
    UNIXVFS("unix-nfs",      nfsIoFinder ),
    UNIXVFS("unix-proxy",    proxyIoFinder ),
#endif
  };
  unsigned int i;          /* Loop counter */

  /* Double-check that the aSyscall[] array has been constructed
  ** correctly.  See ticket [bb3a86e890c8e96ab] */
  assert( ArraySize(aSyscall)==16 );

  /* Register all VFSes defined in the aVfs[] array */
  for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
    sqlite3_vfs_register(&aVfs[i], i==0);
  }
  return SQLITE_OK; 
}

Changes to src/os_win.c.

113
114
115
116
117
118
119

120
121
122
123
124
125
126
...
294
295
296
297
298
299
300







































































































301
302
303
304
305
306
307
...
371
372
373
374
375
376
377

378
379
380
381
382
383
384
...
402
403
404
405
406
407
408

409
410
411
412
413
414
415
...
647
648
649
650
651
652
653

654
655
656
657
658
659
660
...
692
693
694
695
696
697
698
699

700
701
702
703
704
705
706
...
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
...
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
...
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
...
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
...
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
...
919
920
921
922
923
924
925

926
927
928
929
930
931
932
...
939
940
941
942
943
944
945

946
947
948
949
950
951
952
....
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
....
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
....
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
....
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
....
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
....
2201
2202
2203
2204
2205
2206
2207

2208
2209
2210
2211
2212
2213
2214
....
2304
2305
2306
2307
2308
2309
2310
2311

2312
2313
2314
2315
2316
2317
2318
....
2344
2345
2346
2347
2348
2349
2350

2351
2352
2353
2354
2355
2356
2357
  WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
  HANDLE hMutex;          /* Mutex used to control access to shared lock */  
  HANDLE hShared;         /* Shared memory segment used for locking */
  winceLock local;        /* Locks obtained by this instance of winFile */
  winceLock *shared;      /* Global shared lock memory for the file  */
#endif
};


/*
** Forward prototypes.
*/
static int getSectorSize(
    sqlite3_vfs *pVfs,
    const char *zRelative     /* UTF-8 file name */
................................................................................
    return 0;
  }
  zFilenameMbcs = unicodeToMbcs(zTmpWide);
  free(zTmpWide);
  return zFilenameMbcs;
}








































































































#if SQLITE_OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
*/
/*
** WindowsCE does not have a localtime() function.  So create a
** substitute.
................................................................................
    if (*zTok == '\\') *zTok = '_';
  }

  /* Create/open the named mutex */
  pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
  if (!pFile->hMutex){
    pFile->lastErrno = GetLastError();

    free(zName);
    return FALSE;
  }

  /* Acquire the mutex before continuing */
  winceMutexAcquire(pFile->hMutex);
  
................................................................................
  /* If we succeeded in making the shared memory handle, map it. */
  if (pFile->hShared){
    pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, 
             FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
    /* If mapping failed, close the shared memory handle and erase it */
    if (!pFile->shared){
      pFile->lastErrno = GetLastError();

      CloseHandle(pFile->hShared);
      pFile->hShared = NULL;
    }
  }

  /* If shared memory could not be created, then close the mutex and fail */
  if (pFile->hShared == NULL){
................................................................................
  ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine 
  ** whether an error has actually occured, it is also necessary to call 
  ** GetLastError().
  */
  dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
  if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
    pFile->lastErrno = GetLastError();

    return 1;
  }

  return 0;
}

/*
................................................................................
       Sleep(100);  /* Wait a little before trying again */
    }
    free(pFile->zDeleteOnClose);
  }
#endif
  OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
  OpenCounter(-1);
  return rc ? SQLITE_OK : SQLITE_IOERR;

}

/*
** Read data from a file into a buffer.  Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
................................................................................
  OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));

  if( seekWinFile(pFile, offset) ){
    return SQLITE_FULL;
  }
  if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
    pFile->lastErrno = GetLastError();
    return SQLITE_IOERR_READ;
  }
  if( nRead<(DWORD)amt ){
    /* Unread parts of the buffer must be zero-filled */
    memset(&((char*)pBuf)[nRead], 0, amt-nRead);
    return SQLITE_IOERR_SHORT_READ;
  }

................................................................................
    }
  }

  if( rc ){
    if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
      return SQLITE_FULL;
    }
    return SQLITE_IOERR_WRITE;
  }
  return SQLITE_OK;
}

/*
** Truncate an open file to a specified size
*/
................................................................................
  */
  if( pFile->szChunk ){
    nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
  }

  /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
  if( seekWinFile(pFile, nByte) ){
    rc = SQLITE_IOERR_TRUNCATE;
  }else if( 0==SetEndOfFile(pFile->h) ){
    pFile->lastErrno = GetLastError();
    rc = SQLITE_IOERR_TRUNCATE;
  }

  OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
  return rc;
}

#ifdef SQLITE_TEST
................................................................................

/*
** Make sure all writes to a particular file are committed to disk.
*/
static int winSync(sqlite3_file *id, int flags){
#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || defined(SQLITE_DEBUG)
  winFile *pFile = (winFile*)id;

#else
  UNUSED_PARAMETER(id);
#endif

  assert( pFile );
  /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
  assert((flags&0x0F)==SQLITE_SYNC_NORMAL
      || (flags&0x0F)==SQLITE_SYNC_FULL
  );

  OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));






#ifndef SQLITE_TEST
  UNUSED_PARAMETER(flags);
#else
  if( flags & SQLITE_SYNC_FULL ){
    sqlite3_fullsync_count++;
  }
  sqlite3_sync_count++;
#endif

  /* Unix cannot, but some systems may return SQLITE_FULL from here. This
  ** line is to test that doing so does not cause any problems.
  */
  SimulateDiskfullError( return SQLITE_FULL );
  SimulateIOError( return SQLITE_IOERR; );

  /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
  ** no-op
  */
#ifdef SQLITE_NO_SYNC
  return SQLITE_OK;
#else
  if( FlushFileBuffers(pFile->h) ){


    return SQLITE_OK;
  }else{
    pFile->lastErrno = GetLastError();
    return SQLITE_IOERR;
  }
#endif
}

/*
** Determine the current size of a file in bytes
*/
................................................................................
  assert( id!=0 );
  SimulateIOError(return SQLITE_IOERR_FSTAT);
  lowerBits = GetFileSize(pFile->h, &upperBits);
  if(   (lowerBits == INVALID_FILE_SIZE)
     && ((error = GetLastError()) != NO_ERROR) )
  {
    pFile->lastErrno = error;
    return SQLITE_IOERR_FSTAT;
  }
  *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
  return SQLITE_OK;
}

/*
** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
................................................................................
    sqlite3_randomness(sizeof(lk), &lk);
    pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
    res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
#endif
  }
  if( res == 0 ){
    pFile->lastErrno = GetLastError();

  }
  return res;
}

/*
** Undo a readlock
*/
................................................................................
#if SQLITE_OS_WINCE==0
  }else{
    res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
#endif
  }
  if( res == 0 ){
    pFile->lastErrno = GetLastError();

  }
  return res;
}

/*
** Lock the file with the lock specified by parameter locktype - one
** of the following:
................................................................................
          pFile->locktype, pFile->sharedLockByte));
  type = pFile->locktype;
  if( type>=EXCLUSIVE_LOCK ){
    UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
    if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
      /* This should never happen.  We should always be able to
      ** reacquire the read lock */
      rc = SQLITE_IOERR_UNLOCK;
    }
  }
  if( type>=RESERVED_LOCK ){
    UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
  }
  if( locktype==NO_LOCK && type>=SHARED_LOCK ){
    unlockReadLock(pFile);
................................................................................

    /* Check to see if another process is holding the dead-man switch.
    ** If not, truncate the file to zero length. 
    */
    if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
      rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
      if( rc!=SQLITE_OK ){
        rc = SQLITE_IOERR_SHMOPEN;
      }
    }
    if( rc==SQLITE_OK ){
      winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
      rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
    }
    if( rc ) goto shm_open_err;
................................................................................

    /* The requested region is not mapped into this processes address space.
    ** Check to see if it has been allocated (i.e. if the wal-index file is
    ** large enough to contain the requested region).
    */
    rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
    if( rc!=SQLITE_OK ){
      rc = SQLITE_IOERR_SHMSIZE;
      goto shmpage_out;
    }

    if( sz<nByte ){
      /* The requested memory region does not exist. If isWrite is set to
      ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
      **
      ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
      ** the requested memory region.
      */
      if( !isWrite ) goto shmpage_out;
      rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
      if( rc!=SQLITE_OK ){
        rc = SQLITE_IOERR_SHMSIZE;
        goto shmpage_out;
      }
    }

    /* Map the requested memory region into this processes address space. */
    apNew = (struct ShmRegion *)sqlite3_realloc(
        pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
................................................................................
        );
        OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
                 (int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion,
                 pMap ? "ok" : "failed"));
      }
      if( !pMap ){
        pShmNode->lastErrno = GetLastError();
        rc = SQLITE_IOERR;
        if( hMap ) CloseHandle(hMap);
        goto shmpage_out;
      }

      pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
      pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
      pShmNode->nRegion++;
................................................................................
  }
  zBuf[j] = 0;

  OSTRACE(("TEMP FILENAME: %s\n", zBuf));
  return SQLITE_OK; 
}

/*
** The return value of getLastErrorMsg
** is zero if the error message fits in the buffer, or non-zero
** otherwise (if the message was truncated).
*/
static int getLastErrorMsg(int nBuf, char *zBuf){
  /* FormatMessage returns 0 on failure.  Otherwise it
  ** returns the number of TCHARs written to the output
  ** buffer, excluding the terminating null char.
  */
  DWORD error = GetLastError();
  DWORD dwLen = 0;
  char *zOut = 0;

  if( isNT() ){
    WCHAR *zTempWide = NULL;
    dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                           NULL,
                           error,
                           0,
                           (LPWSTR) &zTempWide,
                           0,
                           0);
    if( dwLen > 0 ){
      /* allocate a buffer and convert to UTF8 */
      zOut = unicodeToUtf8(zTempWide);
      /* free the system buffer allocated by FormatMessage */
      LocalFree(zTempWide);
    }
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
  }else{
    char *zTemp = NULL;
    dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                           NULL,
                           error,
                           0,
                           (LPSTR) &zTemp,
                           0,
                           0);
    if( dwLen > 0 ){
      /* allocate a buffer and convert to UTF8 */
      zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
      /* free the system buffer allocated by FormatMessage */
      LocalFree(zTemp);
    }
#endif
  }
  if( 0 == dwLen ){
    sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
  }else{
    /* copy a maximum of nBuf chars to output buffer */
    sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
    /* free the UTF8 buffer */
    free(zOut);
  }
  return 0;
}

/*
** Open a file.
*/
static int winOpen(
  sqlite3_vfs *pVfs,        /* Not used */
  const char *zName,        /* Name of the file (UTF-8) */
  sqlite3_file *id,         /* Write the SQLite file handle here */
................................................................................

  OSTRACE(("OPEN %d %s 0x%lx %s\n", 
           h, zName, dwDesiredAccess, 
           h==INVALID_HANDLE_VALUE ? "failed" : "ok"));

  if( h==INVALID_HANDLE_VALUE ){
    pFile->lastErrno = GetLastError();

    free(zConverted);
    if( isReadWrite ){
      return winOpen(pVfs, zName, id, 
             ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
    }else{
      return SQLITE_CANTOPEN_BKPT;
    }
................................................................................
  }
  free(zConverted);
  OSTRACE(("DELETE \"%s\" %s\n", zFilename,
       ( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ?
         "ok" : "failed" ));
 
  return (   (rc == INVALID_FILE_ATTRIBUTES) 
          && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;

}

/*
** Check the existance and status of a file.
*/
static int winAccess(
  sqlite3_vfs *pVfs,         /* Not used on win32 */
................................................................................
          && sAttrData.nFileSizeLow==0 ){
        attr = INVALID_FILE_ATTRIBUTES;
      }else{
        attr = sAttrData.dwFileAttributes;
      }
    }else{
      if( GetLastError()!=ERROR_FILE_NOT_FOUND ){

        free(zConverted);
        return SQLITE_IOERR_ACCESS;
      }else{
        attr = INVALID_FILE_ATTRIBUTES;
      }
    }
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 







>







 







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







 







>







 







>







 







>







 







|
>







 







|







 







|







 







|


|







 







>












>
>
>
>
>



|





<
<
<
<
<
<






|
>
>



|







 







|







 







>







 







>







 







|







 







|







 







|













|







 







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>







 







|
>







 







>







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
...
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
...
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
...
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
...
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
...
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
...
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
...
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
...
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
....
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
....
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
....
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
....
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
....
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
....
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
....
2080
2081
2082
2083
2084
2085
2086






























































2087
2088
2089
2090
2091
2092
2093
....
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
....
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
....
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
  WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
  HANDLE hMutex;          /* Mutex used to control access to shared lock */  
  HANDLE hShared;         /* Shared memory segment used for locking */
  winceLock local;        /* Locks obtained by this instance of winFile */
  winceLock *shared;      /* Global shared lock memory for the file  */
#endif
};


/*
** Forward prototypes.
*/
static int getSectorSize(
    sqlite3_vfs *pVfs,
    const char *zRelative     /* UTF-8 file name */
................................................................................
    return 0;
  }
  zFilenameMbcs = unicodeToMbcs(zTmpWide);
  free(zTmpWide);
  return zFilenameMbcs;
}


/*
** The return value of getLastErrorMsg
** is zero if the error message fits in the buffer, or non-zero
** otherwise (if the message was truncated).
*/
static int getLastErrorMsg(int nBuf, char *zBuf){
  /* FormatMessage returns 0 on failure.  Otherwise it
  ** returns the number of TCHARs written to the output
  ** buffer, excluding the terminating null char.
  */
  DWORD error = GetLastError();
  DWORD dwLen = 0;
  char *zOut = 0;

  if( isNT() ){
    WCHAR *zTempWide = NULL;
    dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                           NULL,
                           error,
                           0,
                           (LPWSTR) &zTempWide,
                           0,
                           0);
    if( dwLen > 0 ){
      /* allocate a buffer and convert to UTF8 */
      zOut = unicodeToUtf8(zTempWide);
      /* free the system buffer allocated by FormatMessage */
      LocalFree(zTempWide);
    }
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
  }else{
    char *zTemp = NULL;
    dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                           NULL,
                           error,
                           0,
                           (LPSTR) &zTemp,
                           0,
                           0);
    if( dwLen > 0 ){
      /* allocate a buffer and convert to UTF8 */
      zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
      /* free the system buffer allocated by FormatMessage */
      LocalFree(zTemp);
    }
#endif
  }
  if( 0 == dwLen ){
    sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
  }else{
    /* copy a maximum of nBuf chars to output buffer */
    sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
    /* free the UTF8 buffer */
    free(zOut);
  }
  return 0;
}

/*
**
** This function - winLogErrorAtLine() - is only ever called via the macro
** winLogError().
**
** This routine is invoked after an error occurs in an OS function.
** It logs a message using sqlite3_log() containing the current value of
** error code and, if possible, the human-readable equivalent from 
** FormatMessage.
**
** The first argument passed to the macro should be the error code that
** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). 
** The two subsequent arguments should be the name of the OS function that
** failed and the the associated file-system path, if any.
*/
#define winLogError(a,b,c)     winLogErrorAtLine(a,b,c,__LINE__)
static int winLogErrorAtLine(
  int errcode,                    /* SQLite error code */
  const char *zFunc,              /* Name of OS function that failed */
  const char *zPath,              /* File path associated with error */
  int iLine                       /* Source line number where error occurred */
){
  char zMsg[500];                 /* Human readable error text */
  int i;                          /* Loop counter */
  DWORD iErrno = GetLastError();  /* Error code */

  zMsg[0] = 0;
  getLastErrorMsg(sizeof(zMsg), zMsg);
  assert( errcode!=SQLITE_OK );
  if( zPath==0 ) zPath = "";
  for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
  zMsg[i] = 0;
  sqlite3_log(errcode,
      "os_win.c:%d: (%d) %s(%s) - %s",
      iLine, iErrno, zFunc, zPath, zMsg
  );

  return errcode;
}

#if SQLITE_OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
*/
/*
** WindowsCE does not have a localtime() function.  So create a
** substitute.
................................................................................
    if (*zTok == '\\') *zTok = '_';
  }

  /* Create/open the named mutex */
  pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
  if (!pFile->hMutex){
    pFile->lastErrno = GetLastError();
    winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename);
    free(zName);
    return FALSE;
  }

  /* Acquire the mutex before continuing */
  winceMutexAcquire(pFile->hMutex);
  
................................................................................
  /* If we succeeded in making the shared memory handle, map it. */
  if (pFile->hShared){
    pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, 
             FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock));
    /* If mapping failed, close the shared memory handle and erase it */
    if (!pFile->shared){
      pFile->lastErrno = GetLastError();
      winLogError(SQLITE_ERROR, "winceCreateLock2", zFilename);
      CloseHandle(pFile->hShared);
      pFile->hShared = NULL;
    }
  }

  /* If shared memory could not be created, then close the mutex and fail */
  if (pFile->hShared == NULL){
................................................................................
  ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine 
  ** whether an error has actually occured, it is also necessary to call 
  ** GetLastError().
  */
  dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
  if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
    pFile->lastErrno = GetLastError();
    winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile->zPath);
    return 1;
  }

  return 0;
}

/*
................................................................................
       Sleep(100);  /* Wait a little before trying again */
    }
    free(pFile->zDeleteOnClose);
  }
#endif
  OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
  OpenCounter(-1);
  return rc ? SQLITE_OK
            : winLogError(SQLITE_IOERR_CLOSE, "winClose", pFile->zPath);
}

/*
** Read data from a file into a buffer.  Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
*/
................................................................................
  OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));

  if( seekWinFile(pFile, offset) ){
    return SQLITE_FULL;
  }
  if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
    pFile->lastErrno = GetLastError();
    return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath);
  }
  if( nRead<(DWORD)amt ){
    /* Unread parts of the buffer must be zero-filled */
    memset(&((char*)pBuf)[nRead], 0, amt-nRead);
    return SQLITE_IOERR_SHORT_READ;
  }

................................................................................
    }
  }

  if( rc ){
    if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
      return SQLITE_FULL;
    }
    return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath);
  }
  return SQLITE_OK;
}

/*
** Truncate an open file to a specified size
*/
................................................................................
  */
  if( pFile->szChunk ){
    nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
  }

  /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
  if( seekWinFile(pFile, nByte) ){
    rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath);
  }else if( 0==SetEndOfFile(pFile->h) ){
    pFile->lastErrno = GetLastError();
    rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile->zPath);
  }

  OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
  return rc;
}

#ifdef SQLITE_TEST
................................................................................

/*
** Make sure all writes to a particular file are committed to disk.
*/
static int winSync(sqlite3_file *id, int flags){
#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || defined(SQLITE_DEBUG)
  winFile *pFile = (winFile*)id;
  BOOL rc;
#else
  UNUSED_PARAMETER(id);
#endif

  assert( pFile );
  /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */
  assert((flags&0x0F)==SQLITE_SYNC_NORMAL
      || (flags&0x0F)==SQLITE_SYNC_FULL
  );

  OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));

  /* Unix cannot, but some systems may return SQLITE_FULL from here. This
  ** line is to test that doing so does not cause any problems.
  */
  SimulateDiskfullError( return SQLITE_FULL );

#ifndef SQLITE_TEST
  UNUSED_PARAMETER(flags);
#else
  if( (flags&0x0F)==SQLITE_SYNC_FULL ){
    sqlite3_fullsync_count++;
  }
  sqlite3_sync_count++;
#endif







  /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
  ** no-op
  */
#ifdef SQLITE_NO_SYNC
  return SQLITE_OK;
#else
  rc = FlushFileBuffers(pFile->h);
  SimulateIOError( rc=FALSE );
  if( rc ){
    return SQLITE_OK;
  }else{
    pFile->lastErrno = GetLastError();
    return winLogError(SQLITE_IOERR_FSYNC, "winSync", pFile->zPath);
  }
#endif
}

/*
** Determine the current size of a file in bytes
*/
................................................................................
  assert( id!=0 );
  SimulateIOError(return SQLITE_IOERR_FSTAT);
  lowerBits = GetFileSize(pFile->h, &upperBits);
  if(   (lowerBits == INVALID_FILE_SIZE)
     && ((error = GetLastError()) != NO_ERROR) )
  {
    pFile->lastErrno = error;
    return winLogError(SQLITE_IOERR_FSTAT, "winFileSize", pFile->zPath);
  }
  *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
  return SQLITE_OK;
}

/*
** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
................................................................................
    sqlite3_randomness(sizeof(lk), &lk);
    pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
    res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
#endif
  }
  if( res == 0 ){
    pFile->lastErrno = GetLastError();
    /* No need to log a failure to lock */
  }
  return res;
}

/*
** Undo a readlock
*/
................................................................................
#if SQLITE_OS_WINCE==0
  }else{
    res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
#endif
  }
  if( res == 0 ){
    pFile->lastErrno = GetLastError();
    winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath);
  }
  return res;
}

/*
** Lock the file with the lock specified by parameter locktype - one
** of the following:
................................................................................
          pFile->locktype, pFile->sharedLockByte));
  type = pFile->locktype;
  if( type>=EXCLUSIVE_LOCK ){
    UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
    if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
      /* This should never happen.  We should always be able to
      ** reacquire the read lock */
      rc = winLogError(SQLITE_IOERR_UNLOCK, "winUnlock", pFile->zPath);
    }
  }
  if( type>=RESERVED_LOCK ){
    UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
  }
  if( locktype==NO_LOCK && type>=SHARED_LOCK ){
    unlockReadLock(pFile);
................................................................................

    /* Check to see if another process is holding the dead-man switch.
    ** If not, truncate the file to zero length. 
    */
    if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
      rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
      if( rc!=SQLITE_OK ){
        rc = winLogError(SQLITE_IOERR_SHMOPEN, "winOpenShm", pDbFd->zPath);
      }
    }
    if( rc==SQLITE_OK ){
      winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
      rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
    }
    if( rc ) goto shm_open_err;
................................................................................

    /* The requested region is not mapped into this processes address space.
    ** Check to see if it has been allocated (i.e. if the wal-index file is
    ** large enough to contain the requested region).
    */
    rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
    if( rc!=SQLITE_OK ){
      rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap1", pDbFd->zPath);
      goto shmpage_out;
    }

    if( sz<nByte ){
      /* The requested memory region does not exist. If isWrite is set to
      ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
      **
      ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
      ** the requested memory region.
      */
      if( !isWrite ) goto shmpage_out;
      rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
      if( rc!=SQLITE_OK ){
        rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap2", pDbFd->zPath);
        goto shmpage_out;
      }
    }

    /* Map the requested memory region into this processes address space. */
    apNew = (struct ShmRegion *)sqlite3_realloc(
        pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
................................................................................
        );
        OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
                 (int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion,
                 pMap ? "ok" : "failed"));
      }
      if( !pMap ){
        pShmNode->lastErrno = GetLastError();
        rc = winLogError(SQLITE_IOERR_SHMMAP, "winShmMap3", pDbFd->zPath);
        if( hMap ) CloseHandle(hMap);
        goto shmpage_out;
      }

      pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
      pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
      pShmNode->nRegion++;
................................................................................
  }
  zBuf[j] = 0;

  OSTRACE(("TEMP FILENAME: %s\n", zBuf));
  return SQLITE_OK; 
}































































/*
** Open a file.
*/
static int winOpen(
  sqlite3_vfs *pVfs,        /* Not used */
  const char *zName,        /* Name of the file (UTF-8) */
  sqlite3_file *id,         /* Write the SQLite file handle here */
................................................................................

  OSTRACE(("OPEN %d %s 0x%lx %s\n", 
           h, zName, dwDesiredAccess, 
           h==INVALID_HANDLE_VALUE ? "failed" : "ok"));

  if( h==INVALID_HANDLE_VALUE ){
    pFile->lastErrno = GetLastError();
    winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name);
    free(zConverted);
    if( isReadWrite ){
      return winOpen(pVfs, zName, id, 
             ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
    }else{
      return SQLITE_CANTOPEN_BKPT;
    }
................................................................................
  }
  free(zConverted);
  OSTRACE(("DELETE \"%s\" %s\n", zFilename,
       ( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ?
         "ok" : "failed" ));
 
  return (   (rc == INVALID_FILE_ATTRIBUTES) 
          && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK :
                 winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
}

/*
** Check the existance and status of a file.
*/
static int winAccess(
  sqlite3_vfs *pVfs,         /* Not used on win32 */
................................................................................
          && sAttrData.nFileSizeLow==0 ){
        attr = INVALID_FILE_ATTRIBUTES;
      }else{
        attr = sAttrData.dwFileAttributes;
      }
    }else{
      if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
        winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename);
        free(zConverted);
        return SQLITE_IOERR_ACCESS;
      }else{
        attr = INVALID_FILE_ATTRIBUTES;
      }
    }
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 

Changes to src/select.c.

4234
4235
4236
4237
4238
4239
4240


4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
        /* Search for the index that has the least amount of columns. If
        ** there is such an index, and it has less columns than the table
        ** does, then we can assume that it consumes less space on disk and
        ** will therefore be cheaper to scan to determine the query result.
        ** In this case set iRoot to the root page number of the index b-tree
        ** and pKeyInfo to the KeyInfo structure required to navigate the
        ** index.


        **
        ** In practice the KeyInfo structure will not be used. It is only 
        ** passed to keep OP_OpenRead happy.
        */
        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
          if( !pBest || pIdx->nColumn<pBest->nColumn ){
            pBest = pIdx;
          }
        }
        if( pBest && pBest->nColumn<pTab->nCol ){
          iRoot = pBest->tnum;
          pKeyInfo = sqlite3IndexKeyinfo(pParse, pBest);
        }







>
>





|







4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
        /* Search for the index that has the least amount of columns. If
        ** there is such an index, and it has less columns than the table
        ** does, then we can assume that it consumes less space on disk and
        ** will therefore be cheaper to scan to determine the query result.
        ** In this case set iRoot to the root page number of the index b-tree
        ** and pKeyInfo to the KeyInfo structure required to navigate the
        ** index.
        **
        ** (2011-04-15) Do not do a full scan of an unordered index.
        **
        ** In practice the KeyInfo structure will not be used. It is only 
        ** passed to keep OP_OpenRead happy.
        */
        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
          if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){
            pBest = pIdx;
          }
        }
        if( pBest && pBest->nColumn<pTab->nCol ){
          iRoot = pBest->tnum;
          pKeyInfo = sqlite3IndexKeyinfo(pParse, pBest);
        }

Changes to src/shell.c.

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
...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#if defined(_WIN32_WCE)
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
 * thus we always assume that we have a console. That can be
 * overridden with the -batch command line option.
 */
#define isatty(x) 1
#endif




#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
#include <sys/time.h>
#include <sys/resource.h>

/* Saved resource information for the beginning of an operation */
static struct rusage sBegin;

/* True if the timer is enabled */
static int enableTimer = 0;

/*
** Begin timing an operation
*/
static void beginTimer(void){
  if( enableTimer ){
    getrusage(RUSAGE_SELF, &sBegin);
  }
................................................................................
/* Saved resource information for the beginning of an operation */
static HANDLE hProcess;
static FILETIME ftKernelBegin;
static FILETIME ftUserBegin;
typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
static GETPROCTIMES getProcessTimesAddr = NULL;

/* True if the timer is enabled */
static int enableTimer = 0;

/*
** Check to see if we have timer support.  Return 1 if necessary
** support found (or found previously).
*/
static int hasTimer(void){
  if( getProcessTimesAddr ){
    return 1;







>
>
>








<
<
<







 







<
<
<







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
...
120
121
122
123
124
125
126



127
128
129
130
131
132
133
#if defined(_WIN32_WCE)
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
 * thus we always assume that we have a console. That can be
 * overridden with the -batch command line option.
 */
#define isatty(x) 1
#endif

/* True if the timer is enabled */
static int enableTimer = 0;

#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
#include <sys/time.h>
#include <sys/resource.h>

/* Saved resource information for the beginning of an operation */
static struct rusage sBegin;




/*
** Begin timing an operation
*/
static void beginTimer(void){
  if( enableTimer ){
    getrusage(RUSAGE_SELF, &sBegin);
  }
................................................................................
/* Saved resource information for the beginning of an operation */
static HANDLE hProcess;
static FILETIME ftKernelBegin;
static FILETIME ftUserBegin;
typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
static GETPROCTIMES getProcessTimesAddr = NULL;




/*
** Check to see if we have timer support.  Return 1 if necessary
** support found (or found previously).
*/
static int hasTimer(void){
  if( getProcessTimesAddr ){
    return 1;

Changes to src/sqlite.h.in.

443
444
445
446
447
448
449


450
451
452
453
454
455
456
#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8))
#define SQLITE_IOERR_LOCK              (SQLITE_IOERR | (15<<8))
#define SQLITE_IOERR_CLOSE             (SQLITE_IOERR | (16<<8))
#define SQLITE_IOERR_DIR_CLOSE         (SQLITE_IOERR | (17<<8))
#define SQLITE_IOERR_SHMOPEN           (SQLITE_IOERR | (18<<8))
#define SQLITE_IOERR_SHMSIZE           (SQLITE_IOERR | (19<<8))
#define SQLITE_IOERR_SHMLOCK           (SQLITE_IOERR | (20<<8))


#define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
#define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))

/*
** CAPI3REF: Flags For File Open Operations
**







>
>







443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8))
#define SQLITE_IOERR_LOCK              (SQLITE_IOERR | (15<<8))
#define SQLITE_IOERR_CLOSE             (SQLITE_IOERR | (16<<8))
#define SQLITE_IOERR_DIR_CLOSE         (SQLITE_IOERR | (17<<8))
#define SQLITE_IOERR_SHMOPEN           (SQLITE_IOERR | (18<<8))
#define SQLITE_IOERR_SHMSIZE           (SQLITE_IOERR | (19<<8))
#define SQLITE_IOERR_SHMLOCK           (SQLITE_IOERR | (20<<8))
#define SQLITE_IOERR_SHMMAP            (SQLITE_IOERR | (21<<8))
#define SQLITE_IOERR_SEEK              (SQLITE_IOERR | (22<<8))
#define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
#define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))

/*
** CAPI3REF: Flags For File Open Operations
**

Changes to src/util.c.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#endif

/*
** Routine needed to support the testcase() macro.
*/
#ifdef SQLITE_COVERAGE_TEST
void sqlite3Coverage(int x){
  static int dummy = 0;
  dummy += x;
}
#endif

#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Return true if the floating point value is Not a Number (NaN).
**







|
|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#endif

/*
** Routine needed to support the testcase() macro.
*/
#ifdef SQLITE_COVERAGE_TEST
void sqlite3Coverage(int x){
  static unsigned dummy = 0;
  dummy += (unsigned)x;
}
#endif

#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Return true if the floating point value is Not a Number (NaN).
**

Changes to test/exists.test.

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
# that feature "IF EXISTS" or "IF NOT EXISTS" clauses.
#

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




set testprefix exists

# This block of tests is targeted at CREATE XXX IF NOT EXISTS statements.
#
do_multiclient_test tn {

  # TABLE objects.
  #
  do_test 1.$tn.1.1 {

    sql2 { CREATE TABLE t1(x) }
    sql1 { CREATE TABLE IF NOT EXISTS t1(a, b) }
    sql2 { DROP TABLE t1 }
    sql1 { CREATE TABLE IF NOT EXISTS t1(a, b) }
    sql2 { SELECT name FROM sqlite_master WHERE type = 'table' }
  } {t1}

  do_test 1.$tn.1.2 {
    sql2 { CREATE TABLE t2(x) }
    sql1 { CREATE TABLE IF NOT EXISTS t2 AS SELECT * FROM t1 }
    sql2 { DROP TABLE t2 }
    sql1 { CREATE TABLE IF NOT EXISTS t2 AS SELECT * FROM t1 }
    sql2 { SELECT name FROM sqlite_master WHERE type = 'table' }
  } {t1 t2}


  # INDEX objects.
  #
  do_test 1.$tn.2 {
    sql2 { CREATE INDEX i1 ON t1(a) }
    sql1 { CREATE INDEX IF NOT EXISTS i1 ON t1(a, b) }
    sql2 { DROP INDEX i1 }
    sql1 { CREATE INDEX IF NOT EXISTS i1 ON t1(a, b) }
    sql2 { SELECT name FROM sqlite_master WHERE type = 'index' }
  } {i1}

  # VIEW objects.
  #
  do_test 1.$tn.3 {
    sql2 { CREATE VIEW v1 AS SELECT * FROM t1 }
    sql1 { CREATE VIEW IF NOT EXISTS v1 AS SELECT * FROM t1 }
    sql2 { DROP VIEW v1 }
    sql1 { CREATE VIEW IF NOT EXISTS v1 AS SELECT * FROM t1 }
    sql2 { SELECT name FROM sqlite_master WHERE type = 'view' }
  } {v1}

  # TRIGGER objects.
  #
  do_test $tn.4 {
    sql2 { CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END }
sql1 { CREATE TRIGGER IF NOT EXISTS tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END }
    sql2 { DROP TRIGGER tr1 }
sql1 { CREATE TRIGGER IF NOT EXISTS tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END }
    sql2 { SELECT name FROM sqlite_master WHERE type = 'trigger' }
  } {tr1}
}

# This block of tests is targeted at DROP XXX IF EXISTS statements.
#
do_multiclient_test tn {

  # TABLE objects.
  #
  do_test 2.$tn.1 {

    sql1 { DROP TABLE IF EXISTS t1 }
    sql2 { CREATE TABLE t1(x) }
    sql1 { DROP TABLE IF EXISTS t1 }
    sql2 { SELECT name FROM sqlite_master WHERE type = 'table' }
  } {}

  # INDEX objects.
  #
  do_test 2.$tn.2 {
    sql1 { CREATE TABLE t2(x) }
    sql1 { DROP INDEX IF EXISTS i2 }
    sql2 { CREATE INDEX i2 ON t2(x) }
    sql1 { DROP INDEX IF EXISTS i2 }
    sql2 { SELECT name FROM sqlite_master WHERE type = 'index' }
  } {}

  # VIEW objects.
  #
  do_test 2.$tn.3 {
    sql1 { DROP VIEW IF EXISTS v1 }
    sql2 { CREATE VIEW v1 AS SELECT * FROM t2 }
    sql1 { DROP VIEW IF EXISTS v1 }
    sql2 { SELECT name FROM sqlite_master WHERE type = 'view' }
  } {}
  
  # TRIGGER objects.
  #
  do_test 2.$tn.4 {
    sql1 { DROP TRIGGER IF EXISTS tr1 }
    sql2 { CREATE TRIGGER tr1 AFTER INSERT ON t2 BEGIN SELECT 1; END }
    sql1 { DROP TRIGGER IF EXISTS tr1 }
    sql2 { SELECT name FROM sqlite_master WHERE type = 'trigger' }
  } {}
}

# This block of tests is targeted at DROP XXX IF EXISTS statements with
# attached databases.
#
do_multiclient_test tn {

  forcedelete test.db2
  do_test 3.$tn.0 {
    sql1 { ATTACH 'test.db2' AS aux }
    sql2 { ATTACH 'test.db2' AS aux }
  } {}

  # TABLE objects.
  #
  do_test 3.$tn.1.1 {
    sql1 { DROP TABLE IF EXISTS aux.t1 }
    sql2 { CREATE TABLE aux.t1(x) }
    sql1 { DROP TABLE IF EXISTS aux.t1 }
    sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'table' }
  } {}
  do_test 3.$tn.1.2 {
    sql1 { DROP TABLE IF EXISTS t1 }
    sql2 { CREATE TABLE aux.t1(x) }
    sql1 { DROP TABLE IF EXISTS t1 }
    sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'table' }
  } {}

  # INDEX objects.
  #
  do_test 3.$tn.2.1 {
    sql1 { CREATE TABLE aux.t2(x) }
    sql1 { DROP INDEX IF EXISTS aux.i2 }
    sql2 { CREATE INDEX aux.i2 ON t2(x) }
    sql1 { DROP INDEX IF EXISTS aux.i2 }
    sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'index' }
  } {}
  do_test 3.$tn.2.2 {
    sql1 { DROP INDEX IF EXISTS i2 }
    sql2 { CREATE INDEX aux.i2 ON t2(x) }
    sql1 { DROP INDEX IF EXISTS i2 }
    sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'index' }
  } {}

  # VIEW objects.
  #
  do_test 3.$tn.3.1 {
    sql1 { DROP VIEW IF EXISTS aux.v1 }
    sql2 { CREATE VIEW aux.v1 AS SELECT * FROM t2 }
    sql1 { DROP VIEW IF EXISTS aux.v1 }
    sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'view' }
  } {}
  do_test 3.$tn.3.2 {
    sql1 { DROP VIEW IF EXISTS v1 }
    sql2 { CREATE VIEW aux.v1 AS SELECT * FROM t2 }
    sql1 { DROP VIEW IF EXISTS v1 }
    sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'view' }
  } {}
  
  # TRIGGER objects.
  #
  do_test 3.$tn.4.1 {
    sql1 { DROP TRIGGER IF EXISTS aux.tr1 }
    sql2 { CREATE TRIGGER aux.tr1 AFTER INSERT ON t2 BEGIN SELECT 1; END }
    sql1 { DROP TRIGGER IF EXISTS aux.tr1 }
    sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'trigger' }
  } {}
  do_test 3.$tn.4.2 {
    sql1 { DROP TRIGGER IF EXISTS tr1 }
    sql2 { CREATE TRIGGER aux.tr1 AFTER INSERT ON t2 BEGIN SELECT 1; END }
    sql1 { DROP TRIGGER IF EXISTS tr1 }
    sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'trigger' }
  } {}
}



finish_test







>
>
>
|

|
|
|

|
|
|
>
|
|
|
|
|
|

|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|

|
|
|

|
|
|
>
|
|
|
|
|

|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|

|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

>

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
# that feature "IF EXISTS" or "IF NOT EXISTS" clauses.
#

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


foreach jm {rollback wal} {

  set testprefix exists-$jm

  # This block of tests is targeted at CREATE XXX IF NOT EXISTS statements.
  #
  do_multiclient_test tn {

    # TABLE objects.
    #
    do_test 1.$tn.1.1 {
      if {$jm == "wal"} { sql2 { PRAGMA journal_mode = WAL } }
      sql2 { CREATE TABLE t1(x) }
      sql1 { CREATE TABLE IF NOT EXISTS t1(a, b) }
      sql2 { DROP TABLE t1 }
      sql1 { CREATE TABLE IF NOT EXISTS t1(a, b) }
      sql2 { SELECT name FROM sqlite_master WHERE type = 'table' }
    } {t1}

    do_test 1.$tn.1.2 {
      sql2 { CREATE TABLE t2(x) }
      sql1 { CREATE TABLE IF NOT EXISTS t2 AS SELECT * FROM t1 }
      sql2 { DROP TABLE t2 }
      sql1 { CREATE TABLE IF NOT EXISTS t2 AS SELECT * FROM t1 }
      sql2 { SELECT name FROM sqlite_master WHERE type = 'table' }
    } {t1 t2}


    # INDEX objects.
    #
    do_test 1.$tn.2 {
      sql2 { CREATE INDEX i1 ON t1(a) }
      sql1 { CREATE INDEX IF NOT EXISTS i1 ON t1(a, b) }
      sql2 { DROP INDEX i1 }
      sql1 { CREATE INDEX IF NOT EXISTS i1 ON t1(a, b) }
      sql2 { SELECT name FROM sqlite_master WHERE type = 'index' }
    } {i1}

    # VIEW objects.
    #
    do_test 1.$tn.3 {
      sql2 { CREATE VIEW v1 AS SELECT * FROM t1 }
      sql1 { CREATE VIEW IF NOT EXISTS v1 AS SELECT * FROM t1 }
      sql2 { DROP VIEW v1 }
      sql1 { CREATE VIEW IF NOT EXISTS v1 AS SELECT * FROM t1 }
      sql2 { SELECT name FROM sqlite_master WHERE type = 'view' }
    } {v1}

    # TRIGGER objects.
    #
    do_test $tn.4 {
      sql2 { CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END }
  sql1 { CREATE TRIGGER IF NOT EXISTS tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END }
      sql2 { DROP TRIGGER tr1 }
  sql1 { CREATE TRIGGER IF NOT EXISTS tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END }
      sql2 { SELECT name FROM sqlite_master WHERE type = 'trigger' }
    } {tr1}
  }

  # This block of tests is targeted at DROP XXX IF EXISTS statements.
  #
  do_multiclient_test tn {

    # TABLE objects.
    #
    do_test 2.$tn.1 {
      if {$jm == "wal"} { sql1 { PRAGMA journal_mode = WAL } }
      sql1 { DROP TABLE IF EXISTS t1 }
      sql2 { CREATE TABLE t1(x) }
      sql1 { DROP TABLE IF EXISTS t1 }
      sql2 { SELECT name FROM sqlite_master WHERE type = 'table' }
    } {}

    # INDEX objects.
    #
    do_test 2.$tn.2 {
      sql1 { CREATE TABLE t2(x) }
      sql1 { DROP INDEX IF EXISTS i2 }
      sql2 { CREATE INDEX i2 ON t2(x) }
      sql1 { DROP INDEX IF EXISTS i2 }
      sql2 { SELECT name FROM sqlite_master WHERE type = 'index' }
    } {}

    # VIEW objects.
    #
    do_test 2.$tn.3 {
      sql1 { DROP VIEW IF EXISTS v1 }
      sql2 { CREATE VIEW v1 AS SELECT * FROM t2 }
      sql1 { DROP VIEW IF EXISTS v1 }
      sql2 { SELECT name FROM sqlite_master WHERE type = 'view' }
    } {}

    # TRIGGER objects.
    #
    do_test 2.$tn.4 {
      sql1 { DROP TRIGGER IF EXISTS tr1 }
      sql2 { CREATE TRIGGER tr1 AFTER INSERT ON t2 BEGIN SELECT 1; END }
      sql1 { DROP TRIGGER IF EXISTS tr1 }
      sql2 { SELECT name FROM sqlite_master WHERE type = 'trigger' }
    } {}
  }

  # This block of tests is targeted at DROP XXX IF EXISTS statements with
  # attached databases.
  #
  do_multiclient_test tn {

    forcedelete test.db2
    do_test 3.$tn.0 {
      sql1 { ATTACH 'test.db2' AS aux }
      sql2 { ATTACH 'test.db2' AS aux }
    } {}

    # TABLE objects.
    #
    do_test 3.$tn.1.1 {
      sql1 { DROP TABLE IF EXISTS aux.t1 }
      sql2 { CREATE TABLE aux.t1(x) }
      sql1 { DROP TABLE IF EXISTS aux.t1 }
      sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'table' }
    } {}
    do_test 3.$tn.1.2 {
      sql1 { DROP TABLE IF EXISTS t1 }
      sql2 { CREATE TABLE aux.t1(x) }
      sql1 { DROP TABLE IF EXISTS t1 }
      sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'table' }
    } {}

    # INDEX objects.
    #
    do_test 3.$tn.2.1 {
      sql1 { CREATE TABLE aux.t2(x) }
      sql1 { DROP INDEX IF EXISTS aux.i2 }
      sql2 { CREATE INDEX aux.i2 ON t2(x) }
      sql1 { DROP INDEX IF EXISTS aux.i2 }
      sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'index' }
    } {}
    do_test 3.$tn.2.2 {
      sql1 { DROP INDEX IF EXISTS i2 }
      sql2 { CREATE INDEX aux.i2 ON t2(x) }
      sql1 { DROP INDEX IF EXISTS i2 }
      sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'index' }
    } {}

    # VIEW objects.
    #
    do_test 3.$tn.3.1 {
      sql1 { DROP VIEW IF EXISTS aux.v1 }
      sql2 { CREATE VIEW aux.v1 AS SELECT * FROM t2 }
      sql1 { DROP VIEW IF EXISTS aux.v1 }
      sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'view' }
    } {}
    do_test 3.$tn.3.2 {
      sql1 { DROP VIEW IF EXISTS v1 }
      sql2 { CREATE VIEW aux.v1 AS SELECT * FROM t2 }
      sql1 { DROP VIEW IF EXISTS v1 }
      sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'view' }
    } {}

    # TRIGGER objects.
    #
    do_test 3.$tn.4.1 {
      sql1 { DROP TRIGGER IF EXISTS aux.tr1 }
      sql2 { CREATE TRIGGER aux.tr1 AFTER INSERT ON t2 BEGIN SELECT 1; END }
      sql1 { DROP TRIGGER IF EXISTS aux.tr1 }
      sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'trigger' }
    } {}
    do_test 3.$tn.4.2 {
      sql1 { DROP TRIGGER IF EXISTS tr1 }
      sql2 { CREATE TRIGGER aux.tr1 AFTER INSERT ON t2 BEGIN SELECT 1; END }
      sql1 { DROP TRIGGER IF EXISTS tr1 }
      sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'trigger' }
    } {}
  }
}


finish_test

Changes to test/quota.test.

198
199
200
201
202
203
204



205
206
207
208
209
210
211
do_test quota-3.2.9 { 
  catchsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b
} {1 {database or disk is full}}

set ::quota [list]
proc quota_callback {file limitvar size} {
  upvar $limitvar limit



  lappend ::quota $file $size
  set limit 0
}
sqlite3_quota_set * 4096 quota_callback
do_test quota-3.3.1 { 
  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a
  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b







>
>
>







198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
do_test quota-3.2.9 { 
  catchsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b
} {1 {database or disk is full}}

set ::quota [list]
proc quota_callback {file limitvar size} {
  upvar $limitvar limit
  if {$::tcl_platform(platform)=="windows"} {
    set file [ lindex [string map {\\ \/} $file] 0 ]
  }
  lappend ::quota $file $size
  set limit 0
}
sqlite3_quota_set * 4096 quota_callback
do_test quota-3.3.1 { 
  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a
  execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b

Changes to test/sync.test.

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
#
# $Id: sync.test,v 1.6 2007/10/09 08:29:33 danielk1977 Exp $

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

#
# These tests are only applicable on unix when pager pragma are
# enabled. Also, since every test uses an ATTACHed database, they
# are only run when ATTACH is enabled.
#
if {$::tcl_platform(platform)!="unix"} {
  finish_test
  return
}







ifcapable !pager_pragmas||!attach {
  finish_test
  return



}

do_test sync-1.1 {
  set sqlite_sync_count 0
  file delete -force test2.db
  file delete -force test2.db-journal
  execsql {
    PRAGMA fullfsync=OFF;
    CREATE TABLE t1(a,b);
    ATTACH DATABASE 'test2.db' AS db2;
    CREATE TABLE db2.t2(x,y);
  }
  ifcapable !dirsync {
    incr sqlite_sync_count 2
  }
  set sqlite_sync_count
} 8
ifcapable pager_pragmas {
  do_test sync-1.2 {
    set sqlite_sync_count 0
    execsql {
      PRAGMA main.synchronous=on;
      PRAGMA db2.synchronous=on;
      BEGIN;
      INSERT INTO t1 VALUES(1,2);
      INSERT INTO t2 VALUES(3,4);
      COMMIT;
    }
    ifcapable !dirsync {
      incr sqlite_sync_count 3
    }
    set sqlite_sync_count
  } 8
}
do_test sync-1.3 {
  set sqlite_sync_count 0
  execsql {
    PRAGMA main.synchronous=full;
    PRAGMA db2.synchronous=full;
    BEGIN;
    INSERT INTO t1 VALUES(3,4);
    INSERT INTO t2 VALUES(5,6);
    COMMIT;
  }
  ifcapable !dirsync {
    incr sqlite_sync_count 3
  }
  set sqlite_sync_count
} 10
ifcapable pager_pragmas {
  do_test sync-1.4 {
    set sqlite_sync_count 0
    execsql {
      PRAGMA main.synchronous=off;







|



|



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












<
|
<













<
|
<













<
|
<







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
#
# $Id: sync.test,v 1.6 2007/10/09 08:29:33 danielk1977 Exp $

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

#
# These tests are only applicable when pager pragma are
# enabled. Also, since every test uses an ATTACHed database, they
# are only run when ATTACH is enabled.
#
ifcapable !pager_pragmas||!attach {
  finish_test
  return
}

set sqlite_sync_count 0
proc cond_incr_sync_count {adj} {
  global sqlite_sync_count
  if {$::tcl_platform(platform) == "windows"} {
    incr sqlite_sync_count $adj
  } {
    ifcapable !dirsync {


      incr sqlite_sync_count $adj
    }
  }
}

do_test sync-1.1 {
  set sqlite_sync_count 0
  file delete -force test2.db
  file delete -force test2.db-journal
  execsql {
    PRAGMA fullfsync=OFF;
    CREATE TABLE t1(a,b);
    ATTACH DATABASE 'test2.db' AS db2;
    CREATE TABLE db2.t2(x,y);
  }

  cond_incr_sync_count 2

  set sqlite_sync_count
} 8
ifcapable pager_pragmas {
  do_test sync-1.2 {
    set sqlite_sync_count 0
    execsql {
      PRAGMA main.synchronous=on;
      PRAGMA db2.synchronous=on;
      BEGIN;
      INSERT INTO t1 VALUES(1,2);
      INSERT INTO t2 VALUES(3,4);
      COMMIT;
    }

    cond_incr_sync_count 3

    set sqlite_sync_count
  } 8
}
do_test sync-1.3 {
  set sqlite_sync_count 0
  execsql {
    PRAGMA main.synchronous=full;
    PRAGMA db2.synchronous=full;
    BEGIN;
    INSERT INTO t1 VALUES(3,4);
    INSERT INTO t2 VALUES(5,6);
    COMMIT;
  }

  cond_incr_sync_count 3

  set sqlite_sync_count
} 10
ifcapable pager_pragmas {
  do_test sync-1.4 {
    set sqlite_sync_count 0
    execsql {
      PRAGMA main.synchronous=off;

Changes to test/triggerC.test.

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
...
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

    INSERT INTO t22 VALUES(1);
    SELECT count(*) FROM t22;
  }
} {100}

do_test triggerC-2.3 {
  execsql {
    CREATE TABLE t23(x PRIMARY KEY);

    CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN
      INSERT INTO t23 VALUES(new.x + 1);
    END;

    CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN
      SELECT CASE WHEN new.x>500
                  THEN RAISE(IGNORE)
                  ELSE NULL END;
    END;

    INSERT INTO t23 VALUES(1);
    SELECT count(*) FROM t23;
  }
} {500}
 

#-----------------------------------------------------------------------
# This block of tests, triggerC-3.*, test that SQLite throws an exception
# when it detects excessive recursion.
#
do_test triggerC-3.1.1 {
................................................................................
  catchsql { INSERT INTO t3 VALUES(0,0) }
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.1.3 {
  execsql { SELECT * FROM t3 }
} {}

do_test triggerC-3.2.1 {
  execsql {
    CREATE TABLE t3b(x);
    CREATE TRIGGER t3bi AFTER INSERT ON t3b WHEN new.x<2000 BEGIN
      INSERT INTO t3b VALUES(new.x+1);
    END;
  }

  catchsql {
    INSERT INTO t3b VALUES(1);
  }
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.2.2 {
  db eval {SELECT * FROM t3b}
} {}

do_test triggerC-3.3.1 {
  catchsql {
    INSERT INTO t3b VALUES(1001);
  }
} {0 {}}
do_test triggerC-3.3.2 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {1000 2000 1001}

do_test triggerC-3.4.1 {
  catchsql {
    DELETE FROM t3b;
    INSERT INTO t3b VALUES(999);
  }

} {1 {too many levels of trigger recursion}}
do_test triggerC-3.4.2 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {0 {} {}}

do_test triggerC-3.5.1 {
  sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 100
  catchsql {
    INSERT INTO t3b VALUES(1901);
  }

} {0 {}}
do_test triggerC-3.5.2 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {100 2000 1901}

do_test triggerC-3.5.3 {
  catchsql {
    DELETE FROM t3b;
    INSERT INTO t3b VALUES(1900);
  }

} {1 {too many levels of trigger recursion}}
do_test triggerC-3.5.4 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {0 {} {}}

do_test triggerC-3.6.1 {
  sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1
  catchsql {
    INSERT INTO t3b VALUES(2000);
  }
} {0 {}}
do_test triggerC-3.6.2 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {1 2000 2000}

do_test triggerC-3.6.3 {
  catchsql {
    DELETE FROM t3b;
    INSERT INTO t3b VALUES(1999);
  }

} {1 {too many levels of trigger recursion}}
do_test triggerC-3.6.4 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {0 {} {}}
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000
      

#-----------------------------------------------------------------------
# This next block of tests, triggerC-4.*, checks that affinity 
# transformations and constraint processing is performed at the correct 
# times relative to BEFORE and AFTER triggers.
#
# For an INSERT statement, for each row to be inserted:







|







|






|
|







 







|

|


<
>









|
|
|



|


|

|
<
>






|
|
|
<
>



|


|

|
<
>







|
|
|



|


|

|
<
>




|
|







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
...
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

    INSERT INTO t22 VALUES(1);
    SELECT count(*) FROM t22;
  }
} {100}

do_test triggerC-2.3 {
  execsql "
    CREATE TABLE t23(x PRIMARY KEY);

    CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN
      INSERT INTO t23 VALUES(new.x + 1);
    END;

    CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN
      SELECT CASE WHEN new.x>[expr $SQLITE_MAX_TRIGGER_DEPTH / 2]
                  THEN RAISE(IGNORE)
                  ELSE NULL END;
    END;

    INSERT INTO t23 VALUES(1);
    SELECT count(*) FROM t23;
  "
} [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 2]]
 

#-----------------------------------------------------------------------
# This block of tests, triggerC-3.*, test that SQLite throws an exception
# when it detects excessive recursion.
#
do_test triggerC-3.1.1 {
................................................................................
  catchsql { INSERT INTO t3 VALUES(0,0) }
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.1.3 {
  execsql { SELECT * FROM t3 }
} {}

do_test triggerC-3.2.1 {
  execsql "
    CREATE TABLE t3b(x);
    CREATE TRIGGER t3bi AFTER INSERT ON t3b WHEN new.x<[expr $SQLITE_MAX_TRIGGER_DEPTH * 2] BEGIN
      INSERT INTO t3b VALUES(new.x+1);
    END;

  "
  catchsql {
    INSERT INTO t3b VALUES(1);
  }
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.2.2 {
  db eval {SELECT * FROM t3b}
} {}

do_test triggerC-3.3.1 {
  catchsql "
    INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH + 1]);
  "
} {0 {}}
do_test triggerC-3.3.2 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} [list $SQLITE_MAX_TRIGGER_DEPTH [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH + 1]]

do_test triggerC-3.4.1 {
  catchsql "
    DELETE FROM t3b;
    INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH - 1]);

  "
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.4.2 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {0 {} {}}

do_test triggerC-3.5.1 {
  sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH  [expr $SQLITE_MAX_TRIGGER_DEPTH / 10]
  catchsql "
    INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10) + 1]);

  "
} {0 {}}
do_test triggerC-3.5.2 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} [list [expr $SQLITE_MAX_TRIGGER_DEPTH / 10] [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10) + 1]]

do_test triggerC-3.5.3 {
  catchsql "
    DELETE FROM t3b;
    INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - ($SQLITE_MAX_TRIGGER_DEPTH / 10)]);

  "
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.5.4 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {0 {} {}}

do_test triggerC-3.6.1 {
  sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1
  catchsql "
    INSERT INTO t3b VALUES([expr $SQLITE_MAX_TRIGGER_DEPTH * 2]);
  "
} {0 {}}
do_test triggerC-3.6.2 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} [list 1 [expr $SQLITE_MAX_TRIGGER_DEPTH * 2] [expr $SQLITE_MAX_TRIGGER_DEPTH * 2]]

do_test triggerC-3.6.3 {
  catchsql "
    DELETE FROM t3b;
    INSERT INTO t3b VALUES([expr ($SQLITE_MAX_TRIGGER_DEPTH * 2) - 1]);

  "
} {1 {too many levels of trigger recursion}}
do_test triggerC-3.6.4 {
  db eval {SELECT count(*), max(x), min(x) FROM t3b}
} {0 {} {}}
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH $SQLITE_MAX_TRIGGER_DEPTH


#-----------------------------------------------------------------------
# This next block of tests, triggerC-4.*, checks that affinity 
# transformations and constraint processing is performed at the correct 
# times relative to BEFORE and AFTER triggers.
#
# For an INSERT statement, for each row to be inserted:

Added test/unordered.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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 2011 April 9
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  
#

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

set testprefix unordered

do_execsql_test 1.0 {
  CREATE TABLE t1(a, b);
  CREATE INDEX i1 ON t1(a);
  INSERT INTO t1 VALUES(1, 'xxx');
  INSERT INTO t1 SELECT a+1, b FROM t1;
  INSERT INTO t1 SELECT a+2, b FROM t1;
  INSERT INTO t1 SELECT a+4, b FROM t1;
  INSERT INTO t1 SELECT a+8, b FROM t1;
  INSERT INTO t1 SELECT a+16, b FROM t1;
  INSERT INTO t1 SELECT a+32, b FROM t1;
  INSERT INTO t1 SELECT a+64, b FROM t1;
  ANALYZE;
} {}

foreach idxmode {ordered unordered} {
  if {$idxmode == "unordered"} {
    execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' }
    db close
    sqlite3 db test.db
  }
  foreach {tn sql r(ordered) r(unordered)} {
    1   "SELECT * FROM t1 ORDER BY a"
        {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}}
        {0 0 0 {SCAN TABLE t1 (~128 rows)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}}
    2   "SELECT * FROM t1 WHERE a >?"
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~32 rows)}}
        {0 0 0 {SCAN TABLE t1 (~42 rows)}}
    3   "SELECT * FROM t1 WHERE a = ? ORDER BY rowid"
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)} 
         0 0 0 {USE TEMP B-TREE FOR ORDER BY}}
    4   "SELECT max(a) FROM t1"
        {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (~1 rows)}}
        {0 0 0 {SEARCH TABLE t1 (~1 rows)}}
    5   "SELECT group_concat(b) FROM t1 GROUP BY a"
        {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}}
        {0 0 0 {SCAN TABLE t1 (~128 rows)} 0 0 0 {USE TEMP B-TREE FOR GROUP BY}}

    6   "SELECT * FROM t1 WHERE a = ?"
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
    7   "SELECT count(*) FROM t1"
        {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1(~128 rows)}}
        {0 0 0 {SCAN TABLE t1 (~128 rows)}}
  } {
    do_eqp_test 1.$idxmode.$tn $sql $r($idxmode)
  }
}

finish_test

Changes to test/wal2.test.

18
19
20
21
22
23
24












25
26
27
28
29
30
31
....
1185
1186
1187
1188
1189
1190
1191

1192
1193
1194
1195
1196
1197
1198
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl

set testprefix wal2

ifcapable !wal {finish_test ; return }













proc set_tvfs_hdr {file args} {

  # Set $nHdr to the number of bytes in the wal-index header:
  set nHdr 48
  set nInt [expr {$nHdr/4}]

................................................................................
      INSERT INTO t1 VALUES(3, 4);
      INSERT INTO t1 VALUES(5, 6);
    COMMIT;                               -- 1 wal sync
    PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
  } {10 0 5 5 0 2 2}

  do_test wal2-14.$tn.3 {

    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $reslist 0 1]

  set sqlite_sync_count 0
  set sqlite_fullsync_count 0

  do_test wal2-14.$tn.4 {







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







 







>







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
....
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl

set testprefix wal2

ifcapable !wal {finish_test ; return }

set sqlite_sync_count 0
proc cond_incr_sync_count {adj} {
  global sqlite_sync_count
  if {$::tcl_platform(platform) == "windows"} {
    incr sqlite_sync_count $adj
  } {
    ifcapable !dirsync {
      incr sqlite_sync_count $adj
    }
  }
}

proc set_tvfs_hdr {file args} {

  # Set $nHdr to the number of bytes in the wal-index header:
  set nHdr 48
  set nInt [expr {$nHdr/4}]

................................................................................
      INSERT INTO t1 VALUES(3, 4);
      INSERT INTO t1 VALUES(5, 6);
    COMMIT;                               -- 1 wal sync
    PRAGMA wal_checkpoint;                -- 1 wal sync, 1 db sync
  } {10 0 5 5 0 2 2}

  do_test wal2-14.$tn.3 {
    cond_incr_sync_count 1
    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $reslist 0 1]

  set sqlite_sync_count 0
  set sqlite_fullsync_count 0

  do_test wal2-14.$tn.4 {

Added tool/rollback-test.c.























































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
** This program is used to generate and verify databases with hot journals.
** Use this program to generate a hot journal on one machine and verify
** that it rolls back correctly on another machine with a different
** architecture.
**
** Usage:
**
**     rollback-test new [-utf8] [-utf16le] [-utf16be] [-pagesize=N] DATABASE
**     rollback-test check DATABASE
**     rollback-test crash [-wal] [-rollback] DATABASE
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"

static void usage(char *argv0){
  fprintf(stderr,
    "Usage: %s new [-utf8] [-utf16le] [-utf16be] [-pagesize=N] DATABASE\n"
    "       %s check DATABASE\n"
    "       %s crash [-wal] DATABASE\n",
    argv0, argv0, argv0
  );
  exit(1);
}

static sqlite3 *openDb(const char *zFilename){
  int rc;
  sqlite3 *db;
  rc = sqlite3_open(zFilename, &db);
  if( rc ){
    fprintf(stderr, "Cannot open \"%s\": %s\n",
            zFilename, sqlite3_errmsg(db));
    sqlite3_close(db);
    exit(1);
  }
  return db;
}

static int nReply = 0;
static char zReply[1000];

static int execCallback(void *NotUsed, int nArg, char **azArg, char **azCol){
  int i, n;
  char *z;
  for(i=0; i<nArg; i++){
    z = azArg[i];
    if( z==0 ) z = "NULL";
    if( nReply>0 && nReply<sizeof(zReply)-1 ) zReply[nReply++] = ' ';
    n = strlen(z);
    if( nReply+n>=sizeof(zReply)-1 ) n = sizeof(zReply) - nReply - 1;
    memcpy(&zReply[nReply], z, n);
    nReply += n;
    zReply[nReply] = 0;
  }
  return 0;
}

static void runSql(sqlite3 *db, const char *zSql){
  char *zErr = 0;
  int rc;
  nReply = 0;
  rc = sqlite3_exec(db, zSql, execCallback, 0, &zErr);
  if( zErr ){
    fprintf(stderr, "SQL error: %s\n", zErr);
    exit(1);
  }
  if( rc ){
    fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
    exit(1);
  }
}

int main(int argc, char **argv){
  sqlite3 *db;
  int i;

  if( argc<3 ) usage(argv[0]);
  if( strcmp(argv[1], "new")==0 ){
    db = openDb(argv[argc-1]);
    for(i=2; i<argc-1; i++){
      if( strcmp(argv[i],"-utf8")==0 ){
        runSql(db, "PRAGMA encoding=UTF8");
      }else if( strcmp(argv[i], "-utf16le")==0 ){
        runSql(db, "PRAGMA encoding=UTF16LE");
      }else if( strcmp(argv[i], "-utf16be")==0 ){
        runSql(db, "PRAGMA encoding=UTF16BE");
      }else if( strncmp(argv[i], "-pagesize=", 10)==0 ){
        int szPg = atoi(&argv[i][10]);
        char zBuf[100];
        sprintf(zBuf, "PRAGMA pagesize=%d", szPg);
        runSql(db, zBuf);
      }else{
        fprintf(stderr, "unknown option %s\n", argv[i]);
        usage(argv[0]);
      }
    }
    runSql(db, 
       "BEGIN;"
       "CREATE TABLE t1(x INTEGER PRIMARY KEY, y);"
       "INSERT INTO t1(y) VALUES('abcdefghijklmnopqrstuvwxyz');"
       "INSERT INTO t1(y) VALUES('abcdefghijklmnopqrstuvwxyz');"
       "INSERT INTO t1(y) SELECT y FROM t1;" /* 4 */
       "INSERT INTO t1(y) SELECT y FROM t1;" /* 8 */
       "INSERT INTO t1(y) SELECT y FROM t1;" /* 16 */
       "INSERT INTO t1(y) SELECT y FROM t1;" /* 32 */
       "INSERT INTO t1(y) SELECT y FROM t1;" /* 64 */
       "INSERT INTO t1(y) SELECT y FROM t1;" /* 128 */
       "INSERT INTO t1(y) SELECT y FROM t1;" /* 256 */
       "INSERT INTO t1(y) SELECT y FROM t1;" /* 512 */
       "INSERT INTO t1(y) SELECT y FROM t1;" /* 1024 */
       "UPDATE t1 SET y=(y || x);"
       "CREATE INDEX t1y ON t1(y);"
       "COMMIT;"
    );
    sqlite3_close(db);
  }else if( strcmp(argv[1], "check")==0 ){
    db = openDb(argv[argc-1]);
    runSql(db, "PRAGMA integrity_check");
    if( strcmp(zReply, "ok")!=0 ){
      fprintf(stderr, "Integrity check: %s\n", zReply);
      exit(1);
    }
    runSql(db, 
      "SELECT count(*) FROM t1 WHERE y<>('abcdefghijklmnopqrstuvwxyz' || x)"
    );
    if( strcmp(zReply, "0")!=0 ){
      fprintf(stderr, "Wrong content\n");
      exit(1);
    }
    printf("Ok\n");
  }else if( strcmp(argv[1], "crash")==0 ){
    db = openDb(argv[argc-1]);
    for(i=2; i<argc-1; i++){
      if( strcmp(argv[i],"-wal")==0 ){
        runSql(db, "PRAGMA journal_mode=WAL");
      }else if( strcmp(argv[i], "-rollback")==0 ){
        runSql(db, "PRAGMA journal_mode=DELETE");
      }else{
        fprintf(stderr, "unknown option %s\n", argv[i]);
        usage(argv[0]);
      }
    }
    runSql(db,
      "PRAGMA cache_size=10;"
      "BEGIN;"
      "UPDATE t1 SET y=(y || -x)"
    );
    exit(0);
  }else{
    usage(argv[0]);
  }
  return 0;
}

Changes to tool/shell1.test.

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  list $rc \
       [regexp {Error: missing argument for option: -nullvalue} $res]
} {1 1}

# -version             show SQLite version
do_test shell1-1.16.1 {
  catchcmd "-version test.db" "" 
} {0 3.7.6}

#----------------------------------------------------------------------------
# Test cases shell1-2.*: Basic "dot" command token parsing.
#

# check first token handling
do_test shell1-2.1.1 {







|







196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  list $rc \
       [regexp {Error: missing argument for option: -nullvalue} $res]
} {1 1}

# -version             show SQLite version
do_test shell1-1.16.1 {
  catchcmd "-version test.db" "" 
} {0 3.7.6.1}

#----------------------------------------------------------------------------
# Test cases shell1-2.*: Basic "dot" command token parsing.
#

# check first token handling
do_test shell1-2.1.1 {

Changes to tool/showdb.c.

460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
    "    dbheader        Show database header\n"
    "    NNN..MMM        Show hex of pages NNN through MMM\n"
    "    NNN..end        Show hex of pages NNN through end of file\n"
    "    NNNb            Decode btree page NNN\n"
    "    NNNbc           Decode btree page NNN and show content\n"
    "    NNNbm           Decode btree page NNN and show a layout map\n"
    "    NNNt            Decode freelist trunk page NNN\n"
    "    NNNtd           Show leave freelist pages on the decode\n"
    "    NNNtr           Recurisvely decode freelist starting at NNN\n"
  );
}

int main(int argc, char **argv){
  struct stat sbuf;
  unsigned char zPgSz[2];







|







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
    "    dbheader        Show database header\n"
    "    NNN..MMM        Show hex of pages NNN through MMM\n"
    "    NNN..end        Show hex of pages NNN through end of file\n"
    "    NNNb            Decode btree page NNN\n"
    "    NNNbc           Decode btree page NNN and show content\n"
    "    NNNbm           Decode btree page NNN and show a layout map\n"
    "    NNNt            Decode freelist trunk page NNN\n"
    "    NNNtd           Show leaf freelist pages on the decode\n"
    "    NNNtr           Recurisvely decode freelist starting at NNN\n"
  );
}

int main(int argc, char **argv){
  struct stat sbuf;
  unsigned char zPgSz[2];