Index: third_party/sqlite/amalgamation/sqlite3.01.c |
diff --git a/third_party/sqlite/amalgamation/sqlite3.01.c b/third_party/sqlite/amalgamation/sqlite3.01.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..483408fec51f587dc7f4dfb74d65b2ea2cf40e9b |
--- /dev/null |
+++ b/third_party/sqlite/amalgamation/sqlite3.01.c |
@@ -0,0 +1,26166 @@ |
+/************** Begin file date.c ********************************************/ |
+/* |
+** 2003 October 31 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file contains the C functions that implement date and time |
+** functions for SQLite. |
+** |
+** There is only one exported symbol in this file - the function |
+** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. |
+** All other code has file scope. |
+** |
+** SQLite processes all times and dates as julian day numbers. The |
+** dates and times are stored as the number of days since noon |
+** in Greenwich on November 24, 4714 B.C. according to the Gregorian |
+** calendar system. |
+** |
+** 1970-01-01 00:00:00 is JD 2440587.5 |
+** 2000-01-01 00:00:00 is JD 2451544.5 |
+** |
+** This implementation requires years to be expressed as a 4-digit number |
+** which means that only dates between 0000-01-01 and 9999-12-31 can |
+** be represented, even though julian day numbers allow a much wider |
+** range of dates. |
+** |
+** The Gregorian calendar system is used for all dates and times, |
+** even those that predate the Gregorian calendar. Historians usually |
+** use the julian calendar for dates prior to 1582-10-15 and for some |
+** dates afterwards, depending on locale. Beware of this difference. |
+** |
+** The conversion algorithms are implemented based on descriptions |
+** in the following text: |
+** |
+** Jean Meeus |
+** Astronomical Algorithms, 2nd Edition, 1998 |
+** ISBM 0-943396-61-1 |
+** Willmann-Bell, Inc |
+** Richmond, Virginia (USA) |
+*/ |
+/* #include "sqliteInt.h" */ |
+/* #include <stdlib.h> */ |
+/* #include <assert.h> */ |
+#include <time.h> |
+ |
+#ifndef SQLITE_OMIT_DATETIME_FUNCS |
+ |
+/* |
+** The MSVC CRT on Windows CE may not have a localtime() function. |
+** So declare a substitute. The substitute function itself is |
+** defined in "os_win.c". |
+*/ |
+#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \ |
+ (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API) |
+struct tm *__cdecl localtime(const time_t *); |
+#endif |
+ |
+/* |
+** A structure for holding a single date and time. |
+*/ |
+typedef struct DateTime DateTime; |
+struct DateTime { |
+ sqlite3_int64 iJD; /* The julian day number times 86400000 */ |
+ int Y, M, D; /* Year, month, and day */ |
+ int h, m; /* Hour and minutes */ |
+ int tz; /* Timezone offset in minutes */ |
+ double s; /* Seconds */ |
+ char validJD; /* True (1) if iJD is valid */ |
+ char rawS; /* Raw numeric value stored in s */ |
+ char validYMD; /* True (1) if Y,M,D are valid */ |
+ char validHMS; /* True (1) if h,m,s are valid */ |
+ char validTZ; /* True (1) if tz is valid */ |
+ char tzSet; /* Timezone was set explicitly */ |
+ char isError; /* An overflow has occurred */ |
+}; |
+ |
+ |
+/* |
+** Convert zDate into one or more integers according to the conversion |
+** specifier zFormat. |
+** |
+** zFormat[] contains 4 characters for each integer converted, except for |
+** the last integer which is specified by three characters. The meaning |
+** of a four-character format specifiers ABCD is: |
+** |
+** A: number of digits to convert. Always "2" or "4". |
+** B: minimum value. Always "0" or "1". |
+** C: maximum value, decoded as: |
+** a: 12 |
+** b: 14 |
+** c: 24 |
+** d: 31 |
+** e: 59 |
+** f: 9999 |
+** D: the separator character, or \000 to indicate this is the |
+** last number to convert. |
+** |
+** Example: To translate an ISO-8601 date YYYY-MM-DD, the format would |
+** be "40f-21a-20c". The "40f-" indicates the 4-digit year followed by "-". |
+** The "21a-" indicates the 2-digit month followed by "-". The "20c" indicates |
+** the 2-digit day which is the last integer in the set. |
+** |
+** The function returns the number of successful conversions. |
+*/ |
+static int getDigits(const char *zDate, const char *zFormat, ...){ |
+ /* The aMx[] array translates the 3rd character of each format |
+ ** spec into a max size: a b c d e f */ |
+ static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 }; |
+ va_list ap; |
+ int cnt = 0; |
+ char nextC; |
+ va_start(ap, zFormat); |
+ do{ |
+ char N = zFormat[0] - '0'; |
+ char min = zFormat[1] - '0'; |
+ int val = 0; |
+ u16 max; |
+ |
+ assert( zFormat[2]>='a' && zFormat[2]<='f' ); |
+ max = aMx[zFormat[2] - 'a']; |
+ nextC = zFormat[3]; |
+ val = 0; |
+ while( N-- ){ |
+ if( !sqlite3Isdigit(*zDate) ){ |
+ goto end_getDigits; |
+ } |
+ val = val*10 + *zDate - '0'; |
+ zDate++; |
+ } |
+ if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){ |
+ goto end_getDigits; |
+ } |
+ *va_arg(ap,int*) = val; |
+ zDate++; |
+ cnt++; |
+ zFormat += 4; |
+ }while( nextC ); |
+end_getDigits: |
+ va_end(ap); |
+ return cnt; |
+} |
+ |
+/* |
+** Parse a timezone extension on the end of a date-time. |
+** The extension is of the form: |
+** |
+** (+/-)HH:MM |
+** |
+** Or the "zulu" notation: |
+** |
+** Z |
+** |
+** If the parse is successful, write the number of minutes |
+** of change in p->tz and return 0. If a parser error occurs, |
+** return non-zero. |
+** |
+** A missing specifier is not considered an error. |
+*/ |
+static int parseTimezone(const char *zDate, DateTime *p){ |
+ int sgn = 0; |
+ int nHr, nMn; |
+ int c; |
+ while( sqlite3Isspace(*zDate) ){ zDate++; } |
+ p->tz = 0; |
+ c = *zDate; |
+ if( c=='-' ){ |
+ sgn = -1; |
+ }else if( c=='+' ){ |
+ sgn = +1; |
+ }else if( c=='Z' || c=='z' ){ |
+ zDate++; |
+ goto zulu_time; |
+ }else{ |
+ return c!=0; |
+ } |
+ zDate++; |
+ if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){ |
+ return 1; |
+ } |
+ zDate += 5; |
+ p->tz = sgn*(nMn + nHr*60); |
+zulu_time: |
+ while( sqlite3Isspace(*zDate) ){ zDate++; } |
+ p->tzSet = 1; |
+ return *zDate!=0; |
+} |
+ |
+/* |
+** Parse times of the form HH:MM or HH:MM:SS or HH:MM:SS.FFFF. |
+** The HH, MM, and SS must each be exactly 2 digits. The |
+** fractional seconds FFFF can be one or more digits. |
+** |
+** Return 1 if there is a parsing error and 0 on success. |
+*/ |
+static int parseHhMmSs(const char *zDate, DateTime *p){ |
+ int h, m, s; |
+ double ms = 0.0; |
+ if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){ |
+ return 1; |
+ } |
+ zDate += 5; |
+ if( *zDate==':' ){ |
+ zDate++; |
+ if( getDigits(zDate, "20e", &s)!=1 ){ |
+ return 1; |
+ } |
+ zDate += 2; |
+ if( *zDate=='.' && sqlite3Isdigit(zDate[1]) ){ |
+ double rScale = 1.0; |
+ zDate++; |
+ while( sqlite3Isdigit(*zDate) ){ |
+ ms = ms*10.0 + *zDate - '0'; |
+ rScale *= 10.0; |
+ zDate++; |
+ } |
+ ms /= rScale; |
+ } |
+ }else{ |
+ s = 0; |
+ } |
+ p->validJD = 0; |
+ p->rawS = 0; |
+ p->validHMS = 1; |
+ p->h = h; |
+ p->m = m; |
+ p->s = s + ms; |
+ if( parseTimezone(zDate, p) ) return 1; |
+ p->validTZ = (p->tz!=0)?1:0; |
+ return 0; |
+} |
+ |
+/* |
+** Put the DateTime object into its error state. |
+*/ |
+static void datetimeError(DateTime *p){ |
+ memset(p, 0, sizeof(*p)); |
+ p->isError = 1; |
+} |
+ |
+/* |
+** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume |
+** that the YYYY-MM-DD is according to the Gregorian calendar. |
+** |
+** Reference: Meeus page 61 |
+*/ |
+static void computeJD(DateTime *p){ |
+ int Y, M, D, A, B, X1, X2; |
+ |
+ if( p->validJD ) return; |
+ if( p->validYMD ){ |
+ Y = p->Y; |
+ M = p->M; |
+ D = p->D; |
+ }else{ |
+ Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */ |
+ M = 1; |
+ D = 1; |
+ } |
+ if( Y<-4713 || Y>9999 || p->rawS ){ |
+ datetimeError(p); |
+ return; |
+ } |
+ if( M<=2 ){ |
+ Y--; |
+ M += 12; |
+ } |
+ A = Y/100; |
+ B = 2 - A + (A/4); |
+ X1 = 36525*(Y+4716)/100; |
+ X2 = 306001*(M+1)/10000; |
+ p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); |
+ p->validJD = 1; |
+ if( p->validHMS ){ |
+ p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000); |
+ if( p->validTZ ){ |
+ p->iJD -= p->tz*60000; |
+ p->validYMD = 0; |
+ p->validHMS = 0; |
+ p->validTZ = 0; |
+ } |
+ } |
+} |
+ |
+/* |
+** Parse dates of the form |
+** |
+** YYYY-MM-DD HH:MM:SS.FFF |
+** YYYY-MM-DD HH:MM:SS |
+** YYYY-MM-DD HH:MM |
+** YYYY-MM-DD |
+** |
+** Write the result into the DateTime structure and return 0 |
+** on success and 1 if the input string is not a well-formed |
+** date. |
+*/ |
+static int parseYyyyMmDd(const char *zDate, DateTime *p){ |
+ int Y, M, D, neg; |
+ |
+ if( zDate[0]=='-' ){ |
+ zDate++; |
+ neg = 1; |
+ }else{ |
+ neg = 0; |
+ } |
+ if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){ |
+ return 1; |
+ } |
+ zDate += 10; |
+ while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; } |
+ if( parseHhMmSs(zDate, p)==0 ){ |
+ /* We got the time */ |
+ }else if( *zDate==0 ){ |
+ p->validHMS = 0; |
+ }else{ |
+ return 1; |
+ } |
+ p->validJD = 0; |
+ p->validYMD = 1; |
+ p->Y = neg ? -Y : Y; |
+ p->M = M; |
+ p->D = D; |
+ if( p->validTZ ){ |
+ computeJD(p); |
+ } |
+ return 0; |
+} |
+ |
+/* |
+** Set the time to the current time reported by the VFS. |
+** |
+** Return the number of errors. |
+*/ |
+static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){ |
+ p->iJD = sqlite3StmtCurrentTime(context); |
+ if( p->iJD>0 ){ |
+ p->validJD = 1; |
+ return 0; |
+ }else{ |
+ return 1; |
+ } |
+} |
+ |
+/* |
+** Input "r" is a numeric quantity which might be a julian day number, |
+** or the number of seconds since 1970. If the value if r is within |
+** range of a julian day number, install it as such and set validJD. |
+** If the value is a valid unix timestamp, put it in p->s and set p->rawS. |
+*/ |
+static void setRawDateNumber(DateTime *p, double r){ |
+ p->s = r; |
+ p->rawS = 1; |
+ if( r>=0.0 && r<5373484.5 ){ |
+ p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); |
+ p->validJD = 1; |
+ } |
+} |
+ |
+/* |
+** Attempt to parse the given string into a julian day number. Return |
+** the number of errors. |
+** |
+** The following are acceptable forms for the input string: |
+** |
+** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM |
+** DDDD.DD |
+** now |
+** |
+** In the first form, the +/-HH:MM is always optional. The fractional |
+** seconds extension (the ".FFF") is optional. The seconds portion |
+** (":SS.FFF") is option. The year and date can be omitted as long |
+** as there is a time string. The time string can be omitted as long |
+** as there is a year and date. |
+*/ |
+static int parseDateOrTime( |
+ sqlite3_context *context, |
+ const char *zDate, |
+ DateTime *p |
+){ |
+ double r; |
+ if( parseYyyyMmDd(zDate,p)==0 ){ |
+ return 0; |
+ }else if( parseHhMmSs(zDate, p)==0 ){ |
+ return 0; |
+ }else if( sqlite3StrICmp(zDate,"now")==0){ |
+ return setDateTimeToCurrent(context, p); |
+ }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ |
+ setRawDateNumber(p, r); |
+ return 0; |
+ } |
+ return 1; |
+} |
+ |
+/* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999. |
+** Multiplying this by 86400000 gives 464269060799999 as the maximum value |
+** for DateTime.iJD. |
+** |
+** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with |
+** such a large integer literal, so we have to encode it. |
+*/ |
+#define INT_464269060799999 ((((i64)0x1a640)<<32)|0x1072fdff) |
+ |
+/* |
+** Return TRUE if the given julian day number is within range. |
+** |
+** The input is the JulianDay times 86400000. |
+*/ |
+static int validJulianDay(sqlite3_int64 iJD){ |
+ return iJD>=0 && iJD<=INT_464269060799999; |
+} |
+ |
+/* |
+** Compute the Year, Month, and Day from the julian day number. |
+*/ |
+static void computeYMD(DateTime *p){ |
+ int Z, A, B, C, D, E, X1; |
+ if( p->validYMD ) return; |
+ if( !p->validJD ){ |
+ p->Y = 2000; |
+ p->M = 1; |
+ p->D = 1; |
+ }else{ |
+ assert( validJulianDay(p->iJD) ); |
+ Z = (int)((p->iJD + 43200000)/86400000); |
+ A = (int)((Z - 1867216.25)/36524.25); |
+ A = Z + 1 + A - (A/4); |
+ B = A + 1524; |
+ C = (int)((B - 122.1)/365.25); |
+ D = (36525*(C&32767))/100; |
+ E = (int)((B-D)/30.6001); |
+ X1 = (int)(30.6001*E); |
+ p->D = B - D - X1; |
+ p->M = E<14 ? E-1 : E-13; |
+ p->Y = p->M>2 ? C - 4716 : C - 4715; |
+ } |
+ p->validYMD = 1; |
+} |
+ |
+/* |
+** Compute the Hour, Minute, and Seconds from the julian day number. |
+*/ |
+static void computeHMS(DateTime *p){ |
+ int s; |
+ if( p->validHMS ) return; |
+ computeJD(p); |
+ s = (int)((p->iJD + 43200000) % 86400000); |
+ p->s = s/1000.0; |
+ s = (int)p->s; |
+ p->s -= s; |
+ p->h = s/3600; |
+ s -= p->h*3600; |
+ p->m = s/60; |
+ p->s += s - p->m*60; |
+ p->rawS = 0; |
+ p->validHMS = 1; |
+} |
+ |
+/* |
+** Compute both YMD and HMS |
+*/ |
+static void computeYMD_HMS(DateTime *p){ |
+ computeYMD(p); |
+ computeHMS(p); |
+} |
+ |
+/* |
+** Clear the YMD and HMS and the TZ |
+*/ |
+static void clearYMD_HMS_TZ(DateTime *p){ |
+ p->validYMD = 0; |
+ p->validHMS = 0; |
+ p->validTZ = 0; |
+} |
+ |
+#ifndef SQLITE_OMIT_LOCALTIME |
+/* |
+** On recent Windows platforms, the localtime_s() function is available |
+** as part of the "Secure CRT". It is essentially equivalent to |
+** localtime_r() available under most POSIX platforms, except that the |
+** order of the parameters is reversed. |
+** |
+** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx. |
+** |
+** If the user has not indicated to use localtime_r() or localtime_s() |
+** already, check for an MSVC build environment that provides |
+** localtime_s(). |
+*/ |
+#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \ |
+ && defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE) |
+#undef HAVE_LOCALTIME_S |
+#define HAVE_LOCALTIME_S 1 |
+#endif |
+ |
+/* |
+** The following routine implements the rough equivalent of localtime_r() |
+** using whatever operating-system specific localtime facility that |
+** is available. This routine returns 0 on success and |
+** non-zero on any kind of error. |
+** |
+** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this |
+** routine will always fail. |
+** |
+** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C |
+** library function localtime_r() is used to assist in the calculation of |
+** local time. |
+*/ |
+static int osLocaltime(time_t *t, struct tm *pTm){ |
+ int rc; |
+#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S |
+ struct tm *pX; |
+#if SQLITE_THREADSAFE>0 |
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); |
+#endif |
+ sqlite3_mutex_enter(mutex); |
+ pX = localtime(t); |
+#ifndef SQLITE_UNTESTABLE |
+ if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; |
+#endif |
+ if( pX ) *pTm = *pX; |
+ sqlite3_mutex_leave(mutex); |
+ rc = pX==0; |
+#else |
+#ifndef SQLITE_UNTESTABLE |
+ if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; |
+#endif |
+#if HAVE_LOCALTIME_R |
+ rc = localtime_r(t, pTm)==0; |
+#else |
+ rc = localtime_s(pTm, t); |
+#endif /* HAVE_LOCALTIME_R */ |
+#endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */ |
+ return rc; |
+} |
+#endif /* SQLITE_OMIT_LOCALTIME */ |
+ |
+ |
+#ifndef SQLITE_OMIT_LOCALTIME |
+/* |
+** Compute the difference (in milliseconds) between localtime and UTC |
+** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs, |
+** return this value and set *pRc to SQLITE_OK. |
+** |
+** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value |
+** is undefined in this case. |
+*/ |
+static sqlite3_int64 localtimeOffset( |
+ DateTime *p, /* Date at which to calculate offset */ |
+ sqlite3_context *pCtx, /* Write error here if one occurs */ |
+ int *pRc /* OUT: Error code. SQLITE_OK or ERROR */ |
+){ |
+ DateTime x, y; |
+ time_t t; |
+ struct tm sLocal; |
+ |
+ /* Initialize the contents of sLocal to avoid a compiler warning. */ |
+ memset(&sLocal, 0, sizeof(sLocal)); |
+ |
+ x = *p; |
+ computeYMD_HMS(&x); |
+ if( x.Y<1971 || x.Y>=2038 ){ |
+ /* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only |
+ ** works for years between 1970 and 2037. For dates outside this range, |
+ ** SQLite attempts to map the year into an equivalent year within this |
+ ** range, do the calculation, then map the year back. |
+ */ |
+ x.Y = 2000; |
+ x.M = 1; |
+ x.D = 1; |
+ x.h = 0; |
+ x.m = 0; |
+ x.s = 0.0; |
+ } else { |
+ int s = (int)(x.s + 0.5); |
+ x.s = s; |
+ } |
+ x.tz = 0; |
+ x.validJD = 0; |
+ computeJD(&x); |
+ t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); |
+ if( osLocaltime(&t, &sLocal) ){ |
+ sqlite3_result_error(pCtx, "local time unavailable", -1); |
+ *pRc = SQLITE_ERROR; |
+ return 0; |
+ } |
+ y.Y = sLocal.tm_year + 1900; |
+ y.M = sLocal.tm_mon + 1; |
+ y.D = sLocal.tm_mday; |
+ y.h = sLocal.tm_hour; |
+ y.m = sLocal.tm_min; |
+ y.s = sLocal.tm_sec; |
+ y.validYMD = 1; |
+ y.validHMS = 1; |
+ y.validJD = 0; |
+ y.rawS = 0; |
+ y.validTZ = 0; |
+ y.isError = 0; |
+ computeJD(&y); |
+ *pRc = SQLITE_OK; |
+ return y.iJD - x.iJD; |
+} |
+#endif /* SQLITE_OMIT_LOCALTIME */ |
+ |
+/* |
+** The following table defines various date transformations of the form |
+** |
+** 'NNN days' |
+** |
+** Where NNN is an arbitrary floating-point number and "days" can be one |
+** of several units of time. |
+*/ |
+static const struct { |
+ u8 eType; /* Transformation type code */ |
+ u8 nName; /* Length of th name */ |
+ char *zName; /* Name of the transformation */ |
+ double rLimit; /* Maximum NNN value for this transform */ |
+ double rXform; /* Constant used for this transform */ |
+} aXformType[] = { |
+ { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) }, |
+ { 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) }, |
+ { 0, 4, "hour", 128963628.0, 86400000.0/24.0 }, |
+ { 0, 3, "day", 5373485.0, 86400000.0 }, |
+ { 1, 5, "month", 176546.0, 30.0*86400000.0 }, |
+ { 2, 4, "year", 14713.0, 365.0*86400000.0 }, |
+}; |
+ |
+/* |
+** Process a modifier to a date-time stamp. The modifiers are |
+** as follows: |
+** |
+** NNN days |
+** NNN hours |
+** NNN minutes |
+** NNN.NNNN seconds |
+** NNN months |
+** NNN years |
+** start of month |
+** start of year |
+** start of week |
+** start of day |
+** weekday N |
+** unixepoch |
+** localtime |
+** utc |
+** |
+** Return 0 on success and 1 if there is any kind of error. If the error |
+** is in a system call (i.e. localtime()), then an error message is written |
+** to context pCtx. If the error is an unrecognized modifier, no error is |
+** written to pCtx. |
+*/ |
+static int parseModifier( |
+ sqlite3_context *pCtx, /* Function context */ |
+ const char *z, /* The text of the modifier */ |
+ int n, /* Length of zMod in bytes */ |
+ DateTime *p /* The date/time value to be modified */ |
+){ |
+ int rc = 1; |
+ double r; |
+ switch(sqlite3UpperToLower[(u8)z[0]] ){ |
+#ifndef SQLITE_OMIT_LOCALTIME |
+ case 'l': { |
+ /* localtime |
+ ** |
+ ** Assuming the current time value is UTC (a.k.a. GMT), shift it to |
+ ** show local time. |
+ */ |
+ if( sqlite3_stricmp(z, "localtime")==0 ){ |
+ computeJD(p); |
+ p->iJD += localtimeOffset(p, pCtx, &rc); |
+ clearYMD_HMS_TZ(p); |
+ } |
+ break; |
+ } |
+#endif |
+ case 'u': { |
+ /* |
+ ** unixepoch |
+ ** |
+ ** Treat the current value of p->s as the number of |
+ ** seconds since 1970. Convert to a real julian day number. |
+ */ |
+ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){ |
+ r = p->s*1000.0 + 210866760000000.0; |
+ if( r>=0.0 && r<464269060800000.0 ){ |
+ clearYMD_HMS_TZ(p); |
+ p->iJD = (sqlite3_int64)r; |
+ p->validJD = 1; |
+ p->rawS = 0; |
+ rc = 0; |
+ } |
+ } |
+#ifndef SQLITE_OMIT_LOCALTIME |
+ else if( sqlite3_stricmp(z, "utc")==0 ){ |
+ if( p->tzSet==0 ){ |
+ sqlite3_int64 c1; |
+ computeJD(p); |
+ c1 = localtimeOffset(p, pCtx, &rc); |
+ if( rc==SQLITE_OK ){ |
+ p->iJD -= c1; |
+ clearYMD_HMS_TZ(p); |
+ p->iJD += c1 - localtimeOffset(p, pCtx, &rc); |
+ } |
+ p->tzSet = 1; |
+ }else{ |
+ rc = SQLITE_OK; |
+ } |
+ } |
+#endif |
+ break; |
+ } |
+ case 'w': { |
+ /* |
+ ** weekday N |
+ ** |
+ ** Move the date to the same time on the next occurrence of |
+ ** weekday N where 0==Sunday, 1==Monday, and so forth. If the |
+ ** date is already on the appropriate weekday, this is a no-op. |
+ */ |
+ if( sqlite3_strnicmp(z, "weekday ", 8)==0 |
+ && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8) |
+ && (n=(int)r)==r && n>=0 && r<7 ){ |
+ sqlite3_int64 Z; |
+ computeYMD_HMS(p); |
+ p->validTZ = 0; |
+ p->validJD = 0; |
+ computeJD(p); |
+ Z = ((p->iJD + 129600000)/86400000) % 7; |
+ if( Z>n ) Z -= 7; |
+ p->iJD += (n - Z)*86400000; |
+ clearYMD_HMS_TZ(p); |
+ rc = 0; |
+ } |
+ break; |
+ } |
+ case 's': { |
+ /* |
+ ** start of TTTTT |
+ ** |
+ ** Move the date backwards to the beginning of the current day, |
+ ** or month or year. |
+ */ |
+ if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break; |
+ z += 9; |
+ computeYMD(p); |
+ p->validHMS = 1; |
+ p->h = p->m = 0; |
+ p->s = 0.0; |
+ p->validTZ = 0; |
+ p->validJD = 0; |
+ if( sqlite3_stricmp(z,"month")==0 ){ |
+ p->D = 1; |
+ rc = 0; |
+ }else if( sqlite3_stricmp(z,"year")==0 ){ |
+ computeYMD(p); |
+ p->M = 1; |
+ p->D = 1; |
+ rc = 0; |
+ }else if( sqlite3_stricmp(z,"day")==0 ){ |
+ rc = 0; |
+ } |
+ break; |
+ } |
+ case '+': |
+ case '-': |
+ case '0': |
+ case '1': |
+ case '2': |
+ case '3': |
+ case '4': |
+ case '5': |
+ case '6': |
+ case '7': |
+ case '8': |
+ case '9': { |
+ double rRounder; |
+ int i; |
+ for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} |
+ if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){ |
+ rc = 1; |
+ break; |
+ } |
+ if( z[n]==':' ){ |
+ /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the |
+ ** specified number of hours, minutes, seconds, and fractional seconds |
+ ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be |
+ ** omitted. |
+ */ |
+ const char *z2 = z; |
+ DateTime tx; |
+ sqlite3_int64 day; |
+ if( !sqlite3Isdigit(*z2) ) z2++; |
+ memset(&tx, 0, sizeof(tx)); |
+ if( parseHhMmSs(z2, &tx) ) break; |
+ computeJD(&tx); |
+ tx.iJD -= 43200000; |
+ day = tx.iJD/86400000; |
+ tx.iJD -= day*86400000; |
+ if( z[0]=='-' ) tx.iJD = -tx.iJD; |
+ computeJD(p); |
+ clearYMD_HMS_TZ(p); |
+ p->iJD += tx.iJD; |
+ rc = 0; |
+ break; |
+ } |
+ |
+ /* If control reaches this point, it means the transformation is |
+ ** one of the forms like "+NNN days". */ |
+ z += n; |
+ while( sqlite3Isspace(*z) ) z++; |
+ n = sqlite3Strlen30(z); |
+ if( n>10 || n<3 ) break; |
+ if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--; |
+ computeJD(p); |
+ rc = 1; |
+ rRounder = r<0 ? -0.5 : +0.5; |
+ for(i=0; i<ArraySize(aXformType); i++){ |
+ if( aXformType[i].nName==n |
+ && sqlite3_strnicmp(aXformType[i].zName, z, n)==0 |
+ && r>-aXformType[i].rLimit && r<aXformType[i].rLimit |
+ ){ |
+ switch( aXformType[i].eType ){ |
+ case 1: { /* Special processing to add months */ |
+ int x; |
+ computeYMD_HMS(p); |
+ p->M += (int)r; |
+ x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; |
+ p->Y += x; |
+ p->M -= x*12; |
+ p->validJD = 0; |
+ r -= (int)r; |
+ break; |
+ } |
+ case 2: { /* Special processing to add years */ |
+ int y = (int)r; |
+ computeYMD_HMS(p); |
+ p->Y += y; |
+ p->validJD = 0; |
+ r -= (int)r; |
+ break; |
+ } |
+ } |
+ computeJD(p); |
+ p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder); |
+ rc = 0; |
+ break; |
+ } |
+ } |
+ clearYMD_HMS_TZ(p); |
+ break; |
+ } |
+ default: { |
+ break; |
+ } |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Process time function arguments. argv[0] is a date-time stamp. |
+** argv[1] and following are modifiers. Parse them all and write |
+** the resulting time into the DateTime structure p. Return 0 |
+** on success and 1 if there are any errors. |
+** |
+** If there are zero parameters (if even argv[0] is undefined) |
+** then assume a default value of "now" for argv[0]. |
+*/ |
+static int isDate( |
+ sqlite3_context *context, |
+ int argc, |
+ sqlite3_value **argv, |
+ DateTime *p |
+){ |
+ int i, n; |
+ const unsigned char *z; |
+ int eType; |
+ memset(p, 0, sizeof(*p)); |
+ if( argc==0 ){ |
+ return setDateTimeToCurrent(context, p); |
+ } |
+ if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT |
+ || eType==SQLITE_INTEGER ){ |
+ setRawDateNumber(p, sqlite3_value_double(argv[0])); |
+ }else{ |
+ z = sqlite3_value_text(argv[0]); |
+ if( !z || parseDateOrTime(context, (char*)z, p) ){ |
+ return 1; |
+ } |
+ } |
+ for(i=1; i<argc; i++){ |
+ z = sqlite3_value_text(argv[i]); |
+ n = sqlite3_value_bytes(argv[i]); |
+ if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1; |
+ } |
+ computeJD(p); |
+ if( p->isError || !validJulianDay(p->iJD) ) return 1; |
+ return 0; |
+} |
+ |
+ |
+/* |
+** The following routines implement the various date and time functions |
+** of SQLite. |
+*/ |
+ |
+/* |
+** julianday( TIMESTRING, MOD, MOD, ...) |
+** |
+** Return the julian day number of the date specified in the arguments |
+*/ |
+static void juliandayFunc( |
+ sqlite3_context *context, |
+ int argc, |
+ sqlite3_value **argv |
+){ |
+ DateTime x; |
+ if( isDate(context, argc, argv, &x)==0 ){ |
+ computeJD(&x); |
+ sqlite3_result_double(context, x.iJD/86400000.0); |
+ } |
+} |
+ |
+/* |
+** datetime( TIMESTRING, MOD, MOD, ...) |
+** |
+** Return YYYY-MM-DD HH:MM:SS |
+*/ |
+static void datetimeFunc( |
+ sqlite3_context *context, |
+ int argc, |
+ sqlite3_value **argv |
+){ |
+ DateTime x; |
+ if( isDate(context, argc, argv, &x)==0 ){ |
+ char zBuf[100]; |
+ computeYMD_HMS(&x); |
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", |
+ x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); |
+ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); |
+ } |
+} |
+ |
+/* |
+** time( TIMESTRING, MOD, MOD, ...) |
+** |
+** Return HH:MM:SS |
+*/ |
+static void timeFunc( |
+ sqlite3_context *context, |
+ int argc, |
+ sqlite3_value **argv |
+){ |
+ DateTime x; |
+ if( isDate(context, argc, argv, &x)==0 ){ |
+ char zBuf[100]; |
+ computeHMS(&x); |
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); |
+ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); |
+ } |
+} |
+ |
+/* |
+** date( TIMESTRING, MOD, MOD, ...) |
+** |
+** Return YYYY-MM-DD |
+*/ |
+static void dateFunc( |
+ sqlite3_context *context, |
+ int argc, |
+ sqlite3_value **argv |
+){ |
+ DateTime x; |
+ if( isDate(context, argc, argv, &x)==0 ){ |
+ char zBuf[100]; |
+ computeYMD(&x); |
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); |
+ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); |
+ } |
+} |
+ |
+/* |
+** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) |
+** |
+** Return a string described by FORMAT. Conversions as follows: |
+** |
+** %d day of month |
+** %f ** fractional seconds SS.SSS |
+** %H hour 00-24 |
+** %j day of year 000-366 |
+** %J ** julian day number |
+** %m month 01-12 |
+** %M minute 00-59 |
+** %s seconds since 1970-01-01 |
+** %S seconds 00-59 |
+** %w day of week 0-6 sunday==0 |
+** %W week of year 00-53 |
+** %Y year 0000-9999 |
+** %% % |
+*/ |
+static void strftimeFunc( |
+ sqlite3_context *context, |
+ int argc, |
+ sqlite3_value **argv |
+){ |
+ DateTime x; |
+ u64 n; |
+ size_t i,j; |
+ char *z; |
+ sqlite3 *db; |
+ const char *zFmt; |
+ char zBuf[100]; |
+ if( argc==0 ) return; |
+ zFmt = (const char*)sqlite3_value_text(argv[0]); |
+ if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; |
+ db = sqlite3_context_db_handle(context); |
+ for(i=0, n=1; zFmt[i]; i++, n++){ |
+ if( zFmt[i]=='%' ){ |
+ switch( zFmt[i+1] ){ |
+ case 'd': |
+ case 'H': |
+ case 'm': |
+ case 'M': |
+ case 'S': |
+ case 'W': |
+ n++; |
+ /* fall thru */ |
+ case 'w': |
+ case '%': |
+ break; |
+ case 'f': |
+ n += 8; |
+ break; |
+ case 'j': |
+ n += 3; |
+ break; |
+ case 'Y': |
+ n += 8; |
+ break; |
+ case 's': |
+ case 'J': |
+ n += 50; |
+ break; |
+ default: |
+ return; /* ERROR. return a NULL */ |
+ } |
+ i++; |
+ } |
+ } |
+ testcase( n==sizeof(zBuf)-1 ); |
+ testcase( n==sizeof(zBuf) ); |
+ testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); |
+ testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ); |
+ if( n<sizeof(zBuf) ){ |
+ z = zBuf; |
+ }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){ |
+ sqlite3_result_error_toobig(context); |
+ return; |
+ }else{ |
+ z = sqlite3DbMallocRawNN(db, (int)n); |
+ if( z==0 ){ |
+ sqlite3_result_error_nomem(context); |
+ return; |
+ } |
+ } |
+ computeJD(&x); |
+ computeYMD_HMS(&x); |
+ for(i=j=0; zFmt[i]; i++){ |
+ if( zFmt[i]!='%' ){ |
+ z[j++] = zFmt[i]; |
+ }else{ |
+ i++; |
+ switch( zFmt[i] ){ |
+ case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break; |
+ case 'f': { |
+ double s = x.s; |
+ if( s>59.999 ) s = 59.999; |
+ sqlite3_snprintf(7, &z[j],"%06.3f", s); |
+ j += sqlite3Strlen30(&z[j]); |
+ break; |
+ } |
+ case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break; |
+ case 'W': /* Fall thru */ |
+ case 'j': { |
+ int nDay; /* Number of days since 1st day of year */ |
+ DateTime y = x; |
+ y.validJD = 0; |
+ y.M = 1; |
+ y.D = 1; |
+ computeJD(&y); |
+ nDay = (int)((x.iJD-y.iJD+43200000)/86400000); |
+ if( zFmt[i]=='W' ){ |
+ int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ |
+ wd = (int)(((x.iJD+43200000)/86400000)%7); |
+ sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); |
+ j += 2; |
+ }else{ |
+ sqlite3_snprintf(4, &z[j],"%03d",nDay+1); |
+ j += 3; |
+ } |
+ break; |
+ } |
+ case 'J': { |
+ sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0); |
+ j+=sqlite3Strlen30(&z[j]); |
+ break; |
+ } |
+ case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; |
+ case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; |
+ case 's': { |
+ sqlite3_snprintf(30,&z[j],"%lld", |
+ (i64)(x.iJD/1000 - 21086676*(i64)10000)); |
+ j += sqlite3Strlen30(&z[j]); |
+ break; |
+ } |
+ case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; |
+ case 'w': { |
+ z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; |
+ break; |
+ } |
+ case 'Y': { |
+ sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]); |
+ break; |
+ } |
+ default: z[j++] = '%'; break; |
+ } |
+ } |
+ } |
+ z[j] = 0; |
+ sqlite3_result_text(context, z, -1, |
+ z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC); |
+} |
+ |
+/* |
+** current_time() |
+** |
+** This function returns the same value as time('now'). |
+*/ |
+static void ctimeFunc( |
+ sqlite3_context *context, |
+ int NotUsed, |
+ sqlite3_value **NotUsed2 |
+){ |
+ UNUSED_PARAMETER2(NotUsed, NotUsed2); |
+ timeFunc(context, 0, 0); |
+} |
+ |
+/* |
+** current_date() |
+** |
+** This function returns the same value as date('now'). |
+*/ |
+static void cdateFunc( |
+ sqlite3_context *context, |
+ int NotUsed, |
+ sqlite3_value **NotUsed2 |
+){ |
+ UNUSED_PARAMETER2(NotUsed, NotUsed2); |
+ dateFunc(context, 0, 0); |
+} |
+ |
+/* |
+** current_timestamp() |
+** |
+** This function returns the same value as datetime('now'). |
+*/ |
+static void ctimestampFunc( |
+ sqlite3_context *context, |
+ int NotUsed, |
+ sqlite3_value **NotUsed2 |
+){ |
+ UNUSED_PARAMETER2(NotUsed, NotUsed2); |
+ datetimeFunc(context, 0, 0); |
+} |
+#endif /* !defined(SQLITE_OMIT_DATETIME_FUNCS) */ |
+ |
+#ifdef SQLITE_OMIT_DATETIME_FUNCS |
+/* |
+** If the library is compiled to omit the full-scale date and time |
+** handling (to get a smaller binary), the following minimal version |
+** of the functions current_time(), current_date() and current_timestamp() |
+** are included instead. This is to support column declarations that |
+** include "DEFAULT CURRENT_TIME" etc. |
+** |
+** This function uses the C-library functions time(), gmtime() |
+** and strftime(). The format string to pass to strftime() is supplied |
+** as the user-data for the function. |
+*/ |
+static void currentTimeFunc( |
+ sqlite3_context *context, |
+ int argc, |
+ sqlite3_value **argv |
+){ |
+ time_t t; |
+ char *zFormat = (char *)sqlite3_user_data(context); |
+ sqlite3_int64 iT; |
+ struct tm *pTm; |
+ struct tm sNow; |
+ char zBuf[20]; |
+ |
+ UNUSED_PARAMETER(argc); |
+ UNUSED_PARAMETER(argv); |
+ |
+ iT = sqlite3StmtCurrentTime(context); |
+ if( iT<=0 ) return; |
+ t = iT/1000 - 10000*(sqlite3_int64)21086676; |
+#if HAVE_GMTIME_R |
+ pTm = gmtime_r(&t, &sNow); |
+#else |
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); |
+ pTm = gmtime(&t); |
+ if( pTm ) memcpy(&sNow, pTm, sizeof(sNow)); |
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); |
+#endif |
+ if( pTm ){ |
+ strftime(zBuf, 20, zFormat, &sNow); |
+ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); |
+ } |
+} |
+#endif |
+ |
+/* |
+** This function registered all of the above C functions as SQL |
+** functions. This should be the only routine in this file with |
+** external linkage. |
+*/ |
+SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){ |
+ static FuncDef aDateTimeFuncs[] = { |
+#ifndef SQLITE_OMIT_DATETIME_FUNCS |
+ DFUNCTION(julianday, -1, 0, 0, juliandayFunc ), |
+ DFUNCTION(date, -1, 0, 0, dateFunc ), |
+ DFUNCTION(time, -1, 0, 0, timeFunc ), |
+ DFUNCTION(datetime, -1, 0, 0, datetimeFunc ), |
+ DFUNCTION(strftime, -1, 0, 0, strftimeFunc ), |
+ DFUNCTION(current_time, 0, 0, 0, ctimeFunc ), |
+ DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), |
+ DFUNCTION(current_date, 0, 0, 0, cdateFunc ), |
+#else |
+ STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc), |
+ STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc), |
+ STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc), |
+#endif |
+ }; |
+ sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs)); |
+} |
+ |
+/************** End of date.c ************************************************/ |
+/************** Begin file os.c **********************************************/ |
+/* |
+** 2005 November 29 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains OS interface code that is common to all |
+** architectures. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* |
+** If we compile with the SQLITE_TEST macro set, then the following block |
+** of code will give us the ability to simulate a disk I/O error. This |
+** is used for testing the I/O recovery logic. |
+*/ |
+#if defined(SQLITE_TEST) |
+SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */ |
+SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */ |
+SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */ |
+SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */ |
+SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */ |
+SQLITE_API int sqlite3_diskfull_pending = 0; |
+SQLITE_API int sqlite3_diskfull = 0; |
+#endif /* defined(SQLITE_TEST) */ |
+ |
+/* |
+** When testing, also keep a count of the number of open files. |
+*/ |
+#if defined(SQLITE_TEST) |
+SQLITE_API int sqlite3_open_file_count = 0; |
+#endif /* defined(SQLITE_TEST) */ |
+ |
+/* |
+** The default SQLite sqlite3_vfs implementations do not allocate |
+** memory (actually, os_unix.c allocates a small amount of memory |
+** from within OsOpen()), but some third-party implementations may. |
+** So we test the effects of a malloc() failing and the sqlite3OsXXX() |
+** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro. |
+** |
+** The following functions are instrumented for malloc() failure |
+** testing: |
+** |
+** sqlite3OsRead() |
+** sqlite3OsWrite() |
+** sqlite3OsSync() |
+** sqlite3OsFileSize() |
+** sqlite3OsLock() |
+** sqlite3OsCheckReservedLock() |
+** sqlite3OsFileControl() |
+** sqlite3OsShmMap() |
+** sqlite3OsOpen() |
+** sqlite3OsDelete() |
+** sqlite3OsAccess() |
+** sqlite3OsFullPathname() |
+** |
+*/ |
+#if defined(SQLITE_TEST) |
+SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1; |
+ #define DO_OS_MALLOC_TEST(x) \ |
+ if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3JournalIsInMemory(x))) { \ |
+ void *pTstAlloc = sqlite3Malloc(10); \ |
+ if (!pTstAlloc) return SQLITE_IOERR_NOMEM_BKPT; \ |
+ sqlite3_free(pTstAlloc); \ |
+ } |
+#else |
+ #define DO_OS_MALLOC_TEST(x) |
+#endif |
+ |
+/* |
+** The following routines are convenience wrappers around methods |
+** of the sqlite3_file object. This is mostly just syntactic sugar. All |
+** of this would be completely automatic if SQLite were coded using |
+** C++ instead of plain old C. |
+*/ |
+SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file *pId){ |
+ if( pId->pMethods ){ |
+ pId->pMethods->xClose(pId); |
+ pId->pMethods = 0; |
+ } |
+} |
+SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ |
+ DO_OS_MALLOC_TEST(id); |
+ return id->pMethods->xRead(id, pBuf, amt, offset); |
+} |
+SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){ |
+ DO_OS_MALLOC_TEST(id); |
+ return id->pMethods->xWrite(id, pBuf, amt, offset); |
+} |
+SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){ |
+ return id->pMethods->xTruncate(id, size); |
+} |
+SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){ |
+ DO_OS_MALLOC_TEST(id); |
+ return id->pMethods->xSync(id, flags); |
+} |
+SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ |
+ DO_OS_MALLOC_TEST(id); |
+ return id->pMethods->xFileSize(id, pSize); |
+} |
+SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){ |
+ DO_OS_MALLOC_TEST(id); |
+ return id->pMethods->xLock(id, lockType); |
+} |
+SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){ |
+ return id->pMethods->xUnlock(id, lockType); |
+} |
+SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){ |
+ DO_OS_MALLOC_TEST(id); |
+ return id->pMethods->xCheckReservedLock(id, pResOut); |
+} |
+ |
+/* |
+** Use sqlite3OsFileControl() when we are doing something that might fail |
+** and we need to know about the failures. Use sqlite3OsFileControlHint() |
+** when simply tossing information over the wall to the VFS and we do not |
+** really care if the VFS receives and understands the information since it |
+** is only a hint and can be safely ignored. The sqlite3OsFileControlHint() |
+** routine has no return value since the return value would be meaningless. |
+*/ |
+SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ |
+#ifdef SQLITE_TEST |
+ if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){ |
+ /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite |
+ ** is using a regular VFS, it is called after the corresponding |
+ ** transaction has been committed. Injecting a fault at this point |
+ ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM |
+ ** but the transaction is committed anyway. |
+ ** |
+ ** The core must call OsFileControl() though, not OsFileControlHint(), |
+ ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably |
+ ** means the commit really has failed and an error should be returned |
+ ** to the user. */ |
+ DO_OS_MALLOC_TEST(id); |
+ } |
+#endif |
+ return id->pMethods->xFileControl(id, op, pArg); |
+} |
+SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){ |
+ (void)id->pMethods->xFileControl(id, op, pArg); |
+} |
+ |
+SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){ |
+ int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; |
+ return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); |
+} |
+SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ |
+ return id->pMethods->xDeviceCharacteristics(id); |
+} |
+SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){ |
+ return id->pMethods->xShmLock(id, offset, n, flags); |
+} |
+SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){ |
+ id->pMethods->xShmBarrier(id); |
+} |
+SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int deleteFlag){ |
+ return id->pMethods->xShmUnmap(id, deleteFlag); |
+} |
+SQLITE_PRIVATE int sqlite3OsShmMap( |
+ sqlite3_file *id, /* Database file handle */ |
+ int iPage, |
+ int pgsz, |
+ int bExtend, /* True to extend file if necessary */ |
+ void volatile **pp /* OUT: Pointer to mapping */ |
+){ |
+ DO_OS_MALLOC_TEST(id); |
+ return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); |
+} |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+/* The real implementation of xFetch and xUnfetch */ |
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ |
+ DO_OS_MALLOC_TEST(id); |
+ return id->pMethods->xFetch(id, iOff, iAmt, pp); |
+} |
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ |
+ return id->pMethods->xUnfetch(id, iOff, p); |
+} |
+#else |
+/* No-op stubs to use when memory-mapped I/O is disabled */ |
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ |
+ *pp = 0; |
+ return SQLITE_OK; |
+} |
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){ |
+ return SQLITE_OK; |
+} |
+#endif |
+ |
+/* |
+** The next group of routines are convenience wrappers around the |
+** VFS methods. |
+*/ |
+SQLITE_PRIVATE int sqlite3OsOpen( |
+ sqlite3_vfs *pVfs, |
+ const char *zPath, |
+ sqlite3_file *pFile, |
+ int flags, |
+ int *pFlagsOut |
+){ |
+ int rc; |
+ DO_OS_MALLOC_TEST(0); |
+ /* 0x87f7f is a mask of SQLITE_OPEN_ flags that are valid to be passed |
+ ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example, |
+ ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before |
+ ** reaching the VFS. */ |
+ rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut); |
+ assert( rc==SQLITE_OK || pFile->pMethods==0 ); |
+ return rc; |
+} |
+SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ |
+ DO_OS_MALLOC_TEST(0); |
+ assert( dirSync==0 || dirSync==1 ); |
+ return pVfs->xDelete(pVfs, zPath, dirSync); |
+} |
+SQLITE_PRIVATE int sqlite3OsAccess( |
+ sqlite3_vfs *pVfs, |
+ const char *zPath, |
+ int flags, |
+ int *pResOut |
+){ |
+ DO_OS_MALLOC_TEST(0); |
+ return pVfs->xAccess(pVfs, zPath, flags, pResOut); |
+} |
+SQLITE_PRIVATE int sqlite3OsFullPathname( |
+ sqlite3_vfs *pVfs, |
+ const char *zPath, |
+ int nPathOut, |
+ char *zPathOut |
+){ |
+ DO_OS_MALLOC_TEST(0); |
+ zPathOut[0] = 0; |
+ return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut); |
+} |
+#ifndef SQLITE_OMIT_LOAD_EXTENSION |
+SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ |
+ return pVfs->xDlOpen(pVfs, zPath); |
+} |
+SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ |
+ pVfs->xDlError(pVfs, nByte, zBufOut); |
+} |
+SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){ |
+ return pVfs->xDlSym(pVfs, pHdle, zSym); |
+} |
+SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){ |
+ pVfs->xDlClose(pVfs, pHandle); |
+} |
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */ |
+SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ |
+ return pVfs->xRandomness(pVfs, nByte, zBufOut); |
+} |
+SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){ |
+ return pVfs->xSleep(pVfs, nMicro); |
+} |
+SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs *pVfs){ |
+ return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0; |
+} |
+SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){ |
+ int rc; |
+ /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64() |
+ ** method to get the current date and time if that method is available |
+ ** (if iVersion is 2 or greater and the function pointer is not NULL) and |
+ ** will fall back to xCurrentTime() if xCurrentTimeInt64() is |
+ ** unavailable. |
+ */ |
+ if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ |
+ rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut); |
+ }else{ |
+ double r; |
+ rc = pVfs->xCurrentTime(pVfs, &r); |
+ *pTimeOut = (sqlite3_int64)(r*86400000.0); |
+ } |
+ return rc; |
+} |
+ |
+SQLITE_PRIVATE int sqlite3OsOpenMalloc( |
+ sqlite3_vfs *pVfs, |
+ const char *zFile, |
+ sqlite3_file **ppFile, |
+ int flags, |
+ int *pOutFlags |
+){ |
+ int rc; |
+ sqlite3_file *pFile; |
+ pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile); |
+ if( pFile ){ |
+ rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); |
+ if( rc!=SQLITE_OK ){ |
+ sqlite3_free(pFile); |
+ }else{ |
+ *ppFile = pFile; |
+ } |
+ }else{ |
+ rc = SQLITE_NOMEM_BKPT; |
+ } |
+ return rc; |
+} |
+SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){ |
+ assert( pFile ); |
+ sqlite3OsClose(pFile); |
+ sqlite3_free(pFile); |
+} |
+ |
+/* |
+** This function is a wrapper around the OS specific implementation of |
+** sqlite3_os_init(). The purpose of the wrapper is to provide the |
+** ability to simulate a malloc failure, so that the handling of an |
+** error in sqlite3_os_init() by the upper layers can be tested. |
+*/ |
+SQLITE_PRIVATE int sqlite3OsInit(void){ |
+ void *p = sqlite3_malloc(10); |
+ if( p==0 ) return SQLITE_NOMEM_BKPT; |
+ sqlite3_free(p); |
+ return sqlite3_os_init(); |
+} |
+ |
+/* |
+** The list of all registered VFS implementations. |
+*/ |
+static sqlite3_vfs * SQLITE_WSD vfsList = 0; |
+#define vfsList GLOBAL(sqlite3_vfs *, vfsList) |
+ |
+/* |
+** Locate a VFS by name. If no name is given, simply return the |
+** first VFS on the list. |
+*/ |
+SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ |
+ sqlite3_vfs *pVfs = 0; |
+#if SQLITE_THREADSAFE |
+ sqlite3_mutex *mutex; |
+#endif |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ int rc = sqlite3_initialize(); |
+ if( rc ) return 0; |
+#endif |
+#if SQLITE_THREADSAFE |
+ mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); |
+#endif |
+ sqlite3_mutex_enter(mutex); |
+ for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){ |
+ if( zVfs==0 ) break; |
+ if( strcmp(zVfs, pVfs->zName)==0 ) break; |
+ } |
+ sqlite3_mutex_leave(mutex); |
+ return pVfs; |
+} |
+ |
+/* |
+** Unlink a VFS from the linked list |
+*/ |
+static void vfsUnlink(sqlite3_vfs *pVfs){ |
+ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) ); |
+ if( pVfs==0 ){ |
+ /* No-op */ |
+ }else if( vfsList==pVfs ){ |
+ vfsList = pVfs->pNext; |
+ }else if( vfsList ){ |
+ sqlite3_vfs *p = vfsList; |
+ while( p->pNext && p->pNext!=pVfs ){ |
+ p = p->pNext; |
+ } |
+ if( p->pNext==pVfs ){ |
+ p->pNext = pVfs->pNext; |
+ } |
+ } |
+} |
+ |
+/* |
+** Register a VFS with the system. It is harmless to register the same |
+** VFS multiple times. The new VFS becomes the default if makeDflt is |
+** true. |
+*/ |
+SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ |
+ MUTEX_LOGIC(sqlite3_mutex *mutex;) |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ int rc = sqlite3_initialize(); |
+ if( rc ) return rc; |
+#endif |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( pVfs==0 ) return SQLITE_MISUSE_BKPT; |
+#endif |
+ |
+ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) |
+ sqlite3_mutex_enter(mutex); |
+ vfsUnlink(pVfs); |
+ if( makeDflt || vfsList==0 ){ |
+ pVfs->pNext = vfsList; |
+ vfsList = pVfs; |
+ }else{ |
+ pVfs->pNext = vfsList->pNext; |
+ vfsList->pNext = pVfs; |
+ } |
+ assert(vfsList); |
+ sqlite3_mutex_leave(mutex); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Unregister a VFS so that it is no longer accessible. |
+*/ |
+SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ |
+#if SQLITE_THREADSAFE |
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); |
+#endif |
+ sqlite3_mutex_enter(mutex); |
+ vfsUnlink(pVfs); |
+ sqlite3_mutex_leave(mutex); |
+ return SQLITE_OK; |
+} |
+ |
+/************** End of os.c **************************************************/ |
+/************** Begin file fault.c *******************************************/ |
+/* |
+** 2008 Jan 22 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** |
+** This file contains code to support the concept of "benign" |
+** malloc failures (when the xMalloc() or xRealloc() method of the |
+** sqlite3_mem_methods structure fails to allocate a block of memory |
+** and returns 0). |
+** |
+** Most malloc failures are non-benign. After they occur, SQLite |
+** abandons the current operation and returns an error code (usually |
+** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily |
+** fatal. For example, if a malloc fails while resizing a hash table, this |
+** is completely recoverable simply by not carrying out the resize. The |
+** hash table will continue to function normally. So a malloc failure |
+** during a hash table resize is a benign fault. |
+*/ |
+ |
+/* #include "sqliteInt.h" */ |
+ |
+#ifndef SQLITE_UNTESTABLE |
+ |
+/* |
+** Global variables. |
+*/ |
+typedef struct BenignMallocHooks BenignMallocHooks; |
+static SQLITE_WSD struct BenignMallocHooks { |
+ void (*xBenignBegin)(void); |
+ void (*xBenignEnd)(void); |
+} sqlite3Hooks = { 0, 0 }; |
+ |
+/* The "wsdHooks" macro will resolve to the appropriate BenignMallocHooks |
+** structure. If writable static data is unsupported on the target, |
+** we have to locate the state vector at run-time. In the more common |
+** case where writable static data is supported, wsdHooks can refer directly |
+** to the "sqlite3Hooks" state vector declared above. |
+*/ |
+#ifdef SQLITE_OMIT_WSD |
+# define wsdHooksInit \ |
+ BenignMallocHooks *x = &GLOBAL(BenignMallocHooks,sqlite3Hooks) |
+# define wsdHooks x[0] |
+#else |
+# define wsdHooksInit |
+# define wsdHooks sqlite3Hooks |
+#endif |
+ |
+ |
+/* |
+** Register hooks to call when sqlite3BeginBenignMalloc() and |
+** sqlite3EndBenignMalloc() are called, respectively. |
+*/ |
+SQLITE_PRIVATE void sqlite3BenignMallocHooks( |
+ void (*xBenignBegin)(void), |
+ void (*xBenignEnd)(void) |
+){ |
+ wsdHooksInit; |
+ wsdHooks.xBenignBegin = xBenignBegin; |
+ wsdHooks.xBenignEnd = xBenignEnd; |
+} |
+ |
+/* |
+** This (sqlite3EndBenignMalloc()) is called by SQLite code to indicate that |
+** subsequent malloc failures are benign. A call to sqlite3EndBenignMalloc() |
+** indicates that subsequent malloc failures are non-benign. |
+*/ |
+SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void){ |
+ wsdHooksInit; |
+ if( wsdHooks.xBenignBegin ){ |
+ wsdHooks.xBenignBegin(); |
+ } |
+} |
+SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){ |
+ wsdHooksInit; |
+ if( wsdHooks.xBenignEnd ){ |
+ wsdHooks.xBenignEnd(); |
+ } |
+} |
+ |
+#endif /* #ifndef SQLITE_UNTESTABLE */ |
+ |
+/************** End of fault.c ***********************************************/ |
+/************** Begin file mem0.c ********************************************/ |
+/* |
+** 2008 October 28 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** |
+** This file contains a no-op memory allocation drivers for use when |
+** SQLITE_ZERO_MALLOC is defined. The allocation drivers implemented |
+** here always fail. SQLite will not operate with these drivers. These |
+** are merely placeholders. Real drivers must be substituted using |
+** sqlite3_config() before SQLite will operate. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* |
+** This version of the memory allocator is the default. It is |
+** used when no other memory allocator is specified using compile-time |
+** macros. |
+*/ |
+#ifdef SQLITE_ZERO_MALLOC |
+ |
+/* |
+** No-op versions of all memory allocation routines |
+*/ |
+static void *sqlite3MemMalloc(int nByte){ return 0; } |
+static void sqlite3MemFree(void *pPrior){ return; } |
+static void *sqlite3MemRealloc(void *pPrior, int nByte){ return 0; } |
+static int sqlite3MemSize(void *pPrior){ return 0; } |
+static int sqlite3MemRoundup(int n){ return n; } |
+static int sqlite3MemInit(void *NotUsed){ return SQLITE_OK; } |
+static void sqlite3MemShutdown(void *NotUsed){ return; } |
+ |
+/* |
+** This routine is the only routine in this file with external linkage. |
+** |
+** Populate the low-level memory allocation function pointers in |
+** sqlite3GlobalConfig.m with pointers to the routines in this file. |
+*/ |
+SQLITE_PRIVATE void sqlite3MemSetDefault(void){ |
+ static const sqlite3_mem_methods defaultMethods = { |
+ sqlite3MemMalloc, |
+ sqlite3MemFree, |
+ sqlite3MemRealloc, |
+ sqlite3MemSize, |
+ sqlite3MemRoundup, |
+ sqlite3MemInit, |
+ sqlite3MemShutdown, |
+ 0 |
+ }; |
+ sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); |
+} |
+ |
+#endif /* SQLITE_ZERO_MALLOC */ |
+ |
+/************** End of mem0.c ************************************************/ |
+/************** Begin file mem1.c ********************************************/ |
+/* |
+** 2007 August 14 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** |
+** This file contains low-level memory allocation drivers for when |
+** SQLite will use the standard C-library malloc/realloc/free interface |
+** to obtain the memory it needs. |
+** |
+** This file contains implementations of the low-level memory allocation |
+** routines specified in the sqlite3_mem_methods object. The content of |
+** this file is only used if SQLITE_SYSTEM_MALLOC is defined. The |
+** SQLITE_SYSTEM_MALLOC macro is defined automatically if neither the |
+** SQLITE_MEMDEBUG nor the SQLITE_WIN32_MALLOC macros are defined. The |
+** default configuration is to use memory allocation routines in this |
+** file. |
+** |
+** C-preprocessor macro summary: |
+** |
+** HAVE_MALLOC_USABLE_SIZE The configure script sets this symbol if |
+** the malloc_usable_size() interface exists |
+** on the target platform. Or, this symbol |
+** can be set manually, if desired. |
+** If an equivalent interface exists by |
+** a different name, using a separate -D |
+** option to rename it. |
+** |
+** SQLITE_WITHOUT_ZONEMALLOC Some older macs lack support for the zone |
+** memory allocator. Set this symbol to enable |
+** building on older macs. |
+** |
+** SQLITE_WITHOUT_MSIZE Set this symbol to disable the use of |
+** _msize() on windows systems. This might |
+** be necessary when compiling for Delphi, |
+** for example. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* |
+** This version of the memory allocator is the default. It is |
+** used when no other memory allocator is specified using compile-time |
+** macros. |
+*/ |
+#ifdef SQLITE_SYSTEM_MALLOC |
+#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) |
+ |
+/* |
+** Use the zone allocator available on apple products unless the |
+** SQLITE_WITHOUT_ZONEMALLOC symbol is defined. |
+*/ |
+#include <sys/sysctl.h> |
+#include <malloc/malloc.h> |
+#include <libkern/OSAtomic.h> |
+static malloc_zone_t* _sqliteZone_; |
+#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x)) |
+#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x)); |
+#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y)) |
+#define SQLITE_MALLOCSIZE(x) \ |
+ (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x)) |
+ |
+#else /* if not __APPLE__ */ |
+ |
+/* |
+** Use standard C library malloc and free on non-Apple systems. |
+** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined. |
+*/ |
+#define SQLITE_MALLOC(x) malloc(x) |
+#define SQLITE_FREE(x) free(x) |
+#define SQLITE_REALLOC(x,y) realloc((x),(y)) |
+ |
+/* |
+** The malloc.h header file is needed for malloc_usable_size() function |
+** on some systems (e.g. Linux). |
+*/ |
+#if HAVE_MALLOC_H && HAVE_MALLOC_USABLE_SIZE |
+# define SQLITE_USE_MALLOC_H 1 |
+# define SQLITE_USE_MALLOC_USABLE_SIZE 1 |
+/* |
+** The MSVCRT has malloc_usable_size(), but it is called _msize(). The |
+** use of _msize() is automatic, but can be disabled by compiling with |
+** -DSQLITE_WITHOUT_MSIZE. Using the _msize() function also requires |
+** the malloc.h header file. |
+*/ |
+#elif defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE) |
+# define SQLITE_USE_MALLOC_H |
+# define SQLITE_USE_MSIZE |
+#endif |
+ |
+/* |
+** Include the malloc.h header file, if necessary. Also set define macro |
+** SQLITE_MALLOCSIZE to the appropriate function name, which is _msize() |
+** for MSVC and malloc_usable_size() for most other systems (e.g. Linux). |
+** The memory size function can always be overridden manually by defining |
+** the macro SQLITE_MALLOCSIZE to the desired function name. |
+*/ |
+#if defined(SQLITE_USE_MALLOC_H) |
+# include <malloc.h> |
+# if defined(SQLITE_USE_MALLOC_USABLE_SIZE) |
+# if !defined(SQLITE_MALLOCSIZE) |
+# define SQLITE_MALLOCSIZE(x) malloc_usable_size(x) |
+# endif |
+# elif defined(SQLITE_USE_MSIZE) |
+# if !defined(SQLITE_MALLOCSIZE) |
+# define SQLITE_MALLOCSIZE _msize |
+# endif |
+# endif |
+#endif /* defined(SQLITE_USE_MALLOC_H) */ |
+ |
+#endif /* __APPLE__ or not __APPLE__ */ |
+ |
+/* |
+** Like malloc(), but remember the size of the allocation |
+** so that we can find it later using sqlite3MemSize(). |
+** |
+** For this low-level routine, we are guaranteed that nByte>0 because |
+** cases of nByte<=0 will be intercepted and dealt with by higher level |
+** routines. |
+*/ |
+static void *sqlite3MemMalloc(int nByte){ |
+#ifdef SQLITE_MALLOCSIZE |
+ void *p; |
+ testcase( ROUND8(nByte)==nByte ); |
+ p = SQLITE_MALLOC( nByte ); |
+ if( p==0 ){ |
+ testcase( sqlite3GlobalConfig.xLog!=0 ); |
+ sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); |
+ } |
+ return p; |
+#else |
+ sqlite3_int64 *p; |
+ assert( nByte>0 ); |
+ testcase( ROUND8(nByte)!=nByte ); |
+ p = SQLITE_MALLOC( nByte+8 ); |
+ if( p ){ |
+ p[0] = nByte; |
+ p++; |
+ }else{ |
+ testcase( sqlite3GlobalConfig.xLog!=0 ); |
+ sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); |
+ } |
+ return (void *)p; |
+#endif |
+} |
+ |
+/* |
+** Like free() but works for allocations obtained from sqlite3MemMalloc() |
+** or sqlite3MemRealloc(). |
+** |
+** For this low-level routine, we already know that pPrior!=0 since |
+** cases where pPrior==0 will have been intecepted and dealt with |
+** by higher-level routines. |
+*/ |
+static void sqlite3MemFree(void *pPrior){ |
+#ifdef SQLITE_MALLOCSIZE |
+ SQLITE_FREE(pPrior); |
+#else |
+ sqlite3_int64 *p = (sqlite3_int64*)pPrior; |
+ assert( pPrior!=0 ); |
+ p--; |
+ SQLITE_FREE(p); |
+#endif |
+} |
+ |
+/* |
+** Report the allocated size of a prior return from xMalloc() |
+** or xRealloc(). |
+*/ |
+static int sqlite3MemSize(void *pPrior){ |
+#ifdef SQLITE_MALLOCSIZE |
+ assert( pPrior!=0 ); |
+ return (int)SQLITE_MALLOCSIZE(pPrior); |
+#else |
+ sqlite3_int64 *p; |
+ assert( pPrior!=0 ); |
+ p = (sqlite3_int64*)pPrior; |
+ p--; |
+ return (int)p[0]; |
+#endif |
+} |
+ |
+/* |
+** Like realloc(). Resize an allocation previously obtained from |
+** sqlite3MemMalloc(). |
+** |
+** For this low-level interface, we know that pPrior!=0. Cases where |
+** pPrior==0 while have been intercepted by higher-level routine and |
+** redirected to xMalloc. Similarly, we know that nByte>0 because |
+** cases where nByte<=0 will have been intercepted by higher-level |
+** routines and redirected to xFree. |
+*/ |
+static void *sqlite3MemRealloc(void *pPrior, int nByte){ |
+#ifdef SQLITE_MALLOCSIZE |
+ void *p = SQLITE_REALLOC(pPrior, nByte); |
+ if( p==0 ){ |
+ testcase( sqlite3GlobalConfig.xLog!=0 ); |
+ sqlite3_log(SQLITE_NOMEM, |
+ "failed memory resize %u to %u bytes", |
+ SQLITE_MALLOCSIZE(pPrior), nByte); |
+ } |
+ return p; |
+#else |
+ sqlite3_int64 *p = (sqlite3_int64*)pPrior; |
+ assert( pPrior!=0 && nByte>0 ); |
+ assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */ |
+ p--; |
+ p = SQLITE_REALLOC(p, nByte+8 ); |
+ if( p ){ |
+ p[0] = nByte; |
+ p++; |
+ }else{ |
+ testcase( sqlite3GlobalConfig.xLog!=0 ); |
+ sqlite3_log(SQLITE_NOMEM, |
+ "failed memory resize %u to %u bytes", |
+ sqlite3MemSize(pPrior), nByte); |
+ } |
+ return (void*)p; |
+#endif |
+} |
+ |
+/* |
+** Round up a request size to the next valid allocation size. |
+*/ |
+static int sqlite3MemRoundup(int n){ |
+ return ROUND8(n); |
+} |
+ |
+/* |
+** Initialize this module. |
+*/ |
+static int sqlite3MemInit(void *NotUsed){ |
+#if defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) |
+ int cpuCount; |
+ size_t len; |
+ if( _sqliteZone_ ){ |
+ return SQLITE_OK; |
+ } |
+ len = sizeof(cpuCount); |
+ /* One usually wants to use hw.acctivecpu for MT decisions, but not here */ |
+ sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0); |
+ if( cpuCount>1 ){ |
+ /* defer MT decisions to system malloc */ |
+ _sqliteZone_ = malloc_default_zone(); |
+ }else{ |
+ /* only 1 core, use our own zone to contention over global locks, |
+ ** e.g. we have our own dedicated locks */ |
+ bool success; |
+ malloc_zone_t* newzone = malloc_create_zone(4096, 0); |
+ malloc_set_zone_name(newzone, "Sqlite_Heap"); |
+ do{ |
+ success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone, |
+ (void * volatile *)&_sqliteZone_); |
+ }while(!_sqliteZone_); |
+ if( !success ){ |
+ /* somebody registered a zone first */ |
+ malloc_destroy_zone(newzone); |
+ } |
+ } |
+#endif |
+ UNUSED_PARAMETER(NotUsed); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Deinitialize this module. |
+*/ |
+static void sqlite3MemShutdown(void *NotUsed){ |
+ UNUSED_PARAMETER(NotUsed); |
+ return; |
+} |
+ |
+/* |
+** This routine is the only routine in this file with external linkage. |
+** |
+** Populate the low-level memory allocation function pointers in |
+** sqlite3GlobalConfig.m with pointers to the routines in this file. |
+*/ |
+SQLITE_PRIVATE void sqlite3MemSetDefault(void){ |
+ static const sqlite3_mem_methods defaultMethods = { |
+ sqlite3MemMalloc, |
+ sqlite3MemFree, |
+ sqlite3MemRealloc, |
+ sqlite3MemSize, |
+ sqlite3MemRoundup, |
+ sqlite3MemInit, |
+ sqlite3MemShutdown, |
+ 0 |
+ }; |
+ sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); |
+} |
+ |
+#endif /* SQLITE_SYSTEM_MALLOC */ |
+ |
+/************** End of mem1.c ************************************************/ |
+/************** Begin file mem2.c ********************************************/ |
+/* |
+** 2007 August 15 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** |
+** This file contains low-level memory allocation drivers for when |
+** SQLite will use the standard C-library malloc/realloc/free interface |
+** to obtain the memory it needs while adding lots of additional debugging |
+** information to each allocation in order to help detect and fix memory |
+** leaks and memory usage errors. |
+** |
+** This file contains implementations of the low-level memory allocation |
+** routines specified in the sqlite3_mem_methods object. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* |
+** This version of the memory allocator is used only if the |
+** SQLITE_MEMDEBUG macro is defined |
+*/ |
+#ifdef SQLITE_MEMDEBUG |
+ |
+/* |
+** The backtrace functionality is only available with GLIBC |
+*/ |
+#ifdef __GLIBC__ |
+ extern int backtrace(void**,int); |
+ extern void backtrace_symbols_fd(void*const*,int,int); |
+#else |
+# define backtrace(A,B) 1 |
+# define backtrace_symbols_fd(A,B,C) |
+#endif |
+/* #include <stdio.h> */ |
+ |
+/* |
+** Each memory allocation looks like this: |
+** |
+** ------------------------------------------------------------------------ |
+** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | |
+** ------------------------------------------------------------------------ |
+** |
+** The application code sees only a pointer to the allocation. We have |
+** to back up from the allocation pointer to find the MemBlockHdr. The |
+** MemBlockHdr tells us the size of the allocation and the number of |
+** backtrace pointers. There is also a guard word at the end of the |
+** MemBlockHdr. |
+*/ |
+struct MemBlockHdr { |
+ i64 iSize; /* Size of this allocation */ |
+ struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ |
+ char nBacktrace; /* Number of backtraces on this alloc */ |
+ char nBacktraceSlots; /* Available backtrace slots */ |
+ u8 nTitle; /* Bytes of title; includes '\0' */ |
+ u8 eType; /* Allocation type code */ |
+ int iForeGuard; /* Guard word for sanity */ |
+}; |
+ |
+/* |
+** Guard words |
+*/ |
+#define FOREGUARD 0x80F5E153 |
+#define REARGUARD 0xE4676B53 |
+ |
+/* |
+** Number of malloc size increments to track. |
+*/ |
+#define NCSIZE 1000 |
+ |
+/* |
+** All of the static variables used by this module are collected |
+** into a single structure named "mem". This is to keep the |
+** static variables organized and to reduce namespace pollution |
+** when this module is combined with other in the amalgamation. |
+*/ |
+static struct { |
+ |
+ /* |
+ ** Mutex to control access to the memory allocation subsystem. |
+ */ |
+ sqlite3_mutex *mutex; |
+ |
+ /* |
+ ** Head and tail of a linked list of all outstanding allocations |
+ */ |
+ struct MemBlockHdr *pFirst; |
+ struct MemBlockHdr *pLast; |
+ |
+ /* |
+ ** The number of levels of backtrace to save in new allocations. |
+ */ |
+ int nBacktrace; |
+ void (*xBacktrace)(int, int, void **); |
+ |
+ /* |
+ ** Title text to insert in front of each block |
+ */ |
+ int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ |
+ char zTitle[100]; /* The title text */ |
+ |
+ /* |
+ ** sqlite3MallocDisallow() increments the following counter. |
+ ** sqlite3MallocAllow() decrements it. |
+ */ |
+ int disallow; /* Do not allow memory allocation */ |
+ |
+ /* |
+ ** Gather statistics on the sizes of memory allocations. |
+ ** nAlloc[i] is the number of allocation attempts of i*8 |
+ ** bytes. i==NCSIZE is the number of allocation attempts for |
+ ** sizes more than NCSIZE*8 bytes. |
+ */ |
+ int nAlloc[NCSIZE]; /* Total number of allocations */ |
+ int nCurrent[NCSIZE]; /* Current number of allocations */ |
+ int mxCurrent[NCSIZE]; /* Highwater mark for nCurrent */ |
+ |
+} mem; |
+ |
+ |
+/* |
+** Adjust memory usage statistics |
+*/ |
+static void adjustStats(int iSize, int increment){ |
+ int i = ROUND8(iSize)/8; |
+ if( i>NCSIZE-1 ){ |
+ i = NCSIZE - 1; |
+ } |
+ if( increment>0 ){ |
+ mem.nAlloc[i]++; |
+ mem.nCurrent[i]++; |
+ if( mem.nCurrent[i]>mem.mxCurrent[i] ){ |
+ mem.mxCurrent[i] = mem.nCurrent[i]; |
+ } |
+ }else{ |
+ mem.nCurrent[i]--; |
+ assert( mem.nCurrent[i]>=0 ); |
+ } |
+} |
+ |
+/* |
+** Given an allocation, find the MemBlockHdr for that allocation. |
+** |
+** This routine checks the guards at either end of the allocation and |
+** if they are incorrect it asserts. |
+*/ |
+static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ |
+ struct MemBlockHdr *p; |
+ int *pInt; |
+ u8 *pU8; |
+ int nReserve; |
+ |
+ p = (struct MemBlockHdr*)pAllocation; |
+ p--; |
+ assert( p->iForeGuard==(int)FOREGUARD ); |
+ nReserve = ROUND8(p->iSize); |
+ pInt = (int*)pAllocation; |
+ pU8 = (u8*)pAllocation; |
+ assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD ); |
+ /* This checks any of the "extra" bytes allocated due |
+ ** to rounding up to an 8 byte boundary to ensure |
+ ** they haven't been overwritten. |
+ */ |
+ while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 ); |
+ return p; |
+} |
+ |
+/* |
+** Return the number of bytes currently allocated at address p. |
+*/ |
+static int sqlite3MemSize(void *p){ |
+ struct MemBlockHdr *pHdr; |
+ if( !p ){ |
+ return 0; |
+ } |
+ pHdr = sqlite3MemsysGetHeader(p); |
+ return (int)pHdr->iSize; |
+} |
+ |
+/* |
+** Initialize the memory allocation subsystem. |
+*/ |
+static int sqlite3MemInit(void *NotUsed){ |
+ UNUSED_PARAMETER(NotUsed); |
+ assert( (sizeof(struct MemBlockHdr)&7) == 0 ); |
+ if( !sqlite3GlobalConfig.bMemstat ){ |
+ /* If memory status is enabled, then the malloc.c wrapper will already |
+ ** hold the STATIC_MEM mutex when the routines here are invoked. */ |
+ mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); |
+ } |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Deinitialize the memory allocation subsystem. |
+*/ |
+static void sqlite3MemShutdown(void *NotUsed){ |
+ UNUSED_PARAMETER(NotUsed); |
+ mem.mutex = 0; |
+} |
+ |
+/* |
+** Round up a request size to the next valid allocation size. |
+*/ |
+static int sqlite3MemRoundup(int n){ |
+ return ROUND8(n); |
+} |
+ |
+/* |
+** Fill a buffer with pseudo-random bytes. This is used to preset |
+** the content of a new memory allocation to unpredictable values and |
+** to clear the content of a freed allocation to unpredictable values. |
+*/ |
+static void randomFill(char *pBuf, int nByte){ |
+ unsigned int x, y, r; |
+ x = SQLITE_PTR_TO_INT(pBuf); |
+ y = nByte | 1; |
+ while( nByte >= 4 ){ |
+ x = (x>>1) ^ (-(int)(x&1) & 0xd0000001); |
+ y = y*1103515245 + 12345; |
+ r = x ^ y; |
+ *(int*)pBuf = r; |
+ pBuf += 4; |
+ nByte -= 4; |
+ } |
+ while( nByte-- > 0 ){ |
+ x = (x>>1) ^ (-(int)(x&1) & 0xd0000001); |
+ y = y*1103515245 + 12345; |
+ r = x ^ y; |
+ *(pBuf++) = r & 0xff; |
+ } |
+} |
+ |
+/* |
+** Allocate nByte bytes of memory. |
+*/ |
+static void *sqlite3MemMalloc(int nByte){ |
+ struct MemBlockHdr *pHdr; |
+ void **pBt; |
+ char *z; |
+ int *pInt; |
+ void *p = 0; |
+ int totalSize; |
+ int nReserve; |
+ sqlite3_mutex_enter(mem.mutex); |
+ assert( mem.disallow==0 ); |
+ nReserve = ROUND8(nByte); |
+ totalSize = nReserve + sizeof(*pHdr) + sizeof(int) + |
+ mem.nBacktrace*sizeof(void*) + mem.nTitle; |
+ p = malloc(totalSize); |
+ if( p ){ |
+ z = p; |
+ pBt = (void**)&z[mem.nTitle]; |
+ pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace]; |
+ pHdr->pNext = 0; |
+ pHdr->pPrev = mem.pLast; |
+ if( mem.pLast ){ |
+ mem.pLast->pNext = pHdr; |
+ }else{ |
+ mem.pFirst = pHdr; |
+ } |
+ mem.pLast = pHdr; |
+ pHdr->iForeGuard = FOREGUARD; |
+ pHdr->eType = MEMTYPE_HEAP; |
+ pHdr->nBacktraceSlots = mem.nBacktrace; |
+ pHdr->nTitle = mem.nTitle; |
+ if( mem.nBacktrace ){ |
+ void *aAddr[40]; |
+ pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; |
+ memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); |
+ assert(pBt[0]); |
+ if( mem.xBacktrace ){ |
+ mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]); |
+ } |
+ }else{ |
+ pHdr->nBacktrace = 0; |
+ } |
+ if( mem.nTitle ){ |
+ memcpy(z, mem.zTitle, mem.nTitle); |
+ } |
+ pHdr->iSize = nByte; |
+ adjustStats(nByte, +1); |
+ pInt = (int*)&pHdr[1]; |
+ pInt[nReserve/sizeof(int)] = REARGUARD; |
+ randomFill((char*)pInt, nByte); |
+ memset(((char*)pInt)+nByte, 0x65, nReserve-nByte); |
+ p = (void*)pInt; |
+ } |
+ sqlite3_mutex_leave(mem.mutex); |
+ return p; |
+} |
+ |
+/* |
+** Free memory. |
+*/ |
+static void sqlite3MemFree(void *pPrior){ |
+ struct MemBlockHdr *pHdr; |
+ void **pBt; |
+ char *z; |
+ assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0 |
+ || mem.mutex!=0 ); |
+ pHdr = sqlite3MemsysGetHeader(pPrior); |
+ pBt = (void**)pHdr; |
+ pBt -= pHdr->nBacktraceSlots; |
+ sqlite3_mutex_enter(mem.mutex); |
+ if( pHdr->pPrev ){ |
+ assert( pHdr->pPrev->pNext==pHdr ); |
+ pHdr->pPrev->pNext = pHdr->pNext; |
+ }else{ |
+ assert( mem.pFirst==pHdr ); |
+ mem.pFirst = pHdr->pNext; |
+ } |
+ if( pHdr->pNext ){ |
+ assert( pHdr->pNext->pPrev==pHdr ); |
+ pHdr->pNext->pPrev = pHdr->pPrev; |
+ }else{ |
+ assert( mem.pLast==pHdr ); |
+ mem.pLast = pHdr->pPrev; |
+ } |
+ z = (char*)pBt; |
+ z -= pHdr->nTitle; |
+ adjustStats((int)pHdr->iSize, -1); |
+ randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + |
+ (int)pHdr->iSize + sizeof(int) + pHdr->nTitle); |
+ free(z); |
+ sqlite3_mutex_leave(mem.mutex); |
+} |
+ |
+/* |
+** Change the size of an existing memory allocation. |
+** |
+** For this debugging implementation, we *always* make a copy of the |
+** allocation into a new place in memory. In this way, if the |
+** higher level code is using pointer to the old allocation, it is |
+** much more likely to break and we are much more liking to find |
+** the error. |
+*/ |
+static void *sqlite3MemRealloc(void *pPrior, int nByte){ |
+ struct MemBlockHdr *pOldHdr; |
+ void *pNew; |
+ assert( mem.disallow==0 ); |
+ assert( (nByte & 7)==0 ); /* EV: R-46199-30249 */ |
+ pOldHdr = sqlite3MemsysGetHeader(pPrior); |
+ pNew = sqlite3MemMalloc(nByte); |
+ if( pNew ){ |
+ memcpy(pNew, pPrior, (int)(nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize)); |
+ if( nByte>pOldHdr->iSize ){ |
+ randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - (int)pOldHdr->iSize); |
+ } |
+ sqlite3MemFree(pPrior); |
+ } |
+ return pNew; |
+} |
+ |
+/* |
+** Populate the low-level memory allocation function pointers in |
+** sqlite3GlobalConfig.m with pointers to the routines in this file. |
+*/ |
+SQLITE_PRIVATE void sqlite3MemSetDefault(void){ |
+ static const sqlite3_mem_methods defaultMethods = { |
+ sqlite3MemMalloc, |
+ sqlite3MemFree, |
+ sqlite3MemRealloc, |
+ sqlite3MemSize, |
+ sqlite3MemRoundup, |
+ sqlite3MemInit, |
+ sqlite3MemShutdown, |
+ 0 |
+ }; |
+ sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); |
+} |
+ |
+/* |
+** Set the "type" of an allocation. |
+*/ |
+SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){ |
+ if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ |
+ struct MemBlockHdr *pHdr; |
+ pHdr = sqlite3MemsysGetHeader(p); |
+ assert( pHdr->iForeGuard==FOREGUARD ); |
+ pHdr->eType = eType; |
+ } |
+} |
+ |
+/* |
+** Return TRUE if the mask of type in eType matches the type of the |
+** allocation p. Also return true if p==NULL. |
+** |
+** This routine is designed for use within an assert() statement, to |
+** verify the type of an allocation. For example: |
+** |
+** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); |
+*/ |
+SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){ |
+ int rc = 1; |
+ if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ |
+ struct MemBlockHdr *pHdr; |
+ pHdr = sqlite3MemsysGetHeader(p); |
+ assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ |
+ if( (pHdr->eType&eType)==0 ){ |
+ rc = 0; |
+ } |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Return TRUE if the mask of type in eType matches no bits of the type of the |
+** allocation p. Also return true if p==NULL. |
+** |
+** This routine is designed for use within an assert() statement, to |
+** verify the type of an allocation. For example: |
+** |
+** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); |
+*/ |
+SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){ |
+ int rc = 1; |
+ if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ |
+ struct MemBlockHdr *pHdr; |
+ pHdr = sqlite3MemsysGetHeader(p); |
+ assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ |
+ if( (pHdr->eType&eType)!=0 ){ |
+ rc = 0; |
+ } |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Set the number of backtrace levels kept for each allocation. |
+** A value of zero turns off backtracing. The number is always rounded |
+** up to a multiple of 2. |
+*/ |
+SQLITE_PRIVATE void sqlite3MemdebugBacktrace(int depth){ |
+ if( depth<0 ){ depth = 0; } |
+ if( depth>20 ){ depth = 20; } |
+ depth = (depth+1)&0xfe; |
+ mem.nBacktrace = depth; |
+} |
+ |
+SQLITE_PRIVATE void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){ |
+ mem.xBacktrace = xBacktrace; |
+} |
+ |
+/* |
+** Set the title string for subsequent allocations. |
+*/ |
+SQLITE_PRIVATE void sqlite3MemdebugSettitle(const char *zTitle){ |
+ unsigned int n = sqlite3Strlen30(zTitle) + 1; |
+ sqlite3_mutex_enter(mem.mutex); |
+ if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1; |
+ memcpy(mem.zTitle, zTitle, n); |
+ mem.zTitle[n] = 0; |
+ mem.nTitle = ROUND8(n); |
+ sqlite3_mutex_leave(mem.mutex); |
+} |
+ |
+SQLITE_PRIVATE void sqlite3MemdebugSync(){ |
+ struct MemBlockHdr *pHdr; |
+ for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ |
+ void **pBt = (void**)pHdr; |
+ pBt -= pHdr->nBacktraceSlots; |
+ mem.xBacktrace((int)pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]); |
+ } |
+} |
+ |
+/* |
+** Open the file indicated and write a log of all unfreed memory |
+** allocations into that log. |
+*/ |
+SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){ |
+ FILE *out; |
+ struct MemBlockHdr *pHdr; |
+ void **pBt; |
+ int i; |
+ out = fopen(zFilename, "w"); |
+ if( out==0 ){ |
+ fprintf(stderr, "** Unable to output memory debug output log: %s **\n", |
+ zFilename); |
+ return; |
+ } |
+ for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ |
+ char *z = (char*)pHdr; |
+ z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; |
+ fprintf(out, "**** %lld bytes at %p from %s ****\n", |
+ pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); |
+ if( pHdr->nBacktrace ){ |
+ fflush(out); |
+ pBt = (void**)pHdr; |
+ pBt -= pHdr->nBacktraceSlots; |
+ backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out)); |
+ fprintf(out, "\n"); |
+ } |
+ } |
+ fprintf(out, "COUNTS:\n"); |
+ for(i=0; i<NCSIZE-1; i++){ |
+ if( mem.nAlloc[i] ){ |
+ fprintf(out, " %5d: %10d %10d %10d\n", |
+ i*8, mem.nAlloc[i], mem.nCurrent[i], mem.mxCurrent[i]); |
+ } |
+ } |
+ if( mem.nAlloc[NCSIZE-1] ){ |
+ fprintf(out, " %5d: %10d %10d %10d\n", |
+ NCSIZE*8-8, mem.nAlloc[NCSIZE-1], |
+ mem.nCurrent[NCSIZE-1], mem.mxCurrent[NCSIZE-1]); |
+ } |
+ fclose(out); |
+} |
+ |
+/* |
+** Return the number of times sqlite3MemMalloc() has been called. |
+*/ |
+SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){ |
+ int i; |
+ int nTotal = 0; |
+ for(i=0; i<NCSIZE; i++){ |
+ nTotal += mem.nAlloc[i]; |
+ } |
+ return nTotal; |
+} |
+ |
+ |
+#endif /* SQLITE_MEMDEBUG */ |
+ |
+/************** End of mem2.c ************************************************/ |
+/************** Begin file mem3.c ********************************************/ |
+/* |
+** 2007 October 14 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file contains the C functions that implement a memory |
+** allocation subsystem for use by SQLite. |
+** |
+** This version of the memory allocation subsystem omits all |
+** use of malloc(). The SQLite user supplies a block of memory |
+** before calling sqlite3_initialize() from which allocations |
+** are made and returned by the xMalloc() and xRealloc() |
+** implementations. Once sqlite3_initialize() has been called, |
+** the amount of memory available to SQLite is fixed and cannot |
+** be changed. |
+** |
+** This version of the memory allocation subsystem is included |
+** in the build only if SQLITE_ENABLE_MEMSYS3 is defined. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* |
+** This version of the memory allocator is only built into the library |
+** SQLITE_ENABLE_MEMSYS3 is defined. Defining this symbol does not |
+** mean that the library will use a memory-pool by default, just that |
+** it is available. The mempool allocator is activated by calling |
+** sqlite3_config(). |
+*/ |
+#ifdef SQLITE_ENABLE_MEMSYS3 |
+ |
+/* |
+** Maximum size (in Mem3Blocks) of a "small" chunk. |
+*/ |
+#define MX_SMALL 10 |
+ |
+ |
+/* |
+** Number of freelist hash slots |
+*/ |
+#define N_HASH 61 |
+ |
+/* |
+** A memory allocation (also called a "chunk") consists of two or |
+** more blocks where each block is 8 bytes. The first 8 bytes are |
+** a header that is not returned to the user. |
+** |
+** A chunk is two or more blocks that is either checked out or |
+** free. The first block has format u.hdr. u.hdr.size4x is 4 times the |
+** size of the allocation in blocks if the allocation is free. |
+** The u.hdr.size4x&1 bit is true if the chunk is checked out and |
+** false if the chunk is on the freelist. The u.hdr.size4x&2 bit |
+** is true if the previous chunk is checked out and false if the |
+** previous chunk is free. The u.hdr.prevSize field is the size of |
+** the previous chunk in blocks if the previous chunk is on the |
+** freelist. If the previous chunk is checked out, then |
+** u.hdr.prevSize can be part of the data for that chunk and should |
+** not be read or written. |
+** |
+** We often identify a chunk by its index in mem3.aPool[]. When |
+** this is done, the chunk index refers to the second block of |
+** the chunk. In this way, the first chunk has an index of 1. |
+** A chunk index of 0 means "no such chunk" and is the equivalent |
+** of a NULL pointer. |
+** |
+** The second block of free chunks is of the form u.list. The |
+** two fields form a double-linked list of chunks of related sizes. |
+** Pointers to the head of the list are stored in mem3.aiSmall[] |
+** for smaller chunks and mem3.aiHash[] for larger chunks. |
+** |
+** The second block of a chunk is user data if the chunk is checked |
+** out. If a chunk is checked out, the user data may extend into |
+** the u.hdr.prevSize value of the following chunk. |
+*/ |
+typedef struct Mem3Block Mem3Block; |
+struct Mem3Block { |
+ union { |
+ struct { |
+ u32 prevSize; /* Size of previous chunk in Mem3Block elements */ |
+ u32 size4x; /* 4x the size of current chunk in Mem3Block elements */ |
+ } hdr; |
+ struct { |
+ u32 next; /* Index in mem3.aPool[] of next free chunk */ |
+ u32 prev; /* Index in mem3.aPool[] of previous free chunk */ |
+ } list; |
+ } u; |
+}; |
+ |
+/* |
+** All of the static variables used by this module are collected |
+** into a single structure named "mem3". This is to keep the |
+** static variables organized and to reduce namespace pollution |
+** when this module is combined with other in the amalgamation. |
+*/ |
+static SQLITE_WSD struct Mem3Global { |
+ /* |
+ ** Memory available for allocation. nPool is the size of the array |
+ ** (in Mem3Blocks) pointed to by aPool less 2. |
+ */ |
+ u32 nPool; |
+ Mem3Block *aPool; |
+ |
+ /* |
+ ** True if we are evaluating an out-of-memory callback. |
+ */ |
+ int alarmBusy; |
+ |
+ /* |
+ ** Mutex to control access to the memory allocation subsystem. |
+ */ |
+ sqlite3_mutex *mutex; |
+ |
+ /* |
+ ** The minimum amount of free space that we have seen. |
+ */ |
+ u32 mnMaster; |
+ |
+ /* |
+ ** iMaster is the index of the master chunk. Most new allocations |
+ ** occur off of this chunk. szMaster is the size (in Mem3Blocks) |
+ ** of the current master. iMaster is 0 if there is not master chunk. |
+ ** The master chunk is not in either the aiHash[] or aiSmall[]. |
+ */ |
+ u32 iMaster; |
+ u32 szMaster; |
+ |
+ /* |
+ ** Array of lists of free blocks according to the block size |
+ ** for smaller chunks, or a hash on the block size for larger |
+ ** chunks. |
+ */ |
+ u32 aiSmall[MX_SMALL-1]; /* For sizes 2 through MX_SMALL, inclusive */ |
+ u32 aiHash[N_HASH]; /* For sizes MX_SMALL+1 and larger */ |
+} mem3 = { 97535575 }; |
+ |
+#define mem3 GLOBAL(struct Mem3Global, mem3) |
+ |
+/* |
+** Unlink the chunk at mem3.aPool[i] from list it is currently |
+** on. *pRoot is the list that i is a member of. |
+*/ |
+static void memsys3UnlinkFromList(u32 i, u32 *pRoot){ |
+ u32 next = mem3.aPool[i].u.list.next; |
+ u32 prev = mem3.aPool[i].u.list.prev; |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ if( prev==0 ){ |
+ *pRoot = next; |
+ }else{ |
+ mem3.aPool[prev].u.list.next = next; |
+ } |
+ if( next ){ |
+ mem3.aPool[next].u.list.prev = prev; |
+ } |
+ mem3.aPool[i].u.list.next = 0; |
+ mem3.aPool[i].u.list.prev = 0; |
+} |
+ |
+/* |
+** Unlink the chunk at index i from |
+** whatever list is currently a member of. |
+*/ |
+static void memsys3Unlink(u32 i){ |
+ u32 size, hash; |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 ); |
+ assert( i>=1 ); |
+ size = mem3.aPool[i-1].u.hdr.size4x/4; |
+ assert( size==mem3.aPool[i+size-1].u.hdr.prevSize ); |
+ assert( size>=2 ); |
+ if( size <= MX_SMALL ){ |
+ memsys3UnlinkFromList(i, &mem3.aiSmall[size-2]); |
+ }else{ |
+ hash = size % N_HASH; |
+ memsys3UnlinkFromList(i, &mem3.aiHash[hash]); |
+ } |
+} |
+ |
+/* |
+** Link the chunk at mem3.aPool[i] so that is on the list rooted |
+** at *pRoot. |
+*/ |
+static void memsys3LinkIntoList(u32 i, u32 *pRoot){ |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ mem3.aPool[i].u.list.next = *pRoot; |
+ mem3.aPool[i].u.list.prev = 0; |
+ if( *pRoot ){ |
+ mem3.aPool[*pRoot].u.list.prev = i; |
+ } |
+ *pRoot = i; |
+} |
+ |
+/* |
+** Link the chunk at index i into either the appropriate |
+** small chunk list, or into the large chunk hash table. |
+*/ |
+static void memsys3Link(u32 i){ |
+ u32 size, hash; |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ assert( i>=1 ); |
+ assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 ); |
+ size = mem3.aPool[i-1].u.hdr.size4x/4; |
+ assert( size==mem3.aPool[i+size-1].u.hdr.prevSize ); |
+ assert( size>=2 ); |
+ if( size <= MX_SMALL ){ |
+ memsys3LinkIntoList(i, &mem3.aiSmall[size-2]); |
+ }else{ |
+ hash = size % N_HASH; |
+ memsys3LinkIntoList(i, &mem3.aiHash[hash]); |
+ } |
+} |
+ |
+/* |
+** If the STATIC_MEM mutex is not already held, obtain it now. The mutex |
+** will already be held (obtained by code in malloc.c) if |
+** sqlite3GlobalConfig.bMemStat is true. |
+*/ |
+static void memsys3Enter(void){ |
+ if( sqlite3GlobalConfig.bMemstat==0 && mem3.mutex==0 ){ |
+ mem3.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); |
+ } |
+ sqlite3_mutex_enter(mem3.mutex); |
+} |
+static void memsys3Leave(void){ |
+ sqlite3_mutex_leave(mem3.mutex); |
+} |
+ |
+/* |
+** Called when we are unable to satisfy an allocation of nBytes. |
+*/ |
+static void memsys3OutOfMemory(int nByte){ |
+ if( !mem3.alarmBusy ){ |
+ mem3.alarmBusy = 1; |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ sqlite3_mutex_leave(mem3.mutex); |
+ sqlite3_release_memory(nByte); |
+ sqlite3_mutex_enter(mem3.mutex); |
+ mem3.alarmBusy = 0; |
+ } |
+} |
+ |
+ |
+/* |
+** Chunk i is a free chunk that has been unlinked. Adjust its |
+** size parameters for check-out and return a pointer to the |
+** user portion of the chunk. |
+*/ |
+static void *memsys3Checkout(u32 i, u32 nBlock){ |
+ u32 x; |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ assert( i>=1 ); |
+ assert( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ); |
+ assert( mem3.aPool[i+nBlock-1].u.hdr.prevSize==nBlock ); |
+ x = mem3.aPool[i-1].u.hdr.size4x; |
+ mem3.aPool[i-1].u.hdr.size4x = nBlock*4 | 1 | (x&2); |
+ mem3.aPool[i+nBlock-1].u.hdr.prevSize = nBlock; |
+ mem3.aPool[i+nBlock-1].u.hdr.size4x |= 2; |
+ return &mem3.aPool[i]; |
+} |
+ |
+/* |
+** Carve a piece off of the end of the mem3.iMaster free chunk. |
+** Return a pointer to the new allocation. Or, if the master chunk |
+** is not large enough, return 0. |
+*/ |
+static void *memsys3FromMaster(u32 nBlock){ |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ assert( mem3.szMaster>=nBlock ); |
+ if( nBlock>=mem3.szMaster-1 ){ |
+ /* Use the entire master */ |
+ void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster); |
+ mem3.iMaster = 0; |
+ mem3.szMaster = 0; |
+ mem3.mnMaster = 0; |
+ return p; |
+ }else{ |
+ /* Split the master block. Return the tail. */ |
+ u32 newi, x; |
+ newi = mem3.iMaster + mem3.szMaster - nBlock; |
+ assert( newi > mem3.iMaster+1 ); |
+ mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock; |
+ mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2; |
+ mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1; |
+ mem3.szMaster -= nBlock; |
+ mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster; |
+ x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; |
+ mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; |
+ if( mem3.szMaster < mem3.mnMaster ){ |
+ mem3.mnMaster = mem3.szMaster; |
+ } |
+ return (void*)&mem3.aPool[newi]; |
+ } |
+} |
+ |
+/* |
+** *pRoot is the head of a list of free chunks of the same size |
+** or same size hash. In other words, *pRoot is an entry in either |
+** mem3.aiSmall[] or mem3.aiHash[]. |
+** |
+** This routine examines all entries on the given list and tries |
+** to coalesce each entries with adjacent free chunks. |
+** |
+** If it sees a chunk that is larger than mem3.iMaster, it replaces |
+** the current mem3.iMaster with the new larger chunk. In order for |
+** this mem3.iMaster replacement to work, the master chunk must be |
+** linked into the hash tables. That is not the normal state of |
+** affairs, of course. The calling routine must link the master |
+** chunk before invoking this routine, then must unlink the (possibly |
+** changed) master chunk once this routine has finished. |
+*/ |
+static void memsys3Merge(u32 *pRoot){ |
+ u32 iNext, prev, size, i, x; |
+ |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ for(i=*pRoot; i>0; i=iNext){ |
+ iNext = mem3.aPool[i].u.list.next; |
+ size = mem3.aPool[i-1].u.hdr.size4x; |
+ assert( (size&1)==0 ); |
+ if( (size&2)==0 ){ |
+ memsys3UnlinkFromList(i, pRoot); |
+ assert( i > mem3.aPool[i-1].u.hdr.prevSize ); |
+ prev = i - mem3.aPool[i-1].u.hdr.prevSize; |
+ if( prev==iNext ){ |
+ iNext = mem3.aPool[prev].u.list.next; |
+ } |
+ memsys3Unlink(prev); |
+ size = i + size/4 - prev; |
+ x = mem3.aPool[prev-1].u.hdr.size4x & 2; |
+ mem3.aPool[prev-1].u.hdr.size4x = size*4 | x; |
+ mem3.aPool[prev+size-1].u.hdr.prevSize = size; |
+ memsys3Link(prev); |
+ i = prev; |
+ }else{ |
+ size /= 4; |
+ } |
+ if( size>mem3.szMaster ){ |
+ mem3.iMaster = i; |
+ mem3.szMaster = size; |
+ } |
+ } |
+} |
+ |
+/* |
+** Return a block of memory of at least nBytes in size. |
+** Return NULL if unable. |
+** |
+** This function assumes that the necessary mutexes, if any, are |
+** already held by the caller. Hence "Unsafe". |
+*/ |
+static void *memsys3MallocUnsafe(int nByte){ |
+ u32 i; |
+ u32 nBlock; |
+ u32 toFree; |
+ |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ assert( sizeof(Mem3Block)==8 ); |
+ if( nByte<=12 ){ |
+ nBlock = 2; |
+ }else{ |
+ nBlock = (nByte + 11)/8; |
+ } |
+ assert( nBlock>=2 ); |
+ |
+ /* STEP 1: |
+ ** Look for an entry of the correct size in either the small |
+ ** chunk table or in the large chunk hash table. This is |
+ ** successful most of the time (about 9 times out of 10). |
+ */ |
+ if( nBlock <= MX_SMALL ){ |
+ i = mem3.aiSmall[nBlock-2]; |
+ if( i>0 ){ |
+ memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]); |
+ return memsys3Checkout(i, nBlock); |
+ } |
+ }else{ |
+ int hash = nBlock % N_HASH; |
+ for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){ |
+ if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){ |
+ memsys3UnlinkFromList(i, &mem3.aiHash[hash]); |
+ return memsys3Checkout(i, nBlock); |
+ } |
+ } |
+ } |
+ |
+ /* STEP 2: |
+ ** Try to satisfy the allocation by carving a piece off of the end |
+ ** of the master chunk. This step usually works if step 1 fails. |
+ */ |
+ if( mem3.szMaster>=nBlock ){ |
+ return memsys3FromMaster(nBlock); |
+ } |
+ |
+ |
+ /* STEP 3: |
+ ** Loop through the entire memory pool. Coalesce adjacent free |
+ ** chunks. Recompute the master chunk as the largest free chunk. |
+ ** Then try again to satisfy the allocation by carving a piece off |
+ ** of the end of the master chunk. This step happens very |
+ ** rarely (we hope!) |
+ */ |
+ for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){ |
+ memsys3OutOfMemory(toFree); |
+ if( mem3.iMaster ){ |
+ memsys3Link(mem3.iMaster); |
+ mem3.iMaster = 0; |
+ mem3.szMaster = 0; |
+ } |
+ for(i=0; i<N_HASH; i++){ |
+ memsys3Merge(&mem3.aiHash[i]); |
+ } |
+ for(i=0; i<MX_SMALL-1; i++){ |
+ memsys3Merge(&mem3.aiSmall[i]); |
+ } |
+ if( mem3.szMaster ){ |
+ memsys3Unlink(mem3.iMaster); |
+ if( mem3.szMaster>=nBlock ){ |
+ return memsys3FromMaster(nBlock); |
+ } |
+ } |
+ } |
+ |
+ /* If none of the above worked, then we fail. */ |
+ return 0; |
+} |
+ |
+/* |
+** Free an outstanding memory allocation. |
+** |
+** This function assumes that the necessary mutexes, if any, are |
+** already held by the caller. Hence "Unsafe". |
+*/ |
+static void memsys3FreeUnsafe(void *pOld){ |
+ Mem3Block *p = (Mem3Block*)pOld; |
+ int i; |
+ u32 size, x; |
+ assert( sqlite3_mutex_held(mem3.mutex) ); |
+ assert( p>mem3.aPool && p<&mem3.aPool[mem3.nPool] ); |
+ i = p - mem3.aPool; |
+ assert( (mem3.aPool[i-1].u.hdr.size4x&1)==1 ); |
+ size = mem3.aPool[i-1].u.hdr.size4x/4; |
+ assert( i+size<=mem3.nPool+1 ); |
+ mem3.aPool[i-1].u.hdr.size4x &= ~1; |
+ mem3.aPool[i+size-1].u.hdr.prevSize = size; |
+ mem3.aPool[i+size-1].u.hdr.size4x &= ~2; |
+ memsys3Link(i); |
+ |
+ /* Try to expand the master using the newly freed chunk */ |
+ if( mem3.iMaster ){ |
+ while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){ |
+ size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize; |
+ mem3.iMaster -= size; |
+ mem3.szMaster += size; |
+ memsys3Unlink(mem3.iMaster); |
+ x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; |
+ mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; |
+ mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; |
+ } |
+ x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; |
+ while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){ |
+ memsys3Unlink(mem3.iMaster+mem3.szMaster); |
+ mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4; |
+ mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; |
+ mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; |
+ } |
+ } |
+} |
+ |
+/* |
+** Return the size of an outstanding allocation, in bytes. The |
+** size returned omits the 8-byte header overhead. This only |
+** works for chunks that are currently checked out. |
+*/ |
+static int memsys3Size(void *p){ |
+ Mem3Block *pBlock; |
+ assert( p!=0 ); |
+ pBlock = (Mem3Block*)p; |
+ assert( (pBlock[-1].u.hdr.size4x&1)!=0 ); |
+ return (pBlock[-1].u.hdr.size4x&~3)*2 - 4; |
+} |
+ |
+/* |
+** Round up a request size to the next valid allocation size. |
+*/ |
+static int memsys3Roundup(int n){ |
+ if( n<=12 ){ |
+ return 12; |
+ }else{ |
+ return ((n+11)&~7) - 4; |
+ } |
+} |
+ |
+/* |
+** Allocate nBytes of memory. |
+*/ |
+static void *memsys3Malloc(int nBytes){ |
+ sqlite3_int64 *p; |
+ assert( nBytes>0 ); /* malloc.c filters out 0 byte requests */ |
+ memsys3Enter(); |
+ p = memsys3MallocUnsafe(nBytes); |
+ memsys3Leave(); |
+ return (void*)p; |
+} |
+ |
+/* |
+** Free memory. |
+*/ |
+static void memsys3Free(void *pPrior){ |
+ assert( pPrior ); |
+ memsys3Enter(); |
+ memsys3FreeUnsafe(pPrior); |
+ memsys3Leave(); |
+} |
+ |
+/* |
+** Change the size of an existing memory allocation |
+*/ |
+static void *memsys3Realloc(void *pPrior, int nBytes){ |
+ int nOld; |
+ void *p; |
+ if( pPrior==0 ){ |
+ return sqlite3_malloc(nBytes); |
+ } |
+ if( nBytes<=0 ){ |
+ sqlite3_free(pPrior); |
+ return 0; |
+ } |
+ nOld = memsys3Size(pPrior); |
+ if( nBytes<=nOld && nBytes>=nOld-128 ){ |
+ return pPrior; |
+ } |
+ memsys3Enter(); |
+ p = memsys3MallocUnsafe(nBytes); |
+ if( p ){ |
+ if( nOld<nBytes ){ |
+ memcpy(p, pPrior, nOld); |
+ }else{ |
+ memcpy(p, pPrior, nBytes); |
+ } |
+ memsys3FreeUnsafe(pPrior); |
+ } |
+ memsys3Leave(); |
+ return p; |
+} |
+ |
+/* |
+** Initialize this module. |
+*/ |
+static int memsys3Init(void *NotUsed){ |
+ UNUSED_PARAMETER(NotUsed); |
+ if( !sqlite3GlobalConfig.pHeap ){ |
+ return SQLITE_ERROR; |
+ } |
+ |
+ /* Store a pointer to the memory block in global structure mem3. */ |
+ assert( sizeof(Mem3Block)==8 ); |
+ mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap; |
+ mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2; |
+ |
+ /* Initialize the master block. */ |
+ mem3.szMaster = mem3.nPool; |
+ mem3.mnMaster = mem3.szMaster; |
+ mem3.iMaster = 1; |
+ mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2; |
+ mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool; |
+ mem3.aPool[mem3.nPool].u.hdr.size4x = 1; |
+ |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Deinitialize this module. |
+*/ |
+static void memsys3Shutdown(void *NotUsed){ |
+ UNUSED_PARAMETER(NotUsed); |
+ mem3.mutex = 0; |
+ return; |
+} |
+ |
+ |
+ |
+/* |
+** Open the file indicated and write a log of all unfreed memory |
+** allocations into that log. |
+*/ |
+SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){ |
+#ifdef SQLITE_DEBUG |
+ FILE *out; |
+ u32 i, j; |
+ u32 size; |
+ if( zFilename==0 || zFilename[0]==0 ){ |
+ out = stdout; |
+ }else{ |
+ out = fopen(zFilename, "w"); |
+ if( out==0 ){ |
+ fprintf(stderr, "** Unable to output memory debug output log: %s **\n", |
+ zFilename); |
+ return; |
+ } |
+ } |
+ memsys3Enter(); |
+ fprintf(out, "CHUNKS:\n"); |
+ for(i=1; i<=mem3.nPool; i+=size/4){ |
+ size = mem3.aPool[i-1].u.hdr.size4x; |
+ if( size/4<=1 ){ |
+ fprintf(out, "%p size error\n", &mem3.aPool[i]); |
+ assert( 0 ); |
+ break; |
+ } |
+ if( (size&1)==0 && mem3.aPool[i+size/4-1].u.hdr.prevSize!=size/4 ){ |
+ fprintf(out, "%p tail size does not match\n", &mem3.aPool[i]); |
+ assert( 0 ); |
+ break; |
+ } |
+ if( ((mem3.aPool[i+size/4-1].u.hdr.size4x&2)>>1)!=(size&1) ){ |
+ fprintf(out, "%p tail checkout bit is incorrect\n", &mem3.aPool[i]); |
+ assert( 0 ); |
+ break; |
+ } |
+ if( size&1 ){ |
+ fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8); |
+ }else{ |
+ fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8, |
+ i==mem3.iMaster ? " **master**" : ""); |
+ } |
+ } |
+ for(i=0; i<MX_SMALL-1; i++){ |
+ if( mem3.aiSmall[i]==0 ) continue; |
+ fprintf(out, "small(%2d):", i); |
+ for(j = mem3.aiSmall[i]; j>0; j=mem3.aPool[j].u.list.next){ |
+ fprintf(out, " %p(%d)", &mem3.aPool[j], |
+ (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); |
+ } |
+ fprintf(out, "\n"); |
+ } |
+ for(i=0; i<N_HASH; i++){ |
+ if( mem3.aiHash[i]==0 ) continue; |
+ fprintf(out, "hash(%2d):", i); |
+ for(j = mem3.aiHash[i]; j>0; j=mem3.aPool[j].u.list.next){ |
+ fprintf(out, " %p(%d)", &mem3.aPool[j], |
+ (mem3.aPool[j-1].u.hdr.size4x/4)*8-8); |
+ } |
+ fprintf(out, "\n"); |
+ } |
+ fprintf(out, "master=%d\n", mem3.iMaster); |
+ fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8); |
+ fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8); |
+ sqlite3_mutex_leave(mem3.mutex); |
+ if( out==stdout ){ |
+ fflush(stdout); |
+ }else{ |
+ fclose(out); |
+ } |
+#else |
+ UNUSED_PARAMETER(zFilename); |
+#endif |
+} |
+ |
+/* |
+** This routine is the only routine in this file with external |
+** linkage. |
+** |
+** Populate the low-level memory allocation function pointers in |
+** sqlite3GlobalConfig.m with pointers to the routines in this file. The |
+** arguments specify the block of memory to manage. |
+** |
+** This routine is only called by sqlite3_config(), and therefore |
+** is not required to be threadsafe (it is not). |
+*/ |
+SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){ |
+ static const sqlite3_mem_methods mempoolMethods = { |
+ memsys3Malloc, |
+ memsys3Free, |
+ memsys3Realloc, |
+ memsys3Size, |
+ memsys3Roundup, |
+ memsys3Init, |
+ memsys3Shutdown, |
+ 0 |
+ }; |
+ return &mempoolMethods; |
+} |
+ |
+#endif /* SQLITE_ENABLE_MEMSYS3 */ |
+ |
+/************** End of mem3.c ************************************************/ |
+/************** Begin file mem5.c ********************************************/ |
+/* |
+** 2007 October 14 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file contains the C functions that implement a memory |
+** allocation subsystem for use by SQLite. |
+** |
+** This version of the memory allocation subsystem omits all |
+** use of malloc(). The application gives SQLite a block of memory |
+** before calling sqlite3_initialize() from which allocations |
+** are made and returned by the xMalloc() and xRealloc() |
+** implementations. Once sqlite3_initialize() has been called, |
+** the amount of memory available to SQLite is fixed and cannot |
+** be changed. |
+** |
+** This version of the memory allocation subsystem is included |
+** in the build only if SQLITE_ENABLE_MEMSYS5 is defined. |
+** |
+** This memory allocator uses the following algorithm: |
+** |
+** 1. All memory allocation sizes are rounded up to a power of 2. |
+** |
+** 2. If two adjacent free blocks are the halves of a larger block, |
+** then the two blocks are coalesced into the single larger block. |
+** |
+** 3. New memory is allocated from the first available free block. |
+** |
+** This algorithm is described in: J. M. Robson. "Bounds for Some Functions |
+** Concerning Dynamic Storage Allocation". Journal of the Association for |
+** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499. |
+** |
+** Let n be the size of the largest allocation divided by the minimum |
+** allocation size (after rounding all sizes up to a power of 2.) Let M |
+** be the maximum amount of memory ever outstanding at one time. Let |
+** N be the total amount of memory available for allocation. Robson |
+** proved that this memory allocator will never breakdown due to |
+** fragmentation as long as the following constraint holds: |
+** |
+** N >= M*(1 + log2(n)/2) - n + 1 |
+** |
+** The sqlite3_status() logic tracks the maximum values of n and M so |
+** that an application can, at any time, verify this constraint. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* |
+** This version of the memory allocator is used only when |
+** SQLITE_ENABLE_MEMSYS5 is defined. |
+*/ |
+#ifdef SQLITE_ENABLE_MEMSYS5 |
+ |
+/* |
+** A minimum allocation is an instance of the following structure. |
+** Larger allocations are an array of these structures where the |
+** size of the array is a power of 2. |
+** |
+** The size of this object must be a power of two. That fact is |
+** verified in memsys5Init(). |
+*/ |
+typedef struct Mem5Link Mem5Link; |
+struct Mem5Link { |
+ int next; /* Index of next free chunk */ |
+ int prev; /* Index of previous free chunk */ |
+}; |
+ |
+/* |
+** Maximum size of any allocation is ((1<<LOGMAX)*mem5.szAtom). Since |
+** mem5.szAtom is always at least 8 and 32-bit integers are used, |
+** it is not actually possible to reach this limit. |
+*/ |
+#define LOGMAX 30 |
+ |
+/* |
+** Masks used for mem5.aCtrl[] elements. |
+*/ |
+#define CTRL_LOGSIZE 0x1f /* Log2 Size of this block */ |
+#define CTRL_FREE 0x20 /* True if not checked out */ |
+ |
+/* |
+** All of the static variables used by this module are collected |
+** into a single structure named "mem5". This is to keep the |
+** static variables organized and to reduce namespace pollution |
+** when this module is combined with other in the amalgamation. |
+*/ |
+static SQLITE_WSD struct Mem5Global { |
+ /* |
+ ** Memory available for allocation |
+ */ |
+ int szAtom; /* Smallest possible allocation in bytes */ |
+ int nBlock; /* Number of szAtom sized blocks in zPool */ |
+ u8 *zPool; /* Memory available to be allocated */ |
+ |
+ /* |
+ ** Mutex to control access to the memory allocation subsystem. |
+ */ |
+ sqlite3_mutex *mutex; |
+ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
+ /* |
+ ** Performance statistics |
+ */ |
+ u64 nAlloc; /* Total number of calls to malloc */ |
+ u64 totalAlloc; /* Total of all malloc calls - includes internal frag */ |
+ u64 totalExcess; /* Total internal fragmentation */ |
+ u32 currentOut; /* Current checkout, including internal fragmentation */ |
+ u32 currentCount; /* Current number of distinct checkouts */ |
+ u32 maxOut; /* Maximum instantaneous currentOut */ |
+ u32 maxCount; /* Maximum instantaneous currentCount */ |
+ u32 maxRequest; /* Largest allocation (exclusive of internal frag) */ |
+#endif |
+ |
+ /* |
+ ** Lists of free blocks. aiFreelist[0] is a list of free blocks of |
+ ** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2. |
+ ** aiFreelist[2] holds free blocks of size szAtom*4. And so forth. |
+ */ |
+ int aiFreelist[LOGMAX+1]; |
+ |
+ /* |
+ ** Space for tracking which blocks are checked out and the size |
+ ** of each block. One byte per block. |
+ */ |
+ u8 *aCtrl; |
+ |
+} mem5; |
+ |
+/* |
+** Access the static variable through a macro for SQLITE_OMIT_WSD. |
+*/ |
+#define mem5 GLOBAL(struct Mem5Global, mem5) |
+ |
+/* |
+** Assuming mem5.zPool is divided up into an array of Mem5Link |
+** structures, return a pointer to the idx-th such link. |
+*/ |
+#define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.szAtom])) |
+ |
+/* |
+** Unlink the chunk at mem5.aPool[i] from list it is currently |
+** on. It should be found on mem5.aiFreelist[iLogsize]. |
+*/ |
+static void memsys5Unlink(int i, int iLogsize){ |
+ int next, prev; |
+ assert( i>=0 && i<mem5.nBlock ); |
+ assert( iLogsize>=0 && iLogsize<=LOGMAX ); |
+ assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize ); |
+ |
+ next = MEM5LINK(i)->next; |
+ prev = MEM5LINK(i)->prev; |
+ if( prev<0 ){ |
+ mem5.aiFreelist[iLogsize] = next; |
+ }else{ |
+ MEM5LINK(prev)->next = next; |
+ } |
+ if( next>=0 ){ |
+ MEM5LINK(next)->prev = prev; |
+ } |
+} |
+ |
+/* |
+** Link the chunk at mem5.aPool[i] so that is on the iLogsize |
+** free list. |
+*/ |
+static void memsys5Link(int i, int iLogsize){ |
+ int x; |
+ assert( sqlite3_mutex_held(mem5.mutex) ); |
+ assert( i>=0 && i<mem5.nBlock ); |
+ assert( iLogsize>=0 && iLogsize<=LOGMAX ); |
+ assert( (mem5.aCtrl[i] & CTRL_LOGSIZE)==iLogsize ); |
+ |
+ x = MEM5LINK(i)->next = mem5.aiFreelist[iLogsize]; |
+ MEM5LINK(i)->prev = -1; |
+ if( x>=0 ){ |
+ assert( x<mem5.nBlock ); |
+ MEM5LINK(x)->prev = i; |
+ } |
+ mem5.aiFreelist[iLogsize] = i; |
+} |
+ |
+/* |
+** Obtain or release the mutex needed to access global data structures. |
+*/ |
+static void memsys5Enter(void){ |
+ sqlite3_mutex_enter(mem5.mutex); |
+} |
+static void memsys5Leave(void){ |
+ sqlite3_mutex_leave(mem5.mutex); |
+} |
+ |
+/* |
+** Return the size of an outstanding allocation, in bytes. |
+** This only works for chunks that are currently checked out. |
+*/ |
+static int memsys5Size(void *p){ |
+ int iSize, i; |
+ assert( p!=0 ); |
+ i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom); |
+ assert( i>=0 && i<mem5.nBlock ); |
+ iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE)); |
+ return iSize; |
+} |
+ |
+/* |
+** Return a block of memory of at least nBytes in size. |
+** Return NULL if unable. Return NULL if nBytes==0. |
+** |
+** The caller guarantees that nByte is positive. |
+** |
+** The caller has obtained a mutex prior to invoking this |
+** routine so there is never any chance that two or more |
+** threads can be in this routine at the same time. |
+*/ |
+static void *memsys5MallocUnsafe(int nByte){ |
+ int i; /* Index of a mem5.aPool[] slot */ |
+ int iBin; /* Index into mem5.aiFreelist[] */ |
+ int iFullSz; /* Size of allocation rounded up to power of 2 */ |
+ int iLogsize; /* Log2 of iFullSz/POW2_MIN */ |
+ |
+ /* nByte must be a positive */ |
+ assert( nByte>0 ); |
+ |
+ /* No more than 1GiB per allocation */ |
+ if( nByte > 0x40000000 ) return 0; |
+ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
+ /* Keep track of the maximum allocation request. Even unfulfilled |
+ ** requests are counted */ |
+ if( (u32)nByte>mem5.maxRequest ){ |
+ mem5.maxRequest = nByte; |
+ } |
+#endif |
+ |
+ |
+ /* Round nByte up to the next valid power of two */ |
+ for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz<nByte; iFullSz*=2,iLogsize++){} |
+ |
+ /* Make sure mem5.aiFreelist[iLogsize] contains at least one free |
+ ** block. If not, then split a block of the next larger power of |
+ ** two in order to create a new free block of size iLogsize. |
+ */ |
+ for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){} |
+ if( iBin>LOGMAX ){ |
+ testcase( sqlite3GlobalConfig.xLog!=0 ); |
+ sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte); |
+ return 0; |
+ } |
+ i = mem5.aiFreelist[iBin]; |
+ memsys5Unlink(i, iBin); |
+ while( iBin>iLogsize ){ |
+ int newSize; |
+ |
+ iBin--; |
+ newSize = 1 << iBin; |
+ mem5.aCtrl[i+newSize] = CTRL_FREE | iBin; |
+ memsys5Link(i+newSize, iBin); |
+ } |
+ mem5.aCtrl[i] = iLogsize; |
+ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
+ /* Update allocator performance statistics. */ |
+ mem5.nAlloc++; |
+ mem5.totalAlloc += iFullSz; |
+ mem5.totalExcess += iFullSz - nByte; |
+ mem5.currentCount++; |
+ mem5.currentOut += iFullSz; |
+ if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount; |
+ if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut; |
+#endif |
+ |
+#ifdef SQLITE_DEBUG |
+ /* Make sure the allocated memory does not assume that it is set to zero |
+ ** or retains a value from a previous allocation */ |
+ memset(&mem5.zPool[i*mem5.szAtom], 0xAA, iFullSz); |
+#endif |
+ |
+ /* Return a pointer to the allocated memory. */ |
+ return (void*)&mem5.zPool[i*mem5.szAtom]; |
+} |
+ |
+/* |
+** Free an outstanding memory allocation. |
+*/ |
+static void memsys5FreeUnsafe(void *pOld){ |
+ u32 size, iLogsize; |
+ int iBlock; |
+ |
+ /* Set iBlock to the index of the block pointed to by pOld in |
+ ** the array of mem5.szAtom byte blocks pointed to by mem5.zPool. |
+ */ |
+ iBlock = (int)(((u8 *)pOld-mem5.zPool)/mem5.szAtom); |
+ |
+ /* Check that the pointer pOld points to a valid, non-free block. */ |
+ assert( iBlock>=0 && iBlock<mem5.nBlock ); |
+ assert( ((u8 *)pOld-mem5.zPool)%mem5.szAtom==0 ); |
+ assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 ); |
+ |
+ iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE; |
+ size = 1<<iLogsize; |
+ assert( iBlock+size-1<(u32)mem5.nBlock ); |
+ |
+ mem5.aCtrl[iBlock] |= CTRL_FREE; |
+ mem5.aCtrl[iBlock+size-1] |= CTRL_FREE; |
+ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
+ assert( mem5.currentCount>0 ); |
+ assert( mem5.currentOut>=(size*mem5.szAtom) ); |
+ mem5.currentCount--; |
+ mem5.currentOut -= size*mem5.szAtom; |
+ assert( mem5.currentOut>0 || mem5.currentCount==0 ); |
+ assert( mem5.currentCount>0 || mem5.currentOut==0 ); |
+#endif |
+ |
+ mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize; |
+ while( ALWAYS(iLogsize<LOGMAX) ){ |
+ int iBuddy; |
+ if( (iBlock>>iLogsize) & 1 ){ |
+ iBuddy = iBlock - size; |
+ assert( iBuddy>=0 ); |
+ }else{ |
+ iBuddy = iBlock + size; |
+ if( iBuddy>=mem5.nBlock ) break; |
+ } |
+ if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break; |
+ memsys5Unlink(iBuddy, iLogsize); |
+ iLogsize++; |
+ if( iBuddy<iBlock ){ |
+ mem5.aCtrl[iBuddy] = CTRL_FREE | iLogsize; |
+ mem5.aCtrl[iBlock] = 0; |
+ iBlock = iBuddy; |
+ }else{ |
+ mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize; |
+ mem5.aCtrl[iBuddy] = 0; |
+ } |
+ size *= 2; |
+ } |
+ |
+#ifdef SQLITE_DEBUG |
+ /* Overwrite freed memory with the 0x55 bit pattern to verify that it is |
+ ** not used after being freed */ |
+ memset(&mem5.zPool[iBlock*mem5.szAtom], 0x55, size); |
+#endif |
+ |
+ memsys5Link(iBlock, iLogsize); |
+} |
+ |
+/* |
+** Allocate nBytes of memory. |
+*/ |
+static void *memsys5Malloc(int nBytes){ |
+ sqlite3_int64 *p = 0; |
+ if( nBytes>0 ){ |
+ memsys5Enter(); |
+ p = memsys5MallocUnsafe(nBytes); |
+ memsys5Leave(); |
+ } |
+ return (void*)p; |
+} |
+ |
+/* |
+** Free memory. |
+** |
+** The outer layer memory allocator prevents this routine from |
+** being called with pPrior==0. |
+*/ |
+static void memsys5Free(void *pPrior){ |
+ assert( pPrior!=0 ); |
+ memsys5Enter(); |
+ memsys5FreeUnsafe(pPrior); |
+ memsys5Leave(); |
+} |
+ |
+/* |
+** Change the size of an existing memory allocation. |
+** |
+** The outer layer memory allocator prevents this routine from |
+** being called with pPrior==0. |
+** |
+** nBytes is always a value obtained from a prior call to |
+** memsys5Round(). Hence nBytes is always a non-negative power |
+** of two. If nBytes==0 that means that an oversize allocation |
+** (an allocation larger than 0x40000000) was requested and this |
+** routine should return 0 without freeing pPrior. |
+*/ |
+static void *memsys5Realloc(void *pPrior, int nBytes){ |
+ int nOld; |
+ void *p; |
+ assert( pPrior!=0 ); |
+ assert( (nBytes&(nBytes-1))==0 ); /* EV: R-46199-30249 */ |
+ assert( nBytes>=0 ); |
+ if( nBytes==0 ){ |
+ return 0; |
+ } |
+ nOld = memsys5Size(pPrior); |
+ if( nBytes<=nOld ){ |
+ return pPrior; |
+ } |
+ p = memsys5Malloc(nBytes); |
+ if( p ){ |
+ memcpy(p, pPrior, nOld); |
+ memsys5Free(pPrior); |
+ } |
+ return p; |
+} |
+ |
+/* |
+** Round up a request size to the next valid allocation size. If |
+** the allocation is too large to be handled by this allocation system, |
+** return 0. |
+** |
+** All allocations must be a power of two and must be expressed by a |
+** 32-bit signed integer. Hence the largest allocation is 0x40000000 |
+** or 1073741824 bytes. |
+*/ |
+static int memsys5Roundup(int n){ |
+ int iFullSz; |
+ if( n > 0x40000000 ) return 0; |
+ for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2); |
+ return iFullSz; |
+} |
+ |
+/* |
+** Return the ceiling of the logarithm base 2 of iValue. |
+** |
+** Examples: memsys5Log(1) -> 0 |
+** memsys5Log(2) -> 1 |
+** memsys5Log(4) -> 2 |
+** memsys5Log(5) -> 3 |
+** memsys5Log(8) -> 3 |
+** memsys5Log(9) -> 4 |
+*/ |
+static int memsys5Log(int iValue){ |
+ int iLog; |
+ for(iLog=0; (iLog<(int)((sizeof(int)*8)-1)) && (1<<iLog)<iValue; iLog++); |
+ return iLog; |
+} |
+ |
+/* |
+** Initialize the memory allocator. |
+** |
+** This routine is not threadsafe. The caller must be holding a mutex |
+** to prevent multiple threads from entering at the same time. |
+*/ |
+static int memsys5Init(void *NotUsed){ |
+ int ii; /* Loop counter */ |
+ int nByte; /* Number of bytes of memory available to this allocator */ |
+ u8 *zByte; /* Memory usable by this allocator */ |
+ int nMinLog; /* Log base 2 of minimum allocation size in bytes */ |
+ int iOffset; /* An offset into mem5.aCtrl[] */ |
+ |
+ UNUSED_PARAMETER(NotUsed); |
+ |
+ /* For the purposes of this routine, disable the mutex */ |
+ mem5.mutex = 0; |
+ |
+ /* The size of a Mem5Link object must be a power of two. Verify that |
+ ** this is case. |
+ */ |
+ assert( (sizeof(Mem5Link)&(sizeof(Mem5Link)-1))==0 ); |
+ |
+ nByte = sqlite3GlobalConfig.nHeap; |
+ zByte = (u8*)sqlite3GlobalConfig.pHeap; |
+ assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */ |
+ |
+ /* boundaries on sqlite3GlobalConfig.mnReq are enforced in sqlite3_config() */ |
+ nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq); |
+ mem5.szAtom = (1<<nMinLog); |
+ while( (int)sizeof(Mem5Link)>mem5.szAtom ){ |
+ mem5.szAtom = mem5.szAtom << 1; |
+ } |
+ |
+ mem5.nBlock = (nByte / (mem5.szAtom+sizeof(u8))); |
+ mem5.zPool = zByte; |
+ mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.szAtom]; |
+ |
+ for(ii=0; ii<=LOGMAX; ii++){ |
+ mem5.aiFreelist[ii] = -1; |
+ } |
+ |
+ iOffset = 0; |
+ for(ii=LOGMAX; ii>=0; ii--){ |
+ int nAlloc = (1<<ii); |
+ if( (iOffset+nAlloc)<=mem5.nBlock ){ |
+ mem5.aCtrl[iOffset] = ii | CTRL_FREE; |
+ memsys5Link(iOffset, ii); |
+ iOffset += nAlloc; |
+ } |
+ assert((iOffset+nAlloc)>mem5.nBlock); |
+ } |
+ |
+ /* If a mutex is required for normal operation, allocate one */ |
+ if( sqlite3GlobalConfig.bMemstat==0 ){ |
+ mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); |
+ } |
+ |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Deinitialize this module. |
+*/ |
+static void memsys5Shutdown(void *NotUsed){ |
+ UNUSED_PARAMETER(NotUsed); |
+ mem5.mutex = 0; |
+ return; |
+} |
+ |
+#ifdef SQLITE_TEST |
+/* |
+** Open the file indicated and write a log of all unfreed memory |
+** allocations into that log. |
+*/ |
+SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){ |
+ FILE *out; |
+ int i, j, n; |
+ int nMinLog; |
+ |
+ if( zFilename==0 || zFilename[0]==0 ){ |
+ out = stdout; |
+ }else{ |
+ out = fopen(zFilename, "w"); |
+ if( out==0 ){ |
+ fprintf(stderr, "** Unable to output memory debug output log: %s **\n", |
+ zFilename); |
+ return; |
+ } |
+ } |
+ memsys5Enter(); |
+ nMinLog = memsys5Log(mem5.szAtom); |
+ for(i=0; i<=LOGMAX && i+nMinLog<32; i++){ |
+ for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){} |
+ fprintf(out, "freelist items of size %d: %d\n", mem5.szAtom << i, n); |
+ } |
+ fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc); |
+ fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc); |
+ fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess); |
+ fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut); |
+ fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount); |
+ fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut); |
+ fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount); |
+ fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest); |
+ memsys5Leave(); |
+ if( out==stdout ){ |
+ fflush(stdout); |
+ }else{ |
+ fclose(out); |
+ } |
+} |
+#endif |
+ |
+/* |
+** This routine is the only routine in this file with external |
+** linkage. It returns a pointer to a static sqlite3_mem_methods |
+** struct populated with the memsys5 methods. |
+*/ |
+SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){ |
+ static const sqlite3_mem_methods memsys5Methods = { |
+ memsys5Malloc, |
+ memsys5Free, |
+ memsys5Realloc, |
+ memsys5Size, |
+ memsys5Roundup, |
+ memsys5Init, |
+ memsys5Shutdown, |
+ 0 |
+ }; |
+ return &memsys5Methods; |
+} |
+ |
+#endif /* SQLITE_ENABLE_MEMSYS5 */ |
+ |
+/************** End of mem5.c ************************************************/ |
+/************** Begin file mutex.c *******************************************/ |
+/* |
+** 2007 August 14 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file contains the C functions that implement mutexes. |
+** |
+** This file contains code that is common across all mutex implementations. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT) |
+/* |
+** For debugging purposes, record when the mutex subsystem is initialized |
+** and uninitialized so that we can assert() if there is an attempt to |
+** allocate a mutex while the system is uninitialized. |
+*/ |
+static SQLITE_WSD int mutexIsInit = 0; |
+#endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */ |
+ |
+ |
+#ifndef SQLITE_MUTEX_OMIT |
+/* |
+** Initialize the mutex system. |
+*/ |
+SQLITE_PRIVATE int sqlite3MutexInit(void){ |
+ int rc = SQLITE_OK; |
+ if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){ |
+ /* If the xMutexAlloc method has not been set, then the user did not |
+ ** install a mutex implementation via sqlite3_config() prior to |
+ ** sqlite3_initialize() being called. This block copies pointers to |
+ ** the default implementation into the sqlite3GlobalConfig structure. |
+ */ |
+ sqlite3_mutex_methods const *pFrom; |
+ sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex; |
+ |
+ if( sqlite3GlobalConfig.bCoreMutex ){ |
+ pFrom = sqlite3DefaultMutex(); |
+ }else{ |
+ pFrom = sqlite3NoopMutex(); |
+ } |
+ pTo->xMutexInit = pFrom->xMutexInit; |
+ pTo->xMutexEnd = pFrom->xMutexEnd; |
+ pTo->xMutexFree = pFrom->xMutexFree; |
+ pTo->xMutexEnter = pFrom->xMutexEnter; |
+ pTo->xMutexTry = pFrom->xMutexTry; |
+ pTo->xMutexLeave = pFrom->xMutexLeave; |
+ pTo->xMutexHeld = pFrom->xMutexHeld; |
+ pTo->xMutexNotheld = pFrom->xMutexNotheld; |
+ sqlite3MemoryBarrier(); |
+ pTo->xMutexAlloc = pFrom->xMutexAlloc; |
+ } |
+ assert( sqlite3GlobalConfig.mutex.xMutexInit ); |
+ rc = sqlite3GlobalConfig.mutex.xMutexInit(); |
+ |
+#ifdef SQLITE_DEBUG |
+ GLOBAL(int, mutexIsInit) = 1; |
+#endif |
+ |
+ return rc; |
+} |
+ |
+/* |
+** Shutdown the mutex system. This call frees resources allocated by |
+** sqlite3MutexInit(). |
+*/ |
+SQLITE_PRIVATE int sqlite3MutexEnd(void){ |
+ int rc = SQLITE_OK; |
+ if( sqlite3GlobalConfig.mutex.xMutexEnd ){ |
+ rc = sqlite3GlobalConfig.mutex.xMutexEnd(); |
+ } |
+ |
+#ifdef SQLITE_DEBUG |
+ GLOBAL(int, mutexIsInit) = 0; |
+#endif |
+ |
+ return rc; |
+} |
+ |
+/* |
+** Retrieve a pointer to a static mutex or allocate a new dynamic one. |
+*/ |
+SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){ |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; |
+ if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0; |
+#endif |
+ assert( sqlite3GlobalConfig.mutex.xMutexAlloc ); |
+ return sqlite3GlobalConfig.mutex.xMutexAlloc(id); |
+} |
+ |
+SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){ |
+ if( !sqlite3GlobalConfig.bCoreMutex ){ |
+ return 0; |
+ } |
+ assert( GLOBAL(int, mutexIsInit) ); |
+ assert( sqlite3GlobalConfig.mutex.xMutexAlloc ); |
+ return sqlite3GlobalConfig.mutex.xMutexAlloc(id); |
+} |
+ |
+/* |
+** Free a dynamic mutex. |
+*/ |
+SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){ |
+ if( p ){ |
+ assert( sqlite3GlobalConfig.mutex.xMutexFree ); |
+ sqlite3GlobalConfig.mutex.xMutexFree(p); |
+ } |
+} |
+ |
+/* |
+** Obtain the mutex p. If some other thread already has the mutex, block |
+** until it can be obtained. |
+*/ |
+SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){ |
+ if( p ){ |
+ assert( sqlite3GlobalConfig.mutex.xMutexEnter ); |
+ sqlite3GlobalConfig.mutex.xMutexEnter(p); |
+ } |
+} |
+ |
+/* |
+** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another |
+** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY. |
+*/ |
+SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){ |
+ int rc = SQLITE_OK; |
+ if( p ){ |
+ assert( sqlite3GlobalConfig.mutex.xMutexTry ); |
+ return sqlite3GlobalConfig.mutex.xMutexTry(p); |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** The sqlite3_mutex_leave() routine exits a mutex that was previously |
+** entered by the same thread. The behavior is undefined if the mutex |
+** is not currently entered. If a NULL pointer is passed as an argument |
+** this function is a no-op. |
+*/ |
+SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){ |
+ if( p ){ |
+ assert( sqlite3GlobalConfig.mutex.xMutexLeave ); |
+ sqlite3GlobalConfig.mutex.xMutexLeave(p); |
+ } |
+} |
+ |
+#ifndef NDEBUG |
+/* |
+** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are |
+** intended for use inside assert() statements. |
+*/ |
+SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){ |
+ assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld ); |
+ return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p); |
+} |
+SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ |
+ assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld ); |
+ return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p); |
+} |
+#endif |
+ |
+#endif /* !defined(SQLITE_MUTEX_OMIT) */ |
+ |
+/************** End of mutex.c ***********************************************/ |
+/************** Begin file mutex_noop.c **************************************/ |
+/* |
+** 2008 October 07 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file contains the C functions that implement mutexes. |
+** |
+** This implementation in this file does not provide any mutual |
+** exclusion and is thus suitable for use only in applications |
+** that use SQLite in a single thread. The routines defined |
+** here are place-holders. Applications can substitute working |
+** mutex routines at start-time using the |
+** |
+** sqlite3_config(SQLITE_CONFIG_MUTEX,...) |
+** |
+** interface. |
+** |
+** If compiled with SQLITE_DEBUG, then additional logic is inserted |
+** that does error checking on mutexes to make sure they are being |
+** called correctly. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+#ifndef SQLITE_MUTEX_OMIT |
+ |
+#ifndef SQLITE_DEBUG |
+/* |
+** Stub routines for all mutex methods. |
+** |
+** This routines provide no mutual exclusion or error checking. |
+*/ |
+static int noopMutexInit(void){ return SQLITE_OK; } |
+static int noopMutexEnd(void){ return SQLITE_OK; } |
+static sqlite3_mutex *noopMutexAlloc(int id){ |
+ UNUSED_PARAMETER(id); |
+ return (sqlite3_mutex*)8; |
+} |
+static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } |
+static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } |
+static int noopMutexTry(sqlite3_mutex *p){ |
+ UNUSED_PARAMETER(p); |
+ return SQLITE_OK; |
+} |
+static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } |
+ |
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){ |
+ static const sqlite3_mutex_methods sMutex = { |
+ noopMutexInit, |
+ noopMutexEnd, |
+ noopMutexAlloc, |
+ noopMutexFree, |
+ noopMutexEnter, |
+ noopMutexTry, |
+ noopMutexLeave, |
+ |
+ 0, |
+ 0, |
+ }; |
+ |
+ return &sMutex; |
+} |
+#endif /* !SQLITE_DEBUG */ |
+ |
+#ifdef SQLITE_DEBUG |
+/* |
+** In this implementation, error checking is provided for testing |
+** and debugging purposes. The mutexes still do not provide any |
+** mutual exclusion. |
+*/ |
+ |
+/* |
+** The mutex object |
+*/ |
+typedef struct sqlite3_debug_mutex { |
+ int id; /* The mutex type */ |
+ int cnt; /* Number of entries without a matching leave */ |
+} sqlite3_debug_mutex; |
+ |
+/* |
+** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are |
+** intended for use inside assert() statements. |
+*/ |
+static int debugMutexHeld(sqlite3_mutex *pX){ |
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; |
+ return p==0 || p->cnt>0; |
+} |
+static int debugMutexNotheld(sqlite3_mutex *pX){ |
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; |
+ return p==0 || p->cnt==0; |
+} |
+ |
+/* |
+** Initialize and deinitialize the mutex subsystem. |
+*/ |
+static int debugMutexInit(void){ return SQLITE_OK; } |
+static int debugMutexEnd(void){ return SQLITE_OK; } |
+ |
+/* |
+** The sqlite3_mutex_alloc() routine allocates a new |
+** mutex and returns a pointer to it. If it returns NULL |
+** that means that a mutex could not be allocated. |
+*/ |
+static sqlite3_mutex *debugMutexAlloc(int id){ |
+ static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1]; |
+ sqlite3_debug_mutex *pNew = 0; |
+ switch( id ){ |
+ case SQLITE_MUTEX_FAST: |
+ case SQLITE_MUTEX_RECURSIVE: { |
+ pNew = sqlite3Malloc(sizeof(*pNew)); |
+ if( pNew ){ |
+ pNew->id = id; |
+ pNew->cnt = 0; |
+ } |
+ break; |
+ } |
+ default: { |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( id-2<0 || id-2>=ArraySize(aStatic) ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+ pNew = &aStatic[id-2]; |
+ pNew->id = id; |
+ break; |
+ } |
+ } |
+ return (sqlite3_mutex*)pNew; |
+} |
+ |
+/* |
+** This routine deallocates a previously allocated mutex. |
+*/ |
+static void debugMutexFree(sqlite3_mutex *pX){ |
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; |
+ assert( p->cnt==0 ); |
+ if( p->id==SQLITE_MUTEX_RECURSIVE || p->id==SQLITE_MUTEX_FAST ){ |
+ sqlite3_free(p); |
+ }else{ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ (void)SQLITE_MISUSE_BKPT; |
+#endif |
+ } |
+} |
+ |
+/* |
+** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt |
+** to enter a mutex. If another thread is already within the mutex, |
+** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return |
+** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK |
+** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can |
+** be entered multiple times by the same thread. In such cases the, |
+** mutex must be exited an equal number of times before another thread |
+** can enter. If the same thread tries to enter any other kind of mutex |
+** more than once, the behavior is undefined. |
+*/ |
+static void debugMutexEnter(sqlite3_mutex *pX){ |
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; |
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) ); |
+ p->cnt++; |
+} |
+static int debugMutexTry(sqlite3_mutex *pX){ |
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; |
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) ); |
+ p->cnt++; |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** The sqlite3_mutex_leave() routine exits a mutex that was |
+** previously entered by the same thread. The behavior |
+** is undefined if the mutex is not currently entered or |
+** is not currently allocated. SQLite will never do either. |
+*/ |
+static void debugMutexLeave(sqlite3_mutex *pX){ |
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX; |
+ assert( debugMutexHeld(pX) ); |
+ p->cnt--; |
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) ); |
+} |
+ |
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){ |
+ static const sqlite3_mutex_methods sMutex = { |
+ debugMutexInit, |
+ debugMutexEnd, |
+ debugMutexAlloc, |
+ debugMutexFree, |
+ debugMutexEnter, |
+ debugMutexTry, |
+ debugMutexLeave, |
+ |
+ debugMutexHeld, |
+ debugMutexNotheld |
+ }; |
+ |
+ return &sMutex; |
+} |
+#endif /* SQLITE_DEBUG */ |
+ |
+/* |
+** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation |
+** is used regardless of the run-time threadsafety setting. |
+*/ |
+#ifdef SQLITE_MUTEX_NOOP |
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ |
+ return sqlite3NoopMutex(); |
+} |
+#endif /* defined(SQLITE_MUTEX_NOOP) */ |
+#endif /* !defined(SQLITE_MUTEX_OMIT) */ |
+ |
+/************** End of mutex_noop.c ******************************************/ |
+/************** Begin file mutex_unix.c **************************************/ |
+/* |
+** 2007 August 28 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file contains the C functions that implement mutexes for pthreads |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* |
+** The code in this file is only used if we are compiling threadsafe |
+** under unix with pthreads. |
+** |
+** Note that this implementation requires a version of pthreads that |
+** supports recursive mutexes. |
+*/ |
+#ifdef SQLITE_MUTEX_PTHREADS |
+ |
+#include <pthread.h> |
+ |
+/* |
+** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields |
+** are necessary under two condidtions: (1) Debug builds and (2) using |
+** home-grown mutexes. Encapsulate these conditions into a single #define. |
+*/ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX) |
+# define SQLITE_MUTEX_NREF 1 |
+#else |
+# define SQLITE_MUTEX_NREF 0 |
+#endif |
+ |
+/* |
+** Each recursive mutex is an instance of the following structure. |
+*/ |
+struct sqlite3_mutex { |
+ pthread_mutex_t mutex; /* Mutex controlling the lock */ |
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) |
+ int id; /* Mutex type */ |
+#endif |
+#if SQLITE_MUTEX_NREF |
+ volatile int nRef; /* Number of entrances */ |
+ volatile pthread_t owner; /* Thread that is within this mutex */ |
+ int trace; /* True to trace changes */ |
+#endif |
+}; |
+#if SQLITE_MUTEX_NREF |
+#define SQLITE3_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER,0,0,(pthread_t)0,0} |
+#elif defined(SQLITE_ENABLE_API_ARMOR) |
+#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0 } |
+#else |
+#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER } |
+#endif |
+ |
+/* |
+** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are |
+** intended for use only inside assert() statements. On some platforms, |
+** there might be race conditions that can cause these routines to |
+** deliver incorrect results. In particular, if pthread_equal() is |
+** not an atomic operation, then these routines might delivery |
+** incorrect results. On most platforms, pthread_equal() is a |
+** comparison of two integers and is therefore atomic. But we are |
+** told that HPUX is not such a platform. If so, then these routines |
+** will not always work correctly on HPUX. |
+** |
+** On those platforms where pthread_equal() is not atomic, SQLite |
+** should be compiled without -DSQLITE_DEBUG and with -DNDEBUG to |
+** make sure no assert() statements are evaluated and hence these |
+** routines are never called. |
+*/ |
+#if !defined(NDEBUG) || defined(SQLITE_DEBUG) |
+static int pthreadMutexHeld(sqlite3_mutex *p){ |
+ return (p->nRef!=0 && pthread_equal(p->owner, pthread_self())); |
+} |
+static int pthreadMutexNotheld(sqlite3_mutex *p){ |
+ return p->nRef==0 || pthread_equal(p->owner, pthread_self())==0; |
+} |
+#endif |
+ |
+/* |
+** Try to provide a memory barrier operation, needed for initialization |
+** and also for the implementation of xShmBarrier in the VFS in cases |
+** where SQLite is compiled without mutexes. |
+*/ |
+SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ |
+#if defined(SQLITE_MEMORY_BARRIER) |
+ SQLITE_MEMORY_BARRIER; |
+#elif defined(__GNUC__) && GCC_VERSION>=4001000 |
+ __sync_synchronize(); |
+#endif |
+} |
+ |
+/* |
+** Initialize and deinitialize the mutex subsystem. |
+*/ |
+static int pthreadMutexInit(void){ return SQLITE_OK; } |
+static int pthreadMutexEnd(void){ return SQLITE_OK; } |
+ |
+/* |
+** The sqlite3_mutex_alloc() routine allocates a new |
+** mutex and returns a pointer to it. If it returns NULL |
+** that means that a mutex could not be allocated. SQLite |
+** will unwind its stack and return an error. The argument |
+** to sqlite3_mutex_alloc() is one of these integer constants: |
+** |
+** <ul> |
+** <li> SQLITE_MUTEX_FAST |
+** <li> SQLITE_MUTEX_RECURSIVE |
+** <li> SQLITE_MUTEX_STATIC_MASTER |
+** <li> SQLITE_MUTEX_STATIC_MEM |
+** <li> SQLITE_MUTEX_STATIC_OPEN |
+** <li> SQLITE_MUTEX_STATIC_PRNG |
+** <li> SQLITE_MUTEX_STATIC_LRU |
+** <li> SQLITE_MUTEX_STATIC_PMEM |
+** <li> SQLITE_MUTEX_STATIC_APP1 |
+** <li> SQLITE_MUTEX_STATIC_APP2 |
+** <li> SQLITE_MUTEX_STATIC_APP3 |
+** <li> SQLITE_MUTEX_STATIC_VFS1 |
+** <li> SQLITE_MUTEX_STATIC_VFS2 |
+** <li> SQLITE_MUTEX_STATIC_VFS3 |
+** </ul> |
+** |
+** The first two constants cause sqlite3_mutex_alloc() to create |
+** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE |
+** is used but not necessarily so when SQLITE_MUTEX_FAST is used. |
+** The mutex implementation does not need to make a distinction |
+** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does |
+** not want to. But SQLite will only request a recursive mutex in |
+** cases where it really needs one. If a faster non-recursive mutex |
+** implementation is available on the host platform, the mutex subsystem |
+** might return such a mutex in response to SQLITE_MUTEX_FAST. |
+** |
+** The other allowed parameters to sqlite3_mutex_alloc() each return |
+** a pointer to a static preexisting mutex. Six static mutexes are |
+** used by the current version of SQLite. Future versions of SQLite |
+** may add additional static mutexes. Static mutexes are for internal |
+** use by SQLite only. Applications that use SQLite mutexes should |
+** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or |
+** SQLITE_MUTEX_RECURSIVE. |
+** |
+** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST |
+** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() |
+** returns a different mutex on every call. But for the static |
+** mutex types, the same mutex is returned on every call that has |
+** the same type number. |
+*/ |
+static sqlite3_mutex *pthreadMutexAlloc(int iType){ |
+ static sqlite3_mutex staticMutexes[] = { |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER |
+ }; |
+ sqlite3_mutex *p; |
+ switch( iType ){ |
+ case SQLITE_MUTEX_RECURSIVE: { |
+ p = sqlite3MallocZero( sizeof(*p) ); |
+ if( p ){ |
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX |
+ /* If recursive mutexes are not available, we will have to |
+ ** build our own. See below. */ |
+ pthread_mutex_init(&p->mutex, 0); |
+#else |
+ /* Use a recursive mutex if it is available */ |
+ pthread_mutexattr_t recursiveAttr; |
+ pthread_mutexattr_init(&recursiveAttr); |
+ pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE); |
+ pthread_mutex_init(&p->mutex, &recursiveAttr); |
+ pthread_mutexattr_destroy(&recursiveAttr); |
+#endif |
+ } |
+ break; |
+ } |
+ case SQLITE_MUTEX_FAST: { |
+ p = sqlite3MallocZero( sizeof(*p) ); |
+ if( p ){ |
+ pthread_mutex_init(&p->mutex, 0); |
+ } |
+ break; |
+ } |
+ default: { |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+ p = &staticMutexes[iType-2]; |
+ break; |
+ } |
+ } |
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) |
+ if( p ) p->id = iType; |
+#endif |
+ return p; |
+} |
+ |
+ |
+/* |
+** This routine deallocates a previously |
+** allocated mutex. SQLite is careful to deallocate every |
+** mutex that it allocates. |
+*/ |
+static void pthreadMutexFree(sqlite3_mutex *p){ |
+ assert( p->nRef==0 ); |
+#if SQLITE_ENABLE_API_ARMOR |
+ if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ) |
+#endif |
+ { |
+ pthread_mutex_destroy(&p->mutex); |
+ sqlite3_free(p); |
+ } |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ else{ |
+ (void)SQLITE_MISUSE_BKPT; |
+ } |
+#endif |
+} |
+ |
+/* |
+** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt |
+** to enter a mutex. If another thread is already within the mutex, |
+** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return |
+** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK |
+** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can |
+** be entered multiple times by the same thread. In such cases the, |
+** mutex must be exited an equal number of times before another thread |
+** can enter. If the same thread tries to enter any other kind of mutex |
+** more than once, the behavior is undefined. |
+*/ |
+static void pthreadMutexEnter(sqlite3_mutex *p){ |
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) ); |
+ |
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX |
+ /* If recursive mutexes are not available, then we have to grow |
+ ** our own. This implementation assumes that pthread_equal() |
+ ** is atomic - that it cannot be deceived into thinking self |
+ ** and p->owner are equal if p->owner changes between two values |
+ ** that are not equal to self while the comparison is taking place. |
+ ** This implementation also assumes a coherent cache - that |
+ ** separate processes cannot read different values from the same |
+ ** address at the same time. If either of these two conditions |
+ ** are not met, then the mutexes will fail and problems will result. |
+ */ |
+ { |
+ pthread_t self = pthread_self(); |
+ if( p->nRef>0 && pthread_equal(p->owner, self) ){ |
+ p->nRef++; |
+ }else{ |
+ pthread_mutex_lock(&p->mutex); |
+ assert( p->nRef==0 ); |
+ p->owner = self; |
+ p->nRef = 1; |
+ } |
+ } |
+#else |
+ /* Use the built-in recursive mutexes if they are available. |
+ */ |
+ pthread_mutex_lock(&p->mutex); |
+#if SQLITE_MUTEX_NREF |
+ assert( p->nRef>0 || p->owner==0 ); |
+ p->owner = pthread_self(); |
+ p->nRef++; |
+#endif |
+#endif |
+ |
+#ifdef SQLITE_DEBUG |
+ if( p->trace ){ |
+ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); |
+ } |
+#endif |
+} |
+static int pthreadMutexTry(sqlite3_mutex *p){ |
+ int rc; |
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || pthreadMutexNotheld(p) ); |
+ |
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX |
+ /* If recursive mutexes are not available, then we have to grow |
+ ** our own. This implementation assumes that pthread_equal() |
+ ** is atomic - that it cannot be deceived into thinking self |
+ ** and p->owner are equal if p->owner changes between two values |
+ ** that are not equal to self while the comparison is taking place. |
+ ** This implementation also assumes a coherent cache - that |
+ ** separate processes cannot read different values from the same |
+ ** address at the same time. If either of these two conditions |
+ ** are not met, then the mutexes will fail and problems will result. |
+ */ |
+ { |
+ pthread_t self = pthread_self(); |
+ if( p->nRef>0 && pthread_equal(p->owner, self) ){ |
+ p->nRef++; |
+ rc = SQLITE_OK; |
+ }else if( pthread_mutex_trylock(&p->mutex)==0 ){ |
+ assert( p->nRef==0 ); |
+ p->owner = self; |
+ p->nRef = 1; |
+ rc = SQLITE_OK; |
+ }else{ |
+ rc = SQLITE_BUSY; |
+ } |
+ } |
+#else |
+ /* Use the built-in recursive mutexes if they are available. |
+ */ |
+ if( pthread_mutex_trylock(&p->mutex)==0 ){ |
+#if SQLITE_MUTEX_NREF |
+ p->owner = pthread_self(); |
+ p->nRef++; |
+#endif |
+ rc = SQLITE_OK; |
+ }else{ |
+ rc = SQLITE_BUSY; |
+ } |
+#endif |
+ |
+#ifdef SQLITE_DEBUG |
+ if( rc==SQLITE_OK && p->trace ){ |
+ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); |
+ } |
+#endif |
+ return rc; |
+} |
+ |
+/* |
+** The sqlite3_mutex_leave() routine exits a mutex that was |
+** previously entered by the same thread. The behavior |
+** is undefined if the mutex is not currently entered or |
+** is not currently allocated. SQLite will never do either. |
+*/ |
+static void pthreadMutexLeave(sqlite3_mutex *p){ |
+ assert( pthreadMutexHeld(p) ); |
+#if SQLITE_MUTEX_NREF |
+ p->nRef--; |
+ if( p->nRef==0 ) p->owner = 0; |
+#endif |
+ assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); |
+ |
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX |
+ if( p->nRef==0 ){ |
+ pthread_mutex_unlock(&p->mutex); |
+ } |
+#else |
+ pthread_mutex_unlock(&p->mutex); |
+#endif |
+ |
+#ifdef SQLITE_DEBUG |
+ if( p->trace ){ |
+ printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); |
+ } |
+#endif |
+} |
+ |
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ |
+ static const sqlite3_mutex_methods sMutex = { |
+ pthreadMutexInit, |
+ pthreadMutexEnd, |
+ pthreadMutexAlloc, |
+ pthreadMutexFree, |
+ pthreadMutexEnter, |
+ pthreadMutexTry, |
+ pthreadMutexLeave, |
+#ifdef SQLITE_DEBUG |
+ pthreadMutexHeld, |
+ pthreadMutexNotheld |
+#else |
+ 0, |
+ 0 |
+#endif |
+ }; |
+ |
+ return &sMutex; |
+} |
+ |
+#endif /* SQLITE_MUTEX_PTHREADS */ |
+ |
+/************** End of mutex_unix.c ******************************************/ |
+/************** Begin file mutex_w32.c ***************************************/ |
+/* |
+** 2007 August 14 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file contains the C functions that implement mutexes for Win32. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+#if SQLITE_OS_WIN |
+/* |
+** Include code that is common to all os_*.c files |
+*/ |
+/************** Include os_common.h in the middle of mutex_w32.c *************/ |
+/************** Begin file os_common.h ***************************************/ |
+/* |
+** 2004 May 22 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains macros and a little bit of code that is common to |
+** all of the platform-specific files (os_*.c) and is #included into those |
+** files. |
+** |
+** This file should be #included by the os_*.c files only. It is not a |
+** general purpose header file. |
+*/ |
+#ifndef _OS_COMMON_H_ |
+#define _OS_COMMON_H_ |
+ |
+/* |
+** At least two bugs have slipped in because we changed the MEMORY_DEBUG |
+** macro to SQLITE_DEBUG and some older makefiles have not yet made the |
+** switch. The following code should catch this problem at compile-time. |
+*/ |
+#ifdef MEMORY_DEBUG |
+# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." |
+#endif |
+ |
+/* |
+** Macros for performance tracing. Normally turned off. Only works |
+** on i486 hardware. |
+*/ |
+#ifdef SQLITE_PERFORMANCE_TRACE |
+ |
+/* |
+** hwtime.h contains inline assembler code for implementing |
+** high-performance timing routines. |
+*/ |
+/************** Include hwtime.h in the middle of os_common.h ****************/ |
+/************** Begin file hwtime.h ******************************************/ |
+/* |
+** 2008 May 27 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains inline asm code for retrieving "high-performance" |
+** counters for x86 class CPUs. |
+*/ |
+#ifndef SQLITE_HWTIME_H |
+#define SQLITE_HWTIME_H |
+ |
+/* |
+** The following routine only works on pentium-class (or newer) processors. |
+** It uses the RDTSC opcode to read the cycle count value out of the |
+** processor and returns that value. This can be used for high-res |
+** profiling. |
+*/ |
+#if (defined(__GNUC__) || defined(_MSC_VER)) && \ |
+ (defined(i386) || defined(__i386__) || defined(_M_IX86)) |
+ |
+ #if defined(__GNUC__) |
+ |
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
+ unsigned int lo, hi; |
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); |
+ return (sqlite_uint64)hi << 32 | lo; |
+ } |
+ |
+ #elif defined(_MSC_VER) |
+ |
+ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ |
+ __asm { |
+ rdtsc |
+ ret ; return value at EDX:EAX |
+ } |
+ } |
+ |
+ #endif |
+ |
+#elif (defined(__GNUC__) && defined(__x86_64__)) |
+ |
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
+ unsigned long val; |
+ __asm__ __volatile__ ("rdtsc" : "=A" (val)); |
+ return val; |
+ } |
+ |
+#elif (defined(__GNUC__) && defined(__ppc__)) |
+ |
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
+ unsigned long long retval; |
+ unsigned long junk; |
+ __asm__ __volatile__ ("\n\ |
+ 1: mftbu %1\n\ |
+ mftb %L0\n\ |
+ mftbu %0\n\ |
+ cmpw %0,%1\n\ |
+ bne 1b" |
+ : "=r" (retval), "=r" (junk)); |
+ return retval; |
+ } |
+ |
+#else |
+ |
+ #error Need implementation of sqlite3Hwtime() for your platform. |
+ |
+ /* |
+ ** To compile without implementing sqlite3Hwtime() for your platform, |
+ ** you can remove the above #error and use the following |
+ ** stub function. You will lose timing support for many |
+ ** of the debugging and testing utilities, but it should at |
+ ** least compile and run. |
+ */ |
+SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } |
+ |
+#endif |
+ |
+#endif /* !defined(SQLITE_HWTIME_H) */ |
+ |
+/************** End of hwtime.h **********************************************/ |
+/************** Continuing where we left off in os_common.h ******************/ |
+ |
+static sqlite_uint64 g_start; |
+static sqlite_uint64 g_elapsed; |
+#define TIMER_START g_start=sqlite3Hwtime() |
+#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start |
+#define TIMER_ELAPSED g_elapsed |
+#else |
+#define TIMER_START |
+#define TIMER_END |
+#define TIMER_ELAPSED ((sqlite_uint64)0) |
+#endif |
+ |
+/* |
+** If we compile with the SQLITE_TEST macro set, then the following block |
+** of code will give us the ability to simulate a disk I/O error. This |
+** is used for testing the I/O recovery logic. |
+*/ |
+#if defined(SQLITE_TEST) |
+SQLITE_API extern int sqlite3_io_error_hit; |
+SQLITE_API extern int sqlite3_io_error_hardhit; |
+SQLITE_API extern int sqlite3_io_error_pending; |
+SQLITE_API extern int sqlite3_io_error_persist; |
+SQLITE_API extern int sqlite3_io_error_benign; |
+SQLITE_API extern int sqlite3_diskfull_pending; |
+SQLITE_API extern int sqlite3_diskfull; |
+#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) |
+#define SimulateIOError(CODE) \ |
+ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ |
+ || sqlite3_io_error_pending-- == 1 ) \ |
+ { local_ioerr(); CODE; } |
+static void local_ioerr(){ |
+ IOTRACE(("IOERR\n")); |
+ sqlite3_io_error_hit++; |
+ if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; |
+} |
+#define SimulateDiskfullError(CODE) \ |
+ if( sqlite3_diskfull_pending ){ \ |
+ if( sqlite3_diskfull_pending == 1 ){ \ |
+ local_ioerr(); \ |
+ sqlite3_diskfull = 1; \ |
+ sqlite3_io_error_hit = 1; \ |
+ CODE; \ |
+ }else{ \ |
+ sqlite3_diskfull_pending--; \ |
+ } \ |
+ } |
+#else |
+#define SimulateIOErrorBenign(X) |
+#define SimulateIOError(A) |
+#define SimulateDiskfullError(A) |
+#endif /* defined(SQLITE_TEST) */ |
+ |
+/* |
+** When testing, keep a count of the number of open files. |
+*/ |
+#if defined(SQLITE_TEST) |
+SQLITE_API extern int sqlite3_open_file_count; |
+#define OpenCounter(X) sqlite3_open_file_count+=(X) |
+#else |
+#define OpenCounter(X) |
+#endif /* defined(SQLITE_TEST) */ |
+ |
+#endif /* !defined(_OS_COMMON_H_) */ |
+ |
+/************** End of os_common.h *******************************************/ |
+/************** Continuing where we left off in mutex_w32.c ******************/ |
+ |
+/* |
+** Include the header file for the Windows VFS. |
+*/ |
+/************** Include os_win.h in the middle of mutex_w32.c ****************/ |
+/************** Begin file os_win.h ******************************************/ |
+/* |
+** 2013 November 25 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains code that is specific to Windows. |
+*/ |
+#ifndef SQLITE_OS_WIN_H |
+#define SQLITE_OS_WIN_H |
+ |
+/* |
+** Include the primary Windows SDK header file. |
+*/ |
+#include "windows.h" |
+ |
+#ifdef __CYGWIN__ |
+# include <sys/cygwin.h> |
+# include <errno.h> /* amalgamator: dontcache */ |
+#endif |
+ |
+/* |
+** Determine if we are dealing with Windows NT. |
+** |
+** We ought to be able to determine if we are compiling for Windows 9x or |
+** Windows NT using the _WIN32_WINNT macro as follows: |
+** |
+** #if defined(_WIN32_WINNT) |
+** # define SQLITE_OS_WINNT 1 |
+** #else |
+** # define SQLITE_OS_WINNT 0 |
+** #endif |
+** |
+** However, Visual Studio 2005 does not set _WIN32_WINNT by default, as |
+** it ought to, so the above test does not work. We'll just assume that |
+** everything is Windows NT unless the programmer explicitly says otherwise |
+** by setting SQLITE_OS_WINNT to 0. |
+*/ |
+#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT) |
+# define SQLITE_OS_WINNT 1 |
+#endif |
+ |
+/* |
+** Determine if we are dealing with Windows CE - which has a much reduced |
+** API. |
+*/ |
+#if defined(_WIN32_WCE) |
+# define SQLITE_OS_WINCE 1 |
+#else |
+# define SQLITE_OS_WINCE 0 |
+#endif |
+ |
+/* |
+** Determine if we are dealing with WinRT, which provides only a subset of |
+** the full Win32 API. |
+*/ |
+#if !defined(SQLITE_OS_WINRT) |
+# define SQLITE_OS_WINRT 0 |
+#endif |
+ |
+/* |
+** For WinCE, some API function parameters do not appear to be declared as |
+** volatile. |
+*/ |
+#if SQLITE_OS_WINCE |
+# define SQLITE_WIN32_VOLATILE |
+#else |
+# define SQLITE_WIN32_VOLATILE volatile |
+#endif |
+ |
+/* |
+** For some Windows sub-platforms, the _beginthreadex() / _endthreadex() |
+** functions are not available (e.g. those not using MSVC, Cygwin, etc). |
+*/ |
+#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ |
+ SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) |
+# define SQLITE_OS_WIN_THREADS 1 |
+#else |
+# define SQLITE_OS_WIN_THREADS 0 |
+#endif |
+ |
+#endif /* SQLITE_OS_WIN_H */ |
+ |
+/************** End of os_win.h **********************************************/ |
+/************** Continuing where we left off in mutex_w32.c ******************/ |
+#endif |
+ |
+/* |
+** The code in this file is only used if we are compiling multithreaded |
+** on a Win32 system. |
+*/ |
+#ifdef SQLITE_MUTEX_W32 |
+ |
+/* |
+** Each recursive mutex is an instance of the following structure. |
+*/ |
+struct sqlite3_mutex { |
+ CRITICAL_SECTION mutex; /* Mutex controlling the lock */ |
+ int id; /* Mutex type */ |
+#ifdef SQLITE_DEBUG |
+ volatile int nRef; /* Number of enterances */ |
+ volatile DWORD owner; /* Thread holding this mutex */ |
+ volatile int trace; /* True to trace changes */ |
+#endif |
+}; |
+ |
+/* |
+** These are the initializer values used when declaring a "static" mutex |
+** on Win32. It should be noted that all mutexes require initialization |
+** on the Win32 platform. |
+*/ |
+#define SQLITE_W32_MUTEX_INITIALIZER { 0 } |
+ |
+#ifdef SQLITE_DEBUG |
+#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \ |
+ 0L, (DWORD)0, 0 } |
+#else |
+#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 } |
+#endif |
+ |
+#ifdef SQLITE_DEBUG |
+/* |
+** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are |
+** intended for use only inside assert() statements. |
+*/ |
+static int winMutexHeld(sqlite3_mutex *p){ |
+ return p->nRef!=0 && p->owner==GetCurrentThreadId(); |
+} |
+ |
+static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){ |
+ return p->nRef==0 || p->owner!=tid; |
+} |
+ |
+static int winMutexNotheld(sqlite3_mutex *p){ |
+ DWORD tid = GetCurrentThreadId(); |
+ return winMutexNotheld2(p, tid); |
+} |
+#endif |
+ |
+/* |
+** Try to provide a memory barrier operation, needed for initialization |
+** and also for the xShmBarrier method of the VFS in cases when SQLite is |
+** compiled without mutexes (SQLITE_THREADSAFE=0). |
+*/ |
+SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ |
+#if defined(SQLITE_MEMORY_BARRIER) |
+ SQLITE_MEMORY_BARRIER; |
+#elif defined(__GNUC__) |
+ __sync_synchronize(); |
+#elif MSVC_VERSION>=1300 |
+ _ReadWriteBarrier(); |
+#elif defined(MemoryBarrier) |
+ MemoryBarrier(); |
+#endif |
+} |
+ |
+/* |
+** Initialize and deinitialize the mutex subsystem. |
+*/ |
+static sqlite3_mutex winMutex_staticMutexes[] = { |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER, |
+ SQLITE3_MUTEX_INITIALIZER |
+}; |
+ |
+static int winMutex_isInit = 0; |
+static int winMutex_isNt = -1; /* <0 means "need to query" */ |
+ |
+/* As the winMutexInit() and winMutexEnd() functions are called as part |
+** of the sqlite3_initialize() and sqlite3_shutdown() processing, the |
+** "interlocked" magic used here is probably not strictly necessary. |
+*/ |
+static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0; |
+ |
+SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */ |
+SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ |
+ |
+static int winMutexInit(void){ |
+ /* The first to increment to 1 does actual initialization */ |
+ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ |
+ int i; |
+ for(i=0; i<ArraySize(winMutex_staticMutexes); i++){ |
+#if SQLITE_OS_WINRT |
+ InitializeCriticalSectionEx(&winMutex_staticMutexes[i].mutex, 0, 0); |
+#else |
+ InitializeCriticalSection(&winMutex_staticMutexes[i].mutex); |
+#endif |
+ } |
+ winMutex_isInit = 1; |
+ }else{ |
+ /* Another thread is (in the process of) initializing the static |
+ ** mutexes */ |
+ while( !winMutex_isInit ){ |
+ sqlite3_win32_sleep(1); |
+ } |
+ } |
+ return SQLITE_OK; |
+} |
+ |
+static int winMutexEnd(void){ |
+ /* The first to decrement to 0 does actual shutdown |
+ ** (which should be the last to shutdown.) */ |
+ if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){ |
+ if( winMutex_isInit==1 ){ |
+ int i; |
+ for(i=0; i<ArraySize(winMutex_staticMutexes); i++){ |
+ DeleteCriticalSection(&winMutex_staticMutexes[i].mutex); |
+ } |
+ winMutex_isInit = 0; |
+ } |
+ } |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** The sqlite3_mutex_alloc() routine allocates a new |
+** mutex and returns a pointer to it. If it returns NULL |
+** that means that a mutex could not be allocated. SQLite |
+** will unwind its stack and return an error. The argument |
+** to sqlite3_mutex_alloc() is one of these integer constants: |
+** |
+** <ul> |
+** <li> SQLITE_MUTEX_FAST |
+** <li> SQLITE_MUTEX_RECURSIVE |
+** <li> SQLITE_MUTEX_STATIC_MASTER |
+** <li> SQLITE_MUTEX_STATIC_MEM |
+** <li> SQLITE_MUTEX_STATIC_OPEN |
+** <li> SQLITE_MUTEX_STATIC_PRNG |
+** <li> SQLITE_MUTEX_STATIC_LRU |
+** <li> SQLITE_MUTEX_STATIC_PMEM |
+** <li> SQLITE_MUTEX_STATIC_APP1 |
+** <li> SQLITE_MUTEX_STATIC_APP2 |
+** <li> SQLITE_MUTEX_STATIC_APP3 |
+** <li> SQLITE_MUTEX_STATIC_VFS1 |
+** <li> SQLITE_MUTEX_STATIC_VFS2 |
+** <li> SQLITE_MUTEX_STATIC_VFS3 |
+** </ul> |
+** |
+** The first two constants cause sqlite3_mutex_alloc() to create |
+** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE |
+** is used but not necessarily so when SQLITE_MUTEX_FAST is used. |
+** The mutex implementation does not need to make a distinction |
+** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does |
+** not want to. But SQLite will only request a recursive mutex in |
+** cases where it really needs one. If a faster non-recursive mutex |
+** implementation is available on the host platform, the mutex subsystem |
+** might return such a mutex in response to SQLITE_MUTEX_FAST. |
+** |
+** The other allowed parameters to sqlite3_mutex_alloc() each return |
+** a pointer to a static preexisting mutex. Six static mutexes are |
+** used by the current version of SQLite. Future versions of SQLite |
+** may add additional static mutexes. Static mutexes are for internal |
+** use by SQLite only. Applications that use SQLite mutexes should |
+** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or |
+** SQLITE_MUTEX_RECURSIVE. |
+** |
+** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST |
+** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() |
+** returns a different mutex on every call. But for the static |
+** mutex types, the same mutex is returned on every call that has |
+** the same type number. |
+*/ |
+static sqlite3_mutex *winMutexAlloc(int iType){ |
+ sqlite3_mutex *p; |
+ |
+ switch( iType ){ |
+ case SQLITE_MUTEX_FAST: |
+ case SQLITE_MUTEX_RECURSIVE: { |
+ p = sqlite3MallocZero( sizeof(*p) ); |
+ if( p ){ |
+ p->id = iType; |
+#ifdef SQLITE_DEBUG |
+#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC |
+ p->trace = 1; |
+#endif |
+#endif |
+#if SQLITE_OS_WINRT |
+ InitializeCriticalSectionEx(&p->mutex, 0, 0); |
+#else |
+ InitializeCriticalSection(&p->mutex); |
+#endif |
+ } |
+ break; |
+ } |
+ default: { |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+ p = &winMutex_staticMutexes[iType-2]; |
+ p->id = iType; |
+#ifdef SQLITE_DEBUG |
+#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC |
+ p->trace = 1; |
+#endif |
+#endif |
+ break; |
+ } |
+ } |
+ return p; |
+} |
+ |
+ |
+/* |
+** This routine deallocates a previously |
+** allocated mutex. SQLite is careful to deallocate every |
+** mutex that it allocates. |
+*/ |
+static void winMutexFree(sqlite3_mutex *p){ |
+ assert( p ); |
+ assert( p->nRef==0 && p->owner==0 ); |
+ if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ){ |
+ DeleteCriticalSection(&p->mutex); |
+ sqlite3_free(p); |
+ }else{ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ (void)SQLITE_MISUSE_BKPT; |
+#endif |
+ } |
+} |
+ |
+/* |
+** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt |
+** to enter a mutex. If another thread is already within the mutex, |
+** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return |
+** SQLITE_BUSY. The sqlite3_mutex_try() interface returns SQLITE_OK |
+** upon successful entry. Mutexes created using SQLITE_MUTEX_RECURSIVE can |
+** be entered multiple times by the same thread. In such cases the, |
+** mutex must be exited an equal number of times before another thread |
+** can enter. If the same thread tries to enter any other kind of mutex |
+** more than once, the behavior is undefined. |
+*/ |
+static void winMutexEnter(sqlite3_mutex *p){ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
+ DWORD tid = GetCurrentThreadId(); |
+#endif |
+#ifdef SQLITE_DEBUG |
+ assert( p ); |
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); |
+#else |
+ assert( p ); |
+#endif |
+ assert( winMutex_isInit==1 ); |
+ EnterCriticalSection(&p->mutex); |
+#ifdef SQLITE_DEBUG |
+ assert( p->nRef>0 || p->owner==0 ); |
+ p->owner = tid; |
+ p->nRef++; |
+ if( p->trace ){ |
+ OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", |
+ tid, p, p->trace, p->nRef)); |
+ } |
+#endif |
+} |
+ |
+static int winMutexTry(sqlite3_mutex *p){ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
+ DWORD tid = GetCurrentThreadId(); |
+#endif |
+ int rc = SQLITE_BUSY; |
+ assert( p ); |
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); |
+ /* |
+ ** The sqlite3_mutex_try() routine is very rarely used, and when it |
+ ** is used it is merely an optimization. So it is OK for it to always |
+ ** fail. |
+ ** |
+ ** The TryEnterCriticalSection() interface is only available on WinNT. |
+ ** And some windows compilers complain if you try to use it without |
+ ** first doing some #defines that prevent SQLite from building on Win98. |
+ ** For that reason, we will omit this optimization for now. See |
+ ** ticket #2685. |
+ */ |
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 |
+ assert( winMutex_isInit==1 ); |
+ assert( winMutex_isNt>=-1 && winMutex_isNt<=1 ); |
+ if( winMutex_isNt<0 ){ |
+ winMutex_isNt = sqlite3_win32_is_nt(); |
+ } |
+ assert( winMutex_isNt==0 || winMutex_isNt==1 ); |
+ if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){ |
+#ifdef SQLITE_DEBUG |
+ p->owner = tid; |
+ p->nRef++; |
+#endif |
+ rc = SQLITE_OK; |
+ } |
+#else |
+ UNUSED_PARAMETER(p); |
+#endif |
+#ifdef SQLITE_DEBUG |
+ if( p->trace ){ |
+ OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n", |
+ tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); |
+ } |
+#endif |
+ return rc; |
+} |
+ |
+/* |
+** The sqlite3_mutex_leave() routine exits a mutex that was |
+** previously entered by the same thread. The behavior |
+** is undefined if the mutex is not currently entered or |
+** is not currently allocated. SQLite will never do either. |
+*/ |
+static void winMutexLeave(sqlite3_mutex *p){ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
+ DWORD tid = GetCurrentThreadId(); |
+#endif |
+ assert( p ); |
+#ifdef SQLITE_DEBUG |
+ assert( p->nRef>0 ); |
+ assert( p->owner==tid ); |
+ p->nRef--; |
+ if( p->nRef==0 ) p->owner = 0; |
+ assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); |
+#endif |
+ assert( winMutex_isInit==1 ); |
+ LeaveCriticalSection(&p->mutex); |
+#ifdef SQLITE_DEBUG |
+ if( p->trace ){ |
+ OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", |
+ tid, p, p->trace, p->nRef)); |
+ } |
+#endif |
+} |
+ |
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ |
+ static const sqlite3_mutex_methods sMutex = { |
+ winMutexInit, |
+ winMutexEnd, |
+ winMutexAlloc, |
+ winMutexFree, |
+ winMutexEnter, |
+ winMutexTry, |
+ winMutexLeave, |
+#ifdef SQLITE_DEBUG |
+ winMutexHeld, |
+ winMutexNotheld |
+#else |
+ 0, |
+ 0 |
+#endif |
+ }; |
+ return &sMutex; |
+} |
+ |
+#endif /* SQLITE_MUTEX_W32 */ |
+ |
+/************** End of mutex_w32.c *******************************************/ |
+/************** Begin file malloc.c ******************************************/ |
+/* |
+** 2001 September 15 |
+** |
+** 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. |
+** |
+************************************************************************* |
+** |
+** Memory allocation functions used throughout sqlite. |
+*/ |
+/* #include "sqliteInt.h" */ |
+/* #include <stdarg.h> */ |
+ |
+/* |
+** Attempt to release up to n bytes of non-essential memory currently |
+** held by SQLite. An example of non-essential memory is memory used to |
+** cache database pages that are not currently in use. |
+*/ |
+SQLITE_API int sqlite3_release_memory(int n){ |
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT |
+ return sqlite3PcacheReleaseMemory(n); |
+#else |
+ /* IMPLEMENTATION-OF: R-34391-24921 The sqlite3_release_memory() routine |
+ ** is a no-op returning zero if SQLite is not compiled with |
+ ** SQLITE_ENABLE_MEMORY_MANAGEMENT. */ |
+ UNUSED_PARAMETER(n); |
+ return 0; |
+#endif |
+} |
+ |
+/* |
+** An instance of the following object records the location of |
+** each unused scratch buffer. |
+*/ |
+typedef struct ScratchFreeslot { |
+ struct ScratchFreeslot *pNext; /* Next unused scratch buffer */ |
+} ScratchFreeslot; |
+ |
+/* |
+** State information local to the memory allocation subsystem. |
+*/ |
+static SQLITE_WSD struct Mem0Global { |
+ sqlite3_mutex *mutex; /* Mutex to serialize access */ |
+ sqlite3_int64 alarmThreshold; /* The soft heap limit */ |
+ |
+ /* |
+ ** Pointers to the end of sqlite3GlobalConfig.pScratch memory |
+ ** (so that a range test can be used to determine if an allocation |
+ ** being freed came from pScratch) and a pointer to the list of |
+ ** unused scratch allocations. |
+ */ |
+ void *pScratchEnd; |
+ ScratchFreeslot *pScratchFree; |
+ u32 nScratchFree; |
+ |
+ /* |
+ ** True if heap is nearly "full" where "full" is defined by the |
+ ** sqlite3_soft_heap_limit() setting. |
+ */ |
+ int nearlyFull; |
+} mem0 = { 0, 0, 0, 0, 0, 0 }; |
+ |
+#define mem0 GLOBAL(struct Mem0Global, mem0) |
+ |
+/* |
+** Return the memory allocator mutex. sqlite3_status() needs it. |
+*/ |
+SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){ |
+ return mem0.mutex; |
+} |
+ |
+#ifndef SQLITE_OMIT_DEPRECATED |
+/* |
+** Deprecated external interface. It used to set an alarm callback |
+** that was invoked when memory usage grew too large. Now it is a |
+** no-op. |
+*/ |
+SQLITE_API int sqlite3_memory_alarm( |
+ void(*xCallback)(void *pArg, sqlite3_int64 used,int N), |
+ void *pArg, |
+ sqlite3_int64 iThreshold |
+){ |
+ (void)xCallback; |
+ (void)pArg; |
+ (void)iThreshold; |
+ return SQLITE_OK; |
+} |
+#endif |
+ |
+/* |
+** Set the soft heap-size limit for the library. Passing a zero or |
+** negative value indicates no limit. |
+*/ |
+SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){ |
+ sqlite3_int64 priorLimit; |
+ sqlite3_int64 excess; |
+ sqlite3_int64 nUsed; |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ int rc = sqlite3_initialize(); |
+ if( rc ) return -1; |
+#endif |
+ sqlite3_mutex_enter(mem0.mutex); |
+ priorLimit = mem0.alarmThreshold; |
+ if( n<0 ){ |
+ sqlite3_mutex_leave(mem0.mutex); |
+ return priorLimit; |
+ } |
+ mem0.alarmThreshold = n; |
+ nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); |
+ mem0.nearlyFull = (n>0 && n<=nUsed); |
+ sqlite3_mutex_leave(mem0.mutex); |
+ excess = sqlite3_memory_used() - n; |
+ if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff)); |
+ return priorLimit; |
+} |
+SQLITE_API void sqlite3_soft_heap_limit(int n){ |
+ if( n<0 ) n = 0; |
+ sqlite3_soft_heap_limit64(n); |
+} |
+ |
+/* |
+** Initialize the memory allocation subsystem. |
+*/ |
+SQLITE_PRIVATE int sqlite3MallocInit(void){ |
+ int rc; |
+ if( sqlite3GlobalConfig.m.xMalloc==0 ){ |
+ sqlite3MemSetDefault(); |
+ } |
+ memset(&mem0, 0, sizeof(mem0)); |
+ mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); |
+ if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100 |
+ && sqlite3GlobalConfig.nScratch>0 ){ |
+ int i, n, sz; |
+ ScratchFreeslot *pSlot; |
+ sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch); |
+ sqlite3GlobalConfig.szScratch = sz; |
+ pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch; |
+ n = sqlite3GlobalConfig.nScratch; |
+ mem0.pScratchFree = pSlot; |
+ mem0.nScratchFree = n; |
+ for(i=0; i<n-1; i++){ |
+ pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot); |
+ pSlot = pSlot->pNext; |
+ } |
+ pSlot->pNext = 0; |
+ mem0.pScratchEnd = (void*)&pSlot[1]; |
+ }else{ |
+ mem0.pScratchEnd = 0; |
+ sqlite3GlobalConfig.pScratch = 0; |
+ sqlite3GlobalConfig.szScratch = 0; |
+ sqlite3GlobalConfig.nScratch = 0; |
+ } |
+ if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512 |
+ || sqlite3GlobalConfig.nPage<=0 ){ |
+ sqlite3GlobalConfig.pPage = 0; |
+ sqlite3GlobalConfig.szPage = 0; |
+ } |
+ rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData); |
+ if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0)); |
+ return rc; |
+} |
+ |
+/* |
+** Return true if the heap is currently under memory pressure - in other |
+** words if the amount of heap used is close to the limit set by |
+** sqlite3_soft_heap_limit(). |
+*/ |
+SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){ |
+ return mem0.nearlyFull; |
+} |
+ |
+/* |
+** Deinitialize the memory allocation subsystem. |
+*/ |
+SQLITE_PRIVATE void sqlite3MallocEnd(void){ |
+ if( sqlite3GlobalConfig.m.xShutdown ){ |
+ sqlite3GlobalConfig.m.xShutdown(sqlite3GlobalConfig.m.pAppData); |
+ } |
+ memset(&mem0, 0, sizeof(mem0)); |
+} |
+ |
+/* |
+** Return the amount of memory currently checked out. |
+*/ |
+SQLITE_API sqlite3_int64 sqlite3_memory_used(void){ |
+ sqlite3_int64 res, mx; |
+ sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, 0); |
+ return res; |
+} |
+ |
+/* |
+** Return the maximum amount of memory that has ever been |
+** checked out since either the beginning of this process |
+** or since the most recent reset. |
+*/ |
+SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ |
+ sqlite3_int64 res, mx; |
+ sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, resetFlag); |
+ return mx; |
+} |
+ |
+/* |
+** Trigger the alarm |
+*/ |
+static void sqlite3MallocAlarm(int nByte){ |
+ if( mem0.alarmThreshold<=0 ) return; |
+ sqlite3_mutex_leave(mem0.mutex); |
+ sqlite3_release_memory(nByte); |
+ sqlite3_mutex_enter(mem0.mutex); |
+} |
+ |
+/* |
+** Do a memory allocation with statistics and alarms. Assume the |
+** lock is already held. |
+*/ |
+static void mallocWithAlarm(int n, void **pp){ |
+ void *p; |
+ int nFull; |
+ assert( sqlite3_mutex_held(mem0.mutex) ); |
+ assert( n>0 ); |
+ |
+ /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal |
+ ** implementation of malloc_good_size(), which must be called in debug |
+ ** mode and specifically when the DMD "Dark Matter Detector" is enabled |
+ ** or else a crash results. Hence, do not attempt to optimize out the |
+ ** following xRoundup() call. */ |
+ nFull = sqlite3GlobalConfig.m.xRoundup(n); |
+ |
+ sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n); |
+ if( mem0.alarmThreshold>0 ){ |
+ sqlite3_int64 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); |
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT |
+ if( p==0 && mem0.alarmThreshold>0 ){ |
+ sqlite3MallocAlarm(nFull); |
+ p = sqlite3GlobalConfig.m.xMalloc(nFull); |
+ } |
+#endif |
+ if( p ){ |
+ nFull = sqlite3MallocSize(p); |
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull); |
+ sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1); |
+ } |
+ *pp = p; |
+} |
+ |
+/* |
+** Allocate memory. This routine is like sqlite3_malloc() except that it |
+** assumes the memory subsystem has already been initialized. |
+*/ |
+SQLITE_PRIVATE void *sqlite3Malloc(u64 n){ |
+ void *p; |
+ if( n==0 || n>=0x7fffff00 ){ |
+ /* A memory allocation of a number of bytes which is near the maximum |
+ ** signed integer value might cause an integer overflow inside of the |
+ ** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving |
+ ** 255 bytes of overhead. SQLite itself will never use anything near |
+ ** this amount. The only way to reach the limit is with sqlite3_malloc() */ |
+ p = 0; |
+ }else if( sqlite3GlobalConfig.bMemstat ){ |
+ sqlite3_mutex_enter(mem0.mutex); |
+ mallocWithAlarm((int)n, &p); |
+ sqlite3_mutex_leave(mem0.mutex); |
+ }else{ |
+ p = sqlite3GlobalConfig.m.xMalloc((int)n); |
+ } |
+ assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-11148-40995 */ |
+ return p; |
+} |
+ |
+/* |
+** This version of the memory allocation is for use by the application. |
+** First make sure the memory subsystem is initialized, then do the |
+** allocation. |
+*/ |
+SQLITE_API void *sqlite3_malloc(int n){ |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ return n<=0 ? 0 : sqlite3Malloc(n); |
+} |
+SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){ |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ return sqlite3Malloc(n); |
+} |
+ |
+/* |
+** Each thread may only have a single outstanding allocation from |
+** xScratchMalloc(). We verify this constraint in the single-threaded |
+** case by setting scratchAllocOut to 1 when an allocation |
+** is outstanding clearing it when the allocation is freed. |
+*/ |
+#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) |
+static int scratchAllocOut = 0; |
+#endif |
+ |
+ |
+/* |
+** Allocate memory that is to be used and released right away. |
+** This routine is similar to alloca() in that it is not intended |
+** for situations where the memory might be held long-term. This |
+** routine is intended to get memory to old large transient data |
+** structures that would not normally fit on the stack of an |
+** embedded processor. |
+*/ |
+SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){ |
+ void *p; |
+ assert( n>0 ); |
+ |
+ sqlite3_mutex_enter(mem0.mutex); |
+ sqlite3StatusHighwater(SQLITE_STATUS_SCRATCH_SIZE, n); |
+ if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){ |
+ p = mem0.pScratchFree; |
+ mem0.pScratchFree = mem0.pScratchFree->pNext; |
+ mem0.nScratchFree--; |
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1); |
+ sqlite3_mutex_leave(mem0.mutex); |
+ }else{ |
+ sqlite3_mutex_leave(mem0.mutex); |
+ p = sqlite3Malloc(n); |
+ if( sqlite3GlobalConfig.bMemstat && p ){ |
+ sqlite3_mutex_enter(mem0.mutex); |
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p)); |
+ sqlite3_mutex_leave(mem0.mutex); |
+ } |
+ sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH); |
+ } |
+ assert( sqlite3_mutex_notheld(mem0.mutex) ); |
+ |
+ |
+#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) |
+ /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch |
+ ** buffers per thread. |
+ ** |
+ ** This can only be checked in single-threaded mode. |
+ */ |
+ assert( scratchAllocOut==0 ); |
+ if( p ) scratchAllocOut++; |
+#endif |
+ |
+ return p; |
+} |
+SQLITE_PRIVATE void sqlite3ScratchFree(void *p){ |
+ if( p ){ |
+ |
+#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) |
+ /* Verify that no more than two scratch allocation per thread |
+ ** is outstanding at one time. (This is only checked in the |
+ ** single-threaded case since checking in the multi-threaded case |
+ ** would be much more complicated.) */ |
+ assert( scratchAllocOut>=1 && scratchAllocOut<=2 ); |
+ scratchAllocOut--; |
+#endif |
+ |
+ if( SQLITE_WITHIN(p, sqlite3GlobalConfig.pScratch, mem0.pScratchEnd) ){ |
+ /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */ |
+ ScratchFreeslot *pSlot; |
+ pSlot = (ScratchFreeslot*)p; |
+ sqlite3_mutex_enter(mem0.mutex); |
+ pSlot->pNext = mem0.pScratchFree; |
+ mem0.pScratchFree = pSlot; |
+ mem0.nScratchFree++; |
+ assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch ); |
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1); |
+ sqlite3_mutex_leave(mem0.mutex); |
+ }else{ |
+ /* Release memory back to the heap */ |
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) ); |
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) ); |
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP); |
+ if( sqlite3GlobalConfig.bMemstat ){ |
+ int iSize = sqlite3MallocSize(p); |
+ sqlite3_mutex_enter(mem0.mutex); |
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize); |
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize); |
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1); |
+ sqlite3GlobalConfig.m.xFree(p); |
+ sqlite3_mutex_leave(mem0.mutex); |
+ }else{ |
+ sqlite3GlobalConfig.m.xFree(p); |
+ } |
+ } |
+ } |
+} |
+ |
+/* |
+** TRUE if p is a lookaside memory allocation from db |
+*/ |
+#ifndef SQLITE_OMIT_LOOKASIDE |
+static int isLookaside(sqlite3 *db, void *p){ |
+ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd); |
+} |
+#else |
+#define isLookaside(A,B) 0 |
+#endif |
+ |
+/* |
+** Return the size of a memory allocation previously obtained from |
+** sqlite3Malloc() or sqlite3_malloc(). |
+*/ |
+SQLITE_PRIVATE int sqlite3MallocSize(void *p){ |
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); |
+ return sqlite3GlobalConfig.m.xSize(p); |
+} |
+SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){ |
+ assert( p!=0 ); |
+ if( db==0 || !isLookaside(db,p) ){ |
+#if SQLITE_DEBUG |
+ if( db==0 ){ |
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); |
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); |
+ }else{ |
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); |
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); |
+ } |
+#endif |
+ return sqlite3GlobalConfig.m.xSize(p); |
+ }else{ |
+ assert( sqlite3_mutex_held(db->mutex) ); |
+ return db->lookaside.sz; |
+ } |
+} |
+SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){ |
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); |
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); |
+ return p ? sqlite3GlobalConfig.m.xSize(p) : 0; |
+} |
+ |
+/* |
+** Free memory previously obtained from sqlite3Malloc(). |
+*/ |
+SQLITE_API void sqlite3_free(void *p){ |
+ if( p==0 ) return; /* IMP: R-49053-54554 */ |
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); |
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); |
+ if( sqlite3GlobalConfig.bMemstat ){ |
+ sqlite3_mutex_enter(mem0.mutex); |
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, sqlite3MallocSize(p)); |
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1); |
+ sqlite3GlobalConfig.m.xFree(p); |
+ sqlite3_mutex_leave(mem0.mutex); |
+ }else{ |
+ sqlite3GlobalConfig.m.xFree(p); |
+ } |
+} |
+ |
+/* |
+** Add the size of memory allocation "p" to the count in |
+** *db->pnBytesFreed. |
+*/ |
+static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){ |
+ *db->pnBytesFreed += sqlite3DbMallocSize(db,p); |
+} |
+ |
+/* |
+** Free memory that might be associated with a particular database |
+** connection. |
+*/ |
+SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ |
+ assert( db==0 || sqlite3_mutex_held(db->mutex) ); |
+ if( p==0 ) return; |
+ if( db ){ |
+ if( db->pnBytesFreed ){ |
+ measureAllocationSize(db, p); |
+ return; |
+ } |
+ if( isLookaside(db, p) ){ |
+ LookasideSlot *pBuf = (LookasideSlot*)p; |
+#if SQLITE_DEBUG |
+ /* Trash all content in the buffer being freed */ |
+ memset(p, 0xaa, db->lookaside.sz); |
+#endif |
+ pBuf->pNext = db->lookaside.pFree; |
+ db->lookaside.pFree = pBuf; |
+ db->lookaside.nOut--; |
+ return; |
+ } |
+ } |
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); |
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); |
+ assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); |
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP); |
+ sqlite3_free(p); |
+} |
+ |
+/* |
+** Change the size of an existing memory allocation |
+*/ |
+SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ |
+ int nOld, nNew, nDiff; |
+ void *pNew; |
+ assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); |
+ assert( sqlite3MemdebugNoType(pOld, (u8)~MEMTYPE_HEAP) ); |
+ if( pOld==0 ){ |
+ return sqlite3Malloc(nBytes); /* IMP: R-04300-56712 */ |
+ } |
+ if( nBytes==0 ){ |
+ sqlite3_free(pOld); /* IMP: R-26507-47431 */ |
+ return 0; |
+ } |
+ if( nBytes>=0x7fffff00 ){ |
+ /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */ |
+ return 0; |
+ } |
+ nOld = sqlite3MallocSize(pOld); |
+ /* IMPLEMENTATION-OF: R-46199-30249 SQLite guarantees that the second |
+ ** argument to xRealloc is always a value returned by a prior call to |
+ ** xRoundup. */ |
+ nNew = sqlite3GlobalConfig.m.xRoundup((int)nBytes); |
+ if( nOld==nNew ){ |
+ pNew = pOld; |
+ }else if( sqlite3GlobalConfig.bMemstat ){ |
+ sqlite3_mutex_enter(mem0.mutex); |
+ sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); |
+ nDiff = nNew - nOld; |
+ if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= |
+ mem0.alarmThreshold-nDiff ){ |
+ sqlite3MallocAlarm(nDiff); |
+ } |
+ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); |
+ if( pNew==0 && mem0.alarmThreshold>0 ){ |
+ sqlite3MallocAlarm((int)nBytes); |
+ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); |
+ } |
+ if( pNew ){ |
+ nNew = sqlite3MallocSize(pNew); |
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld); |
+ } |
+ sqlite3_mutex_leave(mem0.mutex); |
+ }else{ |
+ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); |
+ } |
+ assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-11148-40995 */ |
+ return pNew; |
+} |
+ |
+/* |
+** The public interface to sqlite3Realloc. Make sure that the memory |
+** subsystem is initialized prior to invoking sqliteRealloc. |
+*/ |
+SQLITE_API void *sqlite3_realloc(void *pOld, int n){ |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ if( n<0 ) n = 0; /* IMP: R-26507-47431 */ |
+ return sqlite3Realloc(pOld, n); |
+} |
+SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){ |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ return sqlite3Realloc(pOld, n); |
+} |
+ |
+ |
+/* |
+** Allocate and zero memory. |
+*/ |
+SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){ |
+ void *p = sqlite3Malloc(n); |
+ if( p ){ |
+ memset(p, 0, (size_t)n); |
+ } |
+ return p; |
+} |
+ |
+/* |
+** Allocate and zero memory. If the allocation fails, make |
+** the mallocFailed flag in the connection pointer. |
+*/ |
+SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){ |
+ void *p; |
+ testcase( db==0 ); |
+ p = sqlite3DbMallocRaw(db, n); |
+ if( p ) memset(p, 0, (size_t)n); |
+ return p; |
+} |
+ |
+ |
+/* Finish the work of sqlite3DbMallocRawNN for the unusual and |
+** slower case when the allocation cannot be fulfilled using lookaside. |
+*/ |
+static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){ |
+ void *p; |
+ assert( db!=0 ); |
+ p = sqlite3Malloc(n); |
+ if( !p ) sqlite3OomFault(db); |
+ sqlite3MemdebugSetType(p, |
+ (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); |
+ return p; |
+} |
+ |
+/* |
+** Allocate memory, either lookaside (if possible) or heap. |
+** If the allocation fails, set the mallocFailed flag in |
+** the connection pointer. |
+** |
+** If db!=0 and db->mallocFailed is true (indicating a prior malloc |
+** failure on the same database connection) then always return 0. |
+** Hence for a particular database connection, once malloc starts |
+** failing, it fails consistently until mallocFailed is reset. |
+** This is an important assumption. There are many places in the |
+** code that do things like this: |
+** |
+** int *a = (int*)sqlite3DbMallocRaw(db, 100); |
+** int *b = (int*)sqlite3DbMallocRaw(db, 200); |
+** if( b ) a[10] = 9; |
+** |
+** In other words, if a subsequent malloc (ex: "b") worked, it is assumed |
+** that all prior mallocs (ex: "a") worked too. |
+** |
+** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is |
+** not a NULL pointer. |
+*/ |
+SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){ |
+ void *p; |
+ if( db ) return sqlite3DbMallocRawNN(db, n); |
+ p = sqlite3Malloc(n); |
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP); |
+ return p; |
+} |
+SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){ |
+#ifndef SQLITE_OMIT_LOOKASIDE |
+ LookasideSlot *pBuf; |
+ assert( db!=0 ); |
+ assert( sqlite3_mutex_held(db->mutex) ); |
+ assert( db->pnBytesFreed==0 ); |
+ if( db->lookaside.bDisable==0 ){ |
+ assert( db->mallocFailed==0 ); |
+ if( n>db->lookaside.sz ){ |
+ db->lookaside.anStat[1]++; |
+ }else if( (pBuf = db->lookaside.pFree)==0 ){ |
+ db->lookaside.anStat[2]++; |
+ }else{ |
+ db->lookaside.pFree = pBuf->pNext; |
+ db->lookaside.nOut++; |
+ db->lookaside.anStat[0]++; |
+ if( db->lookaside.nOut>db->lookaside.mxOut ){ |
+ db->lookaside.mxOut = db->lookaside.nOut; |
+ } |
+ return (void*)pBuf; |
+ } |
+ }else if( db->mallocFailed ){ |
+ return 0; |
+ } |
+#else |
+ assert( db!=0 ); |
+ assert( sqlite3_mutex_held(db->mutex) ); |
+ assert( db->pnBytesFreed==0 ); |
+ if( db->mallocFailed ){ |
+ return 0; |
+ } |
+#endif |
+ return dbMallocRawFinish(db, n); |
+} |
+ |
+/* Forward declaration */ |
+static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n); |
+ |
+/* |
+** Resize the block of memory pointed to by p to n bytes. If the |
+** resize fails, set the mallocFailed flag in the connection object. |
+*/ |
+SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ |
+ assert( db!=0 ); |
+ if( p==0 ) return sqlite3DbMallocRawNN(db, n); |
+ assert( sqlite3_mutex_held(db->mutex) ); |
+ if( isLookaside(db,p) && n<=db->lookaside.sz ) return p; |
+ return dbReallocFinish(db, p, n); |
+} |
+static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){ |
+ void *pNew = 0; |
+ assert( db!=0 ); |
+ assert( p!=0 ); |
+ if( db->mallocFailed==0 ){ |
+ if( isLookaside(db, p) ){ |
+ pNew = sqlite3DbMallocRawNN(db, n); |
+ if( pNew ){ |
+ memcpy(pNew, p, db->lookaside.sz); |
+ sqlite3DbFree(db, p); |
+ } |
+ }else{ |
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); |
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); |
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP); |
+ pNew = sqlite3_realloc64(p, n); |
+ if( !pNew ){ |
+ sqlite3OomFault(db); |
+ } |
+ sqlite3MemdebugSetType(pNew, |
+ (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); |
+ } |
+ } |
+ return pNew; |
+} |
+ |
+/* |
+** Attempt to reallocate p. If the reallocation fails, then free p |
+** and set the mallocFailed flag in the database connection. |
+*/ |
+SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){ |
+ void *pNew; |
+ pNew = sqlite3DbRealloc(db, p, n); |
+ if( !pNew ){ |
+ sqlite3DbFree(db, p); |
+ } |
+ return pNew; |
+} |
+ |
+/* |
+** Make a copy of a string in memory obtained from sqliteMalloc(). These |
+** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This |
+** is because when memory debugging is turned on, these two functions are |
+** called via macros that record the current file and line number in the |
+** ThreadData structure. |
+*/ |
+SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){ |
+ char *zNew; |
+ size_t n; |
+ if( z==0 ){ |
+ return 0; |
+ } |
+ n = strlen(z) + 1; |
+ zNew = sqlite3DbMallocRaw(db, n); |
+ if( zNew ){ |
+ memcpy(zNew, z, n); |
+ } |
+ return zNew; |
+} |
+SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ |
+ char *zNew; |
+ assert( db!=0 ); |
+ if( z==0 ){ |
+ return 0; |
+ } |
+ assert( (n&0x7fffffff)==n ); |
+ zNew = sqlite3DbMallocRawNN(db, n+1); |
+ if( zNew ){ |
+ memcpy(zNew, z, (size_t)n); |
+ zNew[n] = 0; |
+ } |
+ return zNew; |
+} |
+ |
+/* |
+** Free any prior content in *pz and replace it with a copy of zNew. |
+*/ |
+SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){ |
+ sqlite3DbFree(db, *pz); |
+ *pz = sqlite3DbStrDup(db, zNew); |
+} |
+ |
+/* |
+** Call this routine to record the fact that an OOM (out-of-memory) error |
+** has happened. This routine will set db->mallocFailed, and also |
+** temporarily disable the lookaside memory allocator and interrupt |
+** any running VDBEs. |
+*/ |
+SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){ |
+ if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ |
+ db->mallocFailed = 1; |
+ if( db->nVdbeExec>0 ){ |
+ db->u1.isInterrupted = 1; |
+ } |
+ db->lookaside.bDisable++; |
+ } |
+} |
+ |
+/* |
+** This routine reactivates the memory allocator and clears the |
+** db->mallocFailed flag as necessary. |
+** |
+** The memory allocator is not restarted if there are running |
+** VDBEs. |
+*/ |
+SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){ |
+ if( db->mallocFailed && db->nVdbeExec==0 ){ |
+ db->mallocFailed = 0; |
+ db->u1.isInterrupted = 0; |
+ assert( db->lookaside.bDisable>0 ); |
+ db->lookaside.bDisable--; |
+ } |
+} |
+ |
+/* |
+** Take actions at the end of an API call to indicate an OOM error |
+*/ |
+static SQLITE_NOINLINE int apiOomError(sqlite3 *db){ |
+ sqlite3OomClear(db); |
+ sqlite3Error(db, SQLITE_NOMEM); |
+ return SQLITE_NOMEM_BKPT; |
+} |
+ |
+/* |
+** This function must be called before exiting any API function (i.e. |
+** returning control to the user) that has called sqlite3_malloc or |
+** sqlite3_realloc. |
+** |
+** The returned value is normally a copy of the second argument to this |
+** function. However, if a malloc() failure has occurred since the previous |
+** invocation SQLITE_NOMEM is returned instead. |
+** |
+** If an OOM as occurred, then the connection error-code (the value |
+** returned by sqlite3_errcode()) is set to SQLITE_NOMEM. |
+*/ |
+SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ |
+ /* If the db handle must hold the connection handle mutex here. |
+ ** Otherwise the read (and possible write) of db->mallocFailed |
+ ** is unsafe, as is the call to sqlite3Error(). |
+ */ |
+ assert( db!=0 ); |
+ assert( sqlite3_mutex_held(db->mutex) ); |
+ if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ |
+ return apiOomError(db); |
+ } |
+ return rc & db->errMask; |
+} |
+ |
+/************** End of malloc.c **********************************************/ |
+/************** Begin file printf.c ******************************************/ |
+/* |
+** The "printf" code that follows dates from the 1980's. It is in |
+** the public domain. |
+** |
+************************************************************************** |
+** |
+** This file contains code for a set of "printf"-like routines. These |
+** routines format strings much like the printf() from the standard C |
+** library, though the implementation here has enhancements to support |
+** SQLite. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* |
+** Conversion types fall into various categories as defined by the |
+** following enumeration. |
+*/ |
+#define etRADIX 0 /* Integer types. %d, %x, %o, and so forth */ |
+#define etFLOAT 1 /* Floating point. %f */ |
+#define etEXP 2 /* Exponentional notation. %e and %E */ |
+#define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */ |
+#define etSIZE 4 /* Return number of characters processed so far. %n */ |
+#define etSTRING 5 /* Strings. %s */ |
+#define etDYNSTRING 6 /* Dynamically allocated strings. %z */ |
+#define etPERCENT 7 /* Percent symbol. %% */ |
+#define etCHARX 8 /* Characters. %c */ |
+/* The rest are extensions, not normally found in printf() */ |
+#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ |
+#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', |
+ NULL pointers replaced by SQL NULL. %Q */ |
+#define etTOKEN 11 /* a pointer to a Token structure */ |
+#define etSRCLIST 12 /* a pointer to a SrcList */ |
+#define etPOINTER 13 /* The %p conversion */ |
+#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ |
+#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ |
+ |
+#define etINVALID 16 /* Any unrecognized conversion type */ |
+ |
+ |
+/* |
+** An "etByte" is an 8-bit unsigned value. |
+*/ |
+typedef unsigned char etByte; |
+ |
+/* |
+** Each builtin conversion character (ex: the 'd' in "%d") is described |
+** by an instance of the following structure |
+*/ |
+typedef struct et_info { /* Information about each format field */ |
+ char fmttype; /* The format field code letter */ |
+ etByte base; /* The base for radix conversion */ |
+ etByte flags; /* One or more of FLAG_ constants below */ |
+ etByte type; /* Conversion paradigm */ |
+ etByte charset; /* Offset into aDigits[] of the digits string */ |
+ etByte prefix; /* Offset into aPrefix[] of the prefix string */ |
+} et_info; |
+ |
+/* |
+** Allowed values for et_info.flags |
+*/ |
+#define FLAG_SIGNED 1 /* True if the value to convert is signed */ |
+#define FLAG_STRING 4 /* Allow infinity precision */ |
+ |
+ |
+/* |
+** The following table is searched linearly, so it is good to put the |
+** most frequently used conversion types first. |
+*/ |
+static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; |
+static const char aPrefix[] = "-x0\000X0"; |
+static const et_info fmtinfo[] = { |
+ { 'd', 10, 1, etRADIX, 0, 0 }, |
+ { 's', 0, 4, etSTRING, 0, 0 }, |
+ { 'g', 0, 1, etGENERIC, 30, 0 }, |
+ { 'z', 0, 4, etDYNSTRING, 0, 0 }, |
+ { 'q', 0, 4, etSQLESCAPE, 0, 0 }, |
+ { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, |
+ { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, |
+ { 'c', 0, 0, etCHARX, 0, 0 }, |
+ { 'o', 8, 0, etRADIX, 0, 2 }, |
+ { 'u', 10, 0, etRADIX, 0, 0 }, |
+ { 'x', 16, 0, etRADIX, 16, 1 }, |
+ { 'X', 16, 0, etRADIX, 0, 4 }, |
+#ifndef SQLITE_OMIT_FLOATING_POINT |
+ { 'f', 0, 1, etFLOAT, 0, 0 }, |
+ { 'e', 0, 1, etEXP, 30, 0 }, |
+ { 'E', 0, 1, etEXP, 14, 0 }, |
+ { 'G', 0, 1, etGENERIC, 14, 0 }, |
+#endif |
+ { 'i', 10, 1, etRADIX, 0, 0 }, |
+ { 'n', 0, 0, etSIZE, 0, 0 }, |
+ { '%', 0, 0, etPERCENT, 0, 0 }, |
+ { 'p', 16, 0, etPOINTER, 0, 1 }, |
+ |
+ /* All the rest are undocumented and are for internal use only */ |
+ { 'T', 0, 0, etTOKEN, 0, 0 }, |
+ { 'S', 0, 0, etSRCLIST, 0, 0 }, |
+ { 'r', 10, 1, etORDINAL, 0, 0 }, |
+}; |
+ |
+/* |
+** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point |
+** conversions will work. |
+*/ |
+#ifndef SQLITE_OMIT_FLOATING_POINT |
+/* |
+** "*val" is a double such that 0.1 <= *val < 10.0 |
+** Return the ascii code for the leading digit of *val, then |
+** multiply "*val" by 10.0 to renormalize. |
+** |
+** Example: |
+** input: *val = 3.14159 |
+** output: *val = 1.4159 function return = '3' |
+** |
+** The counter *cnt is incremented each time. After counter exceeds |
+** 16 (the number of significant digits in a 64-bit float) '0' is |
+** always returned. |
+*/ |
+static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ |
+ int digit; |
+ LONGDOUBLE_TYPE d; |
+ if( (*cnt)<=0 ) return '0'; |
+ (*cnt)--; |
+ digit = (int)*val; |
+ d = digit; |
+ digit += '0'; |
+ *val = (*val - d)*10.0; |
+ return (char)digit; |
+} |
+#endif /* SQLITE_OMIT_FLOATING_POINT */ |
+ |
+/* |
+** Set the StrAccum object to an error mode. |
+*/ |
+static void setStrAccumError(StrAccum *p, u8 eError){ |
+ assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG ); |
+ p->accError = eError; |
+ p->nAlloc = 0; |
+} |
+ |
+/* |
+** Extra argument values from a PrintfArguments object |
+*/ |
+static sqlite3_int64 getIntArg(PrintfArguments *p){ |
+ if( p->nArg<=p->nUsed ) return 0; |
+ return sqlite3_value_int64(p->apArg[p->nUsed++]); |
+} |
+static double getDoubleArg(PrintfArguments *p){ |
+ if( p->nArg<=p->nUsed ) return 0.0; |
+ return sqlite3_value_double(p->apArg[p->nUsed++]); |
+} |
+static char *getTextArg(PrintfArguments *p){ |
+ if( p->nArg<=p->nUsed ) return 0; |
+ return (char*)sqlite3_value_text(p->apArg[p->nUsed++]); |
+} |
+ |
+ |
+/* |
+** On machines with a small stack size, you can redefine the |
+** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired. |
+*/ |
+#ifndef SQLITE_PRINT_BUF_SIZE |
+# define SQLITE_PRINT_BUF_SIZE 70 |
+#endif |
+#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ |
+ |
+/* |
+** Render a string given by "fmt" into the StrAccum object. |
+*/ |
+SQLITE_PRIVATE void sqlite3VXPrintf( |
+ StrAccum *pAccum, /* Accumulate results here */ |
+ const char *fmt, /* Format string */ |
+ va_list ap /* arguments */ |
+){ |
+ int c; /* Next character in the format string */ |
+ char *bufpt; /* Pointer to the conversion buffer */ |
+ int precision; /* Precision of the current field */ |
+ int length; /* Length of the field */ |
+ int idx; /* A general purpose loop counter */ |
+ int width; /* Width of the current field */ |
+ etByte flag_leftjustify; /* True if "-" flag is present */ |
+ etByte flag_plussign; /* True if "+" flag is present */ |
+ etByte flag_blanksign; /* True if " " flag is present */ |
+ etByte flag_alternateform; /* True if "#" flag is present */ |
+ etByte flag_altform2; /* True if "!" flag is present */ |
+ etByte flag_zeropad; /* True if field width constant starts with zero */ |
+ etByte flag_long; /* True if "l" flag is present */ |
+ etByte flag_longlong; /* True if the "ll" flag is present */ |
+ etByte done; /* Loop termination flag */ |
+ etByte xtype = etINVALID; /* Conversion paradigm */ |
+ u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */ |
+ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ |
+ sqlite_uint64 longvalue; /* Value for integer types */ |
+ LONGDOUBLE_TYPE realvalue; /* Value for real types */ |
+ const et_info *infop; /* Pointer to the appropriate info structure */ |
+ char *zOut; /* Rendering buffer */ |
+ int nOut; /* Size of the rendering buffer */ |
+ char *zExtra = 0; /* Malloced memory used by some conversion */ |
+#ifndef SQLITE_OMIT_FLOATING_POINT |
+ int exp, e2; /* exponent of real numbers */ |
+ int nsd; /* Number of significant digits returned */ |
+ double rounder; /* Used for rounding floating point values */ |
+ etByte flag_dp; /* True if decimal point should be shown */ |
+ etByte flag_rtz; /* True if trailing zeros should be removed */ |
+#endif |
+ PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ |
+ char buf[etBUFSIZE]; /* Conversion buffer */ |
+ |
+ bufpt = 0; |
+ if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){ |
+ pArgList = va_arg(ap, PrintfArguments*); |
+ bArgList = 1; |
+ }else{ |
+ bArgList = 0; |
+ } |
+ for(; (c=(*fmt))!=0; ++fmt){ |
+ if( c!='%' ){ |
+ bufpt = (char *)fmt; |
+#if HAVE_STRCHRNUL |
+ fmt = strchrnul(fmt, '%'); |
+#else |
+ do{ fmt++; }while( *fmt && *fmt != '%' ); |
+#endif |
+ sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); |
+ if( *fmt==0 ) break; |
+ } |
+ if( (c=(*++fmt))==0 ){ |
+ sqlite3StrAccumAppend(pAccum, "%", 1); |
+ break; |
+ } |
+ /* Find out what flags are present */ |
+ flag_leftjustify = flag_plussign = flag_blanksign = |
+ flag_alternateform = flag_altform2 = flag_zeropad = 0; |
+ done = 0; |
+ do{ |
+ switch( c ){ |
+ case '-': flag_leftjustify = 1; break; |
+ case '+': flag_plussign = 1; break; |
+ case ' ': flag_blanksign = 1; break; |
+ case '#': flag_alternateform = 1; break; |
+ case '!': flag_altform2 = 1; break; |
+ case '0': flag_zeropad = 1; break; |
+ default: done = 1; break; |
+ } |
+ }while( !done && (c=(*++fmt))!=0 ); |
+ /* Get the field width */ |
+ if( c=='*' ){ |
+ if( bArgList ){ |
+ width = (int)getIntArg(pArgList); |
+ }else{ |
+ width = va_arg(ap,int); |
+ } |
+ if( width<0 ){ |
+ flag_leftjustify = 1; |
+ width = width >= -2147483647 ? -width : 0; |
+ } |
+ c = *++fmt; |
+ }else{ |
+ unsigned wx = 0; |
+ while( c>='0' && c<='9' ){ |
+ wx = wx*10 + c - '0'; |
+ c = *++fmt; |
+ } |
+ testcase( wx>0x7fffffff ); |
+ width = wx & 0x7fffffff; |
+ } |
+ assert( width>=0 ); |
+#ifdef SQLITE_PRINTF_PRECISION_LIMIT |
+ if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ |
+ width = SQLITE_PRINTF_PRECISION_LIMIT; |
+ } |
+#endif |
+ |
+ /* Get the precision */ |
+ if( c=='.' ){ |
+ c = *++fmt; |
+ if( c=='*' ){ |
+ if( bArgList ){ |
+ precision = (int)getIntArg(pArgList); |
+ }else{ |
+ precision = va_arg(ap,int); |
+ } |
+ c = *++fmt; |
+ if( precision<0 ){ |
+ precision = precision >= -2147483647 ? -precision : -1; |
+ } |
+ }else{ |
+ unsigned px = 0; |
+ while( c>='0' && c<='9' ){ |
+ px = px*10 + c - '0'; |
+ c = *++fmt; |
+ } |
+ testcase( px>0x7fffffff ); |
+ precision = px & 0x7fffffff; |
+ } |
+ }else{ |
+ precision = -1; |
+ } |
+ assert( precision>=(-1) ); |
+#ifdef SQLITE_PRINTF_PRECISION_LIMIT |
+ if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){ |
+ precision = SQLITE_PRINTF_PRECISION_LIMIT; |
+ } |
+#endif |
+ |
+ |
+ /* Get the conversion type modifier */ |
+ if( c=='l' ){ |
+ flag_long = 1; |
+ c = *++fmt; |
+ if( c=='l' ){ |
+ flag_longlong = 1; |
+ c = *++fmt; |
+ }else{ |
+ flag_longlong = 0; |
+ } |
+ }else{ |
+ flag_long = flag_longlong = 0; |
+ } |
+ /* Fetch the info entry for the field */ |
+ infop = &fmtinfo[0]; |
+ xtype = etINVALID; |
+ for(idx=0; idx<ArraySize(fmtinfo); idx++){ |
+ if( c==fmtinfo[idx].fmttype ){ |
+ infop = &fmtinfo[idx]; |
+ xtype = infop->type; |
+ break; |
+ } |
+ } |
+ |
+ /* |
+ ** At this point, variables are initialized as follows: |
+ ** |
+ ** flag_alternateform TRUE if a '#' is present. |
+ ** flag_altform2 TRUE if a '!' is present. |
+ ** flag_plussign TRUE if a '+' is present. |
+ ** flag_leftjustify TRUE if a '-' is present or if the |
+ ** field width was negative. |
+ ** flag_zeropad TRUE if the width began with 0. |
+ ** flag_long TRUE if the letter 'l' (ell) prefixed |
+ ** the conversion character. |
+ ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed |
+ ** the conversion character. |
+ ** flag_blanksign TRUE if a ' ' is present. |
+ ** width The specified field width. This is |
+ ** always non-negative. Zero is the default. |
+ ** precision The specified precision. The default |
+ ** is -1. |
+ ** xtype The class of the conversion. |
+ ** infop Pointer to the appropriate info struct. |
+ */ |
+ switch( xtype ){ |
+ case etPOINTER: |
+ flag_longlong = sizeof(char*)==sizeof(i64); |
+ flag_long = sizeof(char*)==sizeof(long int); |
+ /* Fall through into the next case */ |
+ case etORDINAL: |
+ case etRADIX: |
+ if( infop->flags & FLAG_SIGNED ){ |
+ i64 v; |
+ if( bArgList ){ |
+ v = getIntArg(pArgList); |
+ }else if( flag_longlong ){ |
+ v = va_arg(ap,i64); |
+ }else if( flag_long ){ |
+ v = va_arg(ap,long int); |
+ }else{ |
+ v = va_arg(ap,int); |
+ } |
+ if( v<0 ){ |
+ if( v==SMALLEST_INT64 ){ |
+ longvalue = ((u64)1)<<63; |
+ }else{ |
+ longvalue = -v; |
+ } |
+ prefix = '-'; |
+ }else{ |
+ longvalue = v; |
+ if( flag_plussign ) prefix = '+'; |
+ else if( flag_blanksign ) prefix = ' '; |
+ else prefix = 0; |
+ } |
+ }else{ |
+ if( bArgList ){ |
+ longvalue = (u64)getIntArg(pArgList); |
+ }else if( flag_longlong ){ |
+ longvalue = va_arg(ap,u64); |
+ }else if( flag_long ){ |
+ longvalue = va_arg(ap,unsigned long int); |
+ }else{ |
+ longvalue = va_arg(ap,unsigned int); |
+ } |
+ prefix = 0; |
+ } |
+ if( longvalue==0 ) flag_alternateform = 0; |
+ if( flag_zeropad && precision<width-(prefix!=0) ){ |
+ precision = width-(prefix!=0); |
+ } |
+ if( precision<etBUFSIZE-10 ){ |
+ nOut = etBUFSIZE; |
+ zOut = buf; |
+ }else{ |
+ nOut = precision + 10; |
+ zOut = zExtra = sqlite3Malloc( nOut ); |
+ if( zOut==0 ){ |
+ setStrAccumError(pAccum, STRACCUM_NOMEM); |
+ return; |
+ } |
+ } |
+ bufpt = &zOut[nOut-1]; |
+ if( xtype==etORDINAL ){ |
+ static const char zOrd[] = "thstndrd"; |
+ int x = (int)(longvalue % 10); |
+ if( x>=4 || (longvalue/10)%10==1 ){ |
+ x = 0; |
+ } |
+ *(--bufpt) = zOrd[x*2+1]; |
+ *(--bufpt) = zOrd[x*2]; |
+ } |
+ { |
+ const char *cset = &aDigits[infop->charset]; |
+ u8 base = infop->base; |
+ do{ /* Convert to ascii */ |
+ *(--bufpt) = cset[longvalue%base]; |
+ longvalue = longvalue/base; |
+ }while( longvalue>0 ); |
+ } |
+ length = (int)(&zOut[nOut-1]-bufpt); |
+ for(idx=precision-length; idx>0; idx--){ |
+ *(--bufpt) = '0'; /* Zero pad */ |
+ } |
+ if( prefix ) *(--bufpt) = prefix; /* Add sign */ |
+ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ |
+ const char *pre; |
+ char x; |
+ pre = &aPrefix[infop->prefix]; |
+ for(; (x=(*pre))!=0; pre++) *(--bufpt) = x; |
+ } |
+ length = (int)(&zOut[nOut-1]-bufpt); |
+ break; |
+ case etFLOAT: |
+ case etEXP: |
+ case etGENERIC: |
+ if( bArgList ){ |
+ realvalue = getDoubleArg(pArgList); |
+ }else{ |
+ realvalue = va_arg(ap,double); |
+ } |
+#ifdef SQLITE_OMIT_FLOATING_POINT |
+ length = 0; |
+#else |
+ if( precision<0 ) precision = 6; /* Set default precision */ |
+ if( realvalue<0.0 ){ |
+ realvalue = -realvalue; |
+ prefix = '-'; |
+ }else{ |
+ if( flag_plussign ) prefix = '+'; |
+ else if( flag_blanksign ) prefix = ' '; |
+ else prefix = 0; |
+ } |
+ if( xtype==etGENERIC && precision>0 ) precision--; |
+ testcase( precision>0xfff ); |
+ for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){} |
+ if( xtype==etFLOAT ) realvalue += rounder; |
+ /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ |
+ exp = 0; |
+ if( sqlite3IsNaN((double)realvalue) ){ |
+ bufpt = "NaN"; |
+ length = 3; |
+ break; |
+ } |
+ if( realvalue>0.0 ){ |
+ LONGDOUBLE_TYPE scale = 1.0; |
+ while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;} |
+ while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; } |
+ while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; } |
+ realvalue /= scale; |
+ while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; } |
+ while( realvalue<1.0 ){ realvalue *= 10.0; exp--; } |
+ if( exp>350 ){ |
+ bufpt = buf; |
+ buf[0] = prefix; |
+ memcpy(buf+(prefix!=0),"Inf",4); |
+ length = 3+(prefix!=0); |
+ break; |
+ } |
+ } |
+ bufpt = buf; |
+ /* |
+ ** If the field type is etGENERIC, then convert to either etEXP |
+ ** or etFLOAT, as appropriate. |
+ */ |
+ if( xtype!=etFLOAT ){ |
+ realvalue += rounder; |
+ if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } |
+ } |
+ if( xtype==etGENERIC ){ |
+ flag_rtz = !flag_alternateform; |
+ if( exp<-4 || exp>precision ){ |
+ xtype = etEXP; |
+ }else{ |
+ precision = precision - exp; |
+ xtype = etFLOAT; |
+ } |
+ }else{ |
+ flag_rtz = flag_altform2; |
+ } |
+ if( xtype==etEXP ){ |
+ e2 = 0; |
+ }else{ |
+ e2 = exp; |
+ } |
+ if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){ |
+ bufpt = zExtra |
+ = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 ); |
+ if( bufpt==0 ){ |
+ setStrAccumError(pAccum, STRACCUM_NOMEM); |
+ return; |
+ } |
+ } |
+ zOut = bufpt; |
+ nsd = 16 + flag_altform2*10; |
+ flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; |
+ /* The sign in front of the number */ |
+ if( prefix ){ |
+ *(bufpt++) = prefix; |
+ } |
+ /* Digits prior to the decimal point */ |
+ if( e2<0 ){ |
+ *(bufpt++) = '0'; |
+ }else{ |
+ for(; e2>=0; e2--){ |
+ *(bufpt++) = et_getdigit(&realvalue,&nsd); |
+ } |
+ } |
+ /* The decimal point */ |
+ if( flag_dp ){ |
+ *(bufpt++) = '.'; |
+ } |
+ /* "0" digits after the decimal point but before the first |
+ ** significant digit of the number */ |
+ for(e2++; e2<0; precision--, e2++){ |
+ assert( precision>0 ); |
+ *(bufpt++) = '0'; |
+ } |
+ /* Significant digits after the decimal point */ |
+ while( (precision--)>0 ){ |
+ *(bufpt++) = et_getdigit(&realvalue,&nsd); |
+ } |
+ /* Remove trailing zeros and the "." if no digits follow the "." */ |
+ if( flag_rtz && flag_dp ){ |
+ while( bufpt[-1]=='0' ) *(--bufpt) = 0; |
+ assert( bufpt>zOut ); |
+ if( bufpt[-1]=='.' ){ |
+ if( flag_altform2 ){ |
+ *(bufpt++) = '0'; |
+ }else{ |
+ *(--bufpt) = 0; |
+ } |
+ } |
+ } |
+ /* Add the "eNNN" suffix */ |
+ if( xtype==etEXP ){ |
+ *(bufpt++) = aDigits[infop->charset]; |
+ if( exp<0 ){ |
+ *(bufpt++) = '-'; exp = -exp; |
+ }else{ |
+ *(bufpt++) = '+'; |
+ } |
+ if( exp>=100 ){ |
+ *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */ |
+ exp %= 100; |
+ } |
+ *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */ |
+ *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */ |
+ } |
+ *bufpt = 0; |
+ |
+ /* The converted number is in buf[] and zero terminated. Output it. |
+ ** Note that the number is in the usual order, not reversed as with |
+ ** integer conversions. */ |
+ length = (int)(bufpt-zOut); |
+ bufpt = zOut; |
+ |
+ /* Special case: Add leading zeros if the flag_zeropad flag is |
+ ** set and we are not left justified */ |
+ if( flag_zeropad && !flag_leftjustify && length < width){ |
+ int i; |
+ int nPad = width - length; |
+ for(i=width; i>=nPad; i--){ |
+ bufpt[i] = bufpt[i-nPad]; |
+ } |
+ i = prefix!=0; |
+ while( nPad-- ) bufpt[i++] = '0'; |
+ length = width; |
+ } |
+#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */ |
+ break; |
+ case etSIZE: |
+ if( !bArgList ){ |
+ *(va_arg(ap,int*)) = pAccum->nChar; |
+ } |
+ length = width = 0; |
+ break; |
+ case etPERCENT: |
+ buf[0] = '%'; |
+ bufpt = buf; |
+ length = 1; |
+ break; |
+ case etCHARX: |
+ if( bArgList ){ |
+ bufpt = getTextArg(pArgList); |
+ c = bufpt ? bufpt[0] : 0; |
+ }else{ |
+ c = va_arg(ap,int); |
+ } |
+ if( precision>1 ){ |
+ width -= precision-1; |
+ if( width>1 && !flag_leftjustify ){ |
+ sqlite3AppendChar(pAccum, width-1, ' '); |
+ width = 0; |
+ } |
+ sqlite3AppendChar(pAccum, precision-1, c); |
+ } |
+ length = 1; |
+ buf[0] = c; |
+ bufpt = buf; |
+ break; |
+ case etSTRING: |
+ case etDYNSTRING: |
+ if( bArgList ){ |
+ bufpt = getTextArg(pArgList); |
+ xtype = etSTRING; |
+ }else{ |
+ bufpt = va_arg(ap,char*); |
+ } |
+ if( bufpt==0 ){ |
+ bufpt = ""; |
+ }else if( xtype==etDYNSTRING ){ |
+ zExtra = bufpt; |
+ } |
+ if( precision>=0 ){ |
+ for(length=0; length<precision && bufpt[length]; length++){} |
+ }else{ |
+ length = sqlite3Strlen30(bufpt); |
+ } |
+ break; |
+ case etSQLESCAPE: /* Escape ' characters */ |
+ case etSQLESCAPE2: /* Escape ' and enclose in '...' */ |
+ case etSQLESCAPE3: { /* Escape " characters */ |
+ int i, j, k, n, isnull; |
+ int needQuote; |
+ char ch; |
+ char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ |
+ char *escarg; |
+ |
+ if( bArgList ){ |
+ escarg = getTextArg(pArgList); |
+ }else{ |
+ escarg = va_arg(ap,char*); |
+ } |
+ isnull = escarg==0; |
+ if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); |
+ k = precision; |
+ for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){ |
+ if( ch==q ) n++; |
+ } |
+ needQuote = !isnull && xtype==etSQLESCAPE2; |
+ n += i + 3; |
+ if( n>etBUFSIZE ){ |
+ bufpt = zExtra = sqlite3Malloc( n ); |
+ if( bufpt==0 ){ |
+ setStrAccumError(pAccum, STRACCUM_NOMEM); |
+ return; |
+ } |
+ }else{ |
+ bufpt = buf; |
+ } |
+ j = 0; |
+ if( needQuote ) bufpt[j++] = q; |
+ k = i; |
+ for(i=0; i<k; i++){ |
+ bufpt[j++] = ch = escarg[i]; |
+ if( ch==q ) bufpt[j++] = ch; |
+ } |
+ if( needQuote ) bufpt[j++] = q; |
+ bufpt[j] = 0; |
+ length = j; |
+ /* The precision in %q and %Q means how many input characters to |
+ ** consume, not the length of the output... |
+ ** if( precision>=0 && precision<length ) length = precision; */ |
+ break; |
+ } |
+ case etTOKEN: { |
+ Token *pToken; |
+ if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; |
+ pToken = va_arg(ap, Token*); |
+ assert( bArgList==0 ); |
+ if( pToken && pToken->n ){ |
+ sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n); |
+ } |
+ length = width = 0; |
+ break; |
+ } |
+ case etSRCLIST: { |
+ SrcList *pSrc; |
+ int k; |
+ struct SrcList_item *pItem; |
+ if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; |
+ pSrc = va_arg(ap, SrcList*); |
+ k = va_arg(ap, int); |
+ pItem = &pSrc->a[k]; |
+ assert( bArgList==0 ); |
+ assert( k>=0 && k<pSrc->nSrc ); |
+ if( pItem->zDatabase ){ |
+ sqlite3StrAccumAppendAll(pAccum, pItem->zDatabase); |
+ sqlite3StrAccumAppend(pAccum, ".", 1); |
+ } |
+ sqlite3StrAccumAppendAll(pAccum, pItem->zName); |
+ length = width = 0; |
+ break; |
+ } |
+ default: { |
+ assert( xtype==etINVALID ); |
+ return; |
+ } |
+ }/* End switch over the format type */ |
+ /* |
+ ** The text of the conversion is pointed to by "bufpt" and is |
+ ** "length" characters long. The field width is "width". Do |
+ ** the output. |
+ */ |
+ width -= length; |
+ if( width>0 ){ |
+ if( !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); |
+ sqlite3StrAccumAppend(pAccum, bufpt, length); |
+ if( flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); |
+ }else{ |
+ sqlite3StrAccumAppend(pAccum, bufpt, length); |
+ } |
+ |
+ if( zExtra ){ |
+ sqlite3DbFree(pAccum->db, zExtra); |
+ zExtra = 0; |
+ } |
+ }/* End for loop over the format string */ |
+} /* End of function */ |
+ |
+/* |
+** Enlarge the memory allocation on a StrAccum object so that it is |
+** able to accept at least N more bytes of text. |
+** |
+** Return the number of bytes of text that StrAccum is able to accept |
+** after the attempted enlargement. The value returned might be zero. |
+*/ |
+static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ |
+ char *zNew; |
+ assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ |
+ if( p->accError ){ |
+ testcase(p->accError==STRACCUM_TOOBIG); |
+ testcase(p->accError==STRACCUM_NOMEM); |
+ return 0; |
+ } |
+ if( p->mxAlloc==0 ){ |
+ N = p->nAlloc - p->nChar - 1; |
+ setStrAccumError(p, STRACCUM_TOOBIG); |
+ return N; |
+ }else{ |
+ char *zOld = isMalloced(p) ? p->zText : 0; |
+ i64 szNew = p->nChar; |
+ assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); |
+ szNew += N + 1; |
+ if( szNew+p->nChar<=p->mxAlloc ){ |
+ /* Force exponential buffer size growth as long as it does not overflow, |
+ ** to avoid having to call this routine too often */ |
+ szNew += p->nChar; |
+ } |
+ if( szNew > p->mxAlloc ){ |
+ sqlite3StrAccumReset(p); |
+ setStrAccumError(p, STRACCUM_TOOBIG); |
+ return 0; |
+ }else{ |
+ p->nAlloc = (int)szNew; |
+ } |
+ if( p->db ){ |
+ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); |
+ }else{ |
+ zNew = sqlite3_realloc64(zOld, p->nAlloc); |
+ } |
+ if( zNew ){ |
+ assert( p->zText!=0 || p->nChar==0 ); |
+ if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar); |
+ p->zText = zNew; |
+ p->nAlloc = sqlite3DbMallocSize(p->db, zNew); |
+ p->printfFlags |= SQLITE_PRINTF_MALLOCED; |
+ }else{ |
+ sqlite3StrAccumReset(p); |
+ setStrAccumError(p, STRACCUM_NOMEM); |
+ return 0; |
+ } |
+ } |
+ return N; |
+} |
+ |
+/* |
+** Append N copies of character c to the given string buffer. |
+*/ |
+SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){ |
+ testcase( p->nChar + (i64)N > 0x7fffffff ); |
+ if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){ |
+ return; |
+ } |
+ assert( (p->zText==p->zBase)==!isMalloced(p) ); |
+ while( (N--)>0 ) p->zText[p->nChar++] = c; |
+} |
+ |
+/* |
+** The StrAccum "p" is not large enough to accept N new bytes of z[]. |
+** So enlarge if first, then do the append. |
+** |
+** This is a helper routine to sqlite3StrAccumAppend() that does special-case |
+** work (enlarging the buffer) using tail recursion, so that the |
+** sqlite3StrAccumAppend() routine can use fast calling semantics. |
+*/ |
+static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ |
+ N = sqlite3StrAccumEnlarge(p, N); |
+ if( N>0 ){ |
+ memcpy(&p->zText[p->nChar], z, N); |
+ p->nChar += N; |
+ } |
+ assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); |
+} |
+ |
+/* |
+** Append N bytes of text from z to the StrAccum object. Increase the |
+** size of the memory allocation for StrAccum if necessary. |
+*/ |
+SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ |
+ assert( z!=0 || N==0 ); |
+ assert( p->zText!=0 || p->nChar==0 || p->accError ); |
+ assert( N>=0 ); |
+ assert( p->accError==0 || p->nAlloc==0 ); |
+ if( p->nChar+N >= p->nAlloc ){ |
+ enlargeAndAppend(p,z,N); |
+ }else if( N ){ |
+ assert( p->zText ); |
+ p->nChar += N; |
+ memcpy(&p->zText[p->nChar-N], z, N); |
+ } |
+} |
+ |
+/* |
+** Append the complete text of zero-terminated string z[] to the p string. |
+*/ |
+SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ |
+ sqlite3StrAccumAppend(p, z, sqlite3Strlen30(z)); |
+} |
+ |
+ |
+/* |
+** Finish off a string by making sure it is zero-terminated. |
+** Return a pointer to the resulting string. Return a NULL |
+** pointer if any kind of error was encountered. |
+*/ |
+static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){ |
+ assert( p->mxAlloc>0 && !isMalloced(p) ); |
+ p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); |
+ if( p->zText ){ |
+ memcpy(p->zText, p->zBase, p->nChar+1); |
+ p->printfFlags |= SQLITE_PRINTF_MALLOCED; |
+ }else{ |
+ setStrAccumError(p, STRACCUM_NOMEM); |
+ } |
+ return p->zText; |
+} |
+SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ |
+ if( p->zText ){ |
+ assert( (p->zText==p->zBase)==!isMalloced(p) ); |
+ p->zText[p->nChar] = 0; |
+ if( p->mxAlloc>0 && !isMalloced(p) ){ |
+ return strAccumFinishRealloc(p); |
+ } |
+ } |
+ return p->zText; |
+} |
+ |
+/* |
+** Reset an StrAccum string. Reclaim all malloced memory. |
+*/ |
+SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){ |
+ assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); |
+ if( isMalloced(p) ){ |
+ sqlite3DbFree(p->db, p->zText); |
+ p->printfFlags &= ~SQLITE_PRINTF_MALLOCED; |
+ } |
+ p->zText = 0; |
+} |
+ |
+/* |
+** Initialize a string accumulator. |
+** |
+** p: The accumulator to be initialized. |
+** db: Pointer to a database connection. May be NULL. Lookaside |
+** memory is used if not NULL. db->mallocFailed is set appropriately |
+** when not NULL. |
+** zBase: An initial buffer. May be NULL in which case the initial buffer |
+** is malloced. |
+** n: Size of zBase in bytes. If total space requirements never exceed |
+** n then no memory allocations ever occur. |
+** mx: Maximum number of bytes to accumulate. If mx==0 then no memory |
+** allocations will ever occur. |
+*/ |
+SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){ |
+ p->zText = p->zBase = zBase; |
+ p->db = db; |
+ p->nChar = 0; |
+ p->nAlloc = n; |
+ p->mxAlloc = mx; |
+ p->accError = 0; |
+ p->printfFlags = 0; |
+} |
+ |
+/* |
+** Print into memory obtained from sqliteMalloc(). Use the internal |
+** %-conversion extensions. |
+*/ |
+SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){ |
+ char *z; |
+ char zBase[SQLITE_PRINT_BUF_SIZE]; |
+ StrAccum acc; |
+ assert( db!=0 ); |
+ sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase), |
+ db->aLimit[SQLITE_LIMIT_LENGTH]); |
+ acc.printfFlags = SQLITE_PRINTF_INTERNAL; |
+ sqlite3VXPrintf(&acc, zFormat, ap); |
+ z = sqlite3StrAccumFinish(&acc); |
+ if( acc.accError==STRACCUM_NOMEM ){ |
+ sqlite3OomFault(db); |
+ } |
+ return z; |
+} |
+ |
+/* |
+** Print into memory obtained from sqliteMalloc(). Use the internal |
+** %-conversion extensions. |
+*/ |
+SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){ |
+ va_list ap; |
+ char *z; |
+ va_start(ap, zFormat); |
+ z = sqlite3VMPrintf(db, zFormat, ap); |
+ va_end(ap); |
+ return z; |
+} |
+ |
+/* |
+** Print into memory obtained from sqlite3_malloc(). Omit the internal |
+** %-conversion extensions. |
+*/ |
+SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){ |
+ char *z; |
+ char zBase[SQLITE_PRINT_BUF_SIZE]; |
+ StrAccum acc; |
+ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( zFormat==0 ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); |
+ sqlite3VXPrintf(&acc, zFormat, ap); |
+ z = sqlite3StrAccumFinish(&acc); |
+ return z; |
+} |
+ |
+/* |
+** Print into memory obtained from sqlite3_malloc()(). Omit the internal |
+** %-conversion extensions. |
+*/ |
+SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){ |
+ va_list ap; |
+ char *z; |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ va_start(ap, zFormat); |
+ z = sqlite3_vmprintf(zFormat, ap); |
+ va_end(ap); |
+ return z; |
+} |
+ |
+/* |
+** sqlite3_snprintf() works like snprintf() except that it ignores the |
+** current locale settings. This is important for SQLite because we |
+** are not able to use a "," as the decimal point in place of "." as |
+** specified by some locales. |
+** |
+** Oops: The first two arguments of sqlite3_snprintf() are backwards |
+** from the snprintf() standard. Unfortunately, it is too late to change |
+** this without breaking compatibility, so we just have to live with the |
+** mistake. |
+** |
+** sqlite3_vsnprintf() is the varargs version. |
+*/ |
+SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){ |
+ StrAccum acc; |
+ if( n<=0 ) return zBuf; |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( zBuf==0 || zFormat==0 ) { |
+ (void)SQLITE_MISUSE_BKPT; |
+ if( zBuf ) zBuf[0] = 0; |
+ return zBuf; |
+ } |
+#endif |
+ sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); |
+ sqlite3VXPrintf(&acc, zFormat, ap); |
+ zBuf[acc.nChar] = 0; |
+ return zBuf; |
+} |
+SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ |
+ char *z; |
+ va_list ap; |
+ va_start(ap,zFormat); |
+ z = sqlite3_vsnprintf(n, zBuf, zFormat, ap); |
+ va_end(ap); |
+ return z; |
+} |
+ |
+/* |
+** This is the routine that actually formats the sqlite3_log() message. |
+** We house it in a separate routine from sqlite3_log() to avoid using |
+** stack space on small-stack systems when logging is disabled. |
+** |
+** sqlite3_log() must render into a static buffer. It cannot dynamically |
+** allocate memory because it might be called while the memory allocator |
+** mutex is held. |
+** |
+** sqlite3VXPrintf() might ask for *temporary* memory allocations for |
+** certain format characters (%q) or for very large precisions or widths. |
+** Care must be taken that any sqlite3_log() calls that occur while the |
+** memory mutex is held do not use these mechanisms. |
+*/ |
+static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ |
+ StrAccum acc; /* String accumulator */ |
+ char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ |
+ |
+ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); |
+ sqlite3VXPrintf(&acc, zFormat, ap); |
+ sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, |
+ sqlite3StrAccumFinish(&acc)); |
+} |
+ |
+/* |
+** Format and write a message to the log if logging is enabled. |
+*/ |
+SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){ |
+ va_list ap; /* Vararg list */ |
+ if( sqlite3GlobalConfig.xLog ){ |
+ va_start(ap, zFormat); |
+ renderLogMsg(iErrCode, zFormat, ap); |
+ va_end(ap); |
+ } |
+} |
+ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) |
+/* |
+** A version of printf() that understands %lld. Used for debugging. |
+** The printf() built into some versions of windows does not understand %lld |
+** and segfaults if you give it a long long int. |
+*/ |
+SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ |
+ va_list ap; |
+ StrAccum acc; |
+ char zBuf[500]; |
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); |
+ va_start(ap,zFormat); |
+ sqlite3VXPrintf(&acc, zFormat, ap); |
+ va_end(ap); |
+ sqlite3StrAccumFinish(&acc); |
+ fprintf(stdout,"%s", zBuf); |
+ fflush(stdout); |
+} |
+#endif |
+ |
+ |
+/* |
+** variable-argument wrapper around sqlite3VXPrintf(). The bFlags argument |
+** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats. |
+*/ |
+SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){ |
+ va_list ap; |
+ va_start(ap,zFormat); |
+ sqlite3VXPrintf(p, zFormat, ap); |
+ va_end(ap); |
+} |
+ |
+/************** End of printf.c **********************************************/ |
+/************** Begin file treeview.c ****************************************/ |
+/* |
+** 2015-06-08 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** |
+** This file contains C code to implement the TreeView debugging routines. |
+** These routines print a parse tree to standard output for debugging and |
+** analysis. |
+** |
+** The interfaces in this file is only available when compiling |
+** with SQLITE_DEBUG. |
+*/ |
+/* #include "sqliteInt.h" */ |
+#ifdef SQLITE_DEBUG |
+ |
+/* |
+** Add a new subitem to the tree. The moreToFollow flag indicates that this |
+** is not the last item in the tree. |
+*/ |
+static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ |
+ if( p==0 ){ |
+ p = sqlite3_malloc64( sizeof(*p) ); |
+ if( p==0 ) return 0; |
+ memset(p, 0, sizeof(*p)); |
+ }else{ |
+ p->iLevel++; |
+ } |
+ assert( moreToFollow==0 || moreToFollow==1 ); |
+ if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow; |
+ return p; |
+} |
+ |
+/* |
+** Finished with one layer of the tree |
+*/ |
+static void sqlite3TreeViewPop(TreeView *p){ |
+ if( p==0 ) return; |
+ p->iLevel--; |
+ if( p->iLevel<0 ) sqlite3_free(p); |
+} |
+ |
+/* |
+** Generate a single line of output for the tree, with a prefix that contains |
+** all the appropriate tree lines |
+*/ |
+static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ |
+ va_list ap; |
+ int i; |
+ StrAccum acc; |
+ char zBuf[500]; |
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); |
+ if( p ){ |
+ for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){ |
+ sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); |
+ } |
+ sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); |
+ } |
+ va_start(ap, zFormat); |
+ sqlite3VXPrintf(&acc, zFormat, ap); |
+ va_end(ap); |
+ assert( acc.nChar>0 ); |
+ if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1); |
+ sqlite3StrAccumFinish(&acc); |
+ fprintf(stdout,"%s", zBuf); |
+ fflush(stdout); |
+} |
+ |
+/* |
+** Shorthand for starting a new tree item that consists of a single label |
+*/ |
+static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){ |
+ p = sqlite3TreeViewPush(p, moreFollows); |
+ sqlite3TreeViewLine(p, "%s", zLabel); |
+} |
+ |
+/* |
+** Generate a human-readable description of a WITH clause. |
+*/ |
+SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){ |
+ int i; |
+ if( pWith==0 ) return; |
+ if( pWith->nCte==0 ) return; |
+ if( pWith->pOuter ){ |
+ sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter); |
+ }else{ |
+ sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith); |
+ } |
+ if( pWith->nCte>0 ){ |
+ pView = sqlite3TreeViewPush(pView, 1); |
+ for(i=0; i<pWith->nCte; i++){ |
+ StrAccum x; |
+ char zLine[1000]; |
+ const struct Cte *pCte = &pWith->a[i]; |
+ sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); |
+ sqlite3XPrintf(&x, "%s", pCte->zName); |
+ if( pCte->pCols && pCte->pCols->nExpr>0 ){ |
+ char cSep = '('; |
+ int j; |
+ for(j=0; j<pCte->pCols->nExpr; j++){ |
+ sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName); |
+ cSep = ','; |
+ } |
+ sqlite3XPrintf(&x, ")"); |
+ } |
+ sqlite3XPrintf(&x, " AS"); |
+ sqlite3StrAccumFinish(&x); |
+ sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1); |
+ sqlite3TreeViewSelect(pView, pCte->pSelect, 0); |
+ sqlite3TreeViewPop(pView); |
+ } |
+ sqlite3TreeViewPop(pView); |
+ } |
+} |
+ |
+ |
+/* |
+** Generate a human-readable description of a Select object. |
+*/ |
+SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ |
+ int n = 0; |
+ int cnt = 0; |
+ pView = sqlite3TreeViewPush(pView, moreToFollow); |
+ if( p->pWith ){ |
+ sqlite3TreeViewWith(pView, p->pWith, 1); |
+ cnt = 1; |
+ sqlite3TreeViewPush(pView, 1); |
+ } |
+ do{ |
+ sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d", |
+ ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), |
+ ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags, |
+ (int)p->nSelectRow |
+ ); |
+ if( cnt++ ) sqlite3TreeViewPop(pView); |
+ if( p->pPrior ){ |
+ n = 1000; |
+ }else{ |
+ n = 0; |
+ if( p->pSrc && p->pSrc->nSrc ) n++; |
+ if( p->pWhere ) n++; |
+ if( p->pGroupBy ) n++; |
+ if( p->pHaving ) n++; |
+ if( p->pOrderBy ) n++; |
+ if( p->pLimit ) n++; |
+ if( p->pOffset ) n++; |
+ } |
+ sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set"); |
+ if( p->pSrc && p->pSrc->nSrc ){ |
+ int i; |
+ pView = sqlite3TreeViewPush(pView, (n--)>0); |
+ sqlite3TreeViewLine(pView, "FROM"); |
+ for(i=0; i<p->pSrc->nSrc; i++){ |
+ struct SrcList_item *pItem = &p->pSrc->a[i]; |
+ StrAccum x; |
+ char zLine[100]; |
+ sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); |
+ sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor); |
+ if( pItem->zDatabase ){ |
+ sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName); |
+ }else if( pItem->zName ){ |
+ sqlite3XPrintf(&x, " %s", pItem->zName); |
+ } |
+ if( pItem->pTab ){ |
+ sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName); |
+ } |
+ if( pItem->zAlias ){ |
+ sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias); |
+ } |
+ if( pItem->fg.jointype & JT_LEFT ){ |
+ sqlite3XPrintf(&x, " LEFT-JOIN"); |
+ } |
+ sqlite3StrAccumFinish(&x); |
+ sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1); |
+ if( pItem->pSelect ){ |
+ sqlite3TreeViewSelect(pView, pItem->pSelect, 0); |
+ } |
+ if( pItem->fg.isTabFunc ){ |
+ sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); |
+ } |
+ sqlite3TreeViewPop(pView); |
+ } |
+ sqlite3TreeViewPop(pView); |
+ } |
+ if( p->pWhere ){ |
+ sqlite3TreeViewItem(pView, "WHERE", (n--)>0); |
+ sqlite3TreeViewExpr(pView, p->pWhere, 0); |
+ sqlite3TreeViewPop(pView); |
+ } |
+ if( p->pGroupBy ){ |
+ sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); |
+ } |
+ if( p->pHaving ){ |
+ sqlite3TreeViewItem(pView, "HAVING", (n--)>0); |
+ sqlite3TreeViewExpr(pView, p->pHaving, 0); |
+ sqlite3TreeViewPop(pView); |
+ } |
+ if( p->pOrderBy ){ |
+ sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); |
+ } |
+ if( p->pLimit ){ |
+ sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); |
+ sqlite3TreeViewExpr(pView, p->pLimit, 0); |
+ sqlite3TreeViewPop(pView); |
+ } |
+ if( p->pOffset ){ |
+ sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); |
+ sqlite3TreeViewExpr(pView, p->pOffset, 0); |
+ sqlite3TreeViewPop(pView); |
+ } |
+ if( p->pPrior ){ |
+ const char *zOp = "UNION"; |
+ switch( p->op ){ |
+ case TK_ALL: zOp = "UNION ALL"; break; |
+ case TK_INTERSECT: zOp = "INTERSECT"; break; |
+ case TK_EXCEPT: zOp = "EXCEPT"; break; |
+ } |
+ sqlite3TreeViewItem(pView, zOp, 1); |
+ } |
+ p = p->pPrior; |
+ }while( p!=0 ); |
+ sqlite3TreeViewPop(pView); |
+} |
+ |
+/* |
+** Generate a human-readable explanation of an expression tree. |
+*/ |
+SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ |
+ const char *zBinOp = 0; /* Binary operator */ |
+ const char *zUniOp = 0; /* Unary operator */ |
+ char zFlgs[30]; |
+ pView = sqlite3TreeViewPush(pView, moreToFollow); |
+ if( pExpr==0 ){ |
+ sqlite3TreeViewLine(pView, "nil"); |
+ sqlite3TreeViewPop(pView); |
+ return; |
+ } |
+ if( pExpr->flags ){ |
+ sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags); |
+ }else{ |
+ zFlgs[0] = 0; |
+ } |
+ switch( pExpr->op ){ |
+ case TK_AGG_COLUMN: { |
+ sqlite3TreeViewLine(pView, "AGG{%d:%d}%s", |
+ pExpr->iTable, pExpr->iColumn, zFlgs); |
+ break; |
+ } |
+ case TK_COLUMN: { |
+ if( pExpr->iTable<0 ){ |
+ /* This only happens when coding check constraints */ |
+ sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs); |
+ }else{ |
+ sqlite3TreeViewLine(pView, "{%d:%d}%s", |
+ pExpr->iTable, pExpr->iColumn, zFlgs); |
+ } |
+ break; |
+ } |
+ case TK_INTEGER: { |
+ if( pExpr->flags & EP_IntValue ){ |
+ sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); |
+ }else{ |
+ sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); |
+ } |
+ break; |
+ } |
+#ifndef SQLITE_OMIT_FLOATING_POINT |
+ case TK_FLOAT: { |
+ sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); |
+ break; |
+ } |
+#endif |
+ case TK_STRING: { |
+ sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); |
+ break; |
+ } |
+ case TK_NULL: { |
+ sqlite3TreeViewLine(pView,"NULL"); |
+ break; |
+ } |
+#ifndef SQLITE_OMIT_BLOB_LITERAL |
+ case TK_BLOB: { |
+ sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); |
+ break; |
+ } |
+#endif |
+ case TK_VARIABLE: { |
+ sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", |
+ pExpr->u.zToken, pExpr->iColumn); |
+ break; |
+ } |
+ case TK_REGISTER: { |
+ sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); |
+ break; |
+ } |
+ case TK_ID: { |
+ sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); |
+ break; |
+ } |
+#ifndef SQLITE_OMIT_CAST |
+ case TK_CAST: { |
+ /* Expressions of the form: CAST(pLeft AS token) */ |
+ sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); |
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
+ break; |
+ } |
+#endif /* SQLITE_OMIT_CAST */ |
+ case TK_LT: zBinOp = "LT"; break; |
+ case TK_LE: zBinOp = "LE"; break; |
+ case TK_GT: zBinOp = "GT"; break; |
+ case TK_GE: zBinOp = "GE"; break; |
+ case TK_NE: zBinOp = "NE"; break; |
+ case TK_EQ: zBinOp = "EQ"; break; |
+ case TK_IS: zBinOp = "IS"; break; |
+ case TK_ISNOT: zBinOp = "ISNOT"; break; |
+ case TK_AND: zBinOp = "AND"; break; |
+ case TK_OR: zBinOp = "OR"; break; |
+ case TK_PLUS: zBinOp = "ADD"; break; |
+ case TK_STAR: zBinOp = "MUL"; break; |
+ case TK_MINUS: zBinOp = "SUB"; break; |
+ case TK_REM: zBinOp = "REM"; break; |
+ case TK_BITAND: zBinOp = "BITAND"; break; |
+ case TK_BITOR: zBinOp = "BITOR"; break; |
+ case TK_SLASH: zBinOp = "DIV"; break; |
+ case TK_LSHIFT: zBinOp = "LSHIFT"; break; |
+ case TK_RSHIFT: zBinOp = "RSHIFT"; break; |
+ case TK_CONCAT: zBinOp = "CONCAT"; break; |
+ case TK_DOT: zBinOp = "DOT"; break; |
+ |
+ case TK_UMINUS: zUniOp = "UMINUS"; break; |
+ case TK_UPLUS: zUniOp = "UPLUS"; break; |
+ case TK_BITNOT: zUniOp = "BITNOT"; break; |
+ case TK_NOT: zUniOp = "NOT"; break; |
+ case TK_ISNULL: zUniOp = "ISNULL"; break; |
+ case TK_NOTNULL: zUniOp = "NOTNULL"; break; |
+ |
+ case TK_SPAN: { |
+ sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); |
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
+ break; |
+ } |
+ |
+ case TK_COLLATE: { |
+ sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); |
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
+ break; |
+ } |
+ |
+ case TK_AGG_FUNCTION: |
+ case TK_FUNCTION: { |
+ ExprList *pFarg; /* List of function arguments */ |
+ if( ExprHasProperty(pExpr, EP_TokenOnly) ){ |
+ pFarg = 0; |
+ }else{ |
+ pFarg = pExpr->x.pList; |
+ } |
+ if( pExpr->op==TK_AGG_FUNCTION ){ |
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", |
+ pExpr->op2, pExpr->u.zToken); |
+ }else{ |
+ sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); |
+ } |
+ if( pFarg ){ |
+ sqlite3TreeViewExprList(pView, pFarg, 0, 0); |
+ } |
+ break; |
+ } |
+#ifndef SQLITE_OMIT_SUBQUERY |
+ case TK_EXISTS: { |
+ sqlite3TreeViewLine(pView, "EXISTS-expr"); |
+ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); |
+ break; |
+ } |
+ case TK_SELECT: { |
+ sqlite3TreeViewLine(pView, "SELECT-expr"); |
+ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); |
+ break; |
+ } |
+ case TK_IN: { |
+ sqlite3TreeViewLine(pView, "IN"); |
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); |
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){ |
+ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); |
+ }else{ |
+ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); |
+ } |
+ break; |
+ } |
+#endif /* SQLITE_OMIT_SUBQUERY */ |
+ |
+ /* |
+ ** x BETWEEN y AND z |
+ ** |
+ ** This is equivalent to |
+ ** |
+ ** x>=y AND x<=z |
+ ** |
+ ** X is stored in pExpr->pLeft. |
+ ** Y is stored in pExpr->pList->a[0].pExpr. |
+ ** Z is stored in pExpr->pList->a[1].pExpr. |
+ */ |
+ case TK_BETWEEN: { |
+ Expr *pX = pExpr->pLeft; |
+ Expr *pY = pExpr->x.pList->a[0].pExpr; |
+ Expr *pZ = pExpr->x.pList->a[1].pExpr; |
+ sqlite3TreeViewLine(pView, "BETWEEN"); |
+ sqlite3TreeViewExpr(pView, pX, 1); |
+ sqlite3TreeViewExpr(pView, pY, 1); |
+ sqlite3TreeViewExpr(pView, pZ, 0); |
+ break; |
+ } |
+ case TK_TRIGGER: { |
+ /* If the opcode is TK_TRIGGER, then the expression is a reference |
+ ** to a column in the new.* or old.* pseudo-tables available to |
+ ** trigger programs. In this case Expr.iTable is set to 1 for the |
+ ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn |
+ ** is set to the column of the pseudo-table to read, or to -1 to |
+ ** read the rowid field. |
+ */ |
+ sqlite3TreeViewLine(pView, "%s(%d)", |
+ pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); |
+ break; |
+ } |
+ case TK_CASE: { |
+ sqlite3TreeViewLine(pView, "CASE"); |
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); |
+ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); |
+ break; |
+ } |
+#ifndef SQLITE_OMIT_TRIGGER |
+ case TK_RAISE: { |
+ const char *zType = "unk"; |
+ switch( pExpr->affinity ){ |
+ case OE_Rollback: zType = "rollback"; break; |
+ case OE_Abort: zType = "abort"; break; |
+ case OE_Fail: zType = "fail"; break; |
+ case OE_Ignore: zType = "ignore"; break; |
+ } |
+ sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); |
+ break; |
+ } |
+#endif |
+ case TK_MATCH: { |
+ sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s", |
+ pExpr->iTable, pExpr->iColumn, zFlgs); |
+ sqlite3TreeViewExpr(pView, pExpr->pRight, 0); |
+ break; |
+ } |
+ case TK_VECTOR: { |
+ sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR"); |
+ break; |
+ } |
+ case TK_SELECT_COLUMN: { |
+ sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn); |
+ sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); |
+ break; |
+ } |
+ default: { |
+ sqlite3TreeViewLine(pView, "op=%d", pExpr->op); |
+ break; |
+ } |
+ } |
+ if( zBinOp ){ |
+ sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs); |
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); |
+ sqlite3TreeViewExpr(pView, pExpr->pRight, 0); |
+ }else if( zUniOp ){ |
+ sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs); |
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); |
+ } |
+ sqlite3TreeViewPop(pView); |
+} |
+ |
+ |
+/* |
+** Generate a human-readable explanation of an expression list. |
+*/ |
+SQLITE_PRIVATE void sqlite3TreeViewBareExprList( |
+ TreeView *pView, |
+ const ExprList *pList, |
+ const char *zLabel |
+){ |
+ if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; |
+ if( pList==0 ){ |
+ sqlite3TreeViewLine(pView, "%s (empty)", zLabel); |
+ }else{ |
+ int i; |
+ sqlite3TreeViewLine(pView, "%s", zLabel); |
+ for(i=0; i<pList->nExpr; i++){ |
+ int j = pList->a[i].u.x.iOrderByCol; |
+ if( j ){ |
+ sqlite3TreeViewPush(pView, 0); |
+ sqlite3TreeViewLine(pView, "iOrderByCol=%d", j); |
+ } |
+ sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1); |
+ if( j ) sqlite3TreeViewPop(pView); |
+ } |
+ } |
+} |
+SQLITE_PRIVATE void sqlite3TreeViewExprList( |
+ TreeView *pView, |
+ const ExprList *pList, |
+ u8 moreToFollow, |
+ const char *zLabel |
+){ |
+ pView = sqlite3TreeViewPush(pView, moreToFollow); |
+ sqlite3TreeViewBareExprList(pView, pList, zLabel); |
+ sqlite3TreeViewPop(pView); |
+} |
+ |
+#endif /* SQLITE_DEBUG */ |
+ |
+/************** End of treeview.c ********************************************/ |
+/************** Begin file random.c ******************************************/ |
+/* |
+** 2001 September 15 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file contains code to implement a pseudo-random number |
+** generator (PRNG) for SQLite. |
+** |
+** Random numbers are used by some of the database backends in order |
+** to generate random integer keys for tables or random filenames. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+ |
+/* All threads share a single random number generator. |
+** This structure is the current state of the generator. |
+*/ |
+static SQLITE_WSD struct sqlite3PrngType { |
+ unsigned char isInit; /* True if initialized */ |
+ unsigned char i, j; /* State variables */ |
+ unsigned char s[256]; /* State variables */ |
+} sqlite3Prng; |
+ |
+/* |
+** Return N random bytes. |
+*/ |
+SQLITE_API void sqlite3_randomness(int N, void *pBuf){ |
+ unsigned char t; |
+ unsigned char *zBuf = pBuf; |
+ |
+ /* The "wsdPrng" macro will resolve to the pseudo-random number generator |
+ ** state vector. If writable static data is unsupported on the target, |
+ ** we have to locate the state vector at run-time. In the more common |
+ ** case where writable static data is supported, wsdPrng can refer directly |
+ ** to the "sqlite3Prng" state vector declared above. |
+ */ |
+#ifdef SQLITE_OMIT_WSD |
+ struct sqlite3PrngType *p = &GLOBAL(struct sqlite3PrngType, sqlite3Prng); |
+# define wsdPrng p[0] |
+#else |
+# define wsdPrng sqlite3Prng |
+#endif |
+ |
+#if SQLITE_THREADSAFE |
+ sqlite3_mutex *mutex; |
+#endif |
+ |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return; |
+#endif |
+ |
+#if SQLITE_THREADSAFE |
+ mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); |
+#endif |
+ |
+ sqlite3_mutex_enter(mutex); |
+ if( N<=0 || pBuf==0 ){ |
+ wsdPrng.isInit = 0; |
+ sqlite3_mutex_leave(mutex); |
+ return; |
+ } |
+ |
+ /* Initialize the state of the random number generator once, |
+ ** the first time this routine is called. The seed value does |
+ ** not need to contain a lot of randomness since we are not |
+ ** trying to do secure encryption or anything like that... |
+ ** |
+ ** Nothing in this file or anywhere else in SQLite does any kind of |
+ ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random |
+ ** number generator) not as an encryption device. |
+ */ |
+ if( !wsdPrng.isInit ){ |
+ int i; |
+ char k[256]; |
+ wsdPrng.j = 0; |
+ wsdPrng.i = 0; |
+ sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k); |
+ for(i=0; i<256; i++){ |
+ wsdPrng.s[i] = (u8)i; |
+ } |
+ for(i=0; i<256; i++){ |
+ wsdPrng.j += wsdPrng.s[i] + k[i]; |
+ t = wsdPrng.s[wsdPrng.j]; |
+ wsdPrng.s[wsdPrng.j] = wsdPrng.s[i]; |
+ wsdPrng.s[i] = t; |
+ } |
+ wsdPrng.isInit = 1; |
+ } |
+ |
+ assert( N>0 ); |
+ do{ |
+ wsdPrng.i++; |
+ t = wsdPrng.s[wsdPrng.i]; |
+ wsdPrng.j += t; |
+ wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j]; |
+ wsdPrng.s[wsdPrng.j] = t; |
+ t += wsdPrng.s[wsdPrng.i]; |
+ *(zBuf++) = wsdPrng.s[t]; |
+ }while( --N ); |
+ sqlite3_mutex_leave(mutex); |
+} |
+ |
+#ifndef SQLITE_UNTESTABLE |
+/* |
+** For testing purposes, we sometimes want to preserve the state of |
+** PRNG and restore the PRNG to its saved state at a later time, or |
+** to reset the PRNG to its initial state. These routines accomplish |
+** those tasks. |
+** |
+** The sqlite3_test_control() interface calls these routines to |
+** control the PRNG. |
+*/ |
+static SQLITE_WSD struct sqlite3PrngType sqlite3SavedPrng; |
+SQLITE_PRIVATE void sqlite3PrngSaveState(void){ |
+ memcpy( |
+ &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng), |
+ &GLOBAL(struct sqlite3PrngType, sqlite3Prng), |
+ sizeof(sqlite3Prng) |
+ ); |
+} |
+SQLITE_PRIVATE void sqlite3PrngRestoreState(void){ |
+ memcpy( |
+ &GLOBAL(struct sqlite3PrngType, sqlite3Prng), |
+ &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng), |
+ sizeof(sqlite3Prng) |
+ ); |
+} |
+#endif /* SQLITE_UNTESTABLE */ |
+ |
+/************** End of random.c **********************************************/ |
+/************** Begin file threads.c *****************************************/ |
+/* |
+** 2012 July 21 |
+** |
+** 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 presents a simple cross-platform threading interface for |
+** use internally by SQLite. |
+** |
+** A "thread" can be created using sqlite3ThreadCreate(). This thread |
+** runs independently of its creator until it is joined using |
+** sqlite3ThreadJoin(), at which point it terminates. |
+** |
+** Threads do not have to be real. It could be that the work of the |
+** "thread" is done by the main thread at either the sqlite3ThreadCreate() |
+** or sqlite3ThreadJoin() call. This is, in fact, what happens in |
+** single threaded systems. Nothing in SQLite requires multiple threads. |
+** This interface exists so that applications that want to take advantage |
+** of multiple cores can do so, while also allowing applications to stay |
+** single-threaded if desired. |
+*/ |
+/* #include "sqliteInt.h" */ |
+#if SQLITE_OS_WIN |
+/* # include "os_win.h" */ |
+#endif |
+ |
+#if SQLITE_MAX_WORKER_THREADS>0 |
+ |
+/********************************* Unix Pthreads ****************************/ |
+#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 |
+ |
+#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ |
+/* #include <pthread.h> */ |
+ |
+/* A running thread */ |
+struct SQLiteThread { |
+ pthread_t tid; /* Thread ID */ |
+ int done; /* Set to true when thread finishes */ |
+ void *pOut; /* Result returned by the thread */ |
+ void *(*xTask)(void*); /* The thread routine */ |
+ void *pIn; /* Argument to the thread */ |
+}; |
+ |
+/* Create a new thread */ |
+SQLITE_PRIVATE int sqlite3ThreadCreate( |
+ SQLiteThread **ppThread, /* OUT: Write the thread object here */ |
+ void *(*xTask)(void*), /* Routine to run in a separate thread */ |
+ void *pIn /* Argument passed into xTask() */ |
+){ |
+ SQLiteThread *p; |
+ int rc; |
+ |
+ assert( ppThread!=0 ); |
+ assert( xTask!=0 ); |
+ /* This routine is never used in single-threaded mode */ |
+ assert( sqlite3GlobalConfig.bCoreMutex!=0 ); |
+ |
+ *ppThread = 0; |
+ p = sqlite3Malloc(sizeof(*p)); |
+ if( p==0 ) return SQLITE_NOMEM_BKPT; |
+ memset(p, 0, sizeof(*p)); |
+ p->xTask = xTask; |
+ p->pIn = pIn; |
+ /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a |
+ ** function that returns SQLITE_ERROR when passed the argument 200, that |
+ ** forces worker threads to run sequentially and deterministically |
+ ** for testing purposes. */ |
+ if( sqlite3FaultSim(200) ){ |
+ rc = 1; |
+ }else{ |
+ rc = pthread_create(&p->tid, 0, xTask, pIn); |
+ } |
+ if( rc ){ |
+ p->done = 1; |
+ p->pOut = xTask(pIn); |
+ } |
+ *ppThread = p; |
+ return SQLITE_OK; |
+} |
+ |
+/* Get the results of the thread */ |
+SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ |
+ int rc; |
+ |
+ assert( ppOut!=0 ); |
+ if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; |
+ if( p->done ){ |
+ *ppOut = p->pOut; |
+ rc = SQLITE_OK; |
+ }else{ |
+ rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK; |
+ } |
+ sqlite3_free(p); |
+ return rc; |
+} |
+ |
+#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ |
+/******************************** End Unix Pthreads *************************/ |
+ |
+ |
+/********************************* Win32 Threads ****************************/ |
+#if SQLITE_OS_WIN_THREADS |
+ |
+#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ |
+#include <process.h> |
+ |
+/* A running thread */ |
+struct SQLiteThread { |
+ void *tid; /* The thread handle */ |
+ unsigned id; /* The thread identifier */ |
+ void *(*xTask)(void*); /* The routine to run as a thread */ |
+ void *pIn; /* Argument to xTask */ |
+ void *pResult; /* Result of xTask */ |
+}; |
+ |
+/* Thread procedure Win32 compatibility shim */ |
+static unsigned __stdcall sqlite3ThreadProc( |
+ void *pArg /* IN: Pointer to the SQLiteThread structure */ |
+){ |
+ SQLiteThread *p = (SQLiteThread *)pArg; |
+ |
+ assert( p!=0 ); |
+#if 0 |
+ /* |
+ ** This assert appears to trigger spuriously on certain |
+ ** versions of Windows, possibly due to _beginthreadex() |
+ ** and/or CreateThread() not fully setting their thread |
+ ** ID parameter before starting the thread. |
+ */ |
+ assert( p->id==GetCurrentThreadId() ); |
+#endif |
+ assert( p->xTask!=0 ); |
+ p->pResult = p->xTask(p->pIn); |
+ |
+ _endthreadex(0); |
+ return 0; /* NOT REACHED */ |
+} |
+ |
+/* Create a new thread */ |
+SQLITE_PRIVATE int sqlite3ThreadCreate( |
+ SQLiteThread **ppThread, /* OUT: Write the thread object here */ |
+ void *(*xTask)(void*), /* Routine to run in a separate thread */ |
+ void *pIn /* Argument passed into xTask() */ |
+){ |
+ SQLiteThread *p; |
+ |
+ assert( ppThread!=0 ); |
+ assert( xTask!=0 ); |
+ *ppThread = 0; |
+ p = sqlite3Malloc(sizeof(*p)); |
+ if( p==0 ) return SQLITE_NOMEM_BKPT; |
+ /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a |
+ ** function that returns SQLITE_ERROR when passed the argument 200, that |
+ ** forces worker threads to run sequentially and deterministically |
+ ** (via the sqlite3FaultSim() term of the conditional) for testing |
+ ** purposes. */ |
+ if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){ |
+ memset(p, 0, sizeof(*p)); |
+ }else{ |
+ p->xTask = xTask; |
+ p->pIn = pIn; |
+ p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id); |
+ if( p->tid==0 ){ |
+ memset(p, 0, sizeof(*p)); |
+ } |
+ } |
+ if( p->xTask==0 ){ |
+ p->id = GetCurrentThreadId(); |
+ p->pResult = xTask(pIn); |
+ } |
+ *ppThread = p; |
+ return SQLITE_OK; |
+} |
+ |
+SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */ |
+ |
+/* Get the results of the thread */ |
+SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ |
+ DWORD rc; |
+ BOOL bRc; |
+ |
+ assert( ppOut!=0 ); |
+ if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; |
+ if( p->xTask==0 ){ |
+ /* assert( p->id==GetCurrentThreadId() ); */ |
+ rc = WAIT_OBJECT_0; |
+ assert( p->tid==0 ); |
+ }else{ |
+ assert( p->id!=0 && p->id!=GetCurrentThreadId() ); |
+ rc = sqlite3Win32Wait((HANDLE)p->tid); |
+ assert( rc!=WAIT_IO_COMPLETION ); |
+ bRc = CloseHandle((HANDLE)p->tid); |
+ assert( bRc ); |
+ } |
+ if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; |
+ sqlite3_free(p); |
+ return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; |
+} |
+ |
+#endif /* SQLITE_OS_WIN_THREADS */ |
+/******************************** End Win32 Threads *************************/ |
+ |
+ |
+/********************************* Single-Threaded **************************/ |
+#ifndef SQLITE_THREADS_IMPLEMENTED |
+/* |
+** This implementation does not actually create a new thread. It does the |
+** work of the thread in the main thread, when either the thread is created |
+** or when it is joined |
+*/ |
+ |
+/* A running thread */ |
+struct SQLiteThread { |
+ void *(*xTask)(void*); /* The routine to run as a thread */ |
+ void *pIn; /* Argument to xTask */ |
+ void *pResult; /* Result of xTask */ |
+}; |
+ |
+/* Create a new thread */ |
+SQLITE_PRIVATE int sqlite3ThreadCreate( |
+ SQLiteThread **ppThread, /* OUT: Write the thread object here */ |
+ void *(*xTask)(void*), /* Routine to run in a separate thread */ |
+ void *pIn /* Argument passed into xTask() */ |
+){ |
+ SQLiteThread *p; |
+ |
+ assert( ppThread!=0 ); |
+ assert( xTask!=0 ); |
+ *ppThread = 0; |
+ p = sqlite3Malloc(sizeof(*p)); |
+ if( p==0 ) return SQLITE_NOMEM_BKPT; |
+ if( (SQLITE_PTR_TO_INT(p)/17)&1 ){ |
+ p->xTask = xTask; |
+ p->pIn = pIn; |
+ }else{ |
+ p->xTask = 0; |
+ p->pResult = xTask(pIn); |
+ } |
+ *ppThread = p; |
+ return SQLITE_OK; |
+} |
+ |
+/* Get the results of the thread */ |
+SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ |
+ |
+ assert( ppOut!=0 ); |
+ if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT; |
+ if( p->xTask ){ |
+ *ppOut = p->xTask(p->pIn); |
+ }else{ |
+ *ppOut = p->pResult; |
+ } |
+ sqlite3_free(p); |
+ |
+#if defined(SQLITE_TEST) |
+ { |
+ void *pTstAlloc = sqlite3Malloc(10); |
+ if (!pTstAlloc) return SQLITE_NOMEM_BKPT; |
+ sqlite3_free(pTstAlloc); |
+ } |
+#endif |
+ |
+ return SQLITE_OK; |
+} |
+ |
+#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */ |
+/****************************** End Single-Threaded *************************/ |
+#endif /* SQLITE_MAX_WORKER_THREADS>0 */ |
+ |
+/************** End of threads.c *********************************************/ |
+/************** Begin file utf.c *********************************************/ |
+/* |
+** 2004 April 13 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file contains routines used to translate between UTF-8, |
+** UTF-16, UTF-16BE, and UTF-16LE. |
+** |
+** Notes on UTF-8: |
+** |
+** Byte-0 Byte-1 Byte-2 Byte-3 Value |
+** 0xxxxxxx 00000000 00000000 0xxxxxxx |
+** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx |
+** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx |
+** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx |
+** |
+** |
+** Notes on UTF-16: (with wwww+1==uuuuu) |
+** |
+** Word-0 Word-1 Value |
+** 110110ww wwzzzzyy 110111yy yyxxxxxx 000uuuuu zzzzyyyy yyxxxxxx |
+** zzzzyyyy yyxxxxxx 00000000 zzzzyyyy yyxxxxxx |
+** |
+** |
+** BOM or Byte Order Mark: |
+** 0xff 0xfe little-endian utf-16 follows |
+** 0xfe 0xff big-endian utf-16 follows |
+** |
+*/ |
+/* #include "sqliteInt.h" */ |
+/* #include <assert.h> */ |
+/* #include "vdbeInt.h" */ |
+ |
+#if !defined(SQLITE_AMALGAMATION) && SQLITE_BYTEORDER==0 |
+/* |
+** The following constant value is used by the SQLITE_BIGENDIAN and |
+** SQLITE_LITTLEENDIAN macros. |
+*/ |
+SQLITE_PRIVATE const int sqlite3one = 1; |
+#endif /* SQLITE_AMALGAMATION && SQLITE_BYTEORDER==0 */ |
+ |
+/* |
+** This lookup table is used to help decode the first byte of |
+** a multi-byte UTF8 character. |
+*/ |
+static const unsigned char sqlite3Utf8Trans1[] = { |
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, |
+}; |
+ |
+ |
+#define WRITE_UTF8(zOut, c) { \ |
+ if( c<0x00080 ){ \ |
+ *zOut++ = (u8)(c&0xFF); \ |
+ } \ |
+ else if( c<0x00800 ){ \ |
+ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \ |
+ *zOut++ = 0x80 + (u8)(c & 0x3F); \ |
+ } \ |
+ else if( c<0x10000 ){ \ |
+ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \ |
+ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ |
+ *zOut++ = 0x80 + (u8)(c & 0x3F); \ |
+ }else{ \ |
+ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \ |
+ *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \ |
+ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ |
+ *zOut++ = 0x80 + (u8)(c & 0x3F); \ |
+ } \ |
+} |
+ |
+#define WRITE_UTF16LE(zOut, c) { \ |
+ if( c<=0xFFFF ){ \ |
+ *zOut++ = (u8)(c&0x00FF); \ |
+ *zOut++ = (u8)((c>>8)&0x00FF); \ |
+ }else{ \ |
+ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ |
+ *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \ |
+ *zOut++ = (u8)(c&0x00FF); \ |
+ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \ |
+ } \ |
+} |
+ |
+#define WRITE_UTF16BE(zOut, c) { \ |
+ if( c<=0xFFFF ){ \ |
+ *zOut++ = (u8)((c>>8)&0x00FF); \ |
+ *zOut++ = (u8)(c&0x00FF); \ |
+ }else{ \ |
+ *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \ |
+ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ |
+ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \ |
+ *zOut++ = (u8)(c&0x00FF); \ |
+ } \ |
+} |
+ |
+#define READ_UTF16LE(zIn, TERM, c){ \ |
+ c = (*zIn++); \ |
+ c += ((*zIn++)<<8); \ |
+ if( c>=0xD800 && c<0xE000 && TERM ){ \ |
+ int c2 = (*zIn++); \ |
+ c2 += ((*zIn++)<<8); \ |
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ |
+ } \ |
+} |
+ |
+#define READ_UTF16BE(zIn, TERM, c){ \ |
+ c = ((*zIn++)<<8); \ |
+ c += (*zIn++); \ |
+ if( c>=0xD800 && c<0xE000 && TERM ){ \ |
+ int c2 = ((*zIn++)<<8); \ |
+ c2 += (*zIn++); \ |
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ |
+ } \ |
+} |
+ |
+/* |
+** Translate a single UTF-8 character. Return the unicode value. |
+** |
+** During translation, assume that the byte that zTerm points |
+** is a 0x00. |
+** |
+** Write a pointer to the next unread byte back into *pzNext. |
+** |
+** Notes On Invalid UTF-8: |
+** |
+** * This routine never allows a 7-bit character (0x00 through 0x7f) to |
+** be encoded as a multi-byte character. Any multi-byte character that |
+** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd. |
+** |
+** * This routine never allows a UTF16 surrogate value to be encoded. |
+** If a multi-byte character attempts to encode a value between |
+** 0xd800 and 0xe000 then it is rendered as 0xfffd. |
+** |
+** * Bytes in the range of 0x80 through 0xbf which occur as the first |
+** byte of a character are interpreted as single-byte characters |
+** and rendered as themselves even though they are technically |
+** invalid characters. |
+** |
+** * This routine accepts over-length UTF8 encodings |
+** for unicode values 0x80 and greater. It does not change over-length |
+** encodings to 0xfffd as some systems recommend. |
+*/ |
+#define READ_UTF8(zIn, zTerm, c) \ |
+ c = *(zIn++); \ |
+ if( c>=0xc0 ){ \ |
+ c = sqlite3Utf8Trans1[c-0xc0]; \ |
+ while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ |
+ c = (c<<6) + (0x3f & *(zIn++)); \ |
+ } \ |
+ if( c<0x80 \ |
+ || (c&0xFFFFF800)==0xD800 \ |
+ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ |
+ } |
+SQLITE_PRIVATE u32 sqlite3Utf8Read( |
+ const unsigned char **pz /* Pointer to string from which to read char */ |
+){ |
+ unsigned int c; |
+ |
+ /* Same as READ_UTF8() above but without the zTerm parameter. |
+ ** For this routine, we assume the UTF8 string is always zero-terminated. |
+ */ |
+ c = *((*pz)++); |
+ if( c>=0xc0 ){ |
+ c = sqlite3Utf8Trans1[c-0xc0]; |
+ while( (*(*pz) & 0xc0)==0x80 ){ |
+ c = (c<<6) + (0x3f & *((*pz)++)); |
+ } |
+ if( c<0x80 |
+ || (c&0xFFFFF800)==0xD800 |
+ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } |
+ } |
+ return c; |
+} |
+ |
+ |
+ |
+ |
+/* |
+** If the TRANSLATE_TRACE macro is defined, the value of each Mem is |
+** printed on stderr on the way into and out of sqlite3VdbeMemTranslate(). |
+*/ |
+/* #define TRANSLATE_TRACE 1 */ |
+ |
+#ifndef SQLITE_OMIT_UTF16 |
+/* |
+** This routine transforms the internal text encoding used by pMem to |
+** desiredEnc. It is an error if the string is already of the desired |
+** encoding, or if *pMem does not contain a string value. |
+*/ |
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ |
+ int len; /* Maximum length of output string in bytes */ |
+ unsigned char *zOut; /* Output buffer */ |
+ unsigned char *zIn; /* Input iterator */ |
+ unsigned char *zTerm; /* End of input */ |
+ unsigned char *z; /* Output iterator */ |
+ unsigned int c; |
+ |
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); |
+ assert( pMem->flags&MEM_Str ); |
+ assert( pMem->enc!=desiredEnc ); |
+ assert( pMem->enc!=0 ); |
+ assert( pMem->n>=0 ); |
+ |
+#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) |
+ { |
+ char zBuf[100]; |
+ sqlite3VdbeMemPrettyPrint(pMem, zBuf); |
+ fprintf(stderr, "INPUT: %s\n", zBuf); |
+ } |
+#endif |
+ |
+ /* If the translation is between UTF-16 little and big endian, then |
+ ** all that is required is to swap the byte order. This case is handled |
+ ** differently from the others. |
+ */ |
+ if( pMem->enc!=SQLITE_UTF8 && desiredEnc!=SQLITE_UTF8 ){ |
+ u8 temp; |
+ int rc; |
+ rc = sqlite3VdbeMemMakeWriteable(pMem); |
+ if( rc!=SQLITE_OK ){ |
+ assert( rc==SQLITE_NOMEM ); |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ zIn = (u8*)pMem->z; |
+ zTerm = &zIn[pMem->n&~1]; |
+ while( zIn<zTerm ){ |
+ temp = *zIn; |
+ *zIn = *(zIn+1); |
+ zIn++; |
+ *zIn++ = temp; |
+ } |
+ pMem->enc = desiredEnc; |
+ goto translate_out; |
+ } |
+ |
+ /* Set len to the maximum number of bytes required in the output buffer. */ |
+ if( desiredEnc==SQLITE_UTF8 ){ |
+ /* When converting from UTF-16, the maximum growth results from |
+ ** translating a 2-byte character to a 4-byte UTF-8 character. |
+ ** A single byte is required for the output string |
+ ** nul-terminator. |
+ */ |
+ pMem->n &= ~1; |
+ len = pMem->n * 2 + 1; |
+ }else{ |
+ /* When converting from UTF-8 to UTF-16 the maximum growth is caused |
+ ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16 |
+ ** character. Two bytes are required in the output buffer for the |
+ ** nul-terminator. |
+ */ |
+ len = pMem->n * 2 + 2; |
+ } |
+ |
+ /* Set zIn to point at the start of the input buffer and zTerm to point 1 |
+ ** byte past the end. |
+ ** |
+ ** Variable zOut is set to point at the output buffer, space obtained |
+ ** from sqlite3_malloc(). |
+ */ |
+ zIn = (u8*)pMem->z; |
+ zTerm = &zIn[pMem->n]; |
+ zOut = sqlite3DbMallocRaw(pMem->db, len); |
+ if( !zOut ){ |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ z = zOut; |
+ |
+ if( pMem->enc==SQLITE_UTF8 ){ |
+ if( desiredEnc==SQLITE_UTF16LE ){ |
+ /* UTF-8 -> UTF-16 Little-endian */ |
+ while( zIn<zTerm ){ |
+ READ_UTF8(zIn, zTerm, c); |
+ WRITE_UTF16LE(z, c); |
+ } |
+ }else{ |
+ assert( desiredEnc==SQLITE_UTF16BE ); |
+ /* UTF-8 -> UTF-16 Big-endian */ |
+ while( zIn<zTerm ){ |
+ READ_UTF8(zIn, zTerm, c); |
+ WRITE_UTF16BE(z, c); |
+ } |
+ } |
+ pMem->n = (int)(z - zOut); |
+ *z++ = 0; |
+ }else{ |
+ assert( desiredEnc==SQLITE_UTF8 ); |
+ if( pMem->enc==SQLITE_UTF16LE ){ |
+ /* UTF-16 Little-endian -> UTF-8 */ |
+ while( zIn<zTerm ){ |
+ READ_UTF16LE(zIn, zIn<zTerm, c); |
+ WRITE_UTF8(z, c); |
+ } |
+ }else{ |
+ /* UTF-16 Big-endian -> UTF-8 */ |
+ while( zIn<zTerm ){ |
+ READ_UTF16BE(zIn, zIn<zTerm, c); |
+ WRITE_UTF8(z, c); |
+ } |
+ } |
+ pMem->n = (int)(z - zOut); |
+ } |
+ *z = 0; |
+ assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); |
+ |
+ c = pMem->flags; |
+ sqlite3VdbeMemRelease(pMem); |
+ pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype)); |
+ pMem->enc = desiredEnc; |
+ pMem->z = (char*)zOut; |
+ pMem->zMalloc = pMem->z; |
+ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->z); |
+ |
+translate_out: |
+#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) |
+ { |
+ char zBuf[100]; |
+ sqlite3VdbeMemPrettyPrint(pMem, zBuf); |
+ fprintf(stderr, "OUTPUT: %s\n", zBuf); |
+ } |
+#endif |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** This routine checks for a byte-order mark at the beginning of the |
+** UTF-16 string stored in *pMem. If one is present, it is removed and |
+** the encoding of the Mem adjusted. This routine does not do any |
+** byte-swapping, it just sets Mem.enc appropriately. |
+** |
+** The allocation (static, dynamic etc.) and encoding of the Mem may be |
+** changed by this function. |
+*/ |
+SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){ |
+ int rc = SQLITE_OK; |
+ u8 bom = 0; |
+ |
+ assert( pMem->n>=0 ); |
+ if( pMem->n>1 ){ |
+ u8 b1 = *(u8 *)pMem->z; |
+ u8 b2 = *(((u8 *)pMem->z) + 1); |
+ if( b1==0xFE && b2==0xFF ){ |
+ bom = SQLITE_UTF16BE; |
+ } |
+ if( b1==0xFF && b2==0xFE ){ |
+ bom = SQLITE_UTF16LE; |
+ } |
+ } |
+ |
+ if( bom ){ |
+ rc = sqlite3VdbeMemMakeWriteable(pMem); |
+ if( rc==SQLITE_OK ){ |
+ pMem->n -= 2; |
+ memmove(pMem->z, &pMem->z[2], pMem->n); |
+ pMem->z[pMem->n] = '\0'; |
+ pMem->z[pMem->n+1] = '\0'; |
+ pMem->flags |= MEM_Term; |
+ pMem->enc = bom; |
+ } |
+ } |
+ return rc; |
+} |
+#endif /* SQLITE_OMIT_UTF16 */ |
+ |
+/* |
+** pZ is a UTF-8 encoded unicode string. If nByte is less than zero, |
+** return the number of unicode characters in pZ up to (but not including) |
+** the first 0x00 byte. If nByte is not less than zero, return the |
+** number of unicode characters in the first nByte of pZ (or up to |
+** the first 0x00, whichever comes first). |
+*/ |
+SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){ |
+ int r = 0; |
+ const u8 *z = (const u8*)zIn; |
+ const u8 *zTerm; |
+ if( nByte>=0 ){ |
+ zTerm = &z[nByte]; |
+ }else{ |
+ zTerm = (const u8*)(-1); |
+ } |
+ assert( z<=zTerm ); |
+ while( *z!=0 && z<zTerm ){ |
+ SQLITE_SKIP_UTF8(z); |
+ r++; |
+ } |
+ return r; |
+} |
+ |
+/* This test function is not currently used by the automated test-suite. |
+** Hence it is only available in debug builds. |
+*/ |
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) |
+/* |
+** Translate UTF-8 to UTF-8. |
+** |
+** This has the effect of making sure that the string is well-formed |
+** UTF-8. Miscoded characters are removed. |
+** |
+** The translation is done in-place and aborted if the output |
+** overruns the input. |
+*/ |
+SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char *zIn){ |
+ unsigned char *zOut = zIn; |
+ unsigned char *zStart = zIn; |
+ u32 c; |
+ |
+ while( zIn[0] && zOut<=zIn ){ |
+ c = sqlite3Utf8Read((const u8**)&zIn); |
+ if( c!=0xfffd ){ |
+ WRITE_UTF8(zOut, c); |
+ } |
+ } |
+ *zOut = 0; |
+ return (int)(zOut - zStart); |
+} |
+#endif |
+ |
+#ifndef SQLITE_OMIT_UTF16 |
+/* |
+** Convert a UTF-16 string in the native encoding into a UTF-8 string. |
+** Memory to hold the UTF-8 string is obtained from sqlite3_malloc and must |
+** be freed by the calling function. |
+** |
+** NULL is returned if there is an allocation error. |
+*/ |
+SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){ |
+ Mem m; |
+ memset(&m, 0, sizeof(m)); |
+ m.db = db; |
+ sqlite3VdbeMemSetStr(&m, z, nByte, enc, SQLITE_STATIC); |
+ sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8); |
+ if( db->mallocFailed ){ |
+ sqlite3VdbeMemRelease(&m); |
+ m.z = 0; |
+ } |
+ assert( (m.flags & MEM_Term)!=0 || db->mallocFailed ); |
+ assert( (m.flags & MEM_Str)!=0 || db->mallocFailed ); |
+ assert( m.z || db->mallocFailed ); |
+ return m.z; |
+} |
+ |
+/* |
+** zIn is a UTF-16 encoded unicode string at least nChar characters long. |
+** Return the number of bytes in the first nChar unicode characters |
+** in pZ. nChar must be non-negative. |
+*/ |
+SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){ |
+ int c; |
+ unsigned char const *z = zIn; |
+ int n = 0; |
+ |
+ if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){ |
+ while( n<nChar ){ |
+ READ_UTF16BE(z, 1, c); |
+ n++; |
+ } |
+ }else{ |
+ while( n<nChar ){ |
+ READ_UTF16LE(z, 1, c); |
+ n++; |
+ } |
+ } |
+ return (int)(z-(unsigned char const *)zIn); |
+} |
+ |
+#if defined(SQLITE_TEST) |
+/* |
+** This routine is called from the TCL test function "translate_selftest". |
+** It checks that the primitives for serializing and deserializing |
+** characters in each encoding are inverses of each other. |
+*/ |
+SQLITE_PRIVATE void sqlite3UtfSelfTest(void){ |
+ unsigned int i, t; |
+ unsigned char zBuf[20]; |
+ unsigned char *z; |
+ int n; |
+ unsigned int c; |
+ |
+ for(i=0; i<0x00110000; i++){ |
+ z = zBuf; |
+ WRITE_UTF8(z, i); |
+ n = (int)(z-zBuf); |
+ assert( n>0 && n<=4 ); |
+ z[0] = 0; |
+ z = zBuf; |
+ c = sqlite3Utf8Read((const u8**)&z); |
+ t = i; |
+ if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD; |
+ if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD; |
+ assert( c==t ); |
+ assert( (z-zBuf)==n ); |
+ } |
+ for(i=0; i<0x00110000; i++){ |
+ if( i>=0xD800 && i<0xE000 ) continue; |
+ z = zBuf; |
+ WRITE_UTF16LE(z, i); |
+ n = (int)(z-zBuf); |
+ assert( n>0 && n<=4 ); |
+ z[0] = 0; |
+ z = zBuf; |
+ READ_UTF16LE(z, 1, c); |
+ assert( c==i ); |
+ assert( (z-zBuf)==n ); |
+ } |
+ for(i=0; i<0x00110000; i++){ |
+ if( i>=0xD800 && i<0xE000 ) continue; |
+ z = zBuf; |
+ WRITE_UTF16BE(z, i); |
+ n = (int)(z-zBuf); |
+ assert( n>0 && n<=4 ); |
+ z[0] = 0; |
+ z = zBuf; |
+ READ_UTF16BE(z, 1, c); |
+ assert( c==i ); |
+ assert( (z-zBuf)==n ); |
+ } |
+} |
+#endif /* SQLITE_TEST */ |
+#endif /* SQLITE_OMIT_UTF16 */ |
+ |
+/************** End of utf.c *************************************************/ |
+/************** Begin file util.c ********************************************/ |
+/* |
+** 2001 September 15 |
+** |
+** 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. |
+** |
+************************************************************************* |
+** Utility functions used throughout sqlite. |
+** |
+** This file contains functions for allocating memory, comparing |
+** strings, and stuff like that. |
+** |
+*/ |
+/* #include "sqliteInt.h" */ |
+/* #include <stdarg.h> */ |
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN |
+# include <math.h> |
+#endif |
+ |
+/* |
+** Routine needed to support the testcase() macro. |
+*/ |
+#ifdef SQLITE_COVERAGE_TEST |
+SQLITE_PRIVATE void sqlite3Coverage(int x){ |
+ static unsigned dummy = 0; |
+ dummy += (unsigned)x; |
+} |
+#endif |
+ |
+/* |
+** Give a callback to the test harness that can be used to simulate faults |
+** in places where it is difficult or expensive to do so purely by means |
+** of inputs. |
+** |
+** The intent of the integer argument is to let the fault simulator know |
+** which of multiple sqlite3FaultSim() calls has been hit. |
+** |
+** Return whatever integer value the test callback returns, or return |
+** SQLITE_OK if no test callback is installed. |
+*/ |
+#ifndef SQLITE_UNTESTABLE |
+SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ |
+ int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback; |
+ return xCallback ? xCallback(iTest) : SQLITE_OK; |
+} |
+#endif |
+ |
+#ifndef SQLITE_OMIT_FLOATING_POINT |
+/* |
+** Return true if the floating point value is Not a Number (NaN). |
+** |
+** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN. |
+** Otherwise, we have our own implementation that works on most systems. |
+*/ |
+SQLITE_PRIVATE int sqlite3IsNaN(double x){ |
+ int rc; /* The value return */ |
+#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN |
+ /* |
+ ** Systems that support the isnan() library function should probably |
+ ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have |
+ ** found that many systems do not have a working isnan() function so |
+ ** this implementation is provided as an alternative. |
+ ** |
+ ** This NaN test sometimes fails if compiled on GCC with -ffast-math. |
+ ** On the other hand, the use of -ffast-math comes with the following |
+ ** warning: |
+ ** |
+ ** This option [-ffast-math] should never be turned on by any |
+ ** -O option since it can result in incorrect output for programs |
+ ** which depend on an exact implementation of IEEE or ISO |
+ ** rules/specifications for math functions. |
+ ** |
+ ** Under MSVC, this NaN test may fail if compiled with a floating- |
+ ** point precision mode other than /fp:precise. From the MSDN |
+ ** documentation: |
+ ** |
+ ** The compiler [with /fp:precise] will properly handle comparisons |
+ ** involving NaN. For example, x != x evaluates to true if x is NaN |
+ ** ... |
+ */ |
+#ifdef __FAST_MATH__ |
+# error SQLite will not work correctly with the -ffast-math option of GCC. |
+#endif |
+ volatile double y = x; |
+ volatile double z = y; |
+ rc = (y!=z); |
+#else /* if HAVE_ISNAN */ |
+ rc = isnan(x); |
+#endif /* HAVE_ISNAN */ |
+ testcase( rc ); |
+ return rc; |
+} |
+#endif /* SQLITE_OMIT_FLOATING_POINT */ |
+ |
+/* |
+** Compute a string length that is limited to what can be stored in |
+** lower 30 bits of a 32-bit signed integer. |
+** |
+** The value returned will never be negative. Nor will it ever be greater |
+** than the actual length of the string. For very long strings (greater |
+** than 1GiB) the value returned might be less than the true string length. |
+*/ |
+SQLITE_PRIVATE int sqlite3Strlen30(const char *z){ |
+ if( z==0 ) return 0; |
+ return 0x3fffffff & (int)strlen(z); |
+} |
+ |
+/* |
+** Return the declared type of a column. Or return zDflt if the column |
+** has no declared type. |
+** |
+** The column type is an extra string stored after the zero-terminator on |
+** the column name if and only if the COLFLAG_HASTYPE flag is set. |
+*/ |
+SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){ |
+ if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt; |
+ return pCol->zName + strlen(pCol->zName) + 1; |
+} |
+ |
+/* |
+** Helper function for sqlite3Error() - called rarely. Broken out into |
+** a separate routine to avoid unnecessary register saves on entry to |
+** sqlite3Error(). |
+*/ |
+static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){ |
+ if( db->pErr ) sqlite3ValueSetNull(db->pErr); |
+ sqlite3SystemError(db, err_code); |
+} |
+ |
+/* |
+** Set the current error code to err_code and clear any prior error message. |
+** Also set iSysErrno (by calling sqlite3System) if the err_code indicates |
+** that would be appropriate. |
+*/ |
+SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){ |
+ assert( db!=0 ); |
+ db->errCode = err_code; |
+ if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code); |
+} |
+ |
+/* |
+** Load the sqlite3.iSysErrno field if that is an appropriate thing |
+** to do based on the SQLite error code in rc. |
+*/ |
+SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){ |
+ if( rc==SQLITE_IOERR_NOMEM ) return; |
+ rc &= 0xff; |
+ if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){ |
+ db->iSysErrno = sqlite3OsGetLastError(db->pVfs); |
+ } |
+} |
+ |
+/* |
+** Set the most recent error code and error string for the sqlite |
+** handle "db". The error code is set to "err_code". |
+** |
+** If it is not NULL, string zFormat specifies the format of the |
+** error string in the style of the printf functions: The following |
+** format characters are allowed: |
+** |
+** %s Insert a string |
+** %z A string that should be freed after use |
+** %d Insert an integer |
+** %T Insert a token |
+** %S Insert the first element of a SrcList |
+** |
+** zFormat and any string tokens that follow it are assumed to be |
+** encoded in UTF-8. |
+** |
+** To clear the most recent error for sqlite handle "db", sqlite3Error |
+** should be called with err_code set to SQLITE_OK and zFormat set |
+** to NULL. |
+*/ |
+SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){ |
+ assert( db!=0 ); |
+ db->errCode = err_code; |
+ sqlite3SystemError(db, err_code); |
+ if( zFormat==0 ){ |
+ sqlite3Error(db, err_code); |
+ }else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){ |
+ char *z; |
+ va_list ap; |
+ va_start(ap, zFormat); |
+ z = sqlite3VMPrintf(db, zFormat, ap); |
+ va_end(ap); |
+ sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC); |
+ } |
+} |
+ |
+/* |
+** Add an error message to pParse->zErrMsg and increment pParse->nErr. |
+** The following formatting characters are allowed: |
+** |
+** %s Insert a string |
+** %z A string that should be freed after use |
+** %d Insert an integer |
+** %T Insert a token |
+** %S Insert the first element of a SrcList |
+** |
+** This function should be used to report any error that occurs while |
+** compiling an SQL statement (i.e. within sqlite3_prepare()). The |
+** last thing the sqlite3_prepare() function does is copy the error |
+** stored by this function into the database handle using sqlite3Error(). |
+** Functions sqlite3Error() or sqlite3ErrorWithMsg() should be used |
+** during statement execution (sqlite3_step() etc.). |
+*/ |
+SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ |
+ char *zMsg; |
+ va_list ap; |
+ sqlite3 *db = pParse->db; |
+ va_start(ap, zFormat); |
+ zMsg = sqlite3VMPrintf(db, zFormat, ap); |
+ va_end(ap); |
+ if( db->suppressErr ){ |
+ sqlite3DbFree(db, zMsg); |
+ }else{ |
+ pParse->nErr++; |
+ sqlite3DbFree(db, pParse->zErrMsg); |
+ pParse->zErrMsg = zMsg; |
+ pParse->rc = SQLITE_ERROR; |
+ } |
+} |
+ |
+/* |
+** Convert an SQL-style quoted string into a normal string by removing |
+** the quote characters. The conversion is done in-place. If the |
+** input does not begin with a quote character, then this routine |
+** is a no-op. |
+** |
+** The input string must be zero-terminated. A new zero-terminator |
+** is added to the dequoted string. |
+** |
+** The return value is -1 if no dequoting occurs or the length of the |
+** dequoted string, exclusive of the zero terminator, if dequoting does |
+** occur. |
+** |
+** 2002-Feb-14: This routine is extended to remove MS-Access style |
+** brackets from around identifiers. For example: "[a-b-c]" becomes |
+** "a-b-c". |
+*/ |
+SQLITE_PRIVATE void sqlite3Dequote(char *z){ |
+ char quote; |
+ int i, j; |
+ if( z==0 ) return; |
+ quote = z[0]; |
+ if( !sqlite3Isquote(quote) ) return; |
+ if( quote=='[' ) quote = ']'; |
+ for(i=1, j=0;; i++){ |
+ assert( z[i] ); |
+ if( z[i]==quote ){ |
+ if( z[i+1]==quote ){ |
+ z[j++] = quote; |
+ i++; |
+ }else{ |
+ break; |
+ } |
+ }else{ |
+ z[j++] = z[i]; |
+ } |
+ } |
+ z[j] = 0; |
+} |
+ |
+/* |
+** Generate a Token object from a string |
+*/ |
+SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){ |
+ p->z = z; |
+ p->n = sqlite3Strlen30(z); |
+} |
+ |
+/* Convenient short-hand */ |
+#define UpperToLower sqlite3UpperToLower |
+ |
+/* |
+** Some systems have stricmp(). Others have strcasecmp(). Because |
+** there is no consistency, we will define our own. |
+** |
+** IMPLEMENTATION-OF: R-30243-02494 The sqlite3_stricmp() and |
+** sqlite3_strnicmp() APIs allow applications and extensions to compare |
+** the contents of two buffers containing UTF-8 strings in a |
+** case-independent fashion, using the same definition of "case |
+** independence" that SQLite uses internally when comparing identifiers. |
+*/ |
+SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){ |
+ if( zLeft==0 ){ |
+ return zRight ? -1 : 0; |
+ }else if( zRight==0 ){ |
+ return 1; |
+ } |
+ return sqlite3StrICmp(zLeft, zRight); |
+} |
+SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){ |
+ unsigned char *a, *b; |
+ int c; |
+ a = (unsigned char *)zLeft; |
+ b = (unsigned char *)zRight; |
+ for(;;){ |
+ c = (int)UpperToLower[*a] - (int)UpperToLower[*b]; |
+ if( c || *a==0 ) break; |
+ a++; |
+ b++; |
+ } |
+ return c; |
+} |
+SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ |
+ register unsigned char *a, *b; |
+ if( zLeft==0 ){ |
+ return zRight ? -1 : 0; |
+ }else if( zRight==0 ){ |
+ return 1; |
+ } |
+ a = (unsigned char *)zLeft; |
+ b = (unsigned char *)zRight; |
+ while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } |
+ return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; |
+} |
+ |
+/* |
+** The string z[] is an text representation of a real number. |
+** Convert this string to a double and write it into *pResult. |
+** |
+** The string z[] is length bytes in length (bytes, not characters) and |
+** uses the encoding enc. The string is not necessarily zero-terminated. |
+** |
+** Return TRUE if the result is a valid real number (or integer) and FALSE |
+** if the string is empty or contains extraneous text. Valid numbers |
+** are in one of these formats: |
+** |
+** [+-]digits[E[+-]digits] |
+** [+-]digits.[digits][E[+-]digits] |
+** [+-].digits[E[+-]digits] |
+** |
+** Leading and trailing whitespace is ignored for the purpose of determining |
+** validity. |
+** |
+** If some prefix of the input string is a valid number, this routine |
+** returns FALSE but it still converts the prefix and writes the result |
+** into *pResult. |
+*/ |
+SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ |
+#ifndef SQLITE_OMIT_FLOATING_POINT |
+ int incr; |
+ const char *zEnd = z + length; |
+ /* sign * significand * (10 ^ (esign * exponent)) */ |
+ int sign = 1; /* sign of significand */ |
+ i64 s = 0; /* significand */ |
+ int d = 0; /* adjust exponent for shifting decimal point */ |
+ int esign = 1; /* sign of exponent */ |
+ int e = 0; /* exponent */ |
+ int eValid = 1; /* True exponent is either not used or is well-formed */ |
+ double result; |
+ int nDigits = 0; |
+ int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ |
+ |
+ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); |
+ *pResult = 0.0; /* Default return value, in case of an error */ |
+ |
+ if( enc==SQLITE_UTF8 ){ |
+ incr = 1; |
+ }else{ |
+ int i; |
+ incr = 2; |
+ assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); |
+ for(i=3-enc; i<length && z[i]==0; i+=2){} |
+ nonNum = i<length; |
+ zEnd = &z[i^1]; |
+ z += (enc&1); |
+ } |
+ |
+ /* skip leading spaces */ |
+ while( z<zEnd && sqlite3Isspace(*z) ) z+=incr; |
+ if( z>=zEnd ) return 0; |
+ |
+ /* get sign of significand */ |
+ if( *z=='-' ){ |
+ sign = -1; |
+ z+=incr; |
+ }else if( *z=='+' ){ |
+ z+=incr; |
+ } |
+ |
+ /* copy max significant digits to significand */ |
+ while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ |
+ s = s*10 + (*z - '0'); |
+ z+=incr, nDigits++; |
+ } |
+ |
+ /* skip non-significant significand digits |
+ ** (increase exponent by d to shift decimal left) */ |
+ while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++; |
+ if( z>=zEnd ) goto do_atof_calc; |
+ |
+ /* if decimal point is present */ |
+ if( *z=='.' ){ |
+ z+=incr; |
+ /* copy digits from after decimal to significand |
+ ** (decrease exponent by d to shift decimal right) */ |
+ while( z<zEnd && sqlite3Isdigit(*z) ){ |
+ if( s<((LARGEST_INT64-9)/10) ){ |
+ s = s*10 + (*z - '0'); |
+ d--; |
+ } |
+ z+=incr, nDigits++; |
+ } |
+ } |
+ if( z>=zEnd ) goto do_atof_calc; |
+ |
+ /* if exponent is present */ |
+ if( *z=='e' || *z=='E' ){ |
+ z+=incr; |
+ eValid = 0; |
+ |
+ /* This branch is needed to avoid a (harmless) buffer overread. The |
+ ** special comment alerts the mutation tester that the correct answer |
+ ** is obtained even if the branch is omitted */ |
+ if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/ |
+ |
+ /* get sign of exponent */ |
+ if( *z=='-' ){ |
+ esign = -1; |
+ z+=incr; |
+ }else if( *z=='+' ){ |
+ z+=incr; |
+ } |
+ /* copy digits to exponent */ |
+ while( z<zEnd && sqlite3Isdigit(*z) ){ |
+ e = e<10000 ? (e*10 + (*z - '0')) : 10000; |
+ z+=incr; |
+ eValid = 1; |
+ } |
+ } |
+ |
+ /* skip trailing spaces */ |
+ while( z<zEnd && sqlite3Isspace(*z) ) z+=incr; |
+ |
+do_atof_calc: |
+ /* adjust exponent by d, and update sign */ |
+ e = (e*esign) + d; |
+ if( e<0 ) { |
+ esign = -1; |
+ e *= -1; |
+ } else { |
+ esign = 1; |
+ } |
+ |
+ if( s==0 ) { |
+ /* In the IEEE 754 standard, zero is signed. */ |
+ result = sign<0 ? -(double)0 : (double)0; |
+ } else { |
+ /* Attempt to reduce exponent. |
+ ** |
+ ** Branches that are not required for the correct answer but which only |
+ ** help to obtain the correct answer faster are marked with special |
+ ** comments, as a hint to the mutation tester. |
+ */ |
+ while( e>0 ){ /*OPTIMIZATION-IF-TRUE*/ |
+ if( esign>0 ){ |
+ if( s>=(LARGEST_INT64/10) ) break; /*OPTIMIZATION-IF-FALSE*/ |
+ s *= 10; |
+ }else{ |
+ if( s%10!=0 ) break; /*OPTIMIZATION-IF-FALSE*/ |
+ s /= 10; |
+ } |
+ e--; |
+ } |
+ |
+ /* adjust the sign of significand */ |
+ s = sign<0 ? -s : s; |
+ |
+ if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/ |
+ result = (double)s; |
+ }else{ |
+ LONGDOUBLE_TYPE scale = 1.0; |
+ /* attempt to handle extremely small/large numbers better */ |
+ if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/ |
+ if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/ |
+ while( e%308 ) { scale *= 1.0e+1; e -= 1; } |
+ if( esign<0 ){ |
+ result = s / scale; |
+ result /= 1.0e+308; |
+ }else{ |
+ result = s * scale; |
+ result *= 1.0e+308; |
+ } |
+ }else{ assert( e>=342 ); |
+ if( esign<0 ){ |
+ result = 0.0*s; |
+ }else{ |
+ result = 1e308*1e308*s; /* Infinity */ |
+ } |
+ } |
+ }else{ |
+ /* 1.0e+22 is the largest power of 10 than can be |
+ ** represented exactly. */ |
+ while( e%22 ) { scale *= 1.0e+1; e -= 1; } |
+ while( e>0 ) { scale *= 1.0e+22; e -= 22; } |
+ if( esign<0 ){ |
+ result = s / scale; |
+ }else{ |
+ result = s * scale; |
+ } |
+ } |
+ } |
+ } |
+ |
+ /* store the result */ |
+ *pResult = result; |
+ |
+ /* return true if number and no extra non-whitespace chracters after */ |
+ return z==zEnd && nDigits>0 && eValid && nonNum==0; |
+#else |
+ return !sqlite3Atoi64(z, pResult, length, enc); |
+#endif /* SQLITE_OMIT_FLOATING_POINT */ |
+} |
+ |
+/* |
+** Compare the 19-character string zNum against the text representation |
+** value 2^63: 9223372036854775808. Return negative, zero, or positive |
+** if zNum is less than, equal to, or greater than the string. |
+** Note that zNum must contain exactly 19 characters. |
+** |
+** Unlike memcmp() this routine is guaranteed to return the difference |
+** in the values of the last digit if the only difference is in the |
+** last digit. So, for example, |
+** |
+** compare2pow63("9223372036854775800", 1) |
+** |
+** will return -8. |
+*/ |
+static int compare2pow63(const char *zNum, int incr){ |
+ int c = 0; |
+ int i; |
+ /* 012345678901234567 */ |
+ const char *pow63 = "922337203685477580"; |
+ for(i=0; c==0 && i<18; i++){ |
+ c = (zNum[i*incr]-pow63[i])*10; |
+ } |
+ if( c==0 ){ |
+ c = zNum[18*incr] - '8'; |
+ testcase( c==(-1) ); |
+ testcase( c==0 ); |
+ testcase( c==(+1) ); |
+ } |
+ return c; |
+} |
+ |
+/* |
+** Convert zNum to a 64-bit signed integer. zNum must be decimal. This |
+** routine does *not* accept hexadecimal notation. |
+** |
+** If the zNum value is representable as a 64-bit twos-complement |
+** integer, then write that value into *pNum and return 0. |
+** |
+** If zNum is exactly 9223372036854775808, return 2. This special |
+** case is broken out because while 9223372036854775808 cannot be a |
+** signed 64-bit integer, its negative -9223372036854775808 can be. |
+** |
+** If zNum is too big for a 64-bit integer and is not |
+** 9223372036854775808 or if zNum contains any non-numeric text, |
+** then return 1. |
+** |
+** length is the number of bytes in the string (bytes, not characters). |
+** The string is not necessarily zero-terminated. The encoding is |
+** given by enc. |
+*/ |
+SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ |
+ int incr; |
+ u64 u = 0; |
+ int neg = 0; /* assume positive */ |
+ int i; |
+ int c = 0; |
+ int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ |
+ const char *zStart; |
+ const char *zEnd = zNum + length; |
+ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); |
+ if( enc==SQLITE_UTF8 ){ |
+ incr = 1; |
+ }else{ |
+ incr = 2; |
+ assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); |
+ for(i=3-enc; i<length && zNum[i]==0; i+=2){} |
+ nonNum = i<length; |
+ zEnd = &zNum[i^1]; |
+ zNum += (enc&1); |
+ } |
+ while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr; |
+ if( zNum<zEnd ){ |
+ if( *zNum=='-' ){ |
+ neg = 1; |
+ zNum+=incr; |
+ }else if( *zNum=='+' ){ |
+ zNum+=incr; |
+ } |
+ } |
+ zStart = zNum; |
+ while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */ |
+ for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){ |
+ u = u*10 + c - '0'; |
+ } |
+ if( u>LARGEST_INT64 ){ |
+ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; |
+ }else if( neg ){ |
+ *pNum = -(i64)u; |
+ }else{ |
+ *pNum = (i64)u; |
+ } |
+ testcase( i==18 ); |
+ testcase( i==19 ); |
+ testcase( i==20 ); |
+ if( &zNum[i]<zEnd /* Extra bytes at the end */ |
+ || (i==0 && zStart==zNum) /* No digits */ |
+ || i>19*incr /* Too many digits */ |
+ || nonNum /* UTF16 with high-order bytes non-zero */ |
+ ){ |
+ /* zNum is empty or contains non-numeric text or is longer |
+ ** than 19 digits (thus guaranteeing that it is too large) */ |
+ return 1; |
+ }else if( i<19*incr ){ |
+ /* Less than 19 digits, so we know that it fits in 64 bits */ |
+ assert( u<=LARGEST_INT64 ); |
+ return 0; |
+ }else{ |
+ /* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */ |
+ c = compare2pow63(zNum, incr); |
+ if( c<0 ){ |
+ /* zNum is less than 9223372036854775808 so it fits */ |
+ assert( u<=LARGEST_INT64 ); |
+ return 0; |
+ }else if( c>0 ){ |
+ /* zNum is greater than 9223372036854775808 so it overflows */ |
+ return 1; |
+ }else{ |
+ /* zNum is exactly 9223372036854775808. Fits if negative. The |
+ ** special case 2 overflow if positive */ |
+ assert( u-1==LARGEST_INT64 ); |
+ return neg ? 0 : 2; |
+ } |
+ } |
+} |
+ |
+/* |
+** Transform a UTF-8 integer literal, in either decimal or hexadecimal, |
+** into a 64-bit signed integer. This routine accepts hexadecimal literals, |
+** whereas sqlite3Atoi64() does not. |
+** |
+** Returns: |
+** |
+** 0 Successful transformation. Fits in a 64-bit signed integer. |
+** 1 Integer too large for a 64-bit signed integer or is malformed |
+** 2 Special case of 9223372036854775808 |
+*/ |
+SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ |
+#ifndef SQLITE_OMIT_HEX_INTEGER |
+ if( z[0]=='0' |
+ && (z[1]=='x' || z[1]=='X') |
+ ){ |
+ u64 u = 0; |
+ int i, k; |
+ for(i=2; z[i]=='0'; i++){} |
+ for(k=i; sqlite3Isxdigit(z[k]); k++){ |
+ u = u*16 + sqlite3HexToInt(z[k]); |
+ } |
+ memcpy(pOut, &u, 8); |
+ return (z[k]==0 && k-i<=16) ? 0 : 1; |
+ }else |
+#endif /* SQLITE_OMIT_HEX_INTEGER */ |
+ { |
+ return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8); |
+ } |
+} |
+ |
+/* |
+** If zNum represents an integer that will fit in 32-bits, then set |
+** *pValue to that integer and return true. Otherwise return false. |
+** |
+** This routine accepts both decimal and hexadecimal notation for integers. |
+** |
+** Any non-numeric characters that following zNum are ignored. |
+** This is different from sqlite3Atoi64() which requires the |
+** input number to be zero-terminated. |
+*/ |
+SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){ |
+ sqlite_int64 v = 0; |
+ int i, c; |
+ int neg = 0; |
+ if( zNum[0]=='-' ){ |
+ neg = 1; |
+ zNum++; |
+ }else if( zNum[0]=='+' ){ |
+ zNum++; |
+ } |
+#ifndef SQLITE_OMIT_HEX_INTEGER |
+ else if( zNum[0]=='0' |
+ && (zNum[1]=='x' || zNum[1]=='X') |
+ && sqlite3Isxdigit(zNum[2]) |
+ ){ |
+ u32 u = 0; |
+ zNum += 2; |
+ while( zNum[0]=='0' ) zNum++; |
+ for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){ |
+ u = u*16 + sqlite3HexToInt(zNum[i]); |
+ } |
+ if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){ |
+ memcpy(pValue, &u, 4); |
+ return 1; |
+ }else{ |
+ return 0; |
+ } |
+ } |
+#endif |
+ while( zNum[0]=='0' ) zNum++; |
+ for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ |
+ v = v*10 + c; |
+ } |
+ |
+ /* The longest decimal representation of a 32 bit integer is 10 digits: |
+ ** |
+ ** 1234567890 |
+ ** 2^31 -> 2147483648 |
+ */ |
+ testcase( i==10 ); |
+ if( i>10 ){ |
+ return 0; |
+ } |
+ testcase( v-neg==2147483647 ); |
+ if( v-neg>2147483647 ){ |
+ return 0; |
+ } |
+ if( neg ){ |
+ v = -v; |
+ } |
+ *pValue = (int)v; |
+ return 1; |
+} |
+ |
+/* |
+** Return a 32-bit integer value extracted from a string. If the |
+** string is not an integer, just return 0. |
+*/ |
+SQLITE_PRIVATE int sqlite3Atoi(const char *z){ |
+ int x = 0; |
+ if( z ) sqlite3GetInt32(z, &x); |
+ return x; |
+} |
+ |
+/* |
+** The variable-length integer encoding is as follows: |
+** |
+** KEY: |
+** A = 0xxxxxxx 7 bits of data and one flag bit |
+** B = 1xxxxxxx 7 bits of data and one flag bit |
+** C = xxxxxxxx 8 bits of data |
+** |
+** 7 bits - A |
+** 14 bits - BA |
+** 21 bits - BBA |
+** 28 bits - BBBA |
+** 35 bits - BBBBA |
+** 42 bits - BBBBBA |
+** 49 bits - BBBBBBA |
+** 56 bits - BBBBBBBA |
+** 64 bits - BBBBBBBBC |
+*/ |
+ |
+/* |
+** Write a 64-bit variable-length integer to memory starting at p[0]. |
+** The length of data write will be between 1 and 9 bytes. The number |
+** of bytes written is returned. |
+** |
+** A variable-length integer consists of the lower 7 bits of each byte |
+** for all bytes that have the 8th bit set and one byte with the 8th |
+** bit clear. Except, if we get to the 9th byte, it stores the full |
+** 8 bits and is the last byte. |
+*/ |
+static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){ |
+ int i, j, n; |
+ u8 buf[10]; |
+ if( v & (((u64)0xff000000)<<32) ){ |
+ p[8] = (u8)v; |
+ v >>= 8; |
+ for(i=7; i>=0; i--){ |
+ p[i] = (u8)((v & 0x7f) | 0x80); |
+ v >>= 7; |
+ } |
+ return 9; |
+ } |
+ n = 0; |
+ do{ |
+ buf[n++] = (u8)((v & 0x7f) | 0x80); |
+ v >>= 7; |
+ }while( v!=0 ); |
+ buf[0] &= 0x7f; |
+ assert( n<=9 ); |
+ for(i=0, j=n-1; j>=0; j--, i++){ |
+ p[i] = buf[j]; |
+ } |
+ return n; |
+} |
+SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ |
+ if( v<=0x7f ){ |
+ p[0] = v&0x7f; |
+ return 1; |
+ } |
+ if( v<=0x3fff ){ |
+ p[0] = ((v>>7)&0x7f)|0x80; |
+ p[1] = v&0x7f; |
+ return 2; |
+ } |
+ return putVarint64(p,v); |
+} |
+ |
+/* |
+** Bitmasks used by sqlite3GetVarint(). These precomputed constants |
+** are defined here rather than simply putting the constant expressions |
+** inline in order to work around bugs in the RVT compiler. |
+** |
+** SLOT_2_0 A mask for (0x7f<<14) | 0x7f |
+** |
+** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0 |
+*/ |
+#define SLOT_2_0 0x001fc07f |
+#define SLOT_4_2_0 0xf01fc07f |
+ |
+ |
+/* |
+** Read a 64-bit variable-length integer from memory starting at p[0]. |
+** Return the number of bytes read. The value is stored in *v. |
+*/ |
+SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ |
+ u32 a,b,s; |
+ |
+ a = *p; |
+ /* a: p0 (unmasked) */ |
+ if (!(a&0x80)) |
+ { |
+ *v = a; |
+ return 1; |
+ } |
+ |
+ p++; |
+ b = *p; |
+ /* b: p1 (unmasked) */ |
+ if (!(b&0x80)) |
+ { |
+ a &= 0x7f; |
+ a = a<<7; |
+ a |= b; |
+ *v = a; |
+ return 2; |
+ } |
+ |
+ /* Verify that constants are precomputed correctly */ |
+ assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); |
+ assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); |
+ |
+ p++; |
+ a = a<<14; |
+ a |= *p; |
+ /* a: p0<<14 | p2 (unmasked) */ |
+ if (!(a&0x80)) |
+ { |
+ a &= SLOT_2_0; |
+ b &= 0x7f; |
+ b = b<<7; |
+ a |= b; |
+ *v = a; |
+ return 3; |
+ } |
+ |
+ /* CSE1 from below */ |
+ a &= SLOT_2_0; |
+ p++; |
+ b = b<<14; |
+ b |= *p; |
+ /* b: p1<<14 | p3 (unmasked) */ |
+ if (!(b&0x80)) |
+ { |
+ b &= SLOT_2_0; |
+ /* moved CSE1 up */ |
+ /* a &= (0x7f<<14)|(0x7f); */ |
+ a = a<<7; |
+ a |= b; |
+ *v = a; |
+ return 4; |
+ } |
+ |
+ /* a: p0<<14 | p2 (masked) */ |
+ /* b: p1<<14 | p3 (unmasked) */ |
+ /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ |
+ /* moved CSE1 up */ |
+ /* a &= (0x7f<<14)|(0x7f); */ |
+ b &= SLOT_2_0; |
+ s = a; |
+ /* s: p0<<14 | p2 (masked) */ |
+ |
+ p++; |
+ a = a<<14; |
+ a |= *p; |
+ /* a: p0<<28 | p2<<14 | p4 (unmasked) */ |
+ if (!(a&0x80)) |
+ { |
+ /* we can skip these cause they were (effectively) done above |
+ ** while calculating s */ |
+ /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ |
+ /* b &= (0x7f<<14)|(0x7f); */ |
+ b = b<<7; |
+ a |= b; |
+ s = s>>18; |
+ *v = ((u64)s)<<32 | a; |
+ return 5; |
+ } |
+ |
+ /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ |
+ s = s<<7; |
+ s |= b; |
+ /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ |
+ |
+ p++; |
+ b = b<<14; |
+ b |= *p; |
+ /* b: p1<<28 | p3<<14 | p5 (unmasked) */ |
+ if (!(b&0x80)) |
+ { |
+ /* we can skip this cause it was (effectively) done above in calc'ing s */ |
+ /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ |
+ a &= SLOT_2_0; |
+ a = a<<7; |
+ a |= b; |
+ s = s>>18; |
+ *v = ((u64)s)<<32 | a; |
+ return 6; |
+ } |
+ |
+ p++; |
+ a = a<<14; |
+ a |= *p; |
+ /* a: p2<<28 | p4<<14 | p6 (unmasked) */ |
+ if (!(a&0x80)) |
+ { |
+ a &= SLOT_4_2_0; |
+ b &= SLOT_2_0; |
+ b = b<<7; |
+ a |= b; |
+ s = s>>11; |
+ *v = ((u64)s)<<32 | a; |
+ return 7; |
+ } |
+ |
+ /* CSE2 from below */ |
+ a &= SLOT_2_0; |
+ p++; |
+ b = b<<14; |
+ b |= *p; |
+ /* b: p3<<28 | p5<<14 | p7 (unmasked) */ |
+ if (!(b&0x80)) |
+ { |
+ b &= SLOT_4_2_0; |
+ /* moved CSE2 up */ |
+ /* a &= (0x7f<<14)|(0x7f); */ |
+ a = a<<7; |
+ a |= b; |
+ s = s>>4; |
+ *v = ((u64)s)<<32 | a; |
+ return 8; |
+ } |
+ |
+ p++; |
+ a = a<<15; |
+ a |= *p; |
+ /* a: p4<<29 | p6<<15 | p8 (unmasked) */ |
+ |
+ /* moved CSE2 up */ |
+ /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */ |
+ b &= SLOT_2_0; |
+ b = b<<8; |
+ a |= b; |
+ |
+ s = s<<4; |
+ b = p[-4]; |
+ b &= 0x7f; |
+ b = b>>3; |
+ s |= b; |
+ |
+ *v = ((u64)s)<<32 | a; |
+ |
+ return 9; |
+} |
+ |
+/* |
+** Read a 32-bit variable-length integer from memory starting at p[0]. |
+** Return the number of bytes read. The value is stored in *v. |
+** |
+** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned |
+** integer, then set *v to 0xffffffff. |
+** |
+** A MACRO version, getVarint32, is provided which inlines the |
+** single-byte case. All code should use the MACRO version as |
+** this function assumes the single-byte case has already been handled. |
+*/ |
+SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){ |
+ u32 a,b; |
+ |
+ /* The 1-byte case. Overwhelmingly the most common. Handled inline |
+ ** by the getVarin32() macro */ |
+ a = *p; |
+ /* a: p0 (unmasked) */ |
+#ifndef getVarint32 |
+ if (!(a&0x80)) |
+ { |
+ /* Values between 0 and 127 */ |
+ *v = a; |
+ return 1; |
+ } |
+#endif |
+ |
+ /* The 2-byte case */ |
+ p++; |
+ b = *p; |
+ /* b: p1 (unmasked) */ |
+ if (!(b&0x80)) |
+ { |
+ /* Values between 128 and 16383 */ |
+ a &= 0x7f; |
+ a = a<<7; |
+ *v = a | b; |
+ return 2; |
+ } |
+ |
+ /* The 3-byte case */ |
+ p++; |
+ a = a<<14; |
+ a |= *p; |
+ /* a: p0<<14 | p2 (unmasked) */ |
+ if (!(a&0x80)) |
+ { |
+ /* Values between 16384 and 2097151 */ |
+ a &= (0x7f<<14)|(0x7f); |
+ b &= 0x7f; |
+ b = b<<7; |
+ *v = a | b; |
+ return 3; |
+ } |
+ |
+ /* A 32-bit varint is used to store size information in btrees. |
+ ** Objects are rarely larger than 2MiB limit of a 3-byte varint. |
+ ** A 3-byte varint is sufficient, for example, to record the size |
+ ** of a 1048569-byte BLOB or string. |
+ ** |
+ ** We only unroll the first 1-, 2-, and 3- byte cases. The very |
+ ** rare larger cases can be handled by the slower 64-bit varint |
+ ** routine. |
+ */ |
+#if 1 |
+ { |
+ u64 v64; |
+ u8 n; |
+ |
+ p -= 2; |
+ n = sqlite3GetVarint(p, &v64); |
+ assert( n>3 && n<=9 ); |
+ if( (v64 & SQLITE_MAX_U32)!=v64 ){ |
+ *v = 0xffffffff; |
+ }else{ |
+ *v = (u32)v64; |
+ } |
+ return n; |
+ } |
+ |
+#else |
+ /* For following code (kept for historical record only) shows an |
+ ** unrolling for the 3- and 4-byte varint cases. This code is |
+ ** slightly faster, but it is also larger and much harder to test. |
+ */ |
+ p++; |
+ b = b<<14; |
+ b |= *p; |
+ /* b: p1<<14 | p3 (unmasked) */ |
+ if (!(b&0x80)) |
+ { |
+ /* Values between 2097152 and 268435455 */ |
+ b &= (0x7f<<14)|(0x7f); |
+ a &= (0x7f<<14)|(0x7f); |
+ a = a<<7; |
+ *v = a | b; |
+ return 4; |
+ } |
+ |
+ p++; |
+ a = a<<14; |
+ a |= *p; |
+ /* a: p0<<28 | p2<<14 | p4 (unmasked) */ |
+ if (!(a&0x80)) |
+ { |
+ /* Values between 268435456 and 34359738367 */ |
+ a &= SLOT_4_2_0; |
+ b &= SLOT_4_2_0; |
+ b = b<<7; |
+ *v = a | b; |
+ return 5; |
+ } |
+ |
+ /* We can only reach this point when reading a corrupt database |
+ ** file. In that case we are not in any hurry. Use the (relatively |
+ ** slow) general-purpose sqlite3GetVarint() routine to extract the |
+ ** value. */ |
+ { |
+ u64 v64; |
+ u8 n; |
+ |
+ p -= 4; |
+ n = sqlite3GetVarint(p, &v64); |
+ assert( n>5 && n<=9 ); |
+ *v = (u32)v64; |
+ return n; |
+ } |
+#endif |
+} |
+ |
+/* |
+** Return the number of bytes that will be needed to store the given |
+** 64-bit integer. |
+*/ |
+SQLITE_PRIVATE int sqlite3VarintLen(u64 v){ |
+ int i; |
+ for(i=1; (v >>= 7)!=0; i++){ assert( i<10 ); } |
+ return i; |
+} |
+ |
+ |
+/* |
+** Read or write a four-byte big-endian integer value. |
+*/ |
+SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ |
+#if SQLITE_BYTEORDER==4321 |
+ u32 x; |
+ memcpy(&x,p,4); |
+ return x; |
+#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000) |
+ u32 x; |
+ memcpy(&x,p,4); |
+ return __builtin_bswap32(x); |
+#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 |
+ u32 x; |
+ memcpy(&x,p,4); |
+ return _byteswap_ulong(x); |
+#else |
+ testcase( p[0]&0x80 ); |
+ return ((unsigned)p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; |
+#endif |
+} |
+SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){ |
+#if SQLITE_BYTEORDER==4321 |
+ memcpy(p,&v,4); |
+#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000) |
+ u32 x = __builtin_bswap32(v); |
+ memcpy(p,&x,4); |
+#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 |
+ u32 x = _byteswap_ulong(v); |
+ memcpy(p,&x,4); |
+#else |
+ p[0] = (u8)(v>>24); |
+ p[1] = (u8)(v>>16); |
+ p[2] = (u8)(v>>8); |
+ p[3] = (u8)v; |
+#endif |
+} |
+ |
+ |
+ |
+/* |
+** Translate a single byte of Hex into an integer. |
+** This routine only works if h really is a valid hexadecimal |
+** character: 0..9a..fA..F |
+*/ |
+SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ |
+ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); |
+#ifdef SQLITE_ASCII |
+ h += 9*(1&(h>>6)); |
+#endif |
+#ifdef SQLITE_EBCDIC |
+ h += 9*(1&~(h>>4)); |
+#endif |
+ return (u8)(h & 0xf); |
+} |
+ |
+#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) |
+/* |
+** Convert a BLOB literal of the form "x'hhhhhh'" into its binary |
+** value. Return a pointer to its binary value. Space to hold the |
+** binary value has been obtained from malloc and must be freed by |
+** the calling routine. |
+*/ |
+SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ |
+ char *zBlob; |
+ int i; |
+ |
+ zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1); |
+ n--; |
+ if( zBlob ){ |
+ for(i=0; i<n; i+=2){ |
+ zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]); |
+ } |
+ zBlob[i/2] = 0; |
+ } |
+ return zBlob; |
+} |
+#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ |
+ |
+/* |
+** Log an error that is an API call on a connection pointer that should |
+** not have been used. The "type" of connection pointer is given as the |
+** argument. The zType is a word like "NULL" or "closed" or "invalid". |
+*/ |
+static void logBadConnection(const char *zType){ |
+ sqlite3_log(SQLITE_MISUSE, |
+ "API call with %s database connection pointer", |
+ zType |
+ ); |
+} |
+ |
+/* |
+** Check to make sure we have a valid db pointer. This test is not |
+** foolproof but it does provide some measure of protection against |
+** misuse of the interface such as passing in db pointers that are |
+** NULL or which have been previously closed. If this routine returns |
+** 1 it means that the db pointer is valid and 0 if it should not be |
+** dereferenced for any reason. The calling function should invoke |
+** SQLITE_MISUSE immediately. |
+** |
+** sqlite3SafetyCheckOk() requires that the db pointer be valid for |
+** use. sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to |
+** open properly and is not fit for general use but which can be |
+** used as an argument to sqlite3_errmsg() or sqlite3_close(). |
+*/ |
+SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){ |
+ u32 magic; |
+ if( db==0 ){ |
+ logBadConnection("NULL"); |
+ return 0; |
+ } |
+ magic = db->magic; |
+ if( magic!=SQLITE_MAGIC_OPEN ){ |
+ if( sqlite3SafetyCheckSickOrOk(db) ){ |
+ testcase( sqlite3GlobalConfig.xLog!=0 ); |
+ logBadConnection("unopened"); |
+ } |
+ return 0; |
+ }else{ |
+ return 1; |
+ } |
+} |
+SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ |
+ u32 magic; |
+ magic = db->magic; |
+ if( magic!=SQLITE_MAGIC_SICK && |
+ magic!=SQLITE_MAGIC_OPEN && |
+ magic!=SQLITE_MAGIC_BUSY ){ |
+ testcase( sqlite3GlobalConfig.xLog!=0 ); |
+ logBadConnection("invalid"); |
+ return 0; |
+ }else{ |
+ return 1; |
+ } |
+} |
+ |
+/* |
+** Attempt to add, substract, or multiply the 64-bit signed value iB against |
+** the other 64-bit signed integer at *pA and store the result in *pA. |
+** Return 0 on success. Or if the operation would have resulted in an |
+** overflow, leave *pA unchanged and return 1. |
+*/ |
+SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){ |
+#if GCC_VERSION>=5004000 || CLANG_VERSION>=4000000 |
+ return __builtin_add_overflow(*pA, iB, pA); |
+#else |
+ i64 iA = *pA; |
+ testcase( iA==0 ); testcase( iA==1 ); |
+ testcase( iB==-1 ); testcase( iB==0 ); |
+ if( iB>=0 ){ |
+ testcase( iA>0 && LARGEST_INT64 - iA == iB ); |
+ testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 ); |
+ if( iA>0 && LARGEST_INT64 - iA < iB ) return 1; |
+ }else{ |
+ testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 ); |
+ testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 ); |
+ if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1; |
+ } |
+ *pA += iB; |
+ return 0; |
+#endif |
+} |
+SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ |
+#if GCC_VERSION>=5004000 || CLANG_VERSION>=4000000 |
+ return __builtin_sub_overflow(*pA, iB, pA); |
+#else |
+ testcase( iB==SMALLEST_INT64+1 ); |
+ if( iB==SMALLEST_INT64 ){ |
+ testcase( (*pA)==(-1) ); testcase( (*pA)==0 ); |
+ if( (*pA)>=0 ) return 1; |
+ *pA -= iB; |
+ return 0; |
+ }else{ |
+ return sqlite3AddInt64(pA, -iB); |
+ } |
+#endif |
+} |
+SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ |
+/* TODO(shess): Chromium Android clang generates a link error: |
+** undefined reference to '__mulodi4' |
+** UPDATE(shess): Also, apparently, 32-bit Linux clang. |
+*/ |
+#if GCC_VERSION>=5004000 || \ |
+ (CLANG_VERSION>=4000000 && !defined(__ANDROID__) && \ |
+ (!defined(__linux__) || !defined(__i386__))) |
+ return __builtin_mul_overflow(*pA, iB, pA); |
+#else |
+ i64 iA = *pA; |
+ if( iB>0 ){ |
+ if( iA>LARGEST_INT64/iB ) return 1; |
+ if( iA<SMALLEST_INT64/iB ) return 1; |
+ }else if( iB<0 ){ |
+ if( iA>0 ){ |
+ if( iB<SMALLEST_INT64/iA ) return 1; |
+ }else if( iA<0 ){ |
+ if( iB==SMALLEST_INT64 ) return 1; |
+ if( iA==SMALLEST_INT64 ) return 1; |
+ if( -iA>LARGEST_INT64/-iB ) return 1; |
+ } |
+ } |
+ *pA = iA*iB; |
+ return 0; |
+#endif |
+} |
+ |
+/* |
+** Compute the absolute value of a 32-bit signed integer, of possible. Or |
+** if the integer has a value of -2147483648, return +2147483647 |
+*/ |
+SQLITE_PRIVATE int sqlite3AbsInt32(int x){ |
+ if( x>=0 ) return x; |
+ if( x==(int)0x80000000 ) return 0x7fffffff; |
+ return -x; |
+} |
+ |
+#ifdef SQLITE_ENABLE_8_3_NAMES |
+/* |
+** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database |
+** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and |
+** if filename in z[] has a suffix (a.k.a. "extension") that is longer than |
+** three characters, then shorten the suffix on z[] to be the last three |
+** characters of the original suffix. |
+** |
+** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always |
+** do the suffix shortening regardless of URI parameter. |
+** |
+** Examples: |
+** |
+** test.db-journal => test.nal |
+** test.db-wal => test.wal |
+** test.db-shm => test.shm |
+** test.db-mj7f3319fa => test.9fa |
+*/ |
+SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ |
+#if SQLITE_ENABLE_8_3_NAMES<2 |
+ if( sqlite3_uri_boolean(zBaseFilename, "8_3_names", 0) ) |
+#endif |
+ { |
+ int i, sz; |
+ sz = sqlite3Strlen30(z); |
+ for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} |
+ if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4); |
+ } |
+} |
+#endif |
+ |
+/* |
+** Find (an approximate) sum of two LogEst values. This computation is |
+** not a simple "+" operator because LogEst is stored as a logarithmic |
+** value. |
+** |
+*/ |
+SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){ |
+ static const unsigned char x[] = { |
+ 10, 10, /* 0,1 */ |
+ 9, 9, /* 2,3 */ |
+ 8, 8, /* 4,5 */ |
+ 7, 7, 7, /* 6,7,8 */ |
+ 6, 6, 6, /* 9,10,11 */ |
+ 5, 5, 5, /* 12-14 */ |
+ 4, 4, 4, 4, /* 15-18 */ |
+ 3, 3, 3, 3, 3, 3, /* 19-24 */ |
+ 2, 2, 2, 2, 2, 2, 2, /* 25-31 */ |
+ }; |
+ if( a>=b ){ |
+ if( a>b+49 ) return a; |
+ if( a>b+31 ) return a+1; |
+ return a+x[a-b]; |
+ }else{ |
+ if( b>a+49 ) return b; |
+ if( b>a+31 ) return b+1; |
+ return b+x[b-a]; |
+ } |
+} |
+ |
+/* |
+** Convert an integer into a LogEst. In other words, compute an |
+** approximation for 10*log2(x). |
+*/ |
+SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){ |
+ static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 }; |
+ LogEst y = 40; |
+ if( x<8 ){ |
+ if( x<2 ) return 0; |
+ while( x<8 ){ y -= 10; x <<= 1; } |
+ }else{ |
+ while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/ |
+ while( x>15 ){ y += 10; x >>= 1; } |
+ } |
+ return a[x&7] + y - 10; |
+} |
+ |
+#ifndef SQLITE_OMIT_VIRTUALTABLE |
+/* |
+** Convert a double into a LogEst |
+** In other words, compute an approximation for 10*log2(x). |
+*/ |
+SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){ |
+ u64 a; |
+ LogEst e; |
+ assert( sizeof(x)==8 && sizeof(a)==8 ); |
+ if( x<=1 ) return 0; |
+ if( x<=2000000000 ) return sqlite3LogEst((u64)x); |
+ memcpy(&a, &x, 8); |
+ e = (a>>52) - 1022; |
+ return e*10; |
+} |
+#endif /* SQLITE_OMIT_VIRTUALTABLE */ |
+ |
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ |
+ defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \ |
+ defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) |
+/* |
+** Convert a LogEst into an integer. |
+** |
+** Note that this routine is only used when one or more of various |
+** non-standard compile-time options is enabled. |
+*/ |
+SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){ |
+ u64 n; |
+ n = x%10; |
+ x /= 10; |
+ if( n>=5 ) n -= 2; |
+ else if( n>=1 ) n -= 1; |
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ |
+ defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) |
+ if( x>60 ) return (u64)LARGEST_INT64; |
+#else |
+ /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input |
+ ** possible to this routine is 310, resulting in a maximum x of 31 */ |
+ assert( x<=60 ); |
+#endif |
+ return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x); |
+} |
+#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */ |
+ |
+/* |
+** Add a new name/number pair to a VList. This might require that the |
+** VList object be reallocated, so return the new VList. If an OOM |
+** error occurs, the original VList returned and the |
+** db->mallocFailed flag is set. |
+** |
+** A VList is really just an array of integers. To destroy a VList, |
+** simply pass it to sqlite3DbFree(). |
+** |
+** The first integer is the number of integers allocated for the whole |
+** VList. The second integer is the number of integers actually used. |
+** Each name/number pair is encoded by subsequent groups of 3 or more |
+** integers. |
+** |
+** Each name/number pair starts with two integers which are the numeric |
+** value for the pair and the size of the name/number pair, respectively. |
+** The text name overlays one or more following integers. The text name |
+** is always zero-terminated. |
+** |
+** Conceptually: |
+** |
+** struct VList { |
+** int nAlloc; // Number of allocated slots |
+** int nUsed; // Number of used slots |
+** struct VListEntry { |
+** int iValue; // Value for this entry |
+** int nSlot; // Slots used by this entry |
+** // ... variable name goes here |
+** } a[0]; |
+** } |
+** |
+** During code generation, pointers to the variable names within the |
+** VList are taken. When that happens, nAlloc is set to zero as an |
+** indication that the VList may never again be enlarged, since the |
+** accompanying realloc() would invalidate the pointers. |
+*/ |
+SQLITE_PRIVATE VList *sqlite3VListAdd( |
+ sqlite3 *db, /* The database connection used for malloc() */ |
+ VList *pIn, /* The input VList. Might be NULL */ |
+ const char *zName, /* Name of symbol to add */ |
+ int nName, /* Bytes of text in zName */ |
+ int iVal /* Value to associate with zName */ |
+){ |
+ int nInt; /* number of sizeof(int) objects needed for zName */ |
+ char *z; /* Pointer to where zName will be stored */ |
+ int i; /* Index in pIn[] where zName is stored */ |
+ |
+ nInt = nName/4 + 3; |
+ assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */ |
+ if( pIn==0 || pIn[1]+nInt > pIn[0] ){ |
+ /* Enlarge the allocation */ |
+ int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt; |
+ VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int)); |
+ if( pOut==0 ) return pIn; |
+ if( pIn==0 ) pOut[1] = 2; |
+ pIn = pOut; |
+ pIn[0] = nAlloc; |
+ } |
+ i = pIn[1]; |
+ pIn[i] = iVal; |
+ pIn[i+1] = nInt; |
+ z = (char*)&pIn[i+2]; |
+ pIn[1] = i+nInt; |
+ assert( pIn[1]<=pIn[0] ); |
+ memcpy(z, zName, nName); |
+ z[nName] = 0; |
+ return pIn; |
+} |
+ |
+/* |
+** Return a pointer to the name of a variable in the given VList that |
+** has the value iVal. Or return a NULL if there is no such variable in |
+** the list |
+*/ |
+SQLITE_PRIVATE const char *sqlite3VListNumToName(VList *pIn, int iVal){ |
+ int i, mx; |
+ if( pIn==0 ) return 0; |
+ mx = pIn[1]; |
+ i = 2; |
+ do{ |
+ if( pIn[i]==iVal ) return (char*)&pIn[i+2]; |
+ i += pIn[i+1]; |
+ }while( i<mx ); |
+ return 0; |
+} |
+ |
+/* |
+** Return the number of the variable named zName, if it is in VList. |
+** or return 0 if there is no such variable. |
+*/ |
+SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nName){ |
+ int i, mx; |
+ if( pIn==0 ) return 0; |
+ mx = pIn[1]; |
+ i = 2; |
+ do{ |
+ const char *z = (const char*)&pIn[i+2]; |
+ if( strncmp(z,zName,nName)==0 && z[nName]==0 ) return pIn[i]; |
+ i += pIn[i+1]; |
+ }while( i<mx ); |
+ return 0; |
+} |
+ |
+/************** End of util.c ************************************************/ |
+/************** Begin file hash.c ********************************************/ |
+/* |
+** 2001 September 22 |
+** |
+** 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 is the implementation of generic hash-tables |
+** used in SQLite. |
+*/ |
+/* #include "sqliteInt.h" */ |
+/* #include <assert.h> */ |
+ |
+/* Turn bulk memory into a hash table object by initializing the |
+** fields of the Hash structure. |
+** |
+** "pNew" is a pointer to the hash table that is to be initialized. |
+*/ |
+SQLITE_PRIVATE void sqlite3HashInit(Hash *pNew){ |
+ assert( pNew!=0 ); |
+ pNew->first = 0; |
+ pNew->count = 0; |
+ pNew->htsize = 0; |
+ pNew->ht = 0; |
+} |
+ |
+/* Remove all entries from a hash table. Reclaim all memory. |
+** Call this routine to delete a hash table or to reset a hash table |
+** to the empty state. |
+*/ |
+SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){ |
+ HashElem *elem; /* For looping over all elements of the table */ |
+ |
+ assert( pH!=0 ); |
+ elem = pH->first; |
+ pH->first = 0; |
+ sqlite3_free(pH->ht); |
+ pH->ht = 0; |
+ pH->htsize = 0; |
+ while( elem ){ |
+ HashElem *next_elem = elem->next; |
+ sqlite3_free(elem); |
+ elem = next_elem; |
+ } |
+ pH->count = 0; |
+} |
+ |
+/* |
+** The hashing function. |
+*/ |
+static unsigned int strHash(const char *z){ |
+ unsigned int h = 0; |
+ unsigned char c; |
+ while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/ |
+ /* Knuth multiplicative hashing. (Sorting & Searching, p. 510). |
+ ** 0x9e3779b1 is 2654435761 which is the closest prime number to |
+ ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */ |
+ h += sqlite3UpperToLower[c]; |
+ h *= 0x9e3779b1; |
+ } |
+ return h; |
+} |
+ |
+ |
+/* Link pNew element into the hash table pH. If pEntry!=0 then also |
+** insert pNew into the pEntry hash bucket. |
+*/ |
+static void insertElement( |
+ Hash *pH, /* The complete hash table */ |
+ struct _ht *pEntry, /* The entry into which pNew is inserted */ |
+ HashElem *pNew /* The element to be inserted */ |
+){ |
+ HashElem *pHead; /* First element already in pEntry */ |
+ if( pEntry ){ |
+ pHead = pEntry->count ? pEntry->chain : 0; |
+ pEntry->count++; |
+ pEntry->chain = pNew; |
+ }else{ |
+ pHead = 0; |
+ } |
+ if( pHead ){ |
+ pNew->next = pHead; |
+ pNew->prev = pHead->prev; |
+ if( pHead->prev ){ pHead->prev->next = pNew; } |
+ else { pH->first = pNew; } |
+ pHead->prev = pNew; |
+ }else{ |
+ pNew->next = pH->first; |
+ if( pH->first ){ pH->first->prev = pNew; } |
+ pNew->prev = 0; |
+ pH->first = pNew; |
+ } |
+} |
+ |
+ |
+/* Resize the hash table so that it cantains "new_size" buckets. |
+** |
+** The hash table might fail to resize if sqlite3_malloc() fails or |
+** if the new size is the same as the prior size. |
+** Return TRUE if the resize occurs and false if not. |
+*/ |
+static int rehash(Hash *pH, unsigned int new_size){ |
+ struct _ht *new_ht; /* The new hash table */ |
+ HashElem *elem, *next_elem; /* For looping over existing elements */ |
+ |
+#if SQLITE_MALLOC_SOFT_LIMIT>0 |
+ if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){ |
+ new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht); |
+ } |
+ if( new_size==pH->htsize ) return 0; |
+#endif |
+ |
+ /* The inability to allocates space for a larger hash table is |
+ ** a performance hit but it is not a fatal error. So mark the |
+ ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of |
+ ** sqlite3MallocZero() to make the allocation, as sqlite3MallocZero() |
+ ** only zeroes the requested number of bytes whereas this module will |
+ ** use the actual amount of space allocated for the hash table (which |
+ ** may be larger than the requested amount). |
+ */ |
+ sqlite3BeginBenignMalloc(); |
+ new_ht = (struct _ht *)sqlite3Malloc( new_size*sizeof(struct _ht) ); |
+ sqlite3EndBenignMalloc(); |
+ |
+ if( new_ht==0 ) return 0; |
+ sqlite3_free(pH->ht); |
+ pH->ht = new_ht; |
+ pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht); |
+ memset(new_ht, 0, new_size*sizeof(struct _ht)); |
+ for(elem=pH->first, pH->first=0; elem; elem = next_elem){ |
+ unsigned int h = strHash(elem->pKey) % new_size; |
+ next_elem = elem->next; |
+ insertElement(pH, &new_ht[h], elem); |
+ } |
+ return 1; |
+} |
+ |
+/* This function (for internal use only) locates an element in an |
+** hash table that matches the given key. The hash for this key is |
+** also computed and returned in the *pH parameter. |
+*/ |
+static HashElem *findElementWithHash( |
+ const Hash *pH, /* The pH to be searched */ |
+ const char *pKey, /* The key we are searching for */ |
+ unsigned int *pHash /* Write the hash value here */ |
+){ |
+ HashElem *elem; /* Used to loop thru the element list */ |
+ int count; /* Number of elements left to test */ |
+ unsigned int h; /* The computed hash */ |
+ |
+ if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ |
+ struct _ht *pEntry; |
+ h = strHash(pKey) % pH->htsize; |
+ pEntry = &pH->ht[h]; |
+ elem = pEntry->chain; |
+ count = pEntry->count; |
+ }else{ |
+ h = 0; |
+ elem = pH->first; |
+ count = pH->count; |
+ } |
+ *pHash = h; |
+ while( count-- ){ |
+ assert( elem!=0 ); |
+ if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ |
+ return elem; |
+ } |
+ elem = elem->next; |
+ } |
+ return 0; |
+} |
+ |
+/* Remove a single entry from the hash table given a pointer to that |
+** element and a hash on the element's key. |
+*/ |
+static void removeElementGivenHash( |
+ Hash *pH, /* The pH containing "elem" */ |
+ HashElem* elem, /* The element to be removed from the pH */ |
+ unsigned int h /* Hash value for the element */ |
+){ |
+ struct _ht *pEntry; |
+ if( elem->prev ){ |
+ elem->prev->next = elem->next; |
+ }else{ |
+ pH->first = elem->next; |
+ } |
+ if( elem->next ){ |
+ elem->next->prev = elem->prev; |
+ } |
+ if( pH->ht ){ |
+ pEntry = &pH->ht[h]; |
+ if( pEntry->chain==elem ){ |
+ pEntry->chain = elem->next; |
+ } |
+ pEntry->count--; |
+ assert( pEntry->count>=0 ); |
+ } |
+ sqlite3_free( elem ); |
+ pH->count--; |
+ if( pH->count==0 ){ |
+ assert( pH->first==0 ); |
+ assert( pH->count==0 ); |
+ sqlite3HashClear(pH); |
+ } |
+} |
+ |
+/* Attempt to locate an element of the hash table pH with a key |
+** that matches pKey. Return the data for this element if it is |
+** found, or NULL if there is no match. |
+*/ |
+SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){ |
+ HashElem *elem; /* The element that matches key */ |
+ unsigned int h; /* A hash on key */ |
+ |
+ assert( pH!=0 ); |
+ assert( pKey!=0 ); |
+ elem = findElementWithHash(pH, pKey, &h); |
+ return elem ? elem->data : 0; |
+} |
+ |
+/* Insert an element into the hash table pH. The key is pKey |
+** and the data is "data". |
+** |
+** If no element exists with a matching key, then a new |
+** element is created and NULL is returned. |
+** |
+** If another element already exists with the same key, then the |
+** new data replaces the old data and the old data is returned. |
+** The key is not copied in this instance. If a malloc fails, then |
+** the new data is returned and the hash table is unchanged. |
+** |
+** If the "data" parameter to this function is NULL, then the |
+** element corresponding to "key" is removed from the hash table. |
+*/ |
+SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ |
+ unsigned int h; /* the hash of the key modulo hash table size */ |
+ HashElem *elem; /* Used to loop thru the element list */ |
+ HashElem *new_elem; /* New element added to the pH */ |
+ |
+ assert( pH!=0 ); |
+ assert( pKey!=0 ); |
+ elem = findElementWithHash(pH,pKey,&h); |
+ if( elem ){ |
+ void *old_data = elem->data; |
+ if( data==0 ){ |
+ removeElementGivenHash(pH,elem,h); |
+ }else{ |
+ elem->data = data; |
+ elem->pKey = pKey; |
+ } |
+ return old_data; |
+ } |
+ if( data==0 ) return 0; |
+ new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) ); |
+ if( new_elem==0 ) return data; |
+ new_elem->pKey = pKey; |
+ new_elem->data = data; |
+ pH->count++; |
+ if( pH->count>=10 && pH->count > 2*pH->htsize ){ |
+ if( rehash(pH, pH->count*2) ){ |
+ assert( pH->htsize>0 ); |
+ h = strHash(pKey) % pH->htsize; |
+ } |
+ } |
+ insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem); |
+ return 0; |
+} |
+ |
+/************** End of hash.c ************************************************/ |
+/************** Begin file opcodes.c *****************************************/ |
+/* Automatically generated. Do not edit */ |
+/* See the tool/mkopcodec.tcl script for details. */ |
+#if !defined(SQLITE_OMIT_EXPLAIN) \ |
+ || defined(VDBE_PROFILE) \ |
+ || defined(SQLITE_DEBUG) |
+#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) || defined(SQLITE_DEBUG) |
+# define OpHelp(X) "\0" X |
+#else |
+# define OpHelp(X) |
+#endif |
+SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ |
+ static const char *const azName[] = { |
+ /* 0 */ "Savepoint" OpHelp(""), |
+ /* 1 */ "AutoCommit" OpHelp(""), |
+ /* 2 */ "Transaction" OpHelp(""), |
+ /* 3 */ "SorterNext" OpHelp(""), |
+ /* 4 */ "PrevIfOpen" OpHelp(""), |
+ /* 5 */ "NextIfOpen" OpHelp(""), |
+ /* 6 */ "Prev" OpHelp(""), |
+ /* 7 */ "Next" OpHelp(""), |
+ /* 8 */ "Checkpoint" OpHelp(""), |
+ /* 9 */ "JournalMode" OpHelp(""), |
+ /* 10 */ "Vacuum" OpHelp(""), |
+ /* 11 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), |
+ /* 12 */ "VUpdate" OpHelp("data=r[P3@P2]"), |
+ /* 13 */ "Goto" OpHelp(""), |
+ /* 14 */ "Gosub" OpHelp(""), |
+ /* 15 */ "InitCoroutine" OpHelp(""), |
+ /* 16 */ "Yield" OpHelp(""), |
+ /* 17 */ "MustBeInt" OpHelp(""), |
+ /* 18 */ "Jump" OpHelp(""), |
+ /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), |
+ /* 20 */ "Once" OpHelp(""), |
+ /* 21 */ "If" OpHelp(""), |
+ /* 22 */ "IfNot" OpHelp(""), |
+ /* 23 */ "SeekLT" OpHelp("key=r[P3@P4]"), |
+ /* 24 */ "SeekLE" OpHelp("key=r[P3@P4]"), |
+ /* 25 */ "SeekGE" OpHelp("key=r[P3@P4]"), |
+ /* 26 */ "SeekGT" OpHelp("key=r[P3@P4]"), |
+ /* 27 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), |
+ /* 28 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), |
+ /* 29 */ "NoConflict" OpHelp("key=r[P3@P4]"), |
+ /* 30 */ "NotFound" OpHelp("key=r[P3@P4]"), |
+ /* 31 */ "Found" OpHelp("key=r[P3@P4]"), |
+ /* 32 */ "SeekRowid" OpHelp("intkey=r[P3]"), |
+ /* 33 */ "NotExists" OpHelp("intkey=r[P3]"), |
+ /* 34 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), |
+ /* 35 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), |
+ /* 36 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), |
+ /* 37 */ "Eq" OpHelp("IF r[P3]==r[P1]"), |
+ /* 38 */ "Gt" OpHelp("IF r[P3]>r[P1]"), |
+ /* 39 */ "Le" OpHelp("IF r[P3]<=r[P1]"), |
+ /* 40 */ "Lt" OpHelp("IF r[P3]<r[P1]"), |
+ /* 41 */ "Ge" OpHelp("IF r[P3]>=r[P1]"), |
+ /* 42 */ "ElseNotEq" OpHelp(""), |
+ /* 43 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), |
+ /* 44 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), |
+ /* 45 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"), |
+ /* 46 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"), |
+ /* 47 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), |
+ /* 48 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), |
+ /* 49 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), |
+ /* 50 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), |
+ /* 51 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), |
+ /* 52 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), |
+ /* 53 */ "Last" OpHelp(""), |
+ /* 54 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), |
+ /* 55 */ "SorterSort" OpHelp(""), |
+ /* 56 */ "Sort" OpHelp(""), |
+ /* 57 */ "Rewind" OpHelp(""), |
+ /* 58 */ "IdxLE" OpHelp("key=r[P3@P4]"), |
+ /* 59 */ "IdxGT" OpHelp("key=r[P3@P4]"), |
+ /* 60 */ "IdxLT" OpHelp("key=r[P3@P4]"), |
+ /* 61 */ "IdxGE" OpHelp("key=r[P3@P4]"), |
+ /* 62 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), |
+ /* 63 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), |
+ /* 64 */ "Program" OpHelp(""), |
+ /* 65 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), |
+ /* 66 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), |
+ /* 67 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), |
+ /* 68 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), |
+ /* 69 */ "IncrVacuum" OpHelp(""), |
+ /* 70 */ "VNext" OpHelp(""), |
+ /* 71 */ "Init" OpHelp("Start at P2"), |
+ /* 72 */ "Return" OpHelp(""), |
+ /* 73 */ "EndCoroutine" OpHelp(""), |
+ /* 74 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), |
+ /* 75 */ "Halt" OpHelp(""), |
+ /* 76 */ "Integer" OpHelp("r[P2]=P1"), |
+ /* 77 */ "Int64" OpHelp("r[P2]=P4"), |
+ /* 78 */ "String" OpHelp("r[P2]='P4' (len=P1)"), |
+ /* 79 */ "Null" OpHelp("r[P2..P3]=NULL"), |
+ /* 80 */ "SoftNull" OpHelp("r[P1]=NULL"), |
+ /* 81 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), |
+ /* 82 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), |
+ /* 83 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), |
+ /* 84 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), |
+ /* 85 */ "SCopy" OpHelp("r[P2]=r[P1]"), |
+ /* 86 */ "IntCopy" OpHelp("r[P2]=r[P1]"), |
+ /* 87 */ "ResultRow" OpHelp("output=r[P1@P2]"), |
+ /* 88 */ "CollSeq" OpHelp(""), |
+ /* 89 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), |
+ /* 90 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), |
+ /* 91 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), |
+ /* 92 */ "RealAffinity" OpHelp(""), |
+ /* 93 */ "Cast" OpHelp("affinity(r[P1])"), |
+ /* 94 */ "Permutation" OpHelp(""), |
+ /* 95 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), |
+ /* 96 */ "Column" OpHelp("r[P3]=PX"), |
+ /* 97 */ "String8" OpHelp("r[P2]='P4'"), |
+ /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"), |
+ /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), |
+ /* 100 */ "Count" OpHelp("r[P2]=count()"), |
+ /* 101 */ "ReadCookie" OpHelp(""), |
+ /* 102 */ "SetCookie" OpHelp(""), |
+ /* 103 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), |
+ /* 104 */ "OpenRead" OpHelp("root=P2 iDb=P3"), |
+ /* 105 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), |
+ /* 106 */ "OpenAutoindex" OpHelp("nColumn=P2"), |
+ /* 107 */ "OpenEphemeral" OpHelp("nColumn=P2"), |
+ /* 108 */ "SorterOpen" OpHelp(""), |
+ /* 109 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), |
+ /* 110 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), |
+ /* 111 */ "Close" OpHelp(""), |
+ /* 112 */ "ColumnsUsed" OpHelp(""), |
+ /* 113 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), |
+ /* 114 */ "NewRowid" OpHelp("r[P2]=rowid"), |
+ /* 115 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), |
+ /* 116 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), |
+ /* 117 */ "Delete" OpHelp(""), |
+ /* 118 */ "ResetCount" OpHelp(""), |
+ /* 119 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), |
+ /* 120 */ "SorterData" OpHelp("r[P2]=data"), |
+ /* 121 */ "RowData" OpHelp("r[P2]=data"), |
+ /* 122 */ "Rowid" OpHelp("r[P2]=rowid"), |
+ /* 123 */ "NullRow" OpHelp(""), |
+ /* 124 */ "SorterInsert" OpHelp("key=r[P2]"), |
+ /* 125 */ "IdxInsert" OpHelp("key=r[P2]"), |
+ /* 126 */ "IdxDelete" OpHelp("key=r[P2@P3]"), |
+ /* 127 */ "Seek" OpHelp("Move P3 to P1.rowid"), |
+ /* 128 */ "IdxRowid" OpHelp("r[P2]=rowid"), |
+ /* 129 */ "Destroy" OpHelp(""), |
+ /* 130 */ "Clear" OpHelp(""), |
+ /* 131 */ "ResetSorter" OpHelp(""), |
+ /* 132 */ "Real" OpHelp("r[P2]=P4"), |
+ /* 133 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), |
+ /* 134 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), |
+ /* 135 */ "ParseSchema" OpHelp(""), |
+ /* 136 */ "LoadAnalysis" OpHelp(""), |
+ /* 137 */ "DropTable" OpHelp(""), |
+ /* 138 */ "DropIndex" OpHelp(""), |
+ /* 139 */ "DropTrigger" OpHelp(""), |
+ /* 140 */ "IntegrityCk" OpHelp(""), |
+ /* 141 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), |
+ /* 142 */ "Param" OpHelp(""), |
+ /* 143 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), |
+ /* 144 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), |
+ /* 145 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), |
+ /* 146 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), |
+ /* 147 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), |
+ /* 148 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), |
+ /* 149 */ "Expire" OpHelp(""), |
+ /* 150 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), |
+ /* 151 */ "VBegin" OpHelp(""), |
+ /* 152 */ "VCreate" OpHelp(""), |
+ /* 153 */ "VDestroy" OpHelp(""), |
+ /* 154 */ "VOpen" OpHelp(""), |
+ /* 155 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), |
+ /* 156 */ "VRename" OpHelp(""), |
+ /* 157 */ "Pagecount" OpHelp(""), |
+ /* 158 */ "MaxPgcnt" OpHelp(""), |
+ /* 159 */ "CursorHint" OpHelp(""), |
+ /* 160 */ "Noop" OpHelp(""), |
+ /* 161 */ "Explain" OpHelp(""), |
+ }; |
+ return azName[i]; |
+} |
+#endif |
+ |
+/************** End of opcodes.c *********************************************/ |
+/************** Begin file os_unix.c *****************************************/ |
+/* |
+** 2004 May 22 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains the VFS implementation for unix-like operating systems |
+** include Linux, MacOSX, *BSD, QNX, VxWorks, AIX, HPUX, and others. |
+** |
+** There are actually several different VFS implementations in this file. |
+** The differences are in the way that file locking is done. The default |
+** implementation uses Posix Advisory Locks. Alternative implementations |
+** use flock(), dot-files, various proprietary locking schemas, or simply |
+** skip locking all together. |
+** |
+** This source file is organized into divisions where the logic for various |
+** subfunctions is contained within the appropriate division. PLEASE |
+** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed |
+** in the correct division and should be clearly labeled. |
+** |
+** The layout of divisions is as follows: |
+** |
+** * General-purpose declarations and utility functions. |
+** * Unique file ID logic used by VxWorks. |
+** * Various locking primitive implementations (all except proxy locking): |
+** + for Posix Advisory Locks |
+** + for no-op locks |
+** + for dot-file locks |
+** + for flock() locking |
+** + for named semaphore locks (VxWorks only) |
+** + for AFP filesystem locks (MacOSX only) |
+** * sqlite3_file methods not associated with locking. |
+** * Definitions of sqlite3_io_methods objects for all locking |
+** methods plus "finder" functions for each locking method. |
+** * sqlite3_vfs method implementations. |
+** * Locking primitives for the proxy uber-locking-method. (MacOSX only) |
+** * Definitions of sqlite3_vfs objects for all locking methods |
+** plus implementations of sqlite3_os_init() and sqlite3_os_end(). |
+*/ |
+/* #include "sqliteInt.h" */ |
+#if SQLITE_OS_UNIX /* This file is used on unix only */ |
+ |
+/* |
+** There are various methods for file locking used for concurrency |
+** control: |
+** |
+** 1. POSIX locking (the default), |
+** 2. No locking, |
+** 3. Dot-file locking, |
+** 4. flock() locking, |
+** 5. AFP locking (OSX only), |
+** 6. Named POSIX semaphores (VXWorks only), |
+** 7. proxy locking. (OSX only) |
+** |
+** Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE |
+** is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic |
+** selection of the appropriate locking style based on the filesystem |
+** where the database is located. |
+*/ |
+#if !defined(SQLITE_ENABLE_LOCKING_STYLE) |
+# if defined(__APPLE__) |
+# define SQLITE_ENABLE_LOCKING_STYLE 1 |
+# else |
+# define SQLITE_ENABLE_LOCKING_STYLE 0 |
+# endif |
+#endif |
+ |
+/* Use pread() and pwrite() if they are available */ |
+#if defined(__APPLE__) |
+# define HAVE_PREAD 1 |
+# define HAVE_PWRITE 1 |
+#endif |
+#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64) |
+# undef USE_PREAD |
+# define USE_PREAD64 1 |
+#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE) |
+# undef USE_PREAD64 |
+# define USE_PREAD 1 |
+#endif |
+ |
+/* |
+** standard include files. |
+*/ |
+#include <sys/types.h> |
+#include <sys/stat.h> |
+#include <fcntl.h> |
+#include <unistd.h> |
+/* #include <time.h> */ |
+#include <sys/time.h> |
+#include <errno.h> |
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
+# include <sys/mman.h> |
+#endif |
+ |
+#if SQLITE_ENABLE_LOCKING_STYLE |
+# include <sys/ioctl.h> |
+# include <sys/file.h> |
+# include <sys/param.h> |
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */ |
+ |
+#if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \ |
+ (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000)) |
+# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \ |
+ && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0)) |
+# define HAVE_GETHOSTUUID 1 |
+# else |
+# warning "gethostuuid() is disabled." |
+# endif |
+#endif |
+ |
+ |
+#if OS_VXWORKS |
+/* # include <sys/ioctl.h> */ |
+# include <semaphore.h> |
+# include <limits.h> |
+#endif /* OS_VXWORKS */ |
+ |
+#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE |
+# include <sys/mount.h> |
+#endif |
+ |
+#ifdef HAVE_UTIME |
+# include <utime.h> |
+#endif |
+ |
+/* |
+** Allowed values of unixFile.fsFlags |
+*/ |
+#define SQLITE_FSFLAGS_IS_MSDOS 0x1 |
+ |
+/* |
+** If we are to be thread-safe, include the pthreads header and define |
+** the SQLITE_UNIX_THREADS macro. |
+*/ |
+#if SQLITE_THREADSAFE |
+/* # include <pthread.h> */ |
+# define SQLITE_UNIX_THREADS 1 |
+#endif |
+ |
+/* |
+** Default permissions when creating a new file |
+*/ |
+#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS |
+# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 |
+#endif |
+ |
+/* |
+** Default permissions when creating auto proxy dir |
+*/ |
+#ifndef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS |
+# define SQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755 |
+#endif |
+ |
+/* |
+** Maximum supported path-length. |
+*/ |
+#define MAX_PATHNAME 512 |
+ |
+/* |
+** Maximum supported symbolic links |
+*/ |
+#define SQLITE_MAX_SYMLINKS 100 |
+ |
+/* Always cast the getpid() return type for compatibility with |
+** kernel modules in VxWorks. */ |
+#define osGetpid(X) (pid_t)getpid() |
+ |
+/* |
+** Only set the lastErrno if the error code is a real error and not |
+** a normal expected return code of SQLITE_BUSY or SQLITE_OK |
+*/ |
+#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY)) |
+ |
+/* Forward references */ |
+typedef struct unixShm unixShm; /* Connection shared memory */ |
+typedef struct unixShmNode unixShmNode; /* Shared memory instance */ |
+typedef struct unixInodeInfo unixInodeInfo; /* An i-node */ |
+typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */ |
+ |
+/* |
+** Sometimes, after a file handle is closed by SQLite, the file descriptor |
+** cannot be closed immediately. In these cases, instances of the following |
+** structure are used to store the file descriptor while waiting for an |
+** opportunity to either close or reuse it. |
+*/ |
+struct UnixUnusedFd { |
+ int fd; /* File descriptor to close */ |
+ int flags; /* Flags this file descriptor was opened with */ |
+ UnixUnusedFd *pNext; /* Next unused file descriptor on same file */ |
+}; |
+ |
+/* |
+** The unixFile structure is subclass of sqlite3_file specific to the unix |
+** VFS implementations. |
+*/ |
+typedef struct unixFile unixFile; |
+struct unixFile { |
+ sqlite3_io_methods const *pMethod; /* Always the first entry */ |
+ sqlite3_vfs *pVfs; /* The VFS that created this unixFile */ |
+ unixInodeInfo *pInode; /* Info about locks on this inode */ |
+ int h; /* The file descriptor */ |
+ unsigned char eFileLock; /* The type of lock held on this fd */ |
+ unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ |
+ int lastErrno; /* The unix errno from last I/O error */ |
+ void *lockingContext; /* Locking style specific state */ |
+ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ |
+ const char *zPath; /* Name of the file */ |
+ unixShm *pShm; /* Shared memory segment information */ |
+ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ int nFetchOut; /* Number of outstanding xFetch refs */ |
+ sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */ |
+ sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */ |
+ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ |
+ void *pMapRegion; /* Memory mapped region */ |
+#endif |
+#ifdef __QNXNTO__ |
+ int sectorSize; /* Device sector size */ |
+ int deviceCharacteristics; /* Precomputed device characteristics */ |
+#endif |
+#if SQLITE_ENABLE_LOCKING_STYLE |
+ int openFlags; /* The flags specified at open() */ |
+#endif |
+#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__) |
+ unsigned fsFlags; /* cached details from statfs() */ |
+#endif |
+#if OS_VXWORKS |
+ struct vxworksFileId *pId; /* Unique file ID */ |
+#endif |
+#ifdef SQLITE_DEBUG |
+ /* The next group of variables are used to track whether or not the |
+ ** transaction counter in bytes 24-27 of database files are updated |
+ ** whenever any part of the database changes. An assertion fault will |
+ ** occur if a file is updated without also updating the transaction |
+ ** counter. This test is made to avoid new problems similar to the |
+ ** one described by ticket #3584. |
+ */ |
+ unsigned char transCntrChng; /* True if the transaction counter changed */ |
+ unsigned char dbUpdate; /* True if any part of database file changed */ |
+ unsigned char inNormalWrite; /* True if in a normal write operation */ |
+ |
+#endif |
+ |
+#ifdef SQLITE_TEST |
+ /* In test mode, increase the size of this structure a bit so that |
+ ** it is larger than the struct CrashFile defined in test6.c. |
+ */ |
+ char aPadding[32]; |
+#endif |
+}; |
+ |
+/* This variable holds the process id (pid) from when the xRandomness() |
+** method was called. If xOpen() is called from a different process id, |
+** indicating that a fork() has occurred, the PRNG will be reset. |
+*/ |
+static pid_t randomnessPid = 0; |
+ |
+/* |
+** Allowed values for the unixFile.ctrlFlags bitmask: |
+*/ |
+#define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
+#define UNIXFILE_RDONLY 0x02 /* Connection is read only */ |
+#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ |
+#ifndef SQLITE_DISABLE_DIRSYNC |
+# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */ |
+#else |
+# define UNIXFILE_DIRSYNC 0x00 |
+#endif |
+#define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ |
+#define UNIXFILE_DELETE 0x20 /* Delete on close */ |
+#define UNIXFILE_URI 0x40 /* Filename might have query parameters */ |
+#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ |
+ |
+/* |
+** Include code that is common to all os_*.c files |
+*/ |
+/************** Include os_common.h in the middle of os_unix.c ***************/ |
+/************** Begin file os_common.h ***************************************/ |
+/* |
+** 2004 May 22 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains macros and a little bit of code that is common to |
+** all of the platform-specific files (os_*.c) and is #included into those |
+** files. |
+** |
+** This file should be #included by the os_*.c files only. It is not a |
+** general purpose header file. |
+*/ |
+#ifndef _OS_COMMON_H_ |
+#define _OS_COMMON_H_ |
+ |
+/* |
+** At least two bugs have slipped in because we changed the MEMORY_DEBUG |
+** macro to SQLITE_DEBUG and some older makefiles have not yet made the |
+** switch. The following code should catch this problem at compile-time. |
+*/ |
+#ifdef MEMORY_DEBUG |
+# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." |
+#endif |
+ |
+/* |
+** Macros for performance tracing. Normally turned off. Only works |
+** on i486 hardware. |
+*/ |
+#ifdef SQLITE_PERFORMANCE_TRACE |
+ |
+/* |
+** hwtime.h contains inline assembler code for implementing |
+** high-performance timing routines. |
+*/ |
+/************** Include hwtime.h in the middle of os_common.h ****************/ |
+/************** Begin file hwtime.h ******************************************/ |
+/* |
+** 2008 May 27 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains inline asm code for retrieving "high-performance" |
+** counters for x86 class CPUs. |
+*/ |
+#ifndef SQLITE_HWTIME_H |
+#define SQLITE_HWTIME_H |
+ |
+/* |
+** The following routine only works on pentium-class (or newer) processors. |
+** It uses the RDTSC opcode to read the cycle count value out of the |
+** processor and returns that value. This can be used for high-res |
+** profiling. |
+*/ |
+#if (defined(__GNUC__) || defined(_MSC_VER)) && \ |
+ (defined(i386) || defined(__i386__) || defined(_M_IX86)) |
+ |
+ #if defined(__GNUC__) |
+ |
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
+ unsigned int lo, hi; |
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); |
+ return (sqlite_uint64)hi << 32 | lo; |
+ } |
+ |
+ #elif defined(_MSC_VER) |
+ |
+ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ |
+ __asm { |
+ rdtsc |
+ ret ; return value at EDX:EAX |
+ } |
+ } |
+ |
+ #endif |
+ |
+#elif (defined(__GNUC__) && defined(__x86_64__)) |
+ |
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
+ unsigned long val; |
+ __asm__ __volatile__ ("rdtsc" : "=A" (val)); |
+ return val; |
+ } |
+ |
+#elif (defined(__GNUC__) && defined(__ppc__)) |
+ |
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
+ unsigned long long retval; |
+ unsigned long junk; |
+ __asm__ __volatile__ ("\n\ |
+ 1: mftbu %1\n\ |
+ mftb %L0\n\ |
+ mftbu %0\n\ |
+ cmpw %0,%1\n\ |
+ bne 1b" |
+ : "=r" (retval), "=r" (junk)); |
+ return retval; |
+ } |
+ |
+#else |
+ |
+ #error Need implementation of sqlite3Hwtime() for your platform. |
+ |
+ /* |
+ ** To compile without implementing sqlite3Hwtime() for your platform, |
+ ** you can remove the above #error and use the following |
+ ** stub function. You will lose timing support for many |
+ ** of the debugging and testing utilities, but it should at |
+ ** least compile and run. |
+ */ |
+SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } |
+ |
+#endif |
+ |
+#endif /* !defined(SQLITE_HWTIME_H) */ |
+ |
+/************** End of hwtime.h **********************************************/ |
+/************** Continuing where we left off in os_common.h ******************/ |
+ |
+static sqlite_uint64 g_start; |
+static sqlite_uint64 g_elapsed; |
+#define TIMER_START g_start=sqlite3Hwtime() |
+#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start |
+#define TIMER_ELAPSED g_elapsed |
+#else |
+#define TIMER_START |
+#define TIMER_END |
+#define TIMER_ELAPSED ((sqlite_uint64)0) |
+#endif |
+ |
+/* |
+** If we compile with the SQLITE_TEST macro set, then the following block |
+** of code will give us the ability to simulate a disk I/O error. This |
+** is used for testing the I/O recovery logic. |
+*/ |
+#if defined(SQLITE_TEST) |
+SQLITE_API extern int sqlite3_io_error_hit; |
+SQLITE_API extern int sqlite3_io_error_hardhit; |
+SQLITE_API extern int sqlite3_io_error_pending; |
+SQLITE_API extern int sqlite3_io_error_persist; |
+SQLITE_API extern int sqlite3_io_error_benign; |
+SQLITE_API extern int sqlite3_diskfull_pending; |
+SQLITE_API extern int sqlite3_diskfull; |
+#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) |
+#define SimulateIOError(CODE) \ |
+ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ |
+ || sqlite3_io_error_pending-- == 1 ) \ |
+ { local_ioerr(); CODE; } |
+static void local_ioerr(){ |
+ IOTRACE(("IOERR\n")); |
+ sqlite3_io_error_hit++; |
+ if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; |
+} |
+#define SimulateDiskfullError(CODE) \ |
+ if( sqlite3_diskfull_pending ){ \ |
+ if( sqlite3_diskfull_pending == 1 ){ \ |
+ local_ioerr(); \ |
+ sqlite3_diskfull = 1; \ |
+ sqlite3_io_error_hit = 1; \ |
+ CODE; \ |
+ }else{ \ |
+ sqlite3_diskfull_pending--; \ |
+ } \ |
+ } |
+#else |
+#define SimulateIOErrorBenign(X) |
+#define SimulateIOError(A) |
+#define SimulateDiskfullError(A) |
+#endif /* defined(SQLITE_TEST) */ |
+ |
+/* |
+** When testing, keep a count of the number of open files. |
+*/ |
+#if defined(SQLITE_TEST) |
+SQLITE_API extern int sqlite3_open_file_count; |
+#define OpenCounter(X) sqlite3_open_file_count+=(X) |
+#else |
+#define OpenCounter(X) |
+#endif /* defined(SQLITE_TEST) */ |
+ |
+#endif /* !defined(_OS_COMMON_H_) */ |
+ |
+/************** End of os_common.h *******************************************/ |
+/************** Continuing where we left off in os_unix.c ********************/ |
+ |
+/* |
+** Define various macros that are missing from some systems. |
+*/ |
+#ifndef O_LARGEFILE |
+# define O_LARGEFILE 0 |
+#endif |
+#ifdef SQLITE_DISABLE_LFS |
+# undef O_LARGEFILE |
+# define O_LARGEFILE 0 |
+#endif |
+#ifndef O_NOFOLLOW |
+# define O_NOFOLLOW 0 |
+#endif |
+#ifndef O_BINARY |
+# define O_BINARY 0 |
+#endif |
+ |
+/* |
+** The threadid macro resolves to the thread-id or to 0. Used for |
+** testing and debugging only. |
+*/ |
+#if SQLITE_THREADSAFE |
+#define threadid pthread_self() |
+#else |
+#define threadid 0 |
+#endif |
+ |
+/* |
+** HAVE_MREMAP defaults to true on Linux and false everywhere else. |
+*/ |
+#if !defined(HAVE_MREMAP) |
+# if defined(__linux__) && defined(_GNU_SOURCE) |
+# define HAVE_MREMAP 1 |
+# else |
+# define HAVE_MREMAP 0 |
+# endif |
+#endif |
+ |
+/* |
+** Explicitly call the 64-bit version of lseek() on Android. Otherwise, lseek() |
+** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined. |
+*/ |
+#ifdef __ANDROID__ |
+# define lseek lseek64 |
+#endif |
+ |
+/* |
+** Different Unix systems declare open() in different ways. Same use |
+** open(const char*,int,mode_t). Others use open(const char*,int,...). |
+** The difference is important when using a pointer to the function. |
+** |
+** The safest way to deal with the problem is to always use this wrapper |
+** which always has the same well-defined interface. |
+*/ |
+static int posixOpen(const char *zFile, int flags, int mode){ |
+ return open(zFile, flags, mode); |
+} |
+ |
+/* Forward reference */ |
+static int openDirectory(const char*, int*); |
+static int unixGetpagesize(void); |
+ |
+/* |
+** Many system calls are accessed through pointer-to-functions so that |
+** they may be overridden at runtime to facilitate fault injection during |
+** testing and sandboxing. The following array holds the names and pointers |
+** to all overrideable system calls. |
+*/ |
+static struct unix_syscall { |
+ const char *zName; /* Name of the system call */ |
+ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ |
+ sqlite3_syscall_ptr pDefault; /* Default value */ |
+} aSyscall[] = { |
+ { "open", (sqlite3_syscall_ptr)posixOpen, 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) |
+ |
+ { "getcwd", (sqlite3_syscall_ptr)getcwd, 0 }, |
+#define osGetcwd ((char*(*)(char*,size_t))aSyscall[3].pCurrent) |
+ |
+ { "stat", (sqlite3_syscall_ptr)stat, 0 }, |
+#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent) |
+ |
+/* |
+** The DJGPP compiler environment looks mostly like Unix, but it |
+** lacks the fcntl() system call. So redefine fcntl() to be something |
+** that always succeeds. This means that locking does not occur under |
+** DJGPP. But it is DOS - what did you expect? |
+*/ |
+#ifdef __DJGPP__ |
+ { "fstat", 0, 0 }, |
+#define osFstat(a,b,c) 0 |
+#else |
+ { "fstat", (sqlite3_syscall_ptr)fstat, 0 }, |
+#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent) |
+#endif |
+ |
+ { "ftruncate", (sqlite3_syscall_ptr)ftruncate, 0 }, |
+#define osFtruncate ((int(*)(int,off_t))aSyscall[6].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)pread64, 0 }, |
+#else |
+ { "pread64", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_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) |
+ |
+#if defined(USE_PREAD64) |
+ { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 }, |
+#else |
+ { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_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 |
+#define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent) |
+ |
+ { "unlink", (sqlite3_syscall_ptr)unlink, 0 }, |
+#define osUnlink ((int(*)(const char*))aSyscall[16].pCurrent) |
+ |
+ { "openDirectory", (sqlite3_syscall_ptr)openDirectory, 0 }, |
+#define osOpenDirectory ((int(*)(const char*,int*))aSyscall[17].pCurrent) |
+ |
+ { "mkdir", (sqlite3_syscall_ptr)mkdir, 0 }, |
+#define osMkdir ((int(*)(const char*,mode_t))aSyscall[18].pCurrent) |
+ |
+ { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, |
+#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) |
+ |
+#if defined(HAVE_FCHOWN) |
+ { "fchown", (sqlite3_syscall_ptr)fchown, 0 }, |
+#else |
+ { "fchown", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) |
+ |
+ { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, |
+#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) |
+ |
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
+ { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, |
+#else |
+ { "mmap", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent) |
+ |
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
+ { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, |
+#else |
+ { "munmap", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent) |
+ |
+#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) |
+ { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, |
+#else |
+ { "mremap", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent) |
+ |
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
+ { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 }, |
+#else |
+ { "getpagesize", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent) |
+ |
+#if defined(HAVE_READLINK) |
+ { "readlink", (sqlite3_syscall_ptr)readlink, 0 }, |
+#else |
+ { "readlink", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent) |
+ |
+#if defined(HAVE_LSTAT) |
+ { "lstat", (sqlite3_syscall_ptr)lstat, 0 }, |
+#else |
+ { "lstat", (sqlite3_syscall_ptr)0, 0 }, |
+#endif |
+#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) |
+ |
+}; /* End of the overrideable system calls */ |
+ |
+ |
+/* |
+** On some systems, calls to fchown() will trigger a message in a security |
+** log if they come from non-root processes. So avoid calling fchown() if |
+** we are not running as root. |
+*/ |
+static int robustFchown(int fd, uid_t uid, gid_t gid){ |
+#if defined(HAVE_FCHOWN) |
+ return osGeteuid() ? 0 : osFchown(fd,uid,gid); |
+#else |
+ return 0; |
+#endif |
+} |
+ |
+/* |
+** This is the xSetSystemCall() method of sqlite3_vfs for all of the |
+** "unix" VFSes. Return SQLITE_OK opon successfully updating the |
+** system call pointer, or SQLITE_NOTFOUND if there is no configurable |
+** system call named zName. |
+*/ |
+static int unixSetSystemCall( |
+ sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */ |
+ const char *zName, /* Name of system call to override */ |
+ sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */ |
+){ |
+ unsigned int i; |
+ int rc = SQLITE_NOTFOUND; |
+ |
+ UNUSED_PARAMETER(pNotUsed); |
+ if( zName==0 ){ |
+ /* If no zName is given, restore all system calls to their default |
+ ** settings and return NULL |
+ */ |
+ rc = SQLITE_OK; |
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ |
+ if( aSyscall[i].pDefault ){ |
+ aSyscall[i].pCurrent = aSyscall[i].pDefault; |
+ } |
+ } |
+ }else{ |
+ /* If zName is specified, operate on only the one system call |
+ ** specified. |
+ */ |
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ |
+ if( strcmp(zName, aSyscall[i].zName)==0 ){ |
+ if( aSyscall[i].pDefault==0 ){ |
+ aSyscall[i].pDefault = aSyscall[i].pCurrent; |
+ } |
+ rc = SQLITE_OK; |
+ if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault; |
+ aSyscall[i].pCurrent = pNewFunc; |
+ break; |
+ } |
+ } |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Return the value of a system call. Return NULL if zName is not a |
+** recognized system call name. NULL is also returned if the system call |
+** is currently undefined. |
+*/ |
+static sqlite3_syscall_ptr unixGetSystemCall( |
+ sqlite3_vfs *pNotUsed, |
+ const char *zName |
+){ |
+ unsigned int i; |
+ |
+ UNUSED_PARAMETER(pNotUsed); |
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ |
+ if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent; |
+ } |
+ return 0; |
+} |
+ |
+/* |
+** Return the name of the first system call after zName. If zName==NULL |
+** then return the name of the first system call. Return NULL if zName |
+** is the last system call or if zName is not the name of a valid |
+** system call. |
+*/ |
+static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){ |
+ int i = -1; |
+ |
+ UNUSED_PARAMETER(p); |
+ if( zName ){ |
+ for(i=0; i<ArraySize(aSyscall)-1; i++){ |
+ if( strcmp(zName, aSyscall[i].zName)==0 ) break; |
+ } |
+ } |
+ for(i++; i<ArraySize(aSyscall); i++){ |
+ if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName; |
+ } |
+ return 0; |
+} |
+ |
+/* |
+** Do not accept any file descriptor less than this value, in order to avoid |
+** opening database file using file descriptors that are commonly used for |
+** standard input, output, and error. |
+*/ |
+#ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR |
+# define SQLITE_MINIMUM_FILE_DESCRIPTOR 3 |
+#endif |
+ |
+/* |
+** Invoke open(). Do so multiple times, until it either succeeds or |
+** fails for some reason other than EINTR. |
+** |
+** If the file creation mode "m" is 0 then set it to the default for |
+** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally |
+** 0644) as modified by the system umask. If m is not 0, then |
+** make the file creation mode be exactly m ignoring the umask. |
+** |
+** The m parameter will be non-zero only when creating -wal, -journal, |
+** and -shm files. We want those files to have *exactly* the same |
+** permissions as their original database, unadulterated by the umask. |
+** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a |
+** transaction crashes and leaves behind hot journals, then any |
+** process that is able to write to the database will also be able to |
+** recover the hot journals. |
+*/ |
+static int robust_open(const char *z, int f, mode_t m){ |
+ int fd; |
+ mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS; |
+ while(1){ |
+#if defined(O_CLOEXEC) |
+ fd = osOpen(z,f|O_CLOEXEC,m2); |
+#else |
+ fd = osOpen(z,f,m2); |
+#endif |
+ if( fd<0 ){ |
+ if( errno==EINTR ) continue; |
+ break; |
+ } |
+ if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break; |
+ osClose(fd); |
+ sqlite3_log(SQLITE_WARNING, |
+ "attempt to open \"%s\" as file descriptor %d", z, fd); |
+ fd = -1; |
+ if( osOpen("/dev/null", f, m)<0 ) break; |
+ } |
+ if( fd>=0 ){ |
+ if( m!=0 ){ |
+ struct stat statbuf; |
+ if( osFstat(fd, &statbuf)==0 |
+ && statbuf.st_size==0 |
+ && (statbuf.st_mode&0777)!=m |
+ ){ |
+ osFchmod(fd, m); |
+ } |
+ } |
+#if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0) |
+ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); |
+#endif |
+ } |
+ return fd; |
+} |
+ |
+/* |
+** Helper functions to obtain and relinquish the global mutex. The |
+** global mutex is used to protect the unixInodeInfo and |
+** vxworksFileId objects used by this file, all of which may be |
+** shared by multiple threads. |
+** |
+** Function unixMutexHeld() is used to assert() that the global mutex |
+** is held when required. This function is only used as part of assert() |
+** statements. e.g. |
+** |
+** unixEnterMutex() |
+** assert( unixMutexHeld() ); |
+** unixEnterLeave() |
+*/ |
+static void unixEnterMutex(void){ |
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); |
+} |
+static void unixLeaveMutex(void){ |
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); |
+} |
+#ifdef SQLITE_DEBUG |
+static int unixMutexHeld(void) { |
+ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); |
+} |
+#endif |
+ |
+ |
+#ifdef SQLITE_HAVE_OS_TRACE |
+/* |
+** Helper function for printing out trace information from debugging |
+** binaries. This returns the string representation of the supplied |
+** integer lock-type. |
+*/ |
+static const char *azFileLock(int eFileLock){ |
+ switch( eFileLock ){ |
+ case NO_LOCK: return "NONE"; |
+ case SHARED_LOCK: return "SHARED"; |
+ case RESERVED_LOCK: return "RESERVED"; |
+ case PENDING_LOCK: return "PENDING"; |
+ case EXCLUSIVE_LOCK: return "EXCLUSIVE"; |
+ } |
+ return "ERROR"; |
+} |
+#endif |
+ |
+#ifdef SQLITE_LOCK_TRACE |
+/* |
+** Print out information about all locking operations. |
+** |
+** This routine is used for troubleshooting locks on multithreaded |
+** platforms. Enable by compiling with the -DSQLITE_LOCK_TRACE |
+** command-line option on the compiler. This code is normally |
+** turned off. |
+*/ |
+static int lockTrace(int fd, int op, struct flock *p){ |
+ char *zOpName, *zType; |
+ int s; |
+ int savedErrno; |
+ if( op==F_GETLK ){ |
+ zOpName = "GETLK"; |
+ }else if( op==F_SETLK ){ |
+ zOpName = "SETLK"; |
+ }else{ |
+ s = osFcntl(fd, op, p); |
+ sqlite3DebugPrintf("fcntl unknown %d %d %d\n", fd, op, s); |
+ return s; |
+ } |
+ if( p->l_type==F_RDLCK ){ |
+ zType = "RDLCK"; |
+ }else if( p->l_type==F_WRLCK ){ |
+ zType = "WRLCK"; |
+ }else if( p->l_type==F_UNLCK ){ |
+ zType = "UNLCK"; |
+ }else{ |
+ assert( 0 ); |
+ } |
+ assert( p->l_whence==SEEK_SET ); |
+ s = osFcntl(fd, op, p); |
+ savedErrno = errno; |
+ sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n", |
+ threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len, |
+ (int)p->l_pid, s); |
+ if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){ |
+ struct flock l2; |
+ l2 = *p; |
+ osFcntl(fd, F_GETLK, &l2); |
+ if( l2.l_type==F_RDLCK ){ |
+ zType = "RDLCK"; |
+ }else if( l2.l_type==F_WRLCK ){ |
+ zType = "WRLCK"; |
+ }else if( l2.l_type==F_UNLCK ){ |
+ zType = "UNLCK"; |
+ }else{ |
+ assert( 0 ); |
+ } |
+ sqlite3DebugPrintf("fcntl-failure-reason: %s %d %d %d\n", |
+ zType, (int)l2.l_start, (int)l2.l_len, (int)l2.l_pid); |
+ } |
+ errno = savedErrno; |
+ return s; |
+} |
+#undef osFcntl |
+#define osFcntl lockTrace |
+#endif /* SQLITE_LOCK_TRACE */ |
+ |
+/* |
+** Retry ftruncate() calls that fail due to EINTR |
+** |
+** All calls to ftruncate() within this file should be made through |
+** this wrapper. On the Android platform, bypassing the logic below |
+** could lead to a corrupt database. |
+*/ |
+static int robust_ftruncate(int h, sqlite3_int64 sz){ |
+ int rc; |
+#ifdef __ANDROID__ |
+ /* On Android, ftruncate() always uses 32-bit offsets, even if |
+ ** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to |
+ ** truncate a file to any size larger than 2GiB. Silently ignore any |
+ ** such attempts. */ |
+ if( sz>(sqlite3_int64)0x7FFFFFFF ){ |
+ rc = SQLITE_OK; |
+ }else |
+#endif |
+ do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR ); |
+ return rc; |
+} |
+ |
+/* |
+** This routine translates a standard POSIX errno code into something |
+** useful to the clients of the sqlite3 functions. Specifically, it is |
+** intended to translate a variety of "try again" errors into SQLITE_BUSY |
+** and a variety of "please close the file descriptor NOW" errors into |
+** SQLITE_IOERR |
+** |
+** Errors during initialization of locks, or file system support for locks, |
+** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately. |
+*/ |
+static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { |
+ assert( (sqliteIOErr == SQLITE_IOERR_LOCK) || |
+ (sqliteIOErr == SQLITE_IOERR_UNLOCK) || |
+ (sqliteIOErr == SQLITE_IOERR_RDLOCK) || |
+ (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ); |
+ switch (posixError) { |
+ case EACCES: |
+ case EAGAIN: |
+ case ETIMEDOUT: |
+ case EBUSY: |
+ case EINTR: |
+ case ENOLCK: |
+ /* random NFS retry error, unless during file system support |
+ * introspection, in which it actually means what it says */ |
+ return SQLITE_BUSY; |
+ |
+ case EPERM: |
+ return SQLITE_PERM; |
+ |
+ default: |
+ return sqliteIOErr; |
+ } |
+} |
+ |
+ |
+/****************************************************************************** |
+****************** Begin Unique File ID Utility Used By VxWorks *************** |
+** |
+** On most versions of unix, we can get a unique ID for a file by concatenating |
+** the device number and the inode number. But this does not work on VxWorks. |
+** On VxWorks, a unique file id must be based on the canonical filename. |
+** |
+** A pointer to an instance of the following structure can be used as a |
+** unique file ID in VxWorks. Each instance of this structure contains |
+** a copy of the canonical filename. There is also a reference count. |
+** The structure is reclaimed when the number of pointers to it drops to |
+** zero. |
+** |
+** There are never very many files open at one time and lookups are not |
+** a performance-critical path, so it is sufficient to put these |
+** structures on a linked list. |
+*/ |
+struct vxworksFileId { |
+ struct vxworksFileId *pNext; /* Next in a list of them all */ |
+ int nRef; /* Number of references to this one */ |
+ int nName; /* Length of the zCanonicalName[] string */ |
+ char *zCanonicalName; /* Canonical filename */ |
+}; |
+ |
+#if OS_VXWORKS |
+/* |
+** All unique filenames are held on a linked list headed by this |
+** variable: |
+*/ |
+static struct vxworksFileId *vxworksFileList = 0; |
+ |
+/* |
+** Simplify a filename into its canonical form |
+** by making the following changes: |
+** |
+** * removing any trailing and duplicate / |
+** * convert /./ into just / |
+** * convert /A/../ where A is any simple name into just / |
+** |
+** Changes are made in-place. Return the new name length. |
+** |
+** The original filename is in z[0..n-1]. Return the number of |
+** characters in the simplified name. |
+*/ |
+static int vxworksSimplifyName(char *z, int n){ |
+ int i, j; |
+ while( n>1 && z[n-1]=='/' ){ n--; } |
+ for(i=j=0; i<n; i++){ |
+ if( z[i]=='/' ){ |
+ if( z[i+1]=='/' ) continue; |
+ if( z[i+1]=='.' && i+2<n && z[i+2]=='/' ){ |
+ i += 1; |
+ continue; |
+ } |
+ if( z[i+1]=='.' && i+3<n && z[i+2]=='.' && z[i+3]=='/' ){ |
+ while( j>0 && z[j-1]!='/' ){ j--; } |
+ if( j>0 ){ j--; } |
+ i += 2; |
+ continue; |
+ } |
+ } |
+ z[j++] = z[i]; |
+ } |
+ z[j] = 0; |
+ return j; |
+} |
+ |
+/* |
+** Find a unique file ID for the given absolute pathname. Return |
+** a pointer to the vxworksFileId object. This pointer is the unique |
+** file ID. |
+** |
+** The nRef field of the vxworksFileId object is incremented before |
+** the object is returned. A new vxworksFileId object is created |
+** and added to the global list if necessary. |
+** |
+** If a memory allocation error occurs, return NULL. |
+*/ |
+static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){ |
+ struct vxworksFileId *pNew; /* search key and new file ID */ |
+ struct vxworksFileId *pCandidate; /* For looping over existing file IDs */ |
+ int n; /* Length of zAbsoluteName string */ |
+ |
+ assert( zAbsoluteName[0]=='/' ); |
+ n = (int)strlen(zAbsoluteName); |
+ pNew = sqlite3_malloc64( sizeof(*pNew) + (n+1) ); |
+ if( pNew==0 ) return 0; |
+ pNew->zCanonicalName = (char*)&pNew[1]; |
+ memcpy(pNew->zCanonicalName, zAbsoluteName, n+1); |
+ n = vxworksSimplifyName(pNew->zCanonicalName, n); |
+ |
+ /* Search for an existing entry that matching the canonical name. |
+ ** If found, increment the reference count and return a pointer to |
+ ** the existing file ID. |
+ */ |
+ unixEnterMutex(); |
+ for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){ |
+ if( pCandidate->nName==n |
+ && memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0 |
+ ){ |
+ sqlite3_free(pNew); |
+ pCandidate->nRef++; |
+ unixLeaveMutex(); |
+ return pCandidate; |
+ } |
+ } |
+ |
+ /* No match was found. We will make a new file ID */ |
+ pNew->nRef = 1; |
+ pNew->nName = n; |
+ pNew->pNext = vxworksFileList; |
+ vxworksFileList = pNew; |
+ unixLeaveMutex(); |
+ return pNew; |
+} |
+ |
+/* |
+** Decrement the reference count on a vxworksFileId object. Free |
+** the object when the reference count reaches zero. |
+*/ |
+static void vxworksReleaseFileId(struct vxworksFileId *pId){ |
+ unixEnterMutex(); |
+ assert( pId->nRef>0 ); |
+ pId->nRef--; |
+ if( pId->nRef==0 ){ |
+ struct vxworksFileId **pp; |
+ for(pp=&vxworksFileList; *pp && *pp!=pId; pp = &((*pp)->pNext)){} |
+ assert( *pp==pId ); |
+ *pp = pId->pNext; |
+ sqlite3_free(pId); |
+ } |
+ unixLeaveMutex(); |
+} |
+#endif /* OS_VXWORKS */ |
+/*************** End of Unique File ID Utility Used By VxWorks **************** |
+******************************************************************************/ |
+ |
+ |
+/****************************************************************************** |
+*************************** Posix Advisory Locking **************************** |
+** |
+** POSIX advisory locks are broken by design. ANSI STD 1003.1 (1996) |
+** section 6.5.2.2 lines 483 through 490 specify that when a process |
+** sets or clears a lock, that operation overrides any prior locks set |
+** by the same process. It does not explicitly say so, but this implies |
+** that it overrides locks set by the same process using a different |
+** file descriptor. Consider this test case: |
+** |
+** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644); |
+** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644); |
+** |
+** Suppose ./file1 and ./file2 are really the same file (because |
+** one is a hard or symbolic link to the other) then if you set |
+** an exclusive lock on fd1, then try to get an exclusive lock |
+** on fd2, it works. I would have expected the second lock to |
+** fail since there was already a lock on the file due to fd1. |
+** But not so. Since both locks came from the same process, the |
+** second overrides the first, even though they were on different |
+** file descriptors opened on different file names. |
+** |
+** This means that we cannot use POSIX locks to synchronize file access |
+** among competing threads of the same process. POSIX locks will work fine |
+** to synchronize access for threads in separate processes, but not |
+** threads within the same process. |
+** |
+** To work around the problem, SQLite has to manage file locks internally |
+** on its own. Whenever a new database is opened, we have to find the |
+** specific inode of the database file (the inode is determined by the |
+** st_dev and st_ino fields of the stat structure that fstat() fills in) |
+** and check for locks already existing on that inode. When locks are |
+** created or removed, we have to look at our own internal record of the |
+** locks to see if another thread has previously set a lock on that same |
+** inode. |
+** |
+** (Aside: The use of inode numbers as unique IDs does not work on VxWorks. |
+** For VxWorks, we have to use the alternative unique ID system based on |
+** canonical filename and implemented in the previous division.) |
+** |
+** The sqlite3_file structure for POSIX is no longer just an integer file |
+** descriptor. It is now a structure that holds the integer file |
+** descriptor and a pointer to a structure that describes the internal |
+** locks on the corresponding inode. There is one locking structure |
+** per inode, so if the same inode is opened twice, both unixFile structures |
+** point to the same locking structure. The locking structure keeps |
+** a reference count (so we will know when to delete it) and a "cnt" |
+** field that tells us its internal lock status. cnt==0 means the |
+** file is unlocked. cnt==-1 means the file has an exclusive lock. |
+** cnt>0 means there are cnt shared locks on the file. |
+** |
+** Any attempt to lock or unlock a file first checks the locking |
+** structure. The fcntl() system call is only invoked to set a |
+** POSIX lock if the internal lock structure transitions between |
+** a locked and an unlocked state. |
+** |
+** But wait: there are yet more problems with POSIX advisory locks. |
+** |
+** If you close a file descriptor that points to a file that has locks, |
+** all locks on that file that are owned by the current process are |
+** released. To work around this problem, each unixInodeInfo object |
+** maintains a count of the number of pending locks on tha inode. |
+** When an attempt is made to close an unixFile, if there are |
+** other unixFile open on the same inode that are holding locks, the call |
+** to close() the file descriptor is deferred until all of the locks clear. |
+** The unixInodeInfo structure keeps a list of file descriptors that need to |
+** be closed and that list is walked (and cleared) when the last lock |
+** clears. |
+** |
+** Yet another problem: LinuxThreads do not play well with posix locks. |
+** |
+** Many older versions of linux use the LinuxThreads library which is |
+** not posix compliant. Under LinuxThreads, a lock created by thread |
+** A cannot be modified or overridden by a different thread B. |
+** Only thread A can modify the lock. Locking behavior is correct |
+** if the appliation uses the newer Native Posix Thread Library (NPTL) |
+** on linux - with NPTL a lock created by thread A can override locks |
+** in thread B. But there is no way to know at compile-time which |
+** threading library is being used. So there is no way to know at |
+** compile-time whether or not thread A can override locks on thread B. |
+** One has to do a run-time check to discover the behavior of the |
+** current process. |
+** |
+** SQLite used to support LinuxThreads. But support for LinuxThreads |
+** was dropped beginning with version 3.7.0. SQLite will still work with |
+** LinuxThreads provided that (1) there is no more than one connection |
+** per database file in the same process and (2) database connections |
+** do not move across threads. |
+*/ |
+ |
+/* |
+** An instance of the following structure serves as the key used |
+** to locate a particular unixInodeInfo object. |
+*/ |
+struct unixFileId { |
+ dev_t dev; /* Device number */ |
+#if OS_VXWORKS |
+ struct vxworksFileId *pId; /* Unique file ID for vxworks. */ |
+#else |
+ /* We are told that some versions of Android contain a bug that |
+ ** sizes ino_t at only 32-bits instead of 64-bits. (See |
+ ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c) |
+ ** To work around this, always allocate 64-bits for the inode number. |
+ ** On small machines that only have 32-bit inodes, this wastes 4 bytes, |
+ ** but that should not be a big deal. */ |
+ /* WAS: ino_t ino; */ |
+ u64 ino; /* Inode number */ |
+#endif |
+}; |
+ |
+/* |
+** An instance of the following structure is allocated for each open |
+** inode. Or, on LinuxThreads, there is one of these structures for |
+** each inode opened by each thread. |
+** |
+** A single inode can have multiple file descriptors, so each unixFile |
+** structure contains a pointer to an instance of this object and this |
+** object keeps a count of the number of unixFile pointing to it. |
+*/ |
+struct unixInodeInfo { |
+ struct unixFileId fileId; /* The lookup key */ |
+ int nShared; /* Number of SHARED locks held */ |
+ unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ |
+ 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 |
+}; |
+ |
+/* |
+** A lists of all unixInodeInfo objects. |
+*/ |
+static unixInodeInfo *inodeList = 0; |
+ |
+/* |
+** |
+** This function - unixLogErrorAtLine(), is only ever called via the macro |
+** unixLogError(). |
+** |
+** It is invoked after an error occurs in an OS function and errno has been |
+** set. It logs a message using sqlite3_log() containing the current value of |
+** errno and, if possible, the human-readable equivalent from strerror() or |
+** strerror_r(). |
+** |
+** 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 (e.g. "unlink", "open") and the associated file-system path, |
+** if any. |
+*/ |
+#define unixLogError(a,b,c) unixLogErrorAtLine(a,b,c,__LINE__) |
+static int unixLogErrorAtLine( |
+ 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 *zErr; /* Message from strerror() or equivalent */ |
+ int iErrno = errno; /* Saved syscall error number */ |
+ |
+ /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use |
+ ** the strerror() function to obtain the human-readable error message |
+ ** equivalent to errno. Otherwise, use strerror_r(). |
+ */ |
+#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R) |
+ char aErr[80]; |
+ memset(aErr, 0, sizeof(aErr)); |
+ zErr = aErr; |
+ |
+ /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined, |
+ ** assume that the system provides the GNU version of strerror_r() that |
+ ** returns a pointer to a buffer containing the error message. That pointer |
+ ** may point to aErr[], or it may point to some static storage somewhere. |
+ ** Otherwise, assume that the system provides the POSIX version of |
+ ** strerror_r(), which always writes an error message into aErr[]. |
+ ** |
+ ** If the code incorrectly assumes that it is the POSIX version that is |
+ ** available, the error message will often be an empty string. Not a |
+ ** huge problem. Incorrectly concluding that the GNU version is available |
+ ** could lead to a segfault though. |
+ */ |
+#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU) |
+ zErr = |
+# endif |
+ strerror_r(iErrno, aErr, sizeof(aErr)-1); |
+ |
+#elif SQLITE_THREADSAFE |
+ /* This is a threadsafe build, but strerror_r() is not available. */ |
+ zErr = ""; |
+#else |
+ /* Non-threadsafe build, use strerror(). */ |
+ zErr = strerror(iErrno); |
+#endif |
+ |
+ if( zPath==0 ) zPath = ""; |
+ sqlite3_log(errcode, |
+ "os_unix.c:%d: (%d) %s(%s) - %s", |
+ iLine, iErrno, zFunc, zPath, zErr |
+ ); |
+ |
+ return errcode; |
+} |
+ |
+/* |
+** Close a file descriptor. |
+** |
+** We assume that close() almost always works, since it is only in a |
+** very sick application or on a very sick platform that it might fail. |
+** If it does fail, simply leak the file descriptor, but do log the |
+** error. |
+** |
+** Note that it is not safe to retry close() after EINTR since the |
+** file descriptor might have already been reused by another thread. |
+** So we don't even try to recover from an EINTR. Just log the error |
+** and move on. |
+*/ |
+static void robust_close(unixFile *pFile, int h, int lineno){ |
+ if( osClose(h) ){ |
+ unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close", |
+ pFile ? pFile->zPath : 0, lineno); |
+ } |
+} |
+ |
+/* |
+** Set the pFile->lastErrno. Do this in a subroutine as that provides |
+** a convenient place to set a breakpoint. |
+*/ |
+static void storeLastErrno(unixFile *pFile, int error){ |
+ pFile->lastErrno = error; |
+} |
+ |
+/* |
+** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. |
+*/ |
+static void closePendingFds(unixFile *pFile){ |
+ unixInodeInfo *pInode = pFile->pInode; |
+ UnixUnusedFd *p; |
+ UnixUnusedFd *pNext; |
+ for(p=pInode->pUnused; p; p=pNext){ |
+ pNext = p->pNext; |
+ robust_close(pFile, p->fd, __LINE__); |
+ sqlite3_free(p); |
+ } |
+ pInode->pUnused = 0; |
+} |
+ |
+/* |
+** Release a unixInodeInfo structure previously allocated by findInodeInfo(). |
+** |
+** The mutex entered using the unixEnterMutex() function must be held |
+** when this function is called. |
+*/ |
+static void releaseInodeInfo(unixFile *pFile){ |
+ unixInodeInfo *pInode = pFile->pInode; |
+ assert( unixMutexHeld() ); |
+ if( ALWAYS(pInode) ){ |
+ pInode->nRef--; |
+ if( pInode->nRef==0 ){ |
+ assert( pInode->pShmNode==0 ); |
+ closePendingFds(pFile); |
+ if( pInode->pPrev ){ |
+ assert( pInode->pPrev->pNext==pInode ); |
+ pInode->pPrev->pNext = pInode->pNext; |
+ }else{ |
+ assert( inodeList==pInode ); |
+ inodeList = pInode->pNext; |
+ } |
+ if( pInode->pNext ){ |
+ assert( pInode->pNext->pPrev==pInode ); |
+ pInode->pNext->pPrev = pInode->pPrev; |
+ } |
+ sqlite3_free(pInode); |
+ } |
+ } |
+} |
+ |
+/* |
+** Given a file descriptor, locate the unixInodeInfo object that |
+** describes that file descriptor. Create a new one if necessary. The |
+** return value might be uninitialized if an error occurs. |
+** |
+** The mutex entered using the unixEnterMutex() function must be held |
+** when this function is called. |
+** |
+** Return an appropriate error code. |
+*/ |
+static int findInodeInfo( |
+ unixFile *pFile, /* Unix file with file desc used in the key */ |
+ unixInodeInfo **ppInode /* Return the unixInodeInfo object here */ |
+){ |
+ int rc; /* System call return code */ |
+ int fd; /* The file descriptor for pFile */ |
+ struct unixFileId fileId; /* Lookup key for the unixInodeInfo */ |
+ struct stat statbuf; /* Low-level file information */ |
+ unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */ |
+ |
+ assert( unixMutexHeld() ); |
+ |
+ /* Get low-level information about the file that we can used to |
+ ** create a unique name for the file. |
+ */ |
+ fd = pFile->h; |
+ rc = osFstat(fd, &statbuf); |
+ if( rc!=0 ){ |
+ storeLastErrno(pFile, errno); |
+#if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS) |
+ if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; |
+#endif |
+ return SQLITE_IOERR; |
+ } |
+ |
+#ifdef __APPLE__ |
+ /* On OS X on an msdos filesystem, the inode number is reported |
+ ** incorrectly for zero-size files. See ticket #3260. To work |
+ ** around this problem (we consider it a bug in OS X, not SQLite) |
+ ** we always increase the file size to 1 by writing a single byte |
+ ** prior to accessing the inode number. The one byte written is |
+ ** an ASCII 'S' character which also happens to be the first byte |
+ ** in the header of every SQLite database. In this way, if there |
+ ** is a race condition such that another thread has already populated |
+ ** the first page of the database, no damage is done. |
+ */ |
+ if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){ |
+ do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); |
+ if( rc!=1 ){ |
+ storeLastErrno(pFile, errno); |
+ return SQLITE_IOERR; |
+ } |
+ rc = osFstat(fd, &statbuf); |
+ if( rc!=0 ){ |
+ storeLastErrno(pFile, errno); |
+ return SQLITE_IOERR; |
+ } |
+ } |
+#endif |
+ |
+ memset(&fileId, 0, sizeof(fileId)); |
+ fileId.dev = statbuf.st_dev; |
+#if OS_VXWORKS |
+ fileId.pId = pFile->pId; |
+#else |
+ fileId.ino = (u64)statbuf.st_ino; |
+#endif |
+ pInode = inodeList; |
+ while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ |
+ pInode = pInode->pNext; |
+ } |
+ if( pInode==0 ){ |
+ pInode = sqlite3_malloc64( sizeof(*pInode) ); |
+ if( pInode==0 ){ |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ memset(pInode, 0, sizeof(*pInode)); |
+ memcpy(&pInode->fileId, &fileId, sizeof(fileId)); |
+ pInode->nRef = 1; |
+ pInode->pNext = inodeList; |
+ pInode->pPrev = 0; |
+ if( inodeList ) inodeList->pPrev = pInode; |
+ inodeList = pInode; |
+ }else{ |
+ pInode->nRef++; |
+ } |
+ *ppInode = pInode; |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Return TRUE if pFile has been renamed or unlinked since it was first opened. |
+*/ |
+static int fileHasMoved(unixFile *pFile){ |
+#if OS_VXWORKS |
+ return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId; |
+#else |
+ struct stat buf; |
+ |
+ /* TODO(shess): This check doesn't work when the Chromium's WebDB code is |
+ ** running in the sandbox. |
+ */ |
+ return 0; |
+ |
+ return pFile->pInode!=0 && |
+ (osStat(pFile->zPath, &buf)!=0 |
+ || (u64)buf.st_ino!=pFile->pInode->fileId.ino); |
+#endif |
+} |
+ |
+ |
+/* |
+** Check a unixFile that is a database. Verify the following: |
+** |
+** (1) There is exactly one hard link on the file |
+** (2) The file is not a symbolic link |
+** (3) The file has not been renamed or unlinked |
+** |
+** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right. |
+*/ |
+static void verifyDbFile(unixFile *pFile){ |
+ struct stat buf; |
+ int rc; |
+ |
+ /* These verifications occurs for the main database only */ |
+ if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return; |
+ |
+ rc = osFstat(pFile->h, &buf); |
+ if( rc!=0 ){ |
+ sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath); |
+ return; |
+ } |
+ if( buf.st_nlink==0 ){ |
+ sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath); |
+ return; |
+ } |
+ if( buf.st_nlink>1 ){ |
+ sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath); |
+ return; |
+ } |
+ if( fileHasMoved(pFile) ){ |
+ sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath); |
+ return; |
+ } |
+} |
+ |
+ |
+/* |
+** This routine checks if there is a RESERVED lock held on the specified |
+** file by this or any other process. If such a lock is held, set *pResOut |
+** to a non-zero value otherwise *pResOut is set to zero. The return value |
+** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
+*/ |
+static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ |
+ int rc = SQLITE_OK; |
+ int reserved = 0; |
+ unixFile *pFile = (unixFile*)id; |
+ |
+ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
+ |
+ assert( pFile ); |
+ assert( pFile->eFileLock<=SHARED_LOCK ); |
+ unixEnterMutex(); /* Because pFile->pInode is shared across threads */ |
+ |
+ /* Check if a thread in this process holds such a lock */ |
+ if( pFile->pInode->eFileLock>SHARED_LOCK ){ |
+ reserved = 1; |
+ } |
+ |
+ /* Otherwise see if some other process holds it. |
+ */ |
+#ifndef __DJGPP__ |
+ if( !reserved && !pFile->pInode->bProcessLock ){ |
+ struct flock lock; |
+ lock.l_whence = SEEK_SET; |
+ lock.l_start = RESERVED_BYTE; |
+ lock.l_len = 1; |
+ lock.l_type = F_WRLCK; |
+ if( osFcntl(pFile->h, F_GETLK, &lock) ){ |
+ rc = SQLITE_IOERR_CHECKRESERVEDLOCK; |
+ storeLastErrno(pFile, errno); |
+ } else if( lock.l_type!=F_UNLCK ){ |
+ reserved = 1; |
+ } |
+ } |
+#endif |
+ |
+ unixLeaveMutex(); |
+ OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); |
+ |
+ *pResOut = reserved; |
+ return rc; |
+} |
+ |
+/* |
+** Attempt to set a system-lock on the file pFile. The lock is |
+** described by pLock. |
+** |
+** If the pFile was opened read/write from unix-excl, then the only lock |
+** ever obtained is an exclusive lock, and it is obtained exactly once |
+** the first time any lock is attempted. All subsequent system locking |
+** operations become no-ops. Locking operations still happen internally, |
+** in order to coordinate access between separate database connections |
+** within this process, but all of that is handled in memory and the |
+** operating system does not participate. |
+** |
+** This function is a pass-through to fcntl(F_SETLK) if pFile is using |
+** any VFS other than "unix-excl" or if pFile is opened on "unix-excl" |
+** and is read-only. |
+** |
+** Zero is returned if the call completes successfully, or -1 if a call |
+** to fcntl() fails. In this case, errno is set appropriately (by fcntl()). |
+*/ |
+static int unixFileLock(unixFile *pFile, struct flock *pLock){ |
+ int rc; |
+ unixInodeInfo *pInode = pFile->pInode; |
+ assert( unixMutexHeld() ); |
+ assert( pInode!=0 ); |
+ if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){ |
+ if( pInode->bProcessLock==0 ){ |
+ struct flock lock; |
+ assert( pInode->nLock==0 ); |
+ lock.l_whence = SEEK_SET; |
+ lock.l_start = SHARED_FIRST; |
+ lock.l_len = SHARED_SIZE; |
+ lock.l_type = F_WRLCK; |
+ rc = osFcntl(pFile->h, F_SETLK, &lock); |
+ if( rc<0 ) return rc; |
+ pInode->bProcessLock = 1; |
+ pInode->nLock++; |
+ }else{ |
+ rc = 0; |
+ } |
+ }else{ |
+ rc = osFcntl(pFile->h, F_SETLK, pLock); |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Lock the file with the lock specified by parameter eFileLock - one |
+** of the following: |
+** |
+** (1) SHARED_LOCK |
+** (2) RESERVED_LOCK |
+** (3) PENDING_LOCK |
+** (4) EXCLUSIVE_LOCK |
+** |
+** Sometimes when requesting one lock state, additional lock states |
+** are inserted in between. The locking might fail on one of the later |
+** transitions leaving the lock state different from what it started but |
+** still short of its goal. The following chart shows the allowed |
+** transitions and the inserted intermediate states: |
+** |
+** UNLOCKED -> SHARED |
+** SHARED -> RESERVED |
+** SHARED -> (PENDING) -> EXCLUSIVE |
+** RESERVED -> (PENDING) -> EXCLUSIVE |
+** PENDING -> EXCLUSIVE |
+** |
+** This routine will only increase a lock. Use the sqlite3OsUnlock() |
+** routine to lower a locking level. |
+*/ |
+static int unixLock(sqlite3_file *id, int eFileLock){ |
+ /* The following describes the implementation of the various locks and |
+ ** lock transitions in terms of the POSIX advisory shared and exclusive |
+ ** lock primitives (called read-locks and write-locks below, to avoid |
+ ** confusion with SQLite lock names). The algorithms are complicated |
+ ** slightly in order to be compatible with Windows95 systems simultaneously |
+ ** accessing the same database file, in case that is ever required. |
+ ** |
+ ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved |
+ ** byte', each single bytes at well known offsets, and the 'shared byte |
+ ** range', a range of 510 bytes at a well known offset. |
+ ** |
+ ** To obtain a SHARED lock, a read-lock is obtained on the 'pending |
+ ** byte'. If this is successful, 'shared byte range' is read-locked |
+ ** and the lock on the 'pending byte' released. (Legacy note: When |
+ ** SQLite was first developed, Windows95 systems were still very common, |
+ ** and Widnows95 lacks a shared-lock capability. So on Windows95, a |
+ ** single randomly selected by from the 'shared byte range' is locked. |
+ ** Windows95 is now pretty much extinct, but this work-around for the |
+ ** lack of shared-locks on Windows95 lives on, for backwards |
+ ** compatibility.) |
+ ** |
+ ** A process may only obtain a RESERVED lock after it has a SHARED lock. |
+ ** A RESERVED lock is implemented by grabbing a write-lock on the |
+ ** 'reserved byte'. |
+ ** |
+ ** A process may only obtain a PENDING lock after it has obtained a |
+ ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock |
+ ** on the 'pending byte'. This ensures that no new SHARED locks can be |
+ ** obtained, but existing SHARED locks are allowed to persist. A process |
+ ** does not have to obtain a RESERVED lock on the way to a PENDING lock. |
+ ** This property is used by the algorithm for rolling back a journal file |
+ ** after a crash. |
+ ** |
+ ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is |
+ ** implemented by obtaining a write-lock on the entire 'shared byte |
+ ** range'. Since all other locks require a read-lock on one of the bytes |
+ ** within this range, this ensures that no other locks are held on the |
+ ** database. |
+ */ |
+ int rc = SQLITE_OK; |
+ unixFile *pFile = (unixFile*)id; |
+ unixInodeInfo *pInode; |
+ struct flock lock; |
+ int tErrno = 0; |
+ |
+ assert( pFile ); |
+ OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h, |
+ azFileLock(eFileLock), azFileLock(pFile->eFileLock), |
+ azFileLock(pFile->pInode->eFileLock), pFile->pInode->nShared, |
+ osGetpid(0))); |
+ |
+ /* If there is already a lock of this type or more restrictive on the |
+ ** unixFile, do nothing. Don't use the end_lock: exit path, as |
+ ** unixEnterMutex() hasn't been called yet. |
+ */ |
+ if( pFile->eFileLock>=eFileLock ){ |
+ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h, |
+ azFileLock(eFileLock))); |
+ return SQLITE_OK; |
+ } |
+ |
+ /* Make sure the locking sequence is correct. |
+ ** (1) We never move from unlocked to anything higher than shared lock. |
+ ** (2) SQLite never explicitly requests a pendig lock. |
+ ** (3) A shared lock is always held when a reserve lock is requested. |
+ */ |
+ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); |
+ assert( eFileLock!=PENDING_LOCK ); |
+ assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); |
+ |
+ /* This mutex is needed because pFile->pInode is shared across threads |
+ */ |
+ unixEnterMutex(); |
+ pInode = pFile->pInode; |
+ |
+ /* If some thread using this PID has a lock via a different unixFile* |
+ ** handle that precludes the requested lock, return BUSY. |
+ */ |
+ if( (pFile->eFileLock!=pInode->eFileLock && |
+ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) |
+ ){ |
+ rc = SQLITE_BUSY; |
+ goto end_lock; |
+ } |
+ |
+ /* If a SHARED lock is requested, and some thread using this PID already |
+ ** has a SHARED or RESERVED lock, then increment reference counts and |
+ ** return SQLITE_OK. |
+ */ |
+ if( eFileLock==SHARED_LOCK && |
+ (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ |
+ assert( eFileLock==SHARED_LOCK ); |
+ assert( pFile->eFileLock==0 ); |
+ assert( pInode->nShared>0 ); |
+ pFile->eFileLock = SHARED_LOCK; |
+ pInode->nShared++; |
+ pInode->nLock++; |
+ goto end_lock; |
+ } |
+ |
+ |
+ /* A PENDING lock is needed before acquiring a SHARED lock and before |
+ ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will |
+ ** be released. |
+ */ |
+ lock.l_len = 1L; |
+ lock.l_whence = SEEK_SET; |
+ if( eFileLock==SHARED_LOCK |
+ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK) |
+ ){ |
+ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK); |
+ lock.l_start = PENDING_BYTE; |
+ if( unixFileLock(pFile, &lock) ){ |
+ tErrno = errno; |
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); |
+ if( rc!=SQLITE_BUSY ){ |
+ storeLastErrno(pFile, tErrno); |
+ } |
+ goto end_lock; |
+ } |
+ } |
+ |
+ |
+ /* If control gets to this point, then actually go ahead and make |
+ ** operating system calls for the specified lock. |
+ */ |
+ if( eFileLock==SHARED_LOCK ){ |
+ assert( pInode->nShared==0 ); |
+ assert( pInode->eFileLock==0 ); |
+ assert( rc==SQLITE_OK ); |
+ |
+ /* Now get the read-lock */ |
+ lock.l_start = SHARED_FIRST; |
+ lock.l_len = SHARED_SIZE; |
+ if( unixFileLock(pFile, &lock) ){ |
+ tErrno = errno; |
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); |
+ } |
+ |
+ /* Drop the temporary PENDING lock */ |
+ lock.l_start = PENDING_BYTE; |
+ lock.l_len = 1L; |
+ lock.l_type = F_UNLCK; |
+ if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){ |
+ /* This could happen with a network mount */ |
+ tErrno = errno; |
+ rc = SQLITE_IOERR_UNLOCK; |
+ } |
+ |
+ if( rc ){ |
+ if( rc!=SQLITE_BUSY ){ |
+ storeLastErrno(pFile, tErrno); |
+ } |
+ goto end_lock; |
+ }else{ |
+ pFile->eFileLock = SHARED_LOCK; |
+ pInode->nLock++; |
+ pInode->nShared = 1; |
+ } |
+ }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){ |
+ /* We are trying for an exclusive lock but another thread in this |
+ ** same process is still holding a shared lock. */ |
+ rc = SQLITE_BUSY; |
+ }else{ |
+ /* The request was for a RESERVED or EXCLUSIVE lock. It is |
+ ** assumed that there is a SHARED or greater lock on the file |
+ ** already. |
+ */ |
+ assert( 0!=pFile->eFileLock ); |
+ lock.l_type = F_WRLCK; |
+ |
+ assert( eFileLock==RESERVED_LOCK || eFileLock==EXCLUSIVE_LOCK ); |
+ if( eFileLock==RESERVED_LOCK ){ |
+ lock.l_start = RESERVED_BYTE; |
+ lock.l_len = 1L; |
+ }else{ |
+ lock.l_start = SHARED_FIRST; |
+ lock.l_len = SHARED_SIZE; |
+ } |
+ |
+ if( unixFileLock(pFile, &lock) ){ |
+ tErrno = errno; |
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); |
+ if( rc!=SQLITE_BUSY ){ |
+ storeLastErrno(pFile, tErrno); |
+ } |
+ } |
+ } |
+ |
+ |
+#ifdef SQLITE_DEBUG |
+ /* Set up the transaction-counter change checking flags when |
+ ** transitioning from a SHARED to a RESERVED lock. The change |
+ ** from SHARED to RESERVED marks the beginning of a normal |
+ ** write operation (not a hot journal rollback). |
+ */ |
+ if( rc==SQLITE_OK |
+ && pFile->eFileLock<=SHARED_LOCK |
+ && eFileLock==RESERVED_LOCK |
+ ){ |
+ pFile->transCntrChng = 0; |
+ pFile->dbUpdate = 0; |
+ pFile->inNormalWrite = 1; |
+ } |
+#endif |
+ |
+ |
+ if( rc==SQLITE_OK ){ |
+ pFile->eFileLock = eFileLock; |
+ pInode->eFileLock = eFileLock; |
+ }else if( eFileLock==EXCLUSIVE_LOCK ){ |
+ pFile->eFileLock = PENDING_LOCK; |
+ pInode->eFileLock = PENDING_LOCK; |
+ } |
+ |
+end_lock: |
+ unixLeaveMutex(); |
+ OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), |
+ rc==SQLITE_OK ? "ok" : "failed")); |
+ return rc; |
+} |
+ |
+/* |
+** Add the file descriptor used by file handle pFile to the corresponding |
+** pUnused list. |
+*/ |
+static void setPendingFd(unixFile *pFile){ |
+ unixInodeInfo *pInode = pFile->pInode; |
+ UnixUnusedFd *p = pFile->pUnused; |
+ p->pNext = pInode->pUnused; |
+ pInode->pUnused = p; |
+ pFile->h = -1; |
+ pFile->pUnused = 0; |
+} |
+ |
+/* |
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock |
+** must be either NO_LOCK or SHARED_LOCK. |
+** |
+** If the locking level of the file descriptor is already at or below |
+** the requested locking level, this routine is a no-op. |
+** |
+** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED |
+** the byte range is divided into 2 parts and the first part is unlocked then |
+** set to a read lock, then the other part is simply unlocked. This works |
+** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to |
+** remove the write lock on a region when a read lock is set. |
+*/ |
+static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ |
+ unixFile *pFile = (unixFile*)id; |
+ unixInodeInfo *pInode; |
+ struct flock lock; |
+ int rc = SQLITE_OK; |
+ |
+ assert( pFile ); |
+ OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock, |
+ pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, |
+ osGetpid(0))); |
+ |
+ assert( eFileLock<=SHARED_LOCK ); |
+ if( pFile->eFileLock<=eFileLock ){ |
+ return SQLITE_OK; |
+ } |
+ unixEnterMutex(); |
+ pInode = pFile->pInode; |
+ assert( pInode->nShared!=0 ); |
+ if( pFile->eFileLock>SHARED_LOCK ){ |
+ assert( pInode->eFileLock==pFile->eFileLock ); |
+ |
+#ifdef SQLITE_DEBUG |
+ /* When reducing a lock such that other processes can start |
+ ** reading the database file again, make sure that the |
+ ** transaction counter was updated if any part of the database |
+ ** file changed. If the transaction counter is not updated, |
+ ** other connections to the same file might not realize that |
+ ** the file has changed and hence might not know to flush their |
+ ** cache. The use of a stale cache can lead to database corruption. |
+ */ |
+ pFile->inNormalWrite = 0; |
+#endif |
+ |
+ /* downgrading to a shared lock on NFS involves clearing the write lock |
+ ** before establishing the readlock - to avoid a race condition we downgrade |
+ ** the lock in 2 blocks, so that part of the range will be covered by a |
+ ** write lock until the rest is covered by a read lock: |
+ ** 1: [WWWWW] |
+ ** 2: [....W] |
+ ** 3: [RRRRW] |
+ ** 4: [RRRR.] |
+ */ |
+ if( eFileLock==SHARED_LOCK ){ |
+#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE |
+ (void)handleNFSUnlock; |
+ assert( handleNFSUnlock==0 ); |
+#endif |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+ if( handleNFSUnlock ){ |
+ int tErrno; /* Error code from system call errors */ |
+ off_t divSize = SHARED_SIZE - 1; |
+ |
+ lock.l_type = F_UNLCK; |
+ lock.l_whence = SEEK_SET; |
+ lock.l_start = SHARED_FIRST; |
+ lock.l_len = divSize; |
+ if( unixFileLock(pFile, &lock)==(-1) ){ |
+ tErrno = errno; |
+ rc = SQLITE_IOERR_UNLOCK; |
+ storeLastErrno(pFile, tErrno); |
+ goto end_unlock; |
+ } |
+ lock.l_type = F_RDLCK; |
+ lock.l_whence = SEEK_SET; |
+ lock.l_start = SHARED_FIRST; |
+ lock.l_len = divSize; |
+ if( unixFileLock(pFile, &lock)==(-1) ){ |
+ tErrno = errno; |
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); |
+ if( IS_LOCK_ERROR(rc) ){ |
+ storeLastErrno(pFile, tErrno); |
+ } |
+ goto end_unlock; |
+ } |
+ lock.l_type = F_UNLCK; |
+ lock.l_whence = SEEK_SET; |
+ lock.l_start = SHARED_FIRST+divSize; |
+ lock.l_len = SHARED_SIZE-divSize; |
+ if( unixFileLock(pFile, &lock)==(-1) ){ |
+ tErrno = errno; |
+ rc = SQLITE_IOERR_UNLOCK; |
+ storeLastErrno(pFile, tErrno); |
+ goto end_unlock; |
+ } |
+ }else |
+#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ |
+ { |
+ lock.l_type = F_RDLCK; |
+ lock.l_whence = SEEK_SET; |
+ lock.l_start = SHARED_FIRST; |
+ lock.l_len = SHARED_SIZE; |
+ if( unixFileLock(pFile, &lock) ){ |
+ /* In theory, the call to unixFileLock() cannot fail because another |
+ ** process is holding an incompatible lock. If it does, this |
+ ** indicates that the other process is not following the locking |
+ ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning |
+ ** SQLITE_BUSY would confuse the upper layer (in practice it causes |
+ ** an assert to fail). */ |
+ rc = SQLITE_IOERR_RDLOCK; |
+ storeLastErrno(pFile, errno); |
+ goto end_unlock; |
+ } |
+ } |
+ } |
+ lock.l_type = F_UNLCK; |
+ lock.l_whence = SEEK_SET; |
+ lock.l_start = PENDING_BYTE; |
+ lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); |
+ if( unixFileLock(pFile, &lock)==0 ){ |
+ pInode->eFileLock = SHARED_LOCK; |
+ }else{ |
+ rc = SQLITE_IOERR_UNLOCK; |
+ storeLastErrno(pFile, errno); |
+ goto end_unlock; |
+ } |
+ } |
+ if( eFileLock==NO_LOCK ){ |
+ /* Decrement the shared lock counter. Release the lock using an |
+ ** OS call only when all threads in this same process have released |
+ ** the lock. |
+ */ |
+ pInode->nShared--; |
+ if( pInode->nShared==0 ){ |
+ lock.l_type = F_UNLCK; |
+ lock.l_whence = SEEK_SET; |
+ lock.l_start = lock.l_len = 0L; |
+ if( unixFileLock(pFile, &lock)==0 ){ |
+ pInode->eFileLock = NO_LOCK; |
+ }else{ |
+ rc = SQLITE_IOERR_UNLOCK; |
+ storeLastErrno(pFile, errno); |
+ pInode->eFileLock = NO_LOCK; |
+ pFile->eFileLock = NO_LOCK; |
+ } |
+ } |
+ |
+ /* Decrement the count of locks against this same file. When the |
+ ** count reaches zero, close any other file descriptors whose close |
+ ** was deferred because of outstanding locks. |
+ */ |
+ pInode->nLock--; |
+ assert( pInode->nLock>=0 ); |
+ if( pInode->nLock==0 ){ |
+ closePendingFds(pFile); |
+ } |
+ } |
+ |
+end_unlock: |
+ unixLeaveMutex(); |
+ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; |
+ return rc; |
+} |
+ |
+/* |
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock |
+** must be either NO_LOCK or SHARED_LOCK. |
+** |
+** If the locking level of the file descriptor is already at or below |
+** the requested locking level, this routine is a no-op. |
+*/ |
+static int unixUnlock(sqlite3_file *id, int eFileLock){ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 ); |
+#endif |
+ return posixUnlock(id, eFileLock, 0); |
+} |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+static int unixMapfile(unixFile *pFd, i64 nByte); |
+static void unixUnmapfile(unixFile *pFd); |
+#endif |
+ |
+/* |
+** This function performs the parts of the "close file" operation |
+** common to all locking schemes. It closes the directory and file |
+** handles, if they are valid, and sets all fields of the unixFile |
+** structure to 0. |
+** |
+** It is *not* necessary to hold the mutex when this routine is called, |
+** even on VxWorks. A mutex will be acquired on VxWorks by the |
+** vxworksReleaseFileId() routine. |
+*/ |
+static int closeUnixFile(sqlite3_file *id){ |
+ unixFile *pFile = (unixFile*)id; |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ unixUnmapfile(pFile); |
+#endif |
+ if( pFile->h>=0 ){ |
+ robust_close(pFile, pFile->h, __LINE__); |
+ pFile->h = -1; |
+ } |
+#if OS_VXWORKS |
+ if( pFile->pId ){ |
+ if( pFile->ctrlFlags & UNIXFILE_DELETE ){ |
+ osUnlink(pFile->pId->zCanonicalName); |
+ } |
+ vxworksReleaseFileId(pFile->pId); |
+ pFile->pId = 0; |
+ } |
+#endif |
+#ifdef SQLITE_UNLINK_AFTER_CLOSE |
+ if( pFile->ctrlFlags & UNIXFILE_DELETE ){ |
+ osUnlink(pFile->zPath); |
+ sqlite3_free(*(char**)&pFile->zPath); |
+ pFile->zPath = 0; |
+ } |
+#endif |
+ OSTRACE(("CLOSE %-3d\n", pFile->h)); |
+ OpenCounter(-1); |
+ sqlite3_free(pFile->pUnused); |
+ memset(pFile, 0, sizeof(unixFile)); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Close a file. |
+*/ |
+static int unixClose(sqlite3_file *id){ |
+ int rc = SQLITE_OK; |
+ unixFile *pFile = (unixFile *)id; |
+ verifyDbFile(pFile); |
+ unixUnlock(id, NO_LOCK); |
+ unixEnterMutex(); |
+ |
+ /* unixFile.pInode is always valid here. Otherwise, a different close |
+ ** routine (e.g. nolockClose()) would be called instead. |
+ */ |
+ assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); |
+ if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){ |
+ /* If there are outstanding locks, do not actually close the file just |
+ ** yet because that would clear those locks. Instead, add the file |
+ ** descriptor to pInode->pUnused list. It will be automatically closed |
+ ** when the last lock is cleared. |
+ */ |
+ setPendingFd(pFile); |
+ } |
+ releaseInodeInfo(pFile); |
+ rc = closeUnixFile(id); |
+ unixLeaveMutex(); |
+ return rc; |
+} |
+ |
+/************** End of the posix advisory lock implementation ***************** |
+******************************************************************************/ |
+ |
+/****************************************************************************** |
+****************************** No-op Locking ********************************** |
+** |
+** Of the various locking implementations available, this is by far the |
+** simplest: locking is ignored. No attempt is made to lock the database |
+** file for reading or writing. |
+** |
+** This locking mode is appropriate for use on read-only databases |
+** (ex: databases that are burned into CD-ROM, for example.) It can |
+** also be used if the application employs some external mechanism to |
+** prevent simultaneous access of the same database by two or more |
+** database connections. But there is a serious risk of database |
+** corruption if this locking mode is used in situations where multiple |
+** database connections are accessing the same database file at the same |
+** time and one or more of those connections are writing. |
+*/ |
+ |
+static int nolockCheckReservedLock(sqlite3_file *NotUsed, int *pResOut){ |
+ UNUSED_PARAMETER(NotUsed); |
+ *pResOut = 0; |
+ return SQLITE_OK; |
+} |
+static int nolockLock(sqlite3_file *NotUsed, int NotUsed2){ |
+ UNUSED_PARAMETER2(NotUsed, NotUsed2); |
+ return SQLITE_OK; |
+} |
+static int nolockUnlock(sqlite3_file *NotUsed, int NotUsed2){ |
+ UNUSED_PARAMETER2(NotUsed, NotUsed2); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Close the file. |
+*/ |
+static int nolockClose(sqlite3_file *id) { |
+ return closeUnixFile(id); |
+} |
+ |
+/******************* End of the no-op lock implementation ********************* |
+******************************************************************************/ |
+ |
+/****************************************************************************** |
+************************* Begin dot-file Locking ****************************** |
+** |
+** The dotfile locking implementation uses the existence of separate lock |
+** files (really a directory) to control access to the database. This works |
+** on just about every filesystem imaginable. But there are serious downsides: |
+** |
+** (1) There is zero concurrency. A single reader blocks all other |
+** connections from reading or writing the database. |
+** |
+** (2) An application crash or power loss can leave stale lock files |
+** sitting around that need to be cleared manually. |
+** |
+** Nevertheless, a dotlock is an appropriate locking mode for use if no |
+** other locking strategy is available. |
+** |
+** Dotfile locking works by creating a subdirectory in the same directory as |
+** the database and with the same name but with a ".lock" extension added. |
+** The existence of a lock directory implies an EXCLUSIVE lock. All other |
+** lock types (SHARED, RESERVED, PENDING) are mapped into EXCLUSIVE. |
+*/ |
+ |
+/* |
+** The file suffix added to the data base filename in order to create the |
+** lock directory. |
+*/ |
+#define DOTLOCK_SUFFIX ".lock" |
+ |
+/* |
+** This routine checks if there is a RESERVED lock held on the specified |
+** file by this or any other process. If such a lock is held, set *pResOut |
+** to a non-zero value otherwise *pResOut is set to zero. The return value |
+** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
+** |
+** In dotfile locking, either a lock exists or it does not. So in this |
+** variation of CheckReservedLock(), *pResOut is set to true if any lock |
+** is held on the file and false if the file is unlocked. |
+*/ |
+static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) { |
+ int rc = SQLITE_OK; |
+ int reserved = 0; |
+ unixFile *pFile = (unixFile*)id; |
+ |
+ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
+ |
+ assert( pFile ); |
+ reserved = osAccess((const char*)pFile->lockingContext, 0)==0; |
+ OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved)); |
+ *pResOut = reserved; |
+ return rc; |
+} |
+ |
+/* |
+** Lock the file with the lock specified by parameter eFileLock - one |
+** of the following: |
+** |
+** (1) SHARED_LOCK |
+** (2) RESERVED_LOCK |
+** (3) PENDING_LOCK |
+** (4) EXCLUSIVE_LOCK |
+** |
+** Sometimes when requesting one lock state, additional lock states |
+** are inserted in between. The locking might fail on one of the later |
+** transitions leaving the lock state different from what it started but |
+** still short of its goal. The following chart shows the allowed |
+** transitions and the inserted intermediate states: |
+** |
+** UNLOCKED -> SHARED |
+** SHARED -> RESERVED |
+** SHARED -> (PENDING) -> EXCLUSIVE |
+** RESERVED -> (PENDING) -> EXCLUSIVE |
+** PENDING -> EXCLUSIVE |
+** |
+** This routine will only increase a lock. Use the sqlite3OsUnlock() |
+** routine to lower a locking level. |
+** |
+** With dotfile locking, we really only support state (4): EXCLUSIVE. |
+** But we track the other locking levels internally. |
+*/ |
+static int dotlockLock(sqlite3_file *id, int eFileLock) { |
+ unixFile *pFile = (unixFile*)id; |
+ char *zLockFile = (char *)pFile->lockingContext; |
+ int rc = SQLITE_OK; |
+ |
+ |
+ /* If we have any lock, then the lock file already exists. All we have |
+ ** to do is adjust our internal record of the lock level. |
+ */ |
+ if( pFile->eFileLock > NO_LOCK ){ |
+ pFile->eFileLock = eFileLock; |
+ /* Always update the timestamp on the old file */ |
+#ifdef HAVE_UTIME |
+ utime(zLockFile, NULL); |
+#else |
+ utimes(zLockFile, NULL); |
+#endif |
+ return SQLITE_OK; |
+ } |
+ |
+ /* grab an exclusive lock */ |
+ rc = osMkdir(zLockFile, 0777); |
+ if( rc<0 ){ |
+ /* failed to open/create the lock directory */ |
+ int tErrno = errno; |
+ if( EEXIST == tErrno ){ |
+ rc = SQLITE_BUSY; |
+ } else { |
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); |
+ if( rc!=SQLITE_BUSY ){ |
+ storeLastErrno(pFile, tErrno); |
+ } |
+ } |
+ return rc; |
+ } |
+ |
+ /* got it, set the type and return ok */ |
+ pFile->eFileLock = eFileLock; |
+ return rc; |
+} |
+ |
+/* |
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock |
+** must be either NO_LOCK or SHARED_LOCK. |
+** |
+** If the locking level of the file descriptor is already at or below |
+** the requested locking level, this routine is a no-op. |
+** |
+** When the locking level reaches NO_LOCK, delete the lock file. |
+*/ |
+static int dotlockUnlock(sqlite3_file *id, int eFileLock) { |
+ unixFile *pFile = (unixFile*)id; |
+ char *zLockFile = (char *)pFile->lockingContext; |
+ int rc; |
+ |
+ assert( pFile ); |
+ OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, |
+ pFile->eFileLock, osGetpid(0))); |
+ assert( eFileLock<=SHARED_LOCK ); |
+ |
+ /* no-op if possible */ |
+ if( pFile->eFileLock==eFileLock ){ |
+ return SQLITE_OK; |
+ } |
+ |
+ /* To downgrade to shared, simply update our internal notion of the |
+ ** lock state. No need to mess with the file on disk. |
+ */ |
+ if( eFileLock==SHARED_LOCK ){ |
+ pFile->eFileLock = SHARED_LOCK; |
+ return SQLITE_OK; |
+ } |
+ |
+ /* To fully unlock the database, delete the lock file */ |
+ assert( eFileLock==NO_LOCK ); |
+ rc = osRmdir(zLockFile); |
+ if( rc<0 ){ |
+ int tErrno = errno; |
+ if( tErrno==ENOENT ){ |
+ rc = SQLITE_OK; |
+ }else{ |
+ rc = SQLITE_IOERR_UNLOCK; |
+ storeLastErrno(pFile, tErrno); |
+ } |
+ return rc; |
+ } |
+ pFile->eFileLock = NO_LOCK; |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Close a file. Make sure the lock has been released before closing. |
+*/ |
+static int dotlockClose(sqlite3_file *id) { |
+ unixFile *pFile = (unixFile*)id; |
+ assert( id!=0 ); |
+ dotlockUnlock(id, NO_LOCK); |
+ sqlite3_free(pFile->lockingContext); |
+ return closeUnixFile(id); |
+} |
+/****************** End of the dot-file lock implementation ******************* |
+******************************************************************************/ |
+ |
+/****************************************************************************** |
+************************** Begin flock Locking ******************************** |
+** |
+** Use the flock() system call to do file locking. |
+** |
+** flock() locking is like dot-file locking in that the various |
+** fine-grain locking levels supported by SQLite are collapsed into |
+** a single exclusive lock. In other words, SHARED, RESERVED, and |
+** PENDING locks are the same thing as an EXCLUSIVE lock. SQLite |
+** still works when you do this, but concurrency is reduced since |
+** only a single process can be reading the database at a time. |
+** |
+** Omit this section if SQLITE_ENABLE_LOCKING_STYLE is turned off |
+*/ |
+#if SQLITE_ENABLE_LOCKING_STYLE |
+ |
+/* |
+** Retry flock() calls that fail with EINTR |
+*/ |
+#ifdef EINTR |
+static int robust_flock(int fd, int op){ |
+ int rc; |
+ do{ rc = flock(fd,op); }while( rc<0 && errno==EINTR ); |
+ return rc; |
+} |
+#else |
+# define robust_flock(a,b) flock(a,b) |
+#endif |
+ |
+ |
+/* |
+** This routine checks if there is a RESERVED lock held on the specified |
+** file by this or any other process. If such a lock is held, set *pResOut |
+** to a non-zero value otherwise *pResOut is set to zero. The return value |
+** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
+*/ |
+static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ |
+ int rc = SQLITE_OK; |
+ int reserved = 0; |
+ unixFile *pFile = (unixFile*)id; |
+ |
+ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
+ |
+ assert( pFile ); |
+ |
+ /* Check if a thread in this process holds such a lock */ |
+ if( pFile->eFileLock>SHARED_LOCK ){ |
+ reserved = 1; |
+ } |
+ |
+ /* Otherwise see if some other process holds it. */ |
+ if( !reserved ){ |
+ /* attempt to get the lock */ |
+ int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB); |
+ if( !lrc ){ |
+ /* got the lock, unlock it */ |
+ lrc = robust_flock(pFile->h, LOCK_UN); |
+ if ( lrc ) { |
+ int tErrno = errno; |
+ /* unlock failed with an error */ |
+ lrc = SQLITE_IOERR_UNLOCK; |
+ storeLastErrno(pFile, tErrno); |
+ rc = lrc; |
+ } |
+ } else { |
+ int tErrno = errno; |
+ reserved = 1; |
+ /* someone else might have it reserved */ |
+ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); |
+ if( IS_LOCK_ERROR(lrc) ){ |
+ storeLastErrno(pFile, tErrno); |
+ rc = lrc; |
+ } |
+ } |
+ } |
+ OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved)); |
+ |
+#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS |
+ if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){ |
+ rc = SQLITE_OK; |
+ reserved=1; |
+ } |
+#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ |
+ *pResOut = reserved; |
+ return rc; |
+} |
+ |
+/* |
+** Lock the file with the lock specified by parameter eFileLock - one |
+** of the following: |
+** |
+** (1) SHARED_LOCK |
+** (2) RESERVED_LOCK |
+** (3) PENDING_LOCK |
+** (4) EXCLUSIVE_LOCK |
+** |
+** Sometimes when requesting one lock state, additional lock states |
+** are inserted in between. The locking might fail on one of the later |
+** transitions leaving the lock state different from what it started but |
+** still short of its goal. The following chart shows the allowed |
+** transitions and the inserted intermediate states: |
+** |
+** UNLOCKED -> SHARED |
+** SHARED -> RESERVED |
+** SHARED -> (PENDING) -> EXCLUSIVE |
+** RESERVED -> (PENDING) -> EXCLUSIVE |
+** PENDING -> EXCLUSIVE |
+** |
+** flock() only really support EXCLUSIVE locks. We track intermediate |
+** lock states in the sqlite3_file structure, but all locks SHARED or |
+** above are really EXCLUSIVE locks and exclude all other processes from |
+** access the file. |
+** |
+** This routine will only increase a lock. Use the sqlite3OsUnlock() |
+** routine to lower a locking level. |
+*/ |
+static int flockLock(sqlite3_file *id, int eFileLock) { |
+ int rc = SQLITE_OK; |
+ unixFile *pFile = (unixFile*)id; |
+ |
+ assert( pFile ); |
+ |
+ /* if we already have a lock, it is exclusive. |
+ ** Just adjust level and punt on outta here. */ |
+ if (pFile->eFileLock > NO_LOCK) { |
+ pFile->eFileLock = eFileLock; |
+ return SQLITE_OK; |
+ } |
+ |
+ /* grab an exclusive lock */ |
+ |
+ if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) { |
+ int tErrno = errno; |
+ /* didn't get, must be busy */ |
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); |
+ if( IS_LOCK_ERROR(rc) ){ |
+ storeLastErrno(pFile, tErrno); |
+ } |
+ } else { |
+ /* got it, set the type and return ok */ |
+ pFile->eFileLock = eFileLock; |
+ } |
+ OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), |
+ rc==SQLITE_OK ? "ok" : "failed")); |
+#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS |
+ if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){ |
+ rc = SQLITE_BUSY; |
+ } |
+#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ |
+ return rc; |
+} |
+ |
+ |
+/* |
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock |
+** must be either NO_LOCK or SHARED_LOCK. |
+** |
+** If the locking level of the file descriptor is already at or below |
+** the requested locking level, this routine is a no-op. |
+*/ |
+static int flockUnlock(sqlite3_file *id, int eFileLock) { |
+ unixFile *pFile = (unixFile*)id; |
+ |
+ assert( pFile ); |
+ OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock, |
+ pFile->eFileLock, osGetpid(0))); |
+ assert( eFileLock<=SHARED_LOCK ); |
+ |
+ /* no-op if possible */ |
+ if( pFile->eFileLock==eFileLock ){ |
+ return SQLITE_OK; |
+ } |
+ |
+ /* shared can just be set because we always have an exclusive */ |
+ if (eFileLock==SHARED_LOCK) { |
+ pFile->eFileLock = eFileLock; |
+ return SQLITE_OK; |
+ } |
+ |
+ /* no, really, unlock. */ |
+ if( robust_flock(pFile->h, LOCK_UN) ){ |
+#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS |
+ return SQLITE_OK; |
+#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ |
+ return SQLITE_IOERR_UNLOCK; |
+ }else{ |
+ pFile->eFileLock = NO_LOCK; |
+ return SQLITE_OK; |
+ } |
+} |
+ |
+/* |
+** Close a file. |
+*/ |
+static int flockClose(sqlite3_file *id) { |
+ assert( id!=0 ); |
+ flockUnlock(id, NO_LOCK); |
+ return closeUnixFile(id); |
+} |
+ |
+#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */ |
+ |
+/******************* End of the flock lock implementation ********************* |
+******************************************************************************/ |
+ |
+/****************************************************************************** |
+************************ Begin Named Semaphore Locking ************************ |
+** |
+** Named semaphore locking is only supported on VxWorks. |
+** |
+** Semaphore locking is like dot-lock and flock in that it really only |
+** supports EXCLUSIVE locking. Only a single process can read or write |
+** the database file at a time. This reduces potential concurrency, but |
+** makes the lock implementation much easier. |
+*/ |
+#if OS_VXWORKS |
+ |
+/* |
+** This routine checks if there is a RESERVED lock held on the specified |
+** file by this or any other process. If such a lock is held, set *pResOut |
+** to a non-zero value otherwise *pResOut is set to zero. The return value |
+** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
+*/ |
+static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) { |
+ int rc = SQLITE_OK; |
+ int reserved = 0; |
+ unixFile *pFile = (unixFile*)id; |
+ |
+ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
+ |
+ assert( pFile ); |
+ |
+ /* Check if a thread in this process holds such a lock */ |
+ if( pFile->eFileLock>SHARED_LOCK ){ |
+ reserved = 1; |
+ } |
+ |
+ /* Otherwise see if some other process holds it. */ |
+ if( !reserved ){ |
+ sem_t *pSem = pFile->pInode->pSem; |
+ |
+ if( sem_trywait(pSem)==-1 ){ |
+ int tErrno = errno; |
+ if( EAGAIN != tErrno ){ |
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK); |
+ storeLastErrno(pFile, tErrno); |
+ } else { |
+ /* someone else has the lock when we are in NO_LOCK */ |
+ reserved = (pFile->eFileLock < SHARED_LOCK); |
+ } |
+ }else{ |
+ /* we could have it if we want it */ |
+ sem_post(pSem); |
+ } |
+ } |
+ OSTRACE(("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved)); |
+ |
+ *pResOut = reserved; |
+ return rc; |
+} |
+ |
+/* |
+** Lock the file with the lock specified by parameter eFileLock - one |
+** of the following: |
+** |
+** (1) SHARED_LOCK |
+** (2) RESERVED_LOCK |
+** (3) PENDING_LOCK |
+** (4) EXCLUSIVE_LOCK |
+** |
+** Sometimes when requesting one lock state, additional lock states |
+** are inserted in between. The locking might fail on one of the later |
+** transitions leaving the lock state different from what it started but |
+** still short of its goal. The following chart shows the allowed |
+** transitions and the inserted intermediate states: |
+** |
+** UNLOCKED -> SHARED |
+** SHARED -> RESERVED |
+** SHARED -> (PENDING) -> EXCLUSIVE |
+** RESERVED -> (PENDING) -> EXCLUSIVE |
+** PENDING -> EXCLUSIVE |
+** |
+** Semaphore locks only really support EXCLUSIVE locks. We track intermediate |
+** lock states in the sqlite3_file structure, but all locks SHARED or |
+** above are really EXCLUSIVE locks and exclude all other processes from |
+** access the file. |
+** |
+** This routine will only increase a lock. Use the sqlite3OsUnlock() |
+** routine to lower a locking level. |
+*/ |
+static int semXLock(sqlite3_file *id, int eFileLock) { |
+ unixFile *pFile = (unixFile*)id; |
+ sem_t *pSem = pFile->pInode->pSem; |
+ int rc = SQLITE_OK; |
+ |
+ /* if we already have a lock, it is exclusive. |
+ ** Just adjust level and punt on outta here. */ |
+ if (pFile->eFileLock > NO_LOCK) { |
+ pFile->eFileLock = eFileLock; |
+ rc = SQLITE_OK; |
+ goto sem_end_lock; |
+ } |
+ |
+ /* lock semaphore now but bail out when already locked. */ |
+ if( sem_trywait(pSem)==-1 ){ |
+ rc = SQLITE_BUSY; |
+ goto sem_end_lock; |
+ } |
+ |
+ /* got it, set the type and return ok */ |
+ pFile->eFileLock = eFileLock; |
+ |
+ sem_end_lock: |
+ return rc; |
+} |
+ |
+/* |
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock |
+** must be either NO_LOCK or SHARED_LOCK. |
+** |
+** If the locking level of the file descriptor is already at or below |
+** the requested locking level, this routine is a no-op. |
+*/ |
+static int semXUnlock(sqlite3_file *id, int eFileLock) { |
+ unixFile *pFile = (unixFile*)id; |
+ sem_t *pSem = pFile->pInode->pSem; |
+ |
+ assert( pFile ); |
+ assert( pSem ); |
+ OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, |
+ pFile->eFileLock, osGetpid(0))); |
+ assert( eFileLock<=SHARED_LOCK ); |
+ |
+ /* no-op if possible */ |
+ if( pFile->eFileLock==eFileLock ){ |
+ return SQLITE_OK; |
+ } |
+ |
+ /* shared can just be set because we always have an exclusive */ |
+ if (eFileLock==SHARED_LOCK) { |
+ pFile->eFileLock = eFileLock; |
+ return SQLITE_OK; |
+ } |
+ |
+ /* no, really unlock. */ |
+ if ( sem_post(pSem)==-1 ) { |
+ int rc, tErrno = errno; |
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); |
+ if( IS_LOCK_ERROR(rc) ){ |
+ storeLastErrno(pFile, tErrno); |
+ } |
+ return rc; |
+ } |
+ pFile->eFileLock = NO_LOCK; |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+ ** Close a file. |
+ */ |
+static int semXClose(sqlite3_file *id) { |
+ if( id ){ |
+ unixFile *pFile = (unixFile*)id; |
+ semXUnlock(id, NO_LOCK); |
+ assert( pFile ); |
+ unixEnterMutex(); |
+ releaseInodeInfo(pFile); |
+ unixLeaveMutex(); |
+ closeUnixFile(id); |
+ } |
+ return SQLITE_OK; |
+} |
+ |
+#endif /* OS_VXWORKS */ |
+/* |
+** Named semaphore locking is only available on VxWorks. |
+** |
+*************** End of the named semaphore lock implementation **************** |
+******************************************************************************/ |
+ |
+ |
+/****************************************************************************** |
+*************************** Begin AFP Locking ********************************* |
+** |
+** AFP is the Apple Filing Protocol. AFP is a network filesystem found |
+** on Apple Macintosh computers - both OS9 and OSX. |
+** |
+** Third-party implementations of AFP are available. But this code here |
+** only works on OSX. |
+*/ |
+ |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+/* |
+** The afpLockingContext structure contains all afp lock specific state |
+*/ |
+typedef struct afpLockingContext afpLockingContext; |
+struct afpLockingContext { |
+ int reserved; |
+ const char *dbPath; /* Name of the open file */ |
+}; |
+ |
+struct ByteRangeLockPB2 |
+{ |
+ unsigned long long offset; /* offset to first byte to lock */ |
+ unsigned long long length; /* nbr of bytes to lock */ |
+ unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */ |
+ unsigned char unLockFlag; /* 1 = unlock, 0 = lock */ |
+ unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */ |
+ int fd; /* file desc to assoc this lock with */ |
+}; |
+ |
+#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2) |
+ |
+/* |
+** This is a utility for setting or clearing a bit-range lock on an |
+** AFP filesystem. |
+** |
+** Return SQLITE_OK on success, SQLITE_BUSY on failure. |
+*/ |
+static int afpSetLock( |
+ const char *path, /* Name of the file to be locked or unlocked */ |
+ unixFile *pFile, /* Open file descriptor on path */ |
+ unsigned long long offset, /* First byte to be locked */ |
+ unsigned long long length, /* Number of bytes to lock */ |
+ int setLockFlag /* True to set lock. False to clear lock */ |
+){ |
+ struct ByteRangeLockPB2 pb; |
+ int err; |
+ |
+ pb.unLockFlag = setLockFlag ? 0 : 1; |
+ pb.startEndFlag = 0; |
+ pb.offset = offset; |
+ pb.length = length; |
+ pb.fd = pFile->h; |
+ |
+ OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n", |
+ (setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""), |
+ offset, length)); |
+ err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0); |
+ if ( err==-1 ) { |
+ int rc; |
+ int tErrno = errno; |
+ OSTRACE(("AFPSETLOCK failed to fsctl() '%s' %d %s\n", |
+ path, tErrno, strerror(tErrno))); |
+#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS |
+ rc = SQLITE_BUSY; |
+#else |
+ rc = sqliteErrorFromPosixError(tErrno, |
+ setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK); |
+#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */ |
+ if( IS_LOCK_ERROR(rc) ){ |
+ storeLastErrno(pFile, tErrno); |
+ } |
+ return rc; |
+ } else { |
+ return SQLITE_OK; |
+ } |
+} |
+ |
+/* |
+** This routine checks if there is a RESERVED lock held on the specified |
+** file by this or any other process. If such a lock is held, set *pResOut |
+** to a non-zero value otherwise *pResOut is set to zero. The return value |
+** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
+*/ |
+static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ |
+ int rc = SQLITE_OK; |
+ int reserved = 0; |
+ unixFile *pFile = (unixFile*)id; |
+ afpLockingContext *context; |
+ |
+ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
+ |
+ assert( pFile ); |
+ context = (afpLockingContext *) pFile->lockingContext; |
+ if( context->reserved ){ |
+ *pResOut = 1; |
+ return SQLITE_OK; |
+ } |
+ unixEnterMutex(); /* Because pFile->pInode is shared across threads */ |
+ |
+ /* Check if a thread in this process holds such a lock */ |
+ if( pFile->pInode->eFileLock>SHARED_LOCK ){ |
+ reserved = 1; |
+ } |
+ |
+ /* Otherwise see if some other process holds it. |
+ */ |
+ if( !reserved ){ |
+ /* lock the RESERVED byte */ |
+ int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); |
+ if( SQLITE_OK==lrc ){ |
+ /* if we succeeded in taking the reserved lock, unlock it to restore |
+ ** the original state */ |
+ lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0); |
+ } else { |
+ /* if we failed to get the lock then someone else must have it */ |
+ reserved = 1; |
+ } |
+ if( IS_LOCK_ERROR(lrc) ){ |
+ rc=lrc; |
+ } |
+ } |
+ |
+ unixLeaveMutex(); |
+ OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved)); |
+ |
+ *pResOut = reserved; |
+ return rc; |
+} |
+ |
+/* |
+** Lock the file with the lock specified by parameter eFileLock - one |
+** of the following: |
+** |
+** (1) SHARED_LOCK |
+** (2) RESERVED_LOCK |
+** (3) PENDING_LOCK |
+** (4) EXCLUSIVE_LOCK |
+** |
+** Sometimes when requesting one lock state, additional lock states |
+** are inserted in between. The locking might fail on one of the later |
+** transitions leaving the lock state different from what it started but |
+** still short of its goal. The following chart shows the allowed |
+** transitions and the inserted intermediate states: |
+** |
+** UNLOCKED -> SHARED |
+** SHARED -> RESERVED |
+** SHARED -> (PENDING) -> EXCLUSIVE |
+** RESERVED -> (PENDING) -> EXCLUSIVE |
+** PENDING -> EXCLUSIVE |
+** |
+** This routine will only increase a lock. Use the sqlite3OsUnlock() |
+** routine to lower a locking level. |
+*/ |
+static int afpLock(sqlite3_file *id, int eFileLock){ |
+ int rc = SQLITE_OK; |
+ unixFile *pFile = (unixFile*)id; |
+ unixInodeInfo *pInode = pFile->pInode; |
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; |
+ |
+ assert( pFile ); |
+ OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h, |
+ azFileLock(eFileLock), azFileLock(pFile->eFileLock), |
+ azFileLock(pInode->eFileLock), pInode->nShared , osGetpid(0))); |
+ |
+ /* If there is already a lock of this type or more restrictive on the |
+ ** unixFile, do nothing. Don't use the afp_end_lock: exit path, as |
+ ** unixEnterMutex() hasn't been called yet. |
+ */ |
+ if( pFile->eFileLock>=eFileLock ){ |
+ OSTRACE(("LOCK %d %s ok (already held) (afp)\n", pFile->h, |
+ azFileLock(eFileLock))); |
+ return SQLITE_OK; |
+ } |
+ |
+ /* Make sure the locking sequence is correct |
+ ** (1) We never move from unlocked to anything higher than shared lock. |
+ ** (2) SQLite never explicitly requests a pendig lock. |
+ ** (3) A shared lock is always held when a reserve lock is requested. |
+ */ |
+ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); |
+ assert( eFileLock!=PENDING_LOCK ); |
+ assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); |
+ |
+ /* This mutex is needed because pFile->pInode is shared across threads |
+ */ |
+ unixEnterMutex(); |
+ pInode = pFile->pInode; |
+ |
+ /* If some thread using this PID has a lock via a different unixFile* |
+ ** handle that precludes the requested lock, return BUSY. |
+ */ |
+ if( (pFile->eFileLock!=pInode->eFileLock && |
+ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) |
+ ){ |
+ rc = SQLITE_BUSY; |
+ goto afp_end_lock; |
+ } |
+ |
+ /* If a SHARED lock is requested, and some thread using this PID already |
+ ** has a SHARED or RESERVED lock, then increment reference counts and |
+ ** return SQLITE_OK. |
+ */ |
+ if( eFileLock==SHARED_LOCK && |
+ (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ |
+ assert( eFileLock==SHARED_LOCK ); |
+ assert( pFile->eFileLock==0 ); |
+ assert( pInode->nShared>0 ); |
+ pFile->eFileLock = SHARED_LOCK; |
+ pInode->nShared++; |
+ pInode->nLock++; |
+ goto afp_end_lock; |
+ } |
+ |
+ /* A PENDING lock is needed before acquiring a SHARED lock and before |
+ ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will |
+ ** be released. |
+ */ |
+ if( eFileLock==SHARED_LOCK |
+ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK) |
+ ){ |
+ int failed; |
+ failed = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 1); |
+ if (failed) { |
+ rc = failed; |
+ goto afp_end_lock; |
+ } |
+ } |
+ |
+ /* If control gets to this point, then actually go ahead and make |
+ ** operating system calls for the specified lock. |
+ */ |
+ if( eFileLock==SHARED_LOCK ){ |
+ int lrc1, lrc2, lrc1Errno = 0; |
+ long lk, mask; |
+ |
+ assert( pInode->nShared==0 ); |
+ assert( pInode->eFileLock==0 ); |
+ |
+ mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff; |
+ /* Now get the read-lock SHARED_LOCK */ |
+ /* note that the quality of the randomness doesn't matter that much */ |
+ lk = random(); |
+ pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1); |
+ lrc1 = afpSetLock(context->dbPath, pFile, |
+ SHARED_FIRST+pInode->sharedByte, 1, 1); |
+ if( IS_LOCK_ERROR(lrc1) ){ |
+ lrc1Errno = pFile->lastErrno; |
+ } |
+ /* Drop the temporary PENDING lock */ |
+ lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); |
+ |
+ if( IS_LOCK_ERROR(lrc1) ) { |
+ storeLastErrno(pFile, lrc1Errno); |
+ rc = lrc1; |
+ goto afp_end_lock; |
+ } else if( IS_LOCK_ERROR(lrc2) ){ |
+ rc = lrc2; |
+ goto afp_end_lock; |
+ } else if( lrc1 != SQLITE_OK ) { |
+ rc = lrc1; |
+ } else { |
+ pFile->eFileLock = SHARED_LOCK; |
+ pInode->nLock++; |
+ pInode->nShared = 1; |
+ } |
+ }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){ |
+ /* We are trying for an exclusive lock but another thread in this |
+ ** same process is still holding a shared lock. */ |
+ rc = SQLITE_BUSY; |
+ }else{ |
+ /* The request was for a RESERVED or EXCLUSIVE lock. It is |
+ ** assumed that there is a SHARED or greater lock on the file |
+ ** already. |
+ */ |
+ int failed = 0; |
+ assert( 0!=pFile->eFileLock ); |
+ if (eFileLock >= RESERVED_LOCK && pFile->eFileLock < RESERVED_LOCK) { |
+ /* Acquire a RESERVED lock */ |
+ failed = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); |
+ if( !failed ){ |
+ context->reserved = 1; |
+ } |
+ } |
+ if (!failed && eFileLock == EXCLUSIVE_LOCK) { |
+ /* Acquire an EXCLUSIVE lock */ |
+ |
+ /* Remove the shared lock before trying the range. we'll need to |
+ ** reestablish the shared lock if we can't get the afpUnlock |
+ */ |
+ if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST + |
+ pInode->sharedByte, 1, 0)) ){ |
+ int failed2 = SQLITE_OK; |
+ /* now attemmpt to get the exclusive lock range */ |
+ failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST, |
+ SHARED_SIZE, 1); |
+ if( failed && (failed2 = afpSetLock(context->dbPath, pFile, |
+ SHARED_FIRST + pInode->sharedByte, 1, 1)) ){ |
+ /* Can't reestablish the shared lock. Sqlite can't deal, this is |
+ ** a critical I/O error |
+ */ |
+ rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 : |
+ SQLITE_IOERR_LOCK; |
+ goto afp_end_lock; |
+ } |
+ }else{ |
+ rc = failed; |
+ } |
+ } |
+ if( failed ){ |
+ rc = failed; |
+ } |
+ } |
+ |
+ if( rc==SQLITE_OK ){ |
+ pFile->eFileLock = eFileLock; |
+ pInode->eFileLock = eFileLock; |
+ }else if( eFileLock==EXCLUSIVE_LOCK ){ |
+ pFile->eFileLock = PENDING_LOCK; |
+ pInode->eFileLock = PENDING_LOCK; |
+ } |
+ |
+afp_end_lock: |
+ unixLeaveMutex(); |
+ OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock), |
+ rc==SQLITE_OK ? "ok" : "failed")); |
+ return rc; |
+} |
+ |
+/* |
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock |
+** must be either NO_LOCK or SHARED_LOCK. |
+** |
+** If the locking level of the file descriptor is already at or below |
+** the requested locking level, this routine is a no-op. |
+*/ |
+static int afpUnlock(sqlite3_file *id, int eFileLock) { |
+ int rc = SQLITE_OK; |
+ unixFile *pFile = (unixFile*)id; |
+ unixInodeInfo *pInode; |
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; |
+ int skipShared = 0; |
+#ifdef SQLITE_TEST |
+ int h = pFile->h; |
+#endif |
+ |
+ assert( pFile ); |
+ OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock, |
+ pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, |
+ osGetpid(0))); |
+ |
+ assert( eFileLock<=SHARED_LOCK ); |
+ if( pFile->eFileLock<=eFileLock ){ |
+ return SQLITE_OK; |
+ } |
+ unixEnterMutex(); |
+ pInode = pFile->pInode; |
+ assert( pInode->nShared!=0 ); |
+ if( pFile->eFileLock>SHARED_LOCK ){ |
+ assert( pInode->eFileLock==pFile->eFileLock ); |
+ SimulateIOErrorBenign(1); |
+ SimulateIOError( h=(-1) ) |
+ SimulateIOErrorBenign(0); |
+ |
+#ifdef SQLITE_DEBUG |
+ /* When reducing a lock such that other processes can start |
+ ** reading the database file again, make sure that the |
+ ** transaction counter was updated if any part of the database |
+ ** file changed. If the transaction counter is not updated, |
+ ** other connections to the same file might not realize that |
+ ** the file has changed and hence might not know to flush their |
+ ** cache. The use of a stale cache can lead to database corruption. |
+ */ |
+ assert( pFile->inNormalWrite==0 |
+ || pFile->dbUpdate==0 |
+ || pFile->transCntrChng==1 ); |
+ pFile->inNormalWrite = 0; |
+#endif |
+ |
+ if( pFile->eFileLock==EXCLUSIVE_LOCK ){ |
+ rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0); |
+ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){ |
+ /* only re-establish the shared lock if necessary */ |
+ int sharedLockByte = SHARED_FIRST+pInode->sharedByte; |
+ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 1); |
+ } else { |
+ skipShared = 1; |
+ } |
+ } |
+ if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){ |
+ rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); |
+ } |
+ if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){ |
+ rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0); |
+ if( !rc ){ |
+ context->reserved = 0; |
+ } |
+ } |
+ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){ |
+ pInode->eFileLock = SHARED_LOCK; |
+ } |
+ } |
+ if( rc==SQLITE_OK && eFileLock==NO_LOCK ){ |
+ |
+ /* Decrement the shared lock counter. Release the lock using an |
+ ** OS call only when all threads in this same process have released |
+ ** the lock. |
+ */ |
+ unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte; |
+ pInode->nShared--; |
+ if( pInode->nShared==0 ){ |
+ SimulateIOErrorBenign(1); |
+ SimulateIOError( h=(-1) ) |
+ SimulateIOErrorBenign(0); |
+ if( !skipShared ){ |
+ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0); |
+ } |
+ if( !rc ){ |
+ pInode->eFileLock = NO_LOCK; |
+ pFile->eFileLock = NO_LOCK; |
+ } |
+ } |
+ if( rc==SQLITE_OK ){ |
+ pInode->nLock--; |
+ assert( pInode->nLock>=0 ); |
+ if( pInode->nLock==0 ){ |
+ closePendingFds(pFile); |
+ } |
+ } |
+ } |
+ |
+ unixLeaveMutex(); |
+ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; |
+ return rc; |
+} |
+ |
+/* |
+** Close a file & cleanup AFP specific locking context |
+*/ |
+static int afpClose(sqlite3_file *id) { |
+ int rc = SQLITE_OK; |
+ unixFile *pFile = (unixFile*)id; |
+ assert( id!=0 ); |
+ afpUnlock(id, NO_LOCK); |
+ unixEnterMutex(); |
+ if( pFile->pInode && pFile->pInode->nLock ){ |
+ /* If there are outstanding locks, do not actually close the file just |
+ ** yet because that would clear those locks. Instead, add the file |
+ ** descriptor to pInode->aPending. It will be automatically closed when |
+ ** the last lock is cleared. |
+ */ |
+ setPendingFd(pFile); |
+ } |
+ releaseInodeInfo(pFile); |
+ sqlite3_free(pFile->lockingContext); |
+ rc = closeUnixFile(id); |
+ unixLeaveMutex(); |
+ return rc; |
+} |
+ |
+#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ |
+/* |
+** The code above is the AFP lock implementation. The code is specific |
+** to MacOSX and does not work on other unix platforms. No alternative |
+** is available. If you don't compile for a mac, then the "unix-afp" |
+** VFS is not available. |
+** |
+********************* End of the AFP lock implementation ********************** |
+******************************************************************************/ |
+ |
+/****************************************************************************** |
+*************************** Begin NFS Locking ********************************/ |
+ |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+/* |
+ ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock |
+ ** must be either NO_LOCK or SHARED_LOCK. |
+ ** |
+ ** If the locking level of the file descriptor is already at or below |
+ ** the requested locking level, this routine is a no-op. |
+ */ |
+static int nfsUnlock(sqlite3_file *id, int eFileLock){ |
+ return posixUnlock(id, eFileLock, 1); |
+} |
+ |
+#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ |
+/* |
+** The code above is the NFS lock implementation. The code is specific |
+** to MacOSX and does not work on other unix platforms. No alternative |
+** is available. |
+** |
+********************* End of the NFS lock implementation ********************** |
+******************************************************************************/ |
+ |
+/****************************************************************************** |
+**************** Non-locking sqlite3_file methods ***************************** |
+** |
+** The next division contains implementations for all methods of the |
+** sqlite3_file object other than the locking methods. The locking |
+** methods were defined in divisions above (one locking method per |
+** division). Those methods that are common to all locking modes |
+** are gather together into this division. |
+*/ |
+ |
+/* |
+** Seek to the offset passed as the second argument, then read cnt |
+** bytes into pBuf. Return the number of bytes actually read. |
+** |
+** NB: If you define USE_PREAD or USE_PREAD64, then it might also |
+** be necessary to define _XOPEN_SOURCE to be 500. This varies from |
+** one system to another. Since SQLite does not define USE_PREAD |
+** in any form by default, we will not attempt to define _XOPEN_SOURCE. |
+** See tickets #2741 and #2681. |
+** |
+** To avoid stomping the errno value on a failed read the lastErrno value |
+** is set before returning. |
+*/ |
+static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ |
+ int got; |
+ int prior = 0; |
+#if (!defined(USE_PREAD) && !defined(USE_PREAD64)) |
+ i64 newOffset; |
+#endif |
+ TIMER_START; |
+ assert( cnt==(cnt&0x1ffff) ); |
+ assert( id->h>2 ); |
+ do{ |
+#if defined(USE_PREAD) |
+ got = osPread(id->h, pBuf, cnt, offset); |
+ SimulateIOError( got = -1 ); |
+#elif defined(USE_PREAD64) |
+ got = osPread64(id->h, pBuf, cnt, offset); |
+ SimulateIOError( got = -1 ); |
+#else |
+ newOffset = lseek(id->h, offset, SEEK_SET); |
+ SimulateIOError( newOffset = -1 ); |
+ if( newOffset<0 ){ |
+ storeLastErrno((unixFile*)id, errno); |
+ return -1; |
+ } |
+ got = osRead(id->h, pBuf, cnt); |
+#endif |
+ if( got==cnt ) break; |
+ if( got<0 ){ |
+ if( errno==EINTR ){ got = 1; continue; } |
+ prior = 0; |
+ storeLastErrno((unixFile*)id, errno); |
+ break; |
+ }else if( got>0 ){ |
+ cnt -= got; |
+ offset += got; |
+ prior += got; |
+ pBuf = (void*)(got + (char*)pBuf); |
+ } |
+ }while( got>0 ); |
+ TIMER_END; |
+ OSTRACE(("READ %-3d %5d %7lld %llu\n", |
+ id->h, got+prior, offset-prior, TIMER_ELAPSED)); |
+ return got+prior; |
+} |
+ |
+/* |
+** Read data from a file into a buffer. Return SQLITE_OK if all |
+** bytes were read successfully and SQLITE_IOERR if anything goes |
+** wrong. |
+*/ |
+static int unixRead( |
+ sqlite3_file *id, |
+ void *pBuf, |
+ int amt, |
+ sqlite3_int64 offset |
+){ |
+ unixFile *pFile = (unixFile *)id; |
+ int got; |
+ assert( id ); |
+ assert( offset>=0 ); |
+ assert( amt>0 ); |
+ |
+ /* If this is a database file (not a journal, master-journal or temp |
+ ** file), the bytes in the locking range should never be read or written. */ |
+#if 0 |
+ assert( pFile->pUnused==0 |
+ || offset>=PENDING_BYTE+512 |
+ || offset+amt<=PENDING_BYTE |
+ ); |
+#endif |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ /* Deal with as much of this read request as possible by transfering |
+ ** data from the memory mapping using memcpy(). */ |
+ if( offset<pFile->mmapSize ){ |
+ if( offset+amt <= pFile->mmapSize ){ |
+ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt); |
+ return SQLITE_OK; |
+ }else{ |
+ int nCopy = pFile->mmapSize - offset; |
+ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy); |
+ pBuf = &((u8 *)pBuf)[nCopy]; |
+ amt -= nCopy; |
+ offset += nCopy; |
+ } |
+ } |
+#endif |
+ |
+ got = seekAndRead(pFile, offset, pBuf, amt); |
+ if( got==amt ){ |
+ return SQLITE_OK; |
+ }else if( got<0 ){ |
+ /* lastErrno set by seekAndRead */ |
+ return SQLITE_IOERR_READ; |
+ }else{ |
+ storeLastErrno(pFile, 0); /* not a system error */ |
+ /* Unread parts of the buffer must be zero-filled */ |
+ memset(&((char*)pBuf)[got], 0, amt-got); |
+ return SQLITE_IOERR_SHORT_READ; |
+ } |
+} |
+ |
+/* |
+** Attempt to seek the file-descriptor passed as the first argument to |
+** absolute offset iOff, then attempt to write nBuf bytes of data from |
+** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise, |
+** return the actual number of bytes written (which may be less than |
+** nBuf). |
+*/ |
+static int seekAndWriteFd( |
+ int fd, /* File descriptor to write to */ |
+ i64 iOff, /* File offset to begin writing at */ |
+ const void *pBuf, /* Copy data from this buffer to the file */ |
+ int nBuf, /* Size of buffer pBuf in bytes */ |
+ int *piErrno /* OUT: Error number if error occurs */ |
+){ |
+ int rc = 0; /* Value returned by system call */ |
+ |
+ assert( nBuf==(nBuf&0x1ffff) ); |
+ assert( fd>2 ); |
+ assert( piErrno!=0 ); |
+ nBuf &= 0x1ffff; |
+ TIMER_START; |
+ |
+#if defined(USE_PREAD) |
+ do{ rc = (int)osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR ); |
+#elif defined(USE_PREAD64) |
+ do{ rc = (int)osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR); |
+#else |
+ do{ |
+ i64 iSeek = lseek(fd, iOff, SEEK_SET); |
+ SimulateIOError( iSeek = -1 ); |
+ if( iSeek<0 ){ |
+ rc = -1; |
+ break; |
+ } |
+ rc = osWrite(fd, pBuf, nBuf); |
+ }while( rc<0 && errno==EINTR ); |
+#endif |
+ |
+ TIMER_END; |
+ OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED)); |
+ |
+ if( rc<0 ) *piErrno = errno; |
+ return rc; |
+} |
+ |
+ |
+/* |
+** Seek to the offset in id->offset then read cnt bytes into pBuf. |
+** Return the number of bytes actually read. Update the offset. |
+** |
+** To avoid stomping the errno value on a failed write the lastErrno value |
+** is set before returning. |
+*/ |
+static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ |
+ return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno); |
+} |
+ |
+ |
+/* |
+** Write data from a buffer into a file. Return SQLITE_OK on success |
+** or some other error code on failure. |
+*/ |
+static int unixWrite( |
+ sqlite3_file *id, |
+ const void *pBuf, |
+ int amt, |
+ sqlite3_int64 offset |
+){ |
+ unixFile *pFile = (unixFile*)id; |
+ int wrote = 0; |
+ assert( id ); |
+ assert( amt>0 ); |
+ |
+ /* If this is a database file (not a journal, master-journal or temp |
+ ** file), the bytes in the locking range should never be read or written. */ |
+#if 0 |
+ assert( pFile->pUnused==0 |
+ || offset>=PENDING_BYTE+512 |
+ || offset+amt<=PENDING_BYTE |
+ ); |
+#endif |
+ |
+#ifdef SQLITE_DEBUG |
+ /* If we are doing a normal write to a database file (as opposed to |
+ ** doing a hot-journal rollback or a write to some file other than a |
+ ** normal database file) then record the fact that the database |
+ ** has changed. If the transaction counter is modified, record that |
+ ** fact too. |
+ */ |
+ if( pFile->inNormalWrite ){ |
+ pFile->dbUpdate = 1; /* The database has been modified */ |
+ if( offset<=24 && offset+amt>=27 ){ |
+ int rc; |
+ char oldCntr[4]; |
+ SimulateIOErrorBenign(1); |
+ rc = seekAndRead(pFile, 24, oldCntr, 4); |
+ SimulateIOErrorBenign(0); |
+ if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){ |
+ pFile->transCntrChng = 1; /* The transaction counter has changed */ |
+ } |
+ } |
+ } |
+#endif |
+ |
+#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0 |
+ /* Deal with as much of this write request as possible by transfering |
+ ** data from the memory mapping using memcpy(). */ |
+ if( offset<pFile->mmapSize ){ |
+ if( offset+amt <= pFile->mmapSize ){ |
+ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); |
+ return SQLITE_OK; |
+ }else{ |
+ int nCopy = pFile->mmapSize - offset; |
+ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy); |
+ pBuf = &((u8 *)pBuf)[nCopy]; |
+ amt -= nCopy; |
+ offset += nCopy; |
+ } |
+ } |
+#endif |
+ |
+ while( (wrote = seekAndWrite(pFile, offset, pBuf, amt))<amt && wrote>0 ){ |
+ amt -= wrote; |
+ offset += wrote; |
+ pBuf = &((char*)pBuf)[wrote]; |
+ } |
+ SimulateIOError(( wrote=(-1), amt=1 )); |
+ SimulateDiskfullError(( wrote=0, amt=1 )); |
+ |
+ if( amt>wrote ){ |
+ if( wrote<0 && pFile->lastErrno!=ENOSPC ){ |
+ /* lastErrno set by seekAndWrite */ |
+ return SQLITE_IOERR_WRITE; |
+ }else{ |
+ storeLastErrno(pFile, 0); /* not a system error */ |
+ return SQLITE_FULL; |
+ } |
+ } |
+ |
+ return SQLITE_OK; |
+} |
+ |
+#ifdef SQLITE_TEST |
+/* |
+** Count the number of fullsyncs and normal syncs. This is used to test |
+** that syncs and fullsyncs are occurring at the right times. |
+*/ |
+SQLITE_API int sqlite3_sync_count = 0; |
+SQLITE_API int sqlite3_fullsync_count = 0; |
+#endif |
+ |
+/* |
+** We do not trust systems to provide a working fdatasync(). Some do. |
+** Others do no. To be safe, we will stick with the (slightly slower) |
+** fsync(). If you know that your system does support fdatasync() correctly, |
+** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC |
+*/ |
+#if !defined(fdatasync) && !HAVE_FDATASYNC |
+# define fdatasync fsync |
+#endif |
+ |
+/* |
+** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not |
+** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently |
+** only available on Mac OS X. But that could change. |
+*/ |
+#ifdef F_FULLFSYNC |
+# define HAVE_FULLFSYNC 1 |
+#else |
+# define HAVE_FULLFSYNC 0 |
+#endif |
+ |
+ |
+/* |
+** The fsync() system call does not work as advertised on many |
+** unix systems. The following procedure is an attempt to make |
+** it work better. |
+** |
+** The SQLITE_NO_SYNC macro disables all fsync()s. This is useful |
+** for testing when we want to run through the test suite quickly. |
+** You are strongly advised *not* to deploy with SQLITE_NO_SYNC |
+** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash |
+** or power failure will likely corrupt the database file. |
+** |
+** SQLite sets the dataOnly flag if the size of the file is unchanged. |
+** The idea behind dataOnly is that it should only write the file content |
+** to disk, not the inode. We only set dataOnly if the file size is |
+** unchanged since the file size is part of the inode. However, |
+** Ted Ts'o tells us that fdatasync() will also write the inode if the |
+** file size has changed. The only real difference between fdatasync() |
+** and fsync(), Ted tells us, is that fdatasync() will not flush the |
+** inode if the mtime or owner or other inode attributes have changed. |
+** We only care about the file size, not the other file attributes, so |
+** as far as SQLite is concerned, an fdatasync() is always adequate. |
+** So, we always use fdatasync() if it is available, regardless of |
+** the value of the dataOnly flag. |
+*/ |
+static int full_fsync(int fd, int fullSync, int dataOnly){ |
+ int rc; |
+ |
+ /* The following "ifdef/elif/else/" block has the same structure as |
+ ** the one below. It is replicated here solely to avoid cluttering |
+ ** up the real code with the UNUSED_PARAMETER() macros. |
+ */ |
+#ifdef SQLITE_NO_SYNC |
+ UNUSED_PARAMETER(fd); |
+ UNUSED_PARAMETER(fullSync); |
+ UNUSED_PARAMETER(dataOnly); |
+#elif HAVE_FULLFSYNC |
+ UNUSED_PARAMETER(dataOnly); |
+#else |
+ UNUSED_PARAMETER(fullSync); |
+ UNUSED_PARAMETER(dataOnly); |
+#endif |
+ |
+ /* Record the number of times that we do a normal fsync() and |
+ ** FULLSYNC. This is used during testing to verify that this procedure |
+ ** gets called with the correct arguments. |
+ */ |
+#ifdef SQLITE_TEST |
+ if( fullSync ) sqlite3_fullsync_count++; |
+ sqlite3_sync_count++; |
+#endif |
+ |
+ /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a |
+ ** no-op. But go ahead and call fstat() to validate the file |
+ ** descriptor as we need a method to provoke a failure during |
+ ** coverate testing. |
+ */ |
+#ifdef SQLITE_NO_SYNC |
+ { |
+ struct stat buf; |
+ rc = osFstat(fd, &buf); |
+ } |
+#elif HAVE_FULLFSYNC |
+ if( fullSync ){ |
+ rc = osFcntl(fd, F_FULLFSYNC, 0); |
+ }else{ |
+ rc = 1; |
+ } |
+ /* If the FULLFSYNC failed, fall back to attempting an fsync(). |
+ ** It shouldn't be possible for fullfsync to fail on the local |
+ ** file system (on OSX), so failure indicates that FULLFSYNC |
+ ** isn't supported for this file system. So, attempt an fsync |
+ ** and (for now) ignore the overhead of a superfluous fcntl call. |
+ ** It'd be better to detect fullfsync support once and avoid |
+ ** the fcntl call every time sync is called. |
+ */ |
+ if( rc ) rc = fsync(fd); |
+ |
+#elif defined(__APPLE__) |
+ /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly |
+ ** so currently we default to the macro that redefines fdatasync to fsync |
+ */ |
+ rc = fsync(fd); |
+#else |
+ rc = fdatasync(fd); |
+#if OS_VXWORKS |
+ if( rc==-1 && errno==ENOTSUP ){ |
+ rc = fsync(fd); |
+ } |
+#endif /* OS_VXWORKS */ |
+#endif /* ifdef SQLITE_NO_SYNC elif HAVE_FULLFSYNC */ |
+ |
+ if( OS_VXWORKS && rc!= -1 ){ |
+ rc = 0; |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Open a file descriptor to the directory containing file zFilename. |
+** If successful, *pFd is set to the opened file descriptor and |
+** SQLITE_OK is returned. If an error occurs, either SQLITE_NOMEM |
+** or SQLITE_CANTOPEN is returned and *pFd is set to an undefined |
+** value. |
+** |
+** The directory file descriptor is used for only one thing - to |
+** fsync() a directory to make sure file creation and deletion events |
+** are flushed to disk. Such fsyncs are not needed on newer |
+** journaling filesystems, but are required on older filesystems. |
+** |
+** This routine can be overridden using the xSetSysCall interface. |
+** The ability to override this routine was added in support of the |
+** chromium sandbox. Opening a directory is a security risk (we are |
+** told) so making it overrideable allows the chromium sandbox to |
+** replace this routine with a harmless no-op. To make this routine |
+** a no-op, replace it with a stub that returns SQLITE_OK but leaves |
+** *pFd set to a negative number. |
+** |
+** If SQLITE_OK is returned, the caller is responsible for closing |
+** the file descriptor *pFd using close(). |
+*/ |
+static int openDirectory(const char *zFilename, int *pFd){ |
+ int ii; |
+ int fd = -1; |
+ char zDirname[MAX_PATHNAME+1]; |
+ |
+ sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename); |
+ for(ii=(int)strlen(zDirname); ii>0 && zDirname[ii]!='/'; ii--); |
+ if( ii>0 ){ |
+ zDirname[ii] = '\0'; |
+ }else{ |
+ if( zDirname[0]!='/' ) zDirname[0] = '.'; |
+ zDirname[1] = 0; |
+ } |
+ fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0); |
+ if( fd>=0 ){ |
+ OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname)); |
+ } |
+ *pFd = fd; |
+ if( fd>=0 ) return SQLITE_OK; |
+ return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname); |
+} |
+ |
+/* |
+** Make sure all writes to a particular file are committed to disk. |
+** |
+** If dataOnly==0 then both the file itself and its metadata (file |
+** size, access time, etc) are synced. If dataOnly!=0 then only the |
+** file data is synced. |
+** |
+** Under Unix, also make sure that the directory entry for the file |
+** has been created by fsync-ing the directory that contains the file. |
+** If we do not do this and we encounter a power failure, the directory |
+** entry for the journal might not exist after we reboot. The next |
+** SQLite to access the file will not know that the journal exists (because |
+** the directory entry for the journal was never created) and the transaction |
+** will not roll back - possibly leading to database corruption. |
+*/ |
+static int unixSync(sqlite3_file *id, int flags){ |
+ int rc; |
+ unixFile *pFile = (unixFile*)id; |
+ |
+ int isDataOnly = (flags&SQLITE_SYNC_DATAONLY); |
+ int isFullsync = (flags&0x0F)==SQLITE_SYNC_FULL; |
+ |
+ /* Check that one of SQLITE_SYNC_NORMAL or FULL was passed */ |
+ assert((flags&0x0F)==SQLITE_SYNC_NORMAL |
+ || (flags&0x0F)==SQLITE_SYNC_FULL |
+ ); |
+ |
+ /* 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 ); |
+ |
+ assert( pFile ); |
+ OSTRACE(("SYNC %-3d\n", pFile->h)); |
+ rc = full_fsync(pFile->h, isFullsync, isDataOnly); |
+ SimulateIOError( rc=1 ); |
+ if( rc ){ |
+ storeLastErrno(pFile, errno); |
+ return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath); |
+ } |
+ |
+ /* Also fsync the directory containing the file if the DIRSYNC flag |
+ ** is set. This is a one-time occurrence. Many systems (examples: AIX) |
+ ** are unable to fsync a directory, so ignore errors on the fsync. |
+ */ |
+ if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){ |
+ int dirfd; |
+ OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath, |
+ HAVE_FULLFSYNC, isFullsync)); |
+ rc = osOpenDirectory(pFile->zPath, &dirfd); |
+ if( rc==SQLITE_OK ){ |
+ full_fsync(dirfd, 0, 0); |
+ robust_close(pFile, dirfd, __LINE__); |
+ }else{ |
+ assert( rc==SQLITE_CANTOPEN ); |
+ rc = SQLITE_OK; |
+ } |
+ pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC; |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Truncate an open file to a specified size |
+*/ |
+static int unixTruncate(sqlite3_file *id, i64 nByte){ |
+ unixFile *pFile = (unixFile *)id; |
+ int rc; |
+ assert( pFile ); |
+ 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>0 ){ |
+ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; |
+ } |
+ |
+ rc = robust_ftruncate(pFile->h, nByte); |
+ if( rc ){ |
+ storeLastErrno(pFile, errno); |
+ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); |
+ }else{ |
+#ifdef SQLITE_DEBUG |
+ /* If we are doing a normal write to a database file (as opposed to |
+ ** doing a hot-journal rollback or a write to some file other than a |
+ ** normal database file) and we truncate the file to zero length, |
+ ** that effectively updates the change counter. This might happen |
+ ** when restoring a database using the backup API from a zero-length |
+ ** source. |
+ */ |
+ if( pFile->inNormalWrite && nByte==0 ){ |
+ pFile->transCntrChng = 1; |
+ } |
+#endif |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ /* If the file was just truncated to a size smaller than the currently |
+ ** mapped region, reduce the effective mapping size as well. SQLite will |
+ ** use read() and write() to access data beyond this point from now on. |
+ */ |
+ if( nByte<pFile->mmapSize ){ |
+ pFile->mmapSize = nByte; |
+ } |
+#endif |
+ |
+ return SQLITE_OK; |
+ } |
+} |
+ |
+/* |
+** Determine the current size of a file in bytes |
+*/ |
+static int unixFileSize(sqlite3_file *id, i64 *pSize){ |
+ int rc; |
+ struct stat buf; |
+ assert( id ); |
+ rc = osFstat(((unixFile*)id)->h, &buf); |
+ SimulateIOError( rc=1 ); |
+ if( rc!=0 ){ |
+ storeLastErrno((unixFile*)id, errno); |
+ return SQLITE_IOERR_FSTAT; |
+ } |
+ *pSize = buf.st_size; |
+ |
+ /* When opening a zero-size database, the findInodeInfo() procedure |
+ ** writes a single byte into that file in order to work around a bug |
+ ** in the OS-X msdos filesystem. In order to avoid problems with upper |
+ ** layers, we need to report this file size as zero even though it is |
+ ** really 1. Ticket #3260. |
+ */ |
+ if( *pSize==1 ) *pSize = 0; |
+ |
+ |
+ return SQLITE_OK; |
+} |
+ |
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) |
+/* |
+** Handler for proxy-locking file-control verbs. Defined below in the |
+** proxying locking division. |
+*/ |
+static int proxyFileControl(sqlite3_file*,int,void*); |
+#endif |
+ |
+/* |
+** This function is called to handle the SQLITE_FCNTL_SIZE_HINT |
+** file-control operation. Enlarge the database to nBytes in size |
+** (rounded up to the next chunk-size). If the database is already |
+** nBytes or larger, this routine is a no-op. |
+*/ |
+static int fcntlSizeHint(unixFile *pFile, i64 nByte){ |
+ if( pFile->szChunk>0 ){ |
+ i64 nSize; /* Required file size */ |
+ struct stat buf; /* Used to hold return values of fstat() */ |
+ |
+ if( osFstat(pFile->h, &buf) ){ |
+ return SQLITE_IOERR_FSTAT; |
+ } |
+ |
+ nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk; |
+ if( nSize>(i64)buf.st_size ){ |
+ |
+#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE |
+ /* The code below is handling the return value of osFallocate() |
+ ** correctly. posix_fallocate() is defined to "returns zero on success, |
+ ** or an error number on failure". See the manpage for details. */ |
+ int err; |
+ do{ |
+ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); |
+ }while( err==EINTR ); |
+ if( err ) return SQLITE_IOERR_WRITE; |
+#else |
+ /* If the OS does not have posix_fallocate(), fake it. Write a |
+ ** single byte to the last byte in each block that falls entirely |
+ ** within the extended region. Then, if required, a single byte |
+ ** at offset (nSize-1), to set the size of the file correctly. |
+ ** This is a similar technique to that used by glibc on systems |
+ ** that do not have a real fallocate() call. |
+ */ |
+ int nBlk = buf.st_blksize; /* File-system block size */ |
+ int nWrite = 0; /* Number of bytes written by seekAndWrite */ |
+ i64 iWrite; /* Next offset to write to */ |
+ |
+ iWrite = (buf.st_size/nBlk)*nBlk + nBlk - 1; |
+ assert( iWrite>=buf.st_size ); |
+ assert( ((iWrite+1)%nBlk)==0 ); |
+ for(/*no-op*/; iWrite<nSize+nBlk-1; iWrite+=nBlk ){ |
+ if( iWrite>=nSize ) iWrite = nSize - 1; |
+ nWrite = seekAndWrite(pFile, iWrite, "", 1); |
+ if( nWrite!=1 ) return SQLITE_IOERR_WRITE; |
+ } |
+#endif |
+ } |
+ } |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){ |
+ int rc; |
+ if( pFile->szChunk<=0 ){ |
+ if( robust_ftruncate(pFile->h, nByte) ){ |
+ storeLastErrno(pFile, errno); |
+ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); |
+ } |
+ } |
+ |
+ rc = unixMapfile(pFile, nByte); |
+ return rc; |
+ } |
+#endif |
+ |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** If *pArg is initially negative then this is a query. Set *pArg to |
+** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. |
+** |
+** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. |
+*/ |
+static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){ |
+ if( *pArg<0 ){ |
+ *pArg = (pFile->ctrlFlags & mask)!=0; |
+ }else if( (*pArg)==0 ){ |
+ pFile->ctrlFlags &= ~mask; |
+ }else{ |
+ pFile->ctrlFlags |= mask; |
+ } |
+} |
+ |
+/* Forward declaration */ |
+static int unixGetTempname(int nBuf, char *zBuf); |
+ |
+/* |
+** Information and control of an open file handle. |
+*/ |
+static int unixFileControl(sqlite3_file *id, int op, void *pArg){ |
+ unixFile *pFile = (unixFile*)id; |
+ switch( op ){ |
+ case SQLITE_FCNTL_LOCKSTATE: { |
+ *(int*)pArg = pFile->eFileLock; |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_LAST_ERRNO: { |
+ *(int*)pArg = pFile->lastErrno; |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_CHUNK_SIZE: { |
+ pFile->szChunk = *(int *)pArg; |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_SIZE_HINT: { |
+ int rc; |
+ SimulateIOErrorBenign(1); |
+ rc = fcntlSizeHint(pFile, *(i64 *)pArg); |
+ SimulateIOErrorBenign(0); |
+ return rc; |
+ } |
+ case SQLITE_FCNTL_PERSIST_WAL: { |
+ unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { |
+ unixModeBit(pFile, UNIXFILE_PSOW, (int*)pArg); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_VFSNAME: { |
+ *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_TEMPFILENAME: { |
+ char *zTFile = sqlite3_malloc64( pFile->pVfs->mxPathname ); |
+ if( zTFile ){ |
+ unixGetTempname(pFile->pVfs->mxPathname, zTFile); |
+ *(char**)pArg = zTFile; |
+ } |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_HAS_MOVED: { |
+ *(int*)pArg = fileHasMoved(pFile); |
+ return SQLITE_OK; |
+ } |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ case SQLITE_FCNTL_MMAP_SIZE: { |
+ i64 newLimit = *(i64*)pArg; |
+ int rc = SQLITE_OK; |
+ if( newLimit>sqlite3GlobalConfig.mxMmap ){ |
+ newLimit = sqlite3GlobalConfig.mxMmap; |
+ } |
+ *(i64*)pArg = pFile->mmapSizeMax; |
+ if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ |
+ pFile->mmapSizeMax = newLimit; |
+ if( pFile->mmapSize>0 ){ |
+ unixUnmapfile(pFile); |
+ rc = unixMapfile(pFile, -1); |
+ } |
+ } |
+ return rc; |
+ } |
+#endif |
+#ifdef SQLITE_DEBUG |
+ /* The pager calls this method to signal that it has done |
+ ** a rollback and that the database is therefore unchanged and |
+ ** it hence it is OK for the transaction change counter to be |
+ ** unchanged. |
+ */ |
+ case SQLITE_FCNTL_DB_UNCHANGED: { |
+ ((unixFile*)id)->dbUpdate = 0; |
+ return SQLITE_OK; |
+ } |
+#endif |
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) |
+ case SQLITE_FCNTL_SET_LOCKPROXYFILE: |
+ case SQLITE_FCNTL_GET_LOCKPROXYFILE: { |
+ return proxyFileControl(id,op,pArg); |
+ } |
+#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ |
+ } |
+ 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 |
+** larger for some devices. |
+** |
+** 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. |
+*/ |
+#ifndef __QNXNTO__ |
+static int unixSectorSize(sqlite3_file *NotUsed){ |
+ UNUSED_PARAMETER(NotUsed); |
+ return SQLITE_DEFAULT_SECTOR_SIZE; |
+} |
+#endif |
+ |
+/* |
+** The following version of unixSectorSize() is optimized for QNX. |
+*/ |
+#ifdef __QNXNTO__ |
+#include <sys/dcmd_blk.h> |
+#include <sys/statvfs.h> |
+static int unixSectorSize(sqlite3_file *id){ |
+ unixFile *pFile = (unixFile*)id; |
+ if( pFile->sectorSize == 0 ){ |
+ struct statvfs fsInfo; |
+ |
+ /* Set defaults for non-supported filesystems */ |
+ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; |
+ pFile->deviceCharacteristics = 0; |
+ if( fstatvfs(pFile->h, &fsInfo) == -1 ) { |
+ return pFile->sectorSize; |
+ } |
+ |
+ if( !strcmp(fsInfo.f_basetype, "tmp") ) { |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ SQLITE_IOCAP_ATOMIC4K | /* All ram filesystem writes are atomic */ |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until |
+ ** the write succeeds */ |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else if( strstr(fsInfo.f_basetype, "etfs") ){ |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ /* etfs cluster size writes are atomic */ |
+ (pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) | |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until |
+ ** the write succeeds */ |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else if( !strcmp(fsInfo.f_basetype, "qnx6") ){ |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ SQLITE_IOCAP_ATOMIC | /* All filesystem writes are atomic */ |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until |
+ ** the write succeeds */ |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else if( !strcmp(fsInfo.f_basetype, "qnx4") ){ |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ /* full bitset of atomics from max sector size and smaller */ |
+ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else if( strstr(fsInfo.f_basetype, "dos") ){ |
+ pFile->sectorSize = fsInfo.f_bsize; |
+ pFile->deviceCharacteristics = |
+ /* full bitset of atomics from max sector size and smaller */ |
+ ((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 | |
+ SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind |
+ ** so it is ordered */ |
+ 0; |
+ }else{ |
+ pFile->deviceCharacteristics = |
+ SQLITE_IOCAP_ATOMIC512 | /* blocks are atomic */ |
+ SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until |
+ ** the write succeeds */ |
+ 0; |
+ } |
+ } |
+ /* Last chance verification. If the sector size isn't a multiple of 512 |
+ ** then it isn't valid.*/ |
+ if( pFile->sectorSize % 512 != 0 ){ |
+ pFile->deviceCharacteristics = 0; |
+ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; |
+ } |
+ return pFile->sectorSize; |
+} |
+#endif /* __QNXNTO__ */ |
+ |
+/* |
+** Return the device characteristics for the file. |
+** |
+** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default. |
+** However, that choice is controversial since technically the underlying |
+** file system does not always provide powersafe overwrites. (In other |
+** words, after a power-loss event, parts of the file that were never |
+** written might end up being altered.) However, non-PSOW behavior is very, |
+** very rare. And asserting PSOW makes a large reduction in the amount |
+** of required I/O for journaling, since a lot of padding is eliminated. |
+** Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control |
+** available to turn it off and URI query parameter available to turn it off. |
+*/ |
+static int unixDeviceCharacteristics(sqlite3_file *id){ |
+ unixFile *p = (unixFile*)id; |
+ int rc = 0; |
+#ifdef __QNXNTO__ |
+ if( p->sectorSize==0 ) unixSectorSize(id); |
+ rc = p->deviceCharacteristics; |
+#endif |
+ if( p->ctrlFlags & UNIXFILE_PSOW ){ |
+ rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; |
+ } |
+ return rc; |
+} |
+ |
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
+ |
+/* |
+** Return the system page size. |
+** |
+** This function should not be called directly by other code in this file. |
+** Instead, it should be called via macro osGetpagesize(). |
+*/ |
+static int unixGetpagesize(void){ |
+#if OS_VXWORKS |
+ return 1024; |
+#elif defined(_BSD_SOURCE) |
+ return getpagesize(); |
+#else |
+ return (int)sysconf(_SC_PAGESIZE); |
+#endif |
+} |
+ |
+#endif /* !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 */ |
+ |
+#ifndef SQLITE_OMIT_WAL |
+ |
+/* |
+** Object used to represent an shared memory buffer. |
+** |
+** When multiple threads all reference the same wal-index, each thread |
+** has its own unixShm object, but they all point to a single instance |
+** of this unixShmNode object. In other words, each wal-index is opened |
+** only once per process. |
+** |
+** Each unixShmNode object is connected to a single unixInodeInfo object. |
+** We could coalesce this object into unixInodeInfo, but that would mean |
+** every open file that does not use shared memory (in other words, most |
+** open files) would have to carry around this extra information. So |
+** the unixInodeInfo object contains a pointer to this unixShmNode object |
+** and the unixShmNode object is created only when needed. |
+** |
+** unixMutexHeld() must be true when creating or destroying |
+** this object or while reading or writing the following fields: |
+** |
+** nRef |
+** |
+** The following fields are read-only after the object is created: |
+** |
+** fid |
+** zFilename |
+** |
+** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and |
+** unixMutexHeld() is true when reading or writing any other field |
+** in this structure. |
+*/ |
+struct unixShmNode { |
+ unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ |
+ sqlite3_mutex *mutex; /* Mutex to access this object */ |
+ char *zFilename; /* Name of the mmapped file */ |
+ int h; /* Open file descriptor */ |
+ int szRegion; /* Size of shared-memory regions */ |
+ u16 nRegion; /* Size of array apRegion */ |
+ u8 isReadonly; /* True if read-only */ |
+ char **apRegion; /* Array of mapped shared-memory regions */ |
+ int nRef; /* Number of unixShm objects pointing to this */ |
+ unixShm *pFirst; /* All unixShm objects pointing to this */ |
+#ifdef SQLITE_DEBUG |
+ u8 exclMask; /* Mask of exclusive locks held */ |
+ u8 sharedMask; /* Mask of shared locks held */ |
+ u8 nextShmId; /* Next available unixShm.id value */ |
+#endif |
+}; |
+ |
+/* |
+** 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: |
+** |
+** unixShm.pFile |
+** unixShm.id |
+** |
+** All other fields are read/write. The unixShm.pFile->mutex must be held |
+** while accessing any read/write fields. |
+*/ |
+struct unixShm { |
+ unixShmNode *pShmNode; /* The underlying unixShmNode object */ |
+ unixShm *pNext; /* Next unixShm with the same unixShmNode */ |
+ u8 hasMutex; /* True if holding the unixShmNode mutex */ |
+ u8 id; /* Id of this connection within its unixShmNode */ |
+ u16 sharedMask; /* Mask of shared locks held */ |
+ u16 exclMask; /* Mask of exclusive locks held */ |
+}; |
+ |
+/* |
+** Constants used for locking |
+*/ |
+#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ |
+#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ |
+ |
+/* |
+** Apply posix advisory locks for all bytes from ofst through ofst+n-1. |
+** |
+** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking |
+** otherwise. |
+*/ |
+static int unixShmSystemLock( |
+ unixFile *pFile, /* Open connection to the WAL file */ |
+ int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */ |
+ int ofst, /* First byte of the locking range */ |
+ int n /* Number of bytes to lock */ |
+){ |
+ unixShmNode *pShmNode; /* Apply locks to this open shared-memory segment */ |
+ struct flock f; /* The posix advisory locking structure */ |
+ int rc = SQLITE_OK; /* Result code form fcntl() */ |
+ |
+ /* Access to the unixShmNode object is serialized by the caller */ |
+ pShmNode = pFile->pInode->pShmNode; |
+ assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 ); |
+ |
+ /* Shared locks never span more than one byte */ |
+ assert( n==1 || lockType!=F_RDLCK ); |
+ |
+ /* Locks are within range */ |
+ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); |
+ |
+ if( pShmNode->h>=0 ){ |
+ /* Initialize the locking parameters */ |
+ memset(&f, 0, sizeof(f)); |
+ f.l_type = lockType; |
+ f.l_whence = SEEK_SET; |
+ f.l_start = ofst; |
+ f.l_len = n; |
+ |
+ rc = osFcntl(pShmNode->h, F_SETLK, &f); |
+ rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; |
+ } |
+ |
+ /* Update the global lock state and do debug tracing */ |
+#ifdef SQLITE_DEBUG |
+ { u16 mask; |
+ OSTRACE(("SHM-LOCK ")); |
+ mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst); |
+ if( rc==SQLITE_OK ){ |
+ if( lockType==F_UNLCK ){ |
+ OSTRACE(("unlock %d ok", ofst)); |
+ pShmNode->exclMask &= ~mask; |
+ pShmNode->sharedMask &= ~mask; |
+ }else if( lockType==F_RDLCK ){ |
+ OSTRACE(("read-lock %d ok", ofst)); |
+ pShmNode->exclMask &= ~mask; |
+ pShmNode->sharedMask |= mask; |
+ }else{ |
+ assert( lockType==F_WRLCK ); |
+ OSTRACE(("write-lock %d ok", ofst)); |
+ pShmNode->exclMask |= mask; |
+ pShmNode->sharedMask &= ~mask; |
+ } |
+ }else{ |
+ if( lockType==F_UNLCK ){ |
+ OSTRACE(("unlock %d failed", ofst)); |
+ }else if( lockType==F_RDLCK ){ |
+ OSTRACE(("read-lock failed")); |
+ }else{ |
+ assert( lockType==F_WRLCK ); |
+ OSTRACE(("write-lock %d failed", ofst)); |
+ } |
+ } |
+ OSTRACE((" - afterwards %03x,%03x\n", |
+ pShmNode->sharedMask, pShmNode->exclMask)); |
+ } |
+#endif |
+ |
+ return rc; |
+} |
+ |
+/* |
+** Return the minimum number of 32KB shm regions that should be mapped at |
+** a time, assuming that each mapping must be an integer multiple of the |
+** current system page-size. |
+** |
+** Usually, this is 1. The exception seems to be systems that are configured |
+** to use 64KB pages - in this case each mapping must cover at least two |
+** shm regions. |
+*/ |
+static int unixShmRegionPerMap(void){ |
+ int shmsz = 32*1024; /* SHM region size */ |
+ int pgsz = osGetpagesize(); /* System page size */ |
+ assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */ |
+ if( pgsz<shmsz ) return 1; |
+ return pgsz/shmsz; |
+} |
+ |
+/* |
+** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0. |
+** |
+** This is not a VFS shared-memory method; it is a utility function called |
+** by VFS shared-memory methods. |
+*/ |
+static void unixShmPurge(unixFile *pFd){ |
+ unixShmNode *p = pFd->pInode->pShmNode; |
+ assert( unixMutexHeld() ); |
+ if( p && ALWAYS(p->nRef==0) ){ |
+ int nShmPerMap = unixShmRegionPerMap(); |
+ int i; |
+ assert( p->pInode==pFd->pInode ); |
+ sqlite3_mutex_free(p->mutex); |
+ for(i=0; i<p->nRegion; i+=nShmPerMap){ |
+ if( p->h>=0 ){ |
+ osMunmap(p->apRegion[i], p->szRegion); |
+ }else{ |
+ sqlite3_free(p->apRegion[i]); |
+ } |
+ } |
+ sqlite3_free(p->apRegion); |
+ if( p->h>=0 ){ |
+ robust_close(pFd, p->h, __LINE__); |
+ p->h = -1; |
+ } |
+ p->pInode->pShmNode = 0; |
+ sqlite3_free(p); |
+ } |
+} |
+ |
+/* |
+** Open a shared-memory area associated with open database file pDbFd. |
+** This particular implementation uses mmapped files. |
+** |
+** The file used to implement shared-memory is in the same directory |
+** as the open database file and has the same name as the open database |
+** file with the "-shm" suffix added. For example, if the database file |
+** is "/home/user1/config.db" then the file that is created and mmapped |
+** for shared memory will be called "/home/user1/config.db-shm". |
+** |
+** Another approach to is to use files in /dev/shm or /dev/tmp or an |
+** some other tmpfs mount. But if a file in a different directory |
+** from the database file is used, then differing access permissions |
+** or a chroot() might cause two different processes on the same |
+** database to end up using different files for shared memory - |
+** meaning that their memory would not really be shared - resulting |
+** in database corruption. Nevertheless, this tmpfs file usage |
+** can be enabled at compile-time using -DSQLITE_SHM_DIRECTORY="/dev/shm" |
+** or the equivalent. The use of the SQLITE_SHM_DIRECTORY compile-time |
+** option results in an incompatible build of SQLite; builds of SQLite |
+** that with differing SQLITE_SHM_DIRECTORY settings attempt to use the |
+** same database file at the same time, database corruption will likely |
+** result. The SQLITE_SHM_DIRECTORY compile-time option is considered |
+** "unsupported" and may go away in a future SQLite release. |
+** |
+** When opening a new shared-memory file, if no other instances of that |
+** file are currently open, in this process or in other processes, then |
+** the file must be truncated to zero length or have its header cleared. |
+** |
+** If the original database file (pDbFd) is using the "unix-excl" VFS |
+** that means that an exclusive lock is held on the database file and |
+** that no other processes are able to read or write the database. In |
+** that case, we do not really need shared memory. No shared memory |
+** file is created. The shared memory will be simulated with heap memory. |
+*/ |
+static int unixOpenSharedMemory(unixFile *pDbFd){ |
+ struct unixShm *p = 0; /* The connection to be opened */ |
+ struct unixShmNode *pShmNode; /* The underlying mmapped file */ |
+ int rc; /* Result code */ |
+ unixInodeInfo *pInode; /* The inode of fd */ |
+ char *zShmFilename; /* Name of the file used for SHM */ |
+ int nShmFilename; /* Size of the SHM filename in bytes */ |
+ |
+ /* Allocate space for the new unixShm object. */ |
+ p = sqlite3_malloc64( sizeof(*p) ); |
+ if( p==0 ) return SQLITE_NOMEM_BKPT; |
+ memset(p, 0, sizeof(*p)); |
+ assert( pDbFd->pShm==0 ); |
+ |
+ /* Check to see if a unixShmNode object already exists. Reuse an existing |
+ ** one if present. Create a new one if necessary. |
+ */ |
+ unixEnterMutex(); |
+ pInode = pDbFd->pInode; |
+ pShmNode = pInode->pShmNode; |
+ if( pShmNode==0 ){ |
+ struct stat sStat; /* fstat() info for database file */ |
+#ifndef SQLITE_SHM_DIRECTORY |
+ const char *zBasePath = pDbFd->zPath; |
+#endif |
+ |
+ /* Call fstat() to figure out the permissions on the database file. If |
+ ** a new *-shm file is created, an attempt will be made to create it |
+ ** with the same permissions. |
+ */ |
+ if( osFstat(pDbFd->h, &sStat) ){ |
+ rc = SQLITE_IOERR_FSTAT; |
+ goto shm_open_err; |
+ } |
+ |
+#ifdef SQLITE_SHM_DIRECTORY |
+ nShmFilename = sizeof(SQLITE_SHM_DIRECTORY) + 31; |
+#else |
+ nShmFilename = 6 + (int)strlen(zBasePath); |
+#endif |
+ pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename ); |
+ if( pShmNode==0 ){ |
+ rc = SQLITE_NOMEM_BKPT; |
+ goto shm_open_err; |
+ } |
+ memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename); |
+ zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1]; |
+#ifdef SQLITE_SHM_DIRECTORY |
+ sqlite3_snprintf(nShmFilename, zShmFilename, |
+ SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x", |
+ (u32)sStat.st_ino, (u32)sStat.st_dev); |
+#else |
+ sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath); |
+ sqlite3FileSuffix3(pDbFd->zPath, zShmFilename); |
+#endif |
+ pShmNode->h = -1; |
+ pDbFd->pInode->pShmNode = pShmNode; |
+ pShmNode->pInode = pDbFd->pInode; |
+ if( sqlite3GlobalConfig.bCoreMutex ){ |
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
+ if( pShmNode->mutex==0 ){ |
+ rc = SQLITE_NOMEM_BKPT; |
+ goto shm_open_err; |
+ } |
+ } |
+ |
+ if( pInode->bProcessLock==0 ){ |
+ int openFlags = O_RDWR | O_CREAT; |
+ if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ |
+ openFlags = O_RDONLY; |
+ pShmNode->isReadonly = 1; |
+ } |
+ pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777)); |
+ if( pShmNode->h<0 ){ |
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename); |
+ goto shm_open_err; |
+ } |
+ |
+ /* If this process is running as root, make sure that the SHM file |
+ ** is owned by the same user that owns the original database. Otherwise, |
+ ** the original owner will not be able to connect. |
+ */ |
+ robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid); |
+ |
+ /* Check to see if another process is holding the dead-man switch. |
+ ** If not, truncate the file to zero length. |
+ */ |
+ rc = SQLITE_OK; |
+ if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){ |
+ if( robust_ftruncate(pShmNode->h, 0) ){ |
+ rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename); |
+ } |
+ } |
+ if( rc==SQLITE_OK ){ |
+ rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); |
+ } |
+ if( rc ) goto shm_open_err; |
+ } |
+ } |
+ |
+ /* Make the new connection a child of the unixShmNode */ |
+ p->pShmNode = pShmNode; |
+#ifdef SQLITE_DEBUG |
+ p->id = pShmNode->nextShmId++; |
+#endif |
+ pShmNode->nRef++; |
+ pDbFd->pShm = p; |
+ unixLeaveMutex(); |
+ |
+ /* The reference count on pShmNode has already been incremented under |
+ ** the cover of the unixEnterMutex() mutex and the pointer from the |
+ ** new (struct unixShm) object to the pShmNode has been set. All that is |
+ ** left to do is to link the new object into the linked list starting |
+ ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex |
+ ** mutex. |
+ */ |
+ sqlite3_mutex_enter(pShmNode->mutex); |
+ p->pNext = pShmNode->pFirst; |
+ pShmNode->pFirst = p; |
+ sqlite3_mutex_leave(pShmNode->mutex); |
+ return SQLITE_OK; |
+ |
+ /* Jump here on any error */ |
+shm_open_err: |
+ unixShmPurge(pDbFd); /* This call frees pShmNode if required */ |
+ sqlite3_free(p); |
+ unixLeaveMutex(); |
+ return rc; |
+} |
+ |
+/* |
+** This function is called to obtain a pointer to region iRegion of the |
+** shared-memory associated with the database file fd. 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 unixShmMap( |
+ sqlite3_file *fd, /* Handle open on database file */ |
+ int iRegion, /* Region to retrieve */ |
+ int szRegion, /* Size of regions */ |
+ int bExtend, /* True to extend file if necessary */ |
+ void volatile **pp /* OUT: Mapped memory */ |
+){ |
+ unixFile *pDbFd = (unixFile*)fd; |
+ unixShm *p; |
+ unixShmNode *pShmNode; |
+ int rc = SQLITE_OK; |
+ int nShmPerMap = unixShmRegionPerMap(); |
+ int nReqRegion; |
+ |
+ /* If the shared-memory file has not yet been opened, open it now. */ |
+ if( pDbFd->pShm==0 ){ |
+ rc = unixOpenSharedMemory(pDbFd); |
+ if( rc!=SQLITE_OK ) return rc; |
+ } |
+ |
+ p = pDbFd->pShm; |
+ pShmNode = p->pShmNode; |
+ sqlite3_mutex_enter(pShmNode->mutex); |
+ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); |
+ assert( pShmNode->pInode==pDbFd->pInode ); |
+ assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); |
+ assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); |
+ |
+ /* Minimum number of regions required to be mapped. */ |
+ nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; |
+ |
+ if( pShmNode->nRegion<nReqRegion ){ |
+ char **apNew; /* New apRegion[] array */ |
+ int nByte = nReqRegion*szRegion; /* Minimum required file size */ |
+ struct stat sStat; /* Used by fstat() */ |
+ |
+ pShmNode->szRegion = szRegion; |
+ |
+ if( pShmNode->h>=0 ){ |
+ /* 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). |
+ */ |
+ if( osFstat(pShmNode->h, &sStat) ){ |
+ rc = SQLITE_IOERR_SHMSIZE; |
+ goto shmpage_out; |
+ } |
+ |
+ if( sStat.st_size<nByte ){ |
+ /* The requested memory region does not exist. If bExtend is set to |
+ ** false, exit early. *pp will be set to NULL and SQLITE_OK returned. |
+ */ |
+ if( !bExtend ){ |
+ goto shmpage_out; |
+ } |
+ |
+ /* Alternatively, if bExtend is true, extend the file. Do this by |
+ ** writing a single byte to the end of each (OS) page being |
+ ** allocated or extended. Technically, we need only write to the |
+ ** last page in order to extend the file. But writing to all new |
+ ** pages forces the OS to allocate them immediately, which reduces |
+ ** the chances of SIGBUS while accessing the mapped region later on. |
+ */ |
+ else{ |
+ static const int pgsz = 4096; |
+ int iPg; |
+ |
+ /* Write to the last byte of each newly allocated or extended page */ |
+ assert( (nByte % pgsz)==0 ); |
+ for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){ |
+ int x = 0; |
+ if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){ |
+ const char *zFile = pShmNode->zFilename; |
+ rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile); |
+ goto shmpage_out; |
+ } |
+ } |
+ } |
+ } |
+ } |
+ |
+ /* Map the requested memory region into this processes address space. */ |
+ apNew = (char **)sqlite3_realloc( |
+ pShmNode->apRegion, nReqRegion*sizeof(char *) |
+ ); |
+ if( !apNew ){ |
+ rc = SQLITE_IOERR_NOMEM_BKPT; |
+ goto shmpage_out; |
+ } |
+ pShmNode->apRegion = apNew; |
+ while( pShmNode->nRegion<nReqRegion ){ |
+ int nMap = szRegion*nShmPerMap; |
+ int i; |
+ void *pMem; |
+ if( pShmNode->h>=0 ){ |
+ pMem = osMmap(0, nMap, |
+ pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, |
+ MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion |
+ ); |
+ if( pMem==MAP_FAILED ){ |
+ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); |
+ goto shmpage_out; |
+ } |
+ }else{ |
+ pMem = sqlite3_malloc64(szRegion); |
+ if( pMem==0 ){ |
+ rc = SQLITE_NOMEM_BKPT; |
+ goto shmpage_out; |
+ } |
+ memset(pMem, 0, szRegion); |
+ } |
+ |
+ for(i=0; i<nShmPerMap; i++){ |
+ pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i]; |
+ } |
+ pShmNode->nRegion += nShmPerMap; |
+ } |
+ } |
+ |
+shmpage_out: |
+ if( pShmNode->nRegion>iRegion ){ |
+ *pp = pShmNode->apRegion[iRegion]; |
+ }else{ |
+ *pp = 0; |
+ } |
+ if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; |
+ sqlite3_mutex_leave(pShmNode->mutex); |
+ return rc; |
+} |
+ |
+/* |
+** 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 unixShmLock( |
+ sqlite3_file *fd, /* 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 */ |
+){ |
+ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ |
+ unixShm *p = pDbFd->pShm; /* The shared memory being locked */ |
+ unixShm *pX; /* For looping over all siblings */ |
+ unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ |
+ int rc = SQLITE_OK; /* Result code */ |
+ u16 mask; /* Mask of locks to take or release */ |
+ |
+ assert( pShmNode==pDbFd->pInode->pShmNode ); |
+ assert( pShmNode->pInode==pDbFd->pInode ); |
+ 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 ); |
+ assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); |
+ assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); |
+ |
+ mask = (1<<(ofst+n)) - (1<<ofst); |
+ assert( n>1 || mask==(1<<ofst) ); |
+ sqlite3_mutex_enter(pShmNode->mutex); |
+ if( flags & SQLITE_SHM_UNLOCK ){ |
+ u16 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 = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_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 ){ |
+ u16 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 = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_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 = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_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\n", |
+ p->id, osGetpid(0), p->sharedMask, p->exclMask)); |
+ 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 unixShmBarrier( |
+ sqlite3_file *fd /* Database file holding the shared memory */ |
+){ |
+ UNUSED_PARAMETER(fd); |
+ sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ |
+ unixEnterMutex(); /* Also mutex, for redundancy */ |
+ unixLeaveMutex(); |
+} |
+ |
+/* |
+** 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 unixShmUnmap( |
+ sqlite3_file *fd, /* The underlying database file */ |
+ int deleteFlag /* Delete shared-memory if true */ |
+){ |
+ unixShm *p; /* The connection to be closed */ |
+ unixShmNode *pShmNode; /* The underlying shared-memory file */ |
+ unixShm **pp; /* For looping over sibling connections */ |
+ unixFile *pDbFd; /* The underlying database file */ |
+ |
+ pDbFd = (unixFile*)fd; |
+ p = pDbFd->pShm; |
+ if( p==0 ) return SQLITE_OK; |
+ pShmNode = p->pShmNode; |
+ |
+ assert( pShmNode==pDbFd->pInode->pShmNode ); |
+ assert( pShmNode->pInode==pDbFd->pInode ); |
+ |
+ /* Remove connection p from the set of connections associated |
+ ** with pShmNode */ |
+ sqlite3_mutex_enter(pShmNode->mutex); |
+ for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} |
+ *pp = p->pNext; |
+ |
+ /* Free the connection p */ |
+ sqlite3_free(p); |
+ pDbFd->pShm = 0; |
+ sqlite3_mutex_leave(pShmNode->mutex); |
+ |
+ /* If pShmNode->nRef has reached 0, then close the underlying |
+ ** shared-memory file, too */ |
+ unixEnterMutex(); |
+ assert( pShmNode->nRef>0 ); |
+ pShmNode->nRef--; |
+ if( pShmNode->nRef==0 ){ |
+ if( deleteFlag && pShmNode->h>=0 ){ |
+ osUnlink(pShmNode->zFilename); |
+ } |
+ unixShmPurge(pDbFd); |
+ } |
+ unixLeaveMutex(); |
+ |
+ return SQLITE_OK; |
+} |
+ |
+ |
+#else |
+# define unixShmMap 0 |
+# define unixShmLock 0 |
+# define unixShmBarrier 0 |
+# define unixShmUnmap 0 |
+#endif /* #ifndef SQLITE_OMIT_WAL */ |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+/* |
+** If it is currently memory mapped, unmap file pFd. |
+*/ |
+static void unixUnmapfile(unixFile *pFd){ |
+ assert( pFd->nFetchOut==0 ); |
+ if( pFd->pMapRegion ){ |
+ osMunmap(pFd->pMapRegion, pFd->mmapSizeActual); |
+ pFd->pMapRegion = 0; |
+ pFd->mmapSize = 0; |
+ pFd->mmapSizeActual = 0; |
+ } |
+} |
+ |
+/* |
+** Attempt to set the size of the memory mapping maintained by file |
+** descriptor pFd to nNew bytes. Any existing mapping is discarded. |
+** |
+** If successful, this function sets the following variables: |
+** |
+** unixFile.pMapRegion |
+** unixFile.mmapSize |
+** unixFile.mmapSizeActual |
+** |
+** If unsuccessful, an error message is logged via sqlite3_log() and |
+** the three variables above are zeroed. In this case SQLite should |
+** continue accessing the database using the xRead() and xWrite() |
+** methods. |
+*/ |
+static void unixRemapfile( |
+ unixFile *pFd, /* File descriptor object */ |
+ i64 nNew /* Required mapping size */ |
+){ |
+ const char *zErr = "mmap"; |
+ int h = pFd->h; /* File descriptor open on db file */ |
+ u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */ |
+ i64 nOrig = pFd->mmapSizeActual; /* Size of pOrig region in bytes */ |
+ u8 *pNew = 0; /* Location of new mapping */ |
+ int flags = PROT_READ; /* Flags to pass to mmap() */ |
+ |
+ assert( pFd->nFetchOut==0 ); |
+ assert( nNew>pFd->mmapSize ); |
+ assert( nNew<=pFd->mmapSizeMax ); |
+ assert( nNew>0 ); |
+ assert( pFd->mmapSizeActual>=pFd->mmapSize ); |
+ assert( MAP_FAILED!=0 ); |
+ |
+#ifdef SQLITE_MMAP_READWRITE |
+ if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; |
+#endif |
+ |
+ if( pOrig ){ |
+#if HAVE_MREMAP |
+ i64 nReuse = pFd->mmapSize; |
+#else |
+ const int szSyspage = osGetpagesize(); |
+ i64 nReuse = (pFd->mmapSize & ~(szSyspage-1)); |
+#endif |
+ u8 *pReq = &pOrig[nReuse]; |
+ |
+ /* Unmap any pages of the existing mapping that cannot be reused. */ |
+ if( nReuse!=nOrig ){ |
+ osMunmap(pReq, nOrig-nReuse); |
+ } |
+ |
+#if HAVE_MREMAP |
+ pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE); |
+ zErr = "mremap"; |
+#else |
+ pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse); |
+ if( pNew!=MAP_FAILED ){ |
+ if( pNew!=pReq ){ |
+ osMunmap(pNew, nNew - nReuse); |
+ pNew = 0; |
+ }else{ |
+ pNew = pOrig; |
+ } |
+ } |
+#endif |
+ |
+ /* The attempt to extend the existing mapping failed. Free it. */ |
+ if( pNew==MAP_FAILED || pNew==0 ){ |
+ osMunmap(pOrig, nReuse); |
+ } |
+ } |
+ |
+ /* If pNew is still NULL, try to create an entirely new mapping. */ |
+ if( pNew==0 ){ |
+ pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0); |
+ } |
+ |
+ if( pNew==MAP_FAILED ){ |
+ pNew = 0; |
+ nNew = 0; |
+ unixLogError(SQLITE_OK, zErr, pFd->zPath); |
+ |
+ /* If the mmap() above failed, assume that all subsequent mmap() calls |
+ ** will probably fail too. Fall back to using xRead/xWrite exclusively |
+ ** in this case. */ |
+ pFd->mmapSizeMax = 0; |
+ } |
+ pFd->pMapRegion = (void *)pNew; |
+ pFd->mmapSize = pFd->mmapSizeActual = nNew; |
+} |
+ |
+/* |
+** Memory map or remap the file opened by file-descriptor pFd (if the file |
+** is already mapped, the existing mapping is replaced by the new). Or, if |
+** there already exists a mapping for this file, and there are still |
+** outstanding xFetch() references to it, this function is a no-op. |
+** |
+** If parameter nByte is non-negative, then it is the requested size of |
+** the mapping to create. Otherwise, if nByte is less than zero, then the |
+** requested size is the size of the file on disk. The actual size of the |
+** created mapping is either the requested size or the value configured |
+** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller. |
+** |
+** SQLITE_OK is returned if no error occurs (even if the mapping is not |
+** recreated as a result of outstanding references) or an SQLite error |
+** code otherwise. |
+*/ |
+static int unixMapfile(unixFile *pFd, i64 nMap){ |
+ assert( nMap>=0 || pFd->nFetchOut==0 ); |
+ assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) ); |
+ if( pFd->nFetchOut>0 ) return SQLITE_OK; |
+ |
+ if( nMap<0 ){ |
+ struct stat statbuf; /* Low-level file information */ |
+ if( osFstat(pFd->h, &statbuf) ){ |
+ return SQLITE_IOERR_FSTAT; |
+ } |
+ nMap = statbuf.st_size; |
+ } |
+ if( nMap>pFd->mmapSizeMax ){ |
+ nMap = pFd->mmapSizeMax; |
+ } |
+ |
+ assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) ); |
+ if( nMap!=pFd->mmapSize ){ |
+ unixRemapfile(pFd, nMap); |
+ } |
+ |
+ return SQLITE_OK; |
+} |
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */ |
+ |
+/* |
+** If possible, return a pointer to a mapping of file fd starting at offset |
+** iOff. The mapping must be valid for at least nAmt bytes. |
+** |
+** If such a pointer can be obtained, store it in *pp and return SQLITE_OK. |
+** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK. |
+** Finally, if an error does occur, return an SQLite error code. The final |
+** value of *pp is undefined in this case. |
+** |
+** If this function does return a pointer, the caller must eventually |
+** release the reference by calling unixUnfetch(). |
+*/ |
+static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ unixFile *pFd = (unixFile *)fd; /* The underlying database file */ |
+#endif |
+ *pp = 0; |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ if( pFd->mmapSizeMax>0 ){ |
+ if( pFd->pMapRegion==0 ){ |
+ int rc = unixMapfile(pFd, -1); |
+ if( rc!=SQLITE_OK ) return rc; |
+ } |
+ if( pFd->mmapSize >= iOff+nAmt ){ |
+ *pp = &((u8 *)pFd->pMapRegion)[iOff]; |
+ pFd->nFetchOut++; |
+ } |
+ } |
+#endif |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** If the third argument is non-NULL, then this function releases a |
+** reference obtained by an earlier call to unixFetch(). The second |
+** argument passed to this function must be the same as the corresponding |
+** argument that was passed to the unixFetch() invocation. |
+** |
+** Or, if the third argument is NULL, then this function is being called |
+** to inform the VFS layer that, according to POSIX, any existing mapping |
+** may now be invalid and should be unmapped. |
+*/ |
+static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ unixFile *pFd = (unixFile *)fd; /* The underlying database file */ |
+ UNUSED_PARAMETER(iOff); |
+ |
+ /* If p==0 (unmap the entire file) then there must be no outstanding |
+ ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), |
+ ** then there must be at least one outstanding. */ |
+ assert( (p==0)==(pFd->nFetchOut==0) ); |
+ |
+ /* If p!=0, it must match the iOff value. */ |
+ assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] ); |
+ |
+ if( p ){ |
+ pFd->nFetchOut--; |
+ }else{ |
+ unixUnmapfile(pFd); |
+ } |
+ |
+ assert( pFd->nFetchOut>=0 ); |
+#else |
+ UNUSED_PARAMETER(fd); |
+ UNUSED_PARAMETER(p); |
+ UNUSED_PARAMETER(iOff); |
+#endif |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Here ends the implementation of all sqlite3_file methods. |
+** |
+********************** End sqlite3_file Methods ******************************* |
+******************************************************************************/ |
+ |
+/* |
+** This division contains definitions of sqlite3_io_methods objects that |
+** implement various file locking strategies. It also contains definitions |
+** of "finder" functions. A finder-function is used to locate the appropriate |
+** sqlite3_io_methods object for a particular database file. The pAppData |
+** field of the sqlite3_vfs VFS objects are initialized to be pointers to |
+** the correct finder-function for that VFS. |
+** |
+** Most finder functions return a pointer to a fixed sqlite3_io_methods |
+** object. The only interesting finder-function is autolockIoFinder, which |
+** looks at the filesystem type and tries to guess the best locking |
+** strategy from that. |
+** |
+** For finder-function F, two objects are created: |
+** |
+** (1) The real finder-function named "FImpt()". |
+** |
+** (2) A constant pointer to this function named just "F". |
+** |
+** |
+** A pointer to the F pointer is used as the pAppData value for VFS |
+** objects. We have to do this instead of letting pAppData point |
+** directly at the finder-function since C90 rules prevent a void* |
+** from be cast into a function pointer. |
+** |
+** |
+** Each instance of this macro generates two objects: |
+** |
+** * A constant sqlite3_io_methods object call METHOD that has locking |
+** methods CLOSE, LOCK, UNLOCK, CKRESLOCK. |
+** |
+** * An I/O method finder function called FINDER that returns a pointer |
+** to the METHOD object in the previous bullet. |
+*/ |
+#define IOMETHODS(FINDER,METHOD,VERSION,CLOSE,LOCK,UNLOCK,CKLOCK,SHMMAP) \ |
+static const sqlite3_io_methods METHOD = { \ |
+ VERSION, /* iVersion */ \ |
+ CLOSE, /* xClose */ \ |
+ unixRead, /* xRead */ \ |
+ unixWrite, /* xWrite */ \ |
+ unixTruncate, /* xTruncate */ \ |
+ unixSync, /* xSync */ \ |
+ unixFileSize, /* xFileSize */ \ |
+ LOCK, /* xLock */ \ |
+ UNLOCK, /* xUnlock */ \ |
+ CKLOCK, /* xCheckReservedLock */ \ |
+ unixFileControl, /* xFileControl */ \ |
+ unixSectorSize, /* xSectorSize */ \ |
+ unixDeviceCharacteristics, /* xDeviceCapabilities */ \ |
+ SHMMAP, /* xShmMap */ \ |
+ unixShmLock, /* xShmLock */ \ |
+ unixShmBarrier, /* xShmBarrier */ \ |
+ unixShmUnmap, /* xShmUnmap */ \ |
+ unixFetch, /* xFetch */ \ |
+ unixUnfetch, /* xUnfetch */ \ |
+}; \ |
+static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \ |
+ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \ |
+ return &METHOD; \ |
+} \ |
+static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \ |
+ = FINDER##Impl; |
+ |
+/* |
+** Here are all of the sqlite3_io_methods objects for each of the |
+** locking strategies. Functions that return pointers to these methods |
+** are also created. |
+*/ |
+IOMETHODS( |
+ posixIoFinder, /* Finder function name */ |
+ posixIoMethods, /* sqlite3_io_methods object name */ |
+ 3, /* shared memory and mmap are enabled */ |
+ unixClose, /* xClose method */ |
+ unixLock, /* xLock method */ |
+ unixUnlock, /* xUnlock method */ |
+ unixCheckReservedLock, /* xCheckReservedLock method */ |
+ unixShmMap /* xShmMap method */ |
+) |
+IOMETHODS( |
+ nolockIoFinder, /* Finder function name */ |
+ nolockIoMethods, /* sqlite3_io_methods object name */ |
+ 3, /* shared memory is disabled */ |
+ nolockClose, /* xClose method */ |
+ nolockLock, /* xLock method */ |
+ nolockUnlock, /* xUnlock method */ |
+ nolockCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
+) |
+IOMETHODS( |
+ dotlockIoFinder, /* Finder function name */ |
+ dotlockIoMethods, /* sqlite3_io_methods object name */ |
+ 1, /* shared memory is disabled */ |
+ dotlockClose, /* xClose method */ |
+ dotlockLock, /* xLock method */ |
+ dotlockUnlock, /* xUnlock method */ |
+ dotlockCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
+) |
+ |
+#if SQLITE_ENABLE_LOCKING_STYLE |
+IOMETHODS( |
+ flockIoFinder, /* Finder function name */ |
+ flockIoMethods, /* sqlite3_io_methods object name */ |
+ 1, /* shared memory is disabled */ |
+ flockClose, /* xClose method */ |
+ flockLock, /* xLock method */ |
+ flockUnlock, /* xUnlock method */ |
+ flockCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
+) |
+#endif |
+ |
+#if OS_VXWORKS |
+IOMETHODS( |
+ semIoFinder, /* Finder function name */ |
+ semIoMethods, /* sqlite3_io_methods object name */ |
+ 1, /* shared memory is disabled */ |
+ semXClose, /* xClose method */ |
+ semXLock, /* xLock method */ |
+ semXUnlock, /* xUnlock method */ |
+ semXCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
+) |
+#endif |
+ |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+IOMETHODS( |
+ afpIoFinder, /* Finder function name */ |
+ afpIoMethods, /* sqlite3_io_methods object name */ |
+ 1, /* shared memory is disabled */ |
+ afpClose, /* xClose method */ |
+ afpLock, /* xLock method */ |
+ afpUnlock, /* xUnlock method */ |
+ afpCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
+) |
+#endif |
+ |
+/* |
+** The proxy locking method is a "super-method" in the sense that it |
+** opens secondary file descriptors for the conch and lock files and |
+** it uses proxy, dot-file, AFP, and flock() locking methods on those |
+** secondary files. For this reason, the division that implements |
+** proxy locking is located much further down in the file. But we need |
+** to go ahead and define the sqlite3_io_methods and finder function |
+** for proxy locking here. So we forward declare the I/O methods. |
+*/ |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+static int proxyClose(sqlite3_file*); |
+static int proxyLock(sqlite3_file*, int); |
+static int proxyUnlock(sqlite3_file*, int); |
+static int proxyCheckReservedLock(sqlite3_file*, int*); |
+IOMETHODS( |
+ proxyIoFinder, /* Finder function name */ |
+ proxyIoMethods, /* sqlite3_io_methods object name */ |
+ 1, /* shared memory is disabled */ |
+ proxyClose, /* xClose method */ |
+ proxyLock, /* xLock method */ |
+ proxyUnlock, /* xUnlock method */ |
+ proxyCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
+) |
+#endif |
+ |
+/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */ |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+IOMETHODS( |
+ nfsIoFinder, /* Finder function name */ |
+ nfsIoMethods, /* sqlite3_io_methods object name */ |
+ 1, /* shared memory is disabled */ |
+ unixClose, /* xClose method */ |
+ unixLock, /* xLock method */ |
+ nfsUnlock, /* xUnlock method */ |
+ unixCheckReservedLock, /* xCheckReservedLock method */ |
+ 0 /* xShmMap method */ |
+) |
+#endif |
+ |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+/* |
+** This "finder" function attempts to determine the best locking strategy |
+** for the database file "filePath". It then returns the sqlite3_io_methods |
+** object that implements that strategy. |
+** |
+** This is for MacOSX only. |
+*/ |
+static const sqlite3_io_methods *autolockIoFinderImpl( |
+ const char *filePath, /* name of the database file */ |
+ unixFile *pNew /* open file object for the database file */ |
+){ |
+ static const struct Mapping { |
+ const char *zFilesystem; /* Filesystem type name */ |
+ const sqlite3_io_methods *pMethods; /* Appropriate locking method */ |
+ } aMap[] = { |
+ { "hfs", &posixIoMethods }, |
+ { "ufs", &posixIoMethods }, |
+ { "afpfs", &afpIoMethods }, |
+ { "smbfs", &afpIoMethods }, |
+ { "webdav", &nolockIoMethods }, |
+ { 0, 0 } |
+ }; |
+ int i; |
+ struct statfs fsInfo; |
+ struct flock lockInfo; |
+ |
+ if( !filePath ){ |
+ /* If filePath==NULL that means we are dealing with a transient file |
+ ** that does not need to be locked. */ |
+ return &nolockIoMethods; |
+ } |
+ if( statfs(filePath, &fsInfo) != -1 ){ |
+ if( fsInfo.f_flags & MNT_RDONLY ){ |
+ return &nolockIoMethods; |
+ } |
+ for(i=0; aMap[i].zFilesystem; i++){ |
+ if( strcmp(fsInfo.f_fstypename, aMap[i].zFilesystem)==0 ){ |
+ return aMap[i].pMethods; |
+ } |
+ } |
+ } |
+ |
+ /* Default case. Handles, amongst others, "nfs". |
+ ** Test byte-range lock using fcntl(). If the call succeeds, |
+ ** assume that the file-system supports POSIX style locks. |
+ */ |
+ lockInfo.l_len = 1; |
+ lockInfo.l_start = 0; |
+ lockInfo.l_whence = SEEK_SET; |
+ lockInfo.l_type = F_RDLCK; |
+ if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) { |
+ if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){ |
+ return &nfsIoMethods; |
+ } else { |
+ return &posixIoMethods; |
+ } |
+ }else{ |
+ return &dotlockIoMethods; |
+ } |
+} |
+static const sqlite3_io_methods |
+ *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; |
+ |
+#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ |
+ |
+#if OS_VXWORKS |
+/* |
+** This "finder" function for VxWorks checks to see if posix advisory |
+** locking works. If it does, then that is what is used. If it does not |
+** work, then fallback to named semaphore locking. |
+*/ |
+static const sqlite3_io_methods *vxworksIoFinderImpl( |
+ const char *filePath, /* name of the database file */ |
+ unixFile *pNew /* the open file object */ |
+){ |
+ struct flock lockInfo; |
+ |
+ if( !filePath ){ |
+ /* If filePath==NULL that means we are dealing with a transient file |
+ ** that does not need to be locked. */ |
+ return &nolockIoMethods; |
+ } |
+ |
+ /* Test if fcntl() is supported and use POSIX style locks. |
+ ** Otherwise fall back to the named semaphore method. |
+ */ |
+ lockInfo.l_len = 1; |
+ lockInfo.l_start = 0; |
+ lockInfo.l_whence = SEEK_SET; |
+ lockInfo.l_type = F_RDLCK; |
+ if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) { |
+ return &posixIoMethods; |
+ }else{ |
+ return &semIoMethods; |
+ } |
+} |
+static const sqlite3_io_methods |
+ *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl; |
+ |
+#endif /* OS_VXWORKS */ |
+ |
+/* |
+** An abstract type for a pointer to an IO method finder function: |
+*/ |
+typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); |
+ |
+ |
+/**************************************************************************** |
+**************************** sqlite3_vfs methods **************************** |
+** |
+** This division contains the implementation of methods on the |
+** sqlite3_vfs object. |
+*/ |
+ |
+/* |
+** Initialize the contents of the unixFile structure pointed to by pId. |
+*/ |
+static int fillInUnixFile( |
+ sqlite3_vfs *pVfs, /* Pointer to vfs object */ |
+ int h, /* Open file descriptor of file being opened */ |
+ sqlite3_file *pId, /* Write to the unixFile structure here */ |
+ const char *zFilename, /* Name of the file being opened */ |
+ int ctrlFlags /* Zero or more UNIXFILE_* values */ |
+){ |
+ const sqlite3_io_methods *pLockingStyle; |
+ unixFile *pNew = (unixFile *)pId; |
+ int rc = SQLITE_OK; |
+ |
+ assert( pNew->pInode==NULL ); |
+ |
+ /* Usually the path zFilename should not be a relative pathname. The |
+ ** exception is when opening the proxy "conch" file in builds that |
+ ** include the special Apple locking styles. |
+ */ |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+ assert( zFilename==0 || zFilename[0]=='/' |
+ || pVfs->pAppData==(void*)&autolockIoFinder ); |
+#else |
+ assert( zFilename==0 || zFilename[0]=='/' ); |
+#endif |
+ |
+ /* No locking occurs in temporary files */ |
+ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); |
+ |
+ OSTRACE(("OPEN %-3d %s\n", h, zFilename)); |
+ pNew->h = h; |
+ pNew->pVfs = pVfs; |
+ pNew->zPath = zFilename; |
+ pNew->ctrlFlags = (u8)ctrlFlags; |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap; |
+#endif |
+ if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), |
+ "psow", SQLITE_POWERSAFE_OVERWRITE) ){ |
+ pNew->ctrlFlags |= UNIXFILE_PSOW; |
+ } |
+ if( strcmp(pVfs->zName,"unix-excl")==0 ){ |
+ pNew->ctrlFlags |= UNIXFILE_EXCL; |
+ } |
+ |
+#if OS_VXWORKS |
+ pNew->pId = vxworksFindFileId(zFilename); |
+ if( pNew->pId==0 ){ |
+ ctrlFlags |= UNIXFILE_NOLOCK; |
+ rc = SQLITE_NOMEM_BKPT; |
+ } |
+#endif |
+ |
+ if( ctrlFlags & UNIXFILE_NOLOCK ){ |
+ pLockingStyle = &nolockIoMethods; |
+ }else{ |
+ pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew); |
+#if SQLITE_ENABLE_LOCKING_STYLE |
+ /* Cache zFilename in the locking context (AFP and dotlock override) for |
+ ** proxyLock activation is possible (remote proxy is based on db name) |
+ ** zFilename remains valid until file is closed, to support */ |
+ pNew->lockingContext = (void*)zFilename; |
+#endif |
+ } |
+ |
+ if( pLockingStyle == &posixIoMethods |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+ || pLockingStyle == &nfsIoMethods |
+#endif |
+ ){ |
+ unixEnterMutex(); |
+ rc = findInodeInfo(pNew, &pNew->pInode); |
+ if( rc!=SQLITE_OK ){ |
+ /* If an error occurred in findInodeInfo(), close the file descriptor |
+ ** immediately, before releasing the mutex. findInodeInfo() may fail |
+ ** in two scenarios: |
+ ** |
+ ** (a) A call to fstat() failed. |
+ ** (b) A malloc failed. |
+ ** |
+ ** Scenario (b) may only occur if the process is holding no other |
+ ** file descriptors open on the same file. If there were other file |
+ ** descriptors on this file, then no malloc would be required by |
+ ** findInodeInfo(). If this is the case, it is quite safe to close |
+ ** handle h - as it is guaranteed that no posix locks will be released |
+ ** by doing so. |
+ ** |
+ ** If scenario (a) caused the error then things are not so safe. The |
+ ** implicit assumption here is that if fstat() fails, things are in |
+ ** such bad shape that dropping a lock or two doesn't matter much. |
+ */ |
+ robust_close(pNew, h, __LINE__); |
+ h = -1; |
+ } |
+ unixLeaveMutex(); |
+ } |
+ |
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) |
+ else if( pLockingStyle == &afpIoMethods ){ |
+ /* AFP locking uses the file path so it needs to be included in |
+ ** the afpLockingContext. |
+ */ |
+ afpLockingContext *pCtx; |
+ pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) ); |
+ if( pCtx==0 ){ |
+ rc = SQLITE_NOMEM_BKPT; |
+ }else{ |
+ /* NB: zFilename exists and remains valid until the file is closed |
+ ** according to requirement F11141. So we do not need to make a |
+ ** copy of the filename. */ |
+ pCtx->dbPath = zFilename; |
+ pCtx->reserved = 0; |
+ srandomdev(); |
+ unixEnterMutex(); |
+ rc = findInodeInfo(pNew, &pNew->pInode); |
+ if( rc!=SQLITE_OK ){ |
+ sqlite3_free(pNew->lockingContext); |
+ robust_close(pNew, h, __LINE__); |
+ h = -1; |
+ } |
+ unixLeaveMutex(); |
+ } |
+ } |
+#endif |
+ |
+ else if( pLockingStyle == &dotlockIoMethods ){ |
+ /* Dotfile locking uses the file path so it needs to be included in |
+ ** the dotlockLockingContext |
+ */ |
+ char *zLockFile; |
+ int nFilename; |
+ assert( zFilename!=0 ); |
+ nFilename = (int)strlen(zFilename) + 6; |
+ zLockFile = (char *)sqlite3_malloc64(nFilename); |
+ if( zLockFile==0 ){ |
+ rc = SQLITE_NOMEM_BKPT; |
+ }else{ |
+ sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename); |
+ } |
+ pNew->lockingContext = zLockFile; |
+ } |
+ |
+#if OS_VXWORKS |
+ else if( pLockingStyle == &semIoMethods ){ |
+ /* Named semaphore locking uses the file path so it needs to be |
+ ** included in the semLockingContext |
+ */ |
+ unixEnterMutex(); |
+ rc = findInodeInfo(pNew, &pNew->pInode); |
+ if( (rc==SQLITE_OK) && (pNew->pInode->pSem==NULL) ){ |
+ char *zSemName = pNew->pInode->aSemName; |
+ int n; |
+ sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem", |
+ pNew->pId->zCanonicalName); |
+ for( n=1; zSemName[n]; n++ ) |
+ if( zSemName[n]=='/' ) zSemName[n] = '_'; |
+ pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1); |
+ if( pNew->pInode->pSem == SEM_FAILED ){ |
+ rc = SQLITE_NOMEM_BKPT; |
+ pNew->pInode->aSemName[0] = '\0'; |
+ } |
+ } |
+ unixLeaveMutex(); |
+ } |
+#endif |
+ |
+ storeLastErrno(pNew, 0); |
+#if OS_VXWORKS |
+ if( rc!=SQLITE_OK ){ |
+ if( h>=0 ) robust_close(pNew, h, __LINE__); |
+ h = -1; |
+ osUnlink(zFilename); |
+ pNew->ctrlFlags |= UNIXFILE_DELETE; |
+ } |
+#endif |
+ if( rc!=SQLITE_OK ){ |
+ if( h>=0 ) robust_close(pNew, h, __LINE__); |
+ }else{ |
+ pNew->pMethod = pLockingStyle; |
+ OpenCounter(+1); |
+ verifyDbFile(pNew); |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Return the name of a directory in which to put temporary files. |
+** If no suitable temporary file directory can be found, return NULL. |
+*/ |
+static const char *unixTempFileDir(void){ |
+ static const char *azDirs[] = { |
+ 0, |
+ 0, |
+ "/var/tmp", |
+ "/usr/tmp", |
+ "/tmp", |
+ "." |
+ }; |
+ unsigned int i = 0; |
+ struct stat buf; |
+ const char *zDir = sqlite3_temp_directory; |
+ |
+ if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); |
+ if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); |
+ while(1){ |
+ if( zDir!=0 |
+ && osStat(zDir, &buf)==0 |
+ && S_ISDIR(buf.st_mode) |
+ && osAccess(zDir, 03)==0 |
+ ){ |
+ return zDir; |
+ } |
+ if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break; |
+ zDir = azDirs[i++]; |
+ } |
+ return 0; |
+} |
+ |
+/* |
+** Create a temporary file name in zBuf. zBuf must be allocated |
+** by the calling process and must be big enough to hold at least |
+** pVfs->mxPathname bytes. |
+*/ |
+static int unixGetTempname(int nBuf, char *zBuf){ |
+ const char *zDir; |
+ int iLimit = 0; |
+ |
+ /* It's odd to simulate an io-error here, but really this is just |
+ ** using the io-error infrastructure to test that SQLite handles this |
+ ** function failing. |
+ */ |
+ zBuf[0] = 0; |
+ SimulateIOError( return SQLITE_IOERR ); |
+ |
+ zDir = unixTempFileDir(); |
+ if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH; |
+ do{ |
+ u64 r; |
+ sqlite3_randomness(sizeof(r), &r); |
+ assert( nBuf>2 ); |
+ zBuf[nBuf-2] = 0; |
+ sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c", |
+ zDir, r, 0); |
+ if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR; |
+ }while( osAccess(zBuf,0)==0 ); |
+ return SQLITE_OK; |
+} |
+ |
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) |
+/* |
+** Routine to transform a unixFile into a proxy-locking unixFile. |
+** Implementation in the proxy-lock division, but used by unixOpen() |
+** if SQLITE_PREFER_PROXY_LOCKING is defined. |
+*/ |
+static int proxyTransformUnixFile(unixFile*, const char*); |
+#endif |
+ |
+/* |
+** Search for an unused file descriptor that was opened on the database |
+** file (not a journal or master-journal file) identified by pathname |
+** zPath with SQLITE_OPEN_XXX flags matching those passed as the second |
+** argument to this function. |
+** |
+** Such a file descriptor may exist if a database connection was closed |
+** but the associated file descriptor could not be closed because some |
+** other file descriptor open on the same file is holding a file-lock. |
+** Refer to comments in the unixClose() function and the lengthy comment |
+** describing "Posix Advisory Locking" at the start of this file for |
+** further details. Also, ticket #4018. |
+** |
+** If a suitable file descriptor is found, then it is returned. If no |
+** such file descriptor is located, -1 is returned. |
+*/ |
+static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ |
+ UnixUnusedFd *pUnused = 0; |
+ |
+ /* Do not search for an unused file descriptor on vxworks. Not because |
+ ** vxworks would not benefit from the change (it might, we're not sure), |
+ ** but because no way to test it is currently available. It is better |
+ ** not to risk breaking vxworks support for the sake of such an obscure |
+ ** feature. */ |
+#if !OS_VXWORKS |
+ struct stat sStat; /* Results of stat() call */ |
+ |
+ /* A stat() call may fail for various reasons. If this happens, it is |
+ ** almost certain that an open() call on the same path will also fail. |
+ ** For this reason, if an error occurs in the stat() call here, it is |
+ ** ignored and -1 is returned. The caller will try to open a new file |
+ ** descriptor on the same path, fail, and return an error to SQLite. |
+ ** |
+ ** Even if a subsequent open() call does succeed, the consequences of |
+ ** not searching for a reusable file descriptor are not dire. */ |
+ if( 0==osStat(zPath, &sStat) ){ |
+ unixInodeInfo *pInode; |
+ |
+ unixEnterMutex(); |
+ pInode = inodeList; |
+ while( pInode && (pInode->fileId.dev!=sStat.st_dev |
+ || pInode->fileId.ino!=(u64)sStat.st_ino) ){ |
+ pInode = pInode->pNext; |
+ } |
+ if( pInode ){ |
+ UnixUnusedFd **pp; |
+ for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); |
+ pUnused = *pp; |
+ if( pUnused ){ |
+ *pp = pUnused->pNext; |
+ } |
+ } |
+ unixLeaveMutex(); |
+ } |
+#endif /* if !OS_VXWORKS */ |
+ return pUnused; |
+} |
+ |
+/* |
+** Find the mode, uid and gid of file zFile. |
+*/ |
+static int getFileMode( |
+ const char *zFile, /* File name */ |
+ mode_t *pMode, /* OUT: Permissions of zFile */ |
+ uid_t *pUid, /* OUT: uid of zFile. */ |
+ gid_t *pGid /* OUT: gid of zFile. */ |
+){ |
+ struct stat sStat; /* Output of stat() on database file */ |
+ int rc = SQLITE_OK; |
+ if( 0==osStat(zFile, &sStat) ){ |
+ *pMode = sStat.st_mode & 0777; |
+ *pUid = sStat.st_uid; |
+ *pGid = sStat.st_gid; |
+ }else{ |
+ rc = SQLITE_IOERR_FSTAT; |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** This function is called by unixOpen() to determine the unix permissions |
+** to create new files with. If no error occurs, then SQLITE_OK is returned |
+** and a value suitable for passing as the third argument to open(2) is |
+** written to *pMode. If an IO error occurs, an SQLite error code is |
+** returned and the value of *pMode is not modified. |
+** |
+** In most cases, this routine sets *pMode to 0, which will become |
+** an indication to robust_open() to create the file using |
+** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask. |
+** But if the file being opened is a WAL or regular journal file, then |
+** this function queries the file-system for the permissions on the |
+** corresponding database file and sets *pMode to this value. Whenever |
+** possible, WAL and journal files are created using the same permissions |
+** as the associated database file. |
+** |
+** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the |
+** original filename is unavailable. But 8_3_NAMES is only used for |
+** FAT filesystems and permissions do not matter there, so just use |
+** the default permissions. |
+*/ |
+static int findCreateFileMode( |
+ const char *zPath, /* Path of file (possibly) being created */ |
+ int flags, /* Flags passed as 4th argument to xOpen() */ |
+ mode_t *pMode, /* OUT: Permissions to open file with */ |
+ uid_t *pUid, /* OUT: uid to set on the file */ |
+ gid_t *pGid /* OUT: gid to set on the file */ |
+){ |
+ int rc = SQLITE_OK; /* Return Code */ |
+ *pMode = 0; |
+ *pUid = 0; |
+ *pGid = 0; |
+ if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ |
+ char zDb[MAX_PATHNAME+1]; /* Database file path */ |
+ int nDb; /* Number of valid bytes in zDb */ |
+ |
+ /* zPath is a path to a WAL or journal file. The following block derives |
+ ** the path to the associated database file from zPath. This block handles |
+ ** the following naming conventions: |
+ ** |
+ ** "<path to db>-journal" |
+ ** "<path to db>-wal" |
+ ** "<path to db>-journalNN" |
+ ** "<path to db>-walNN" |
+ ** |
+ ** where NN is a decimal number. The NN naming schemes are |
+ ** used by the test_multiplex.c module. |
+ */ |
+ nDb = sqlite3Strlen30(zPath) - 1; |
+ while( zPath[nDb]!='-' ){ |
+#ifndef SQLITE_ENABLE_8_3_NAMES |
+ /* In the normal case (8+3 filenames disabled) the journal filename |
+ ** is guaranteed to contain a '-' character. */ |
+ assert( nDb>0 ); |
+ assert( sqlite3Isalnum(zPath[nDb]) ); |
+#else |
+ /* If 8+3 names are possible, then the journal file might not contain |
+ ** a '-' character. So check for that case and return early. */ |
+ if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; |
+#endif |
+ nDb--; |
+ } |
+ memcpy(zDb, zPath, nDb); |
+ zDb[nDb] = '\0'; |
+ |
+ rc = getFileMode(zDb, pMode, pUid, pGid); |
+ }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ |
+ *pMode = 0600; |
+ }else if( flags & SQLITE_OPEN_URI ){ |
+ /* If this is a main database file and the file was opened using a URI |
+ ** filename, check for the "modeof" parameter. If present, interpret |
+ ** its value as a filename and try to copy the mode, uid and gid from |
+ ** that file. */ |
+ const char *z = sqlite3_uri_parameter(zPath, "modeof"); |
+ if( z ){ |
+ rc = getFileMode(z, pMode, pUid, pGid); |
+ } |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Initialize |unixFile| internals of |file| on behalf of chromiumOpen() in |
+** WebDatabase SQLiteFileSystemPosix.cpp. Function is a subset of unixOpen(), |
+** each duplicated piece is marked by "Duplicated in" comment in unixOpen(). |
+*/ |
+CHROMIUM_SQLITE_API |
+int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs, |
+ int fd, |
+ sqlite3_file* pFile, |
+ const char* zPath, |
+ int noLock, |
+ int flags) { |
+ unixFile *p = (unixFile *)pFile; |
+ const int eType = flags&0xFFFFFF00; /* Type of file to open */ |
+ const int ctrlFlags = (noLock ? UNIXFILE_NOLOCK : 0); |
+ int rc; |
+ |
+ memset(p, 0, sizeof(unixFile)); |
+ |
+ /* osStat() will not work in the sandbox, so findReusableFd() will always |
+ ** fail, so directly include the failure-case setup then initialize pUnused. |
+ */ |
+ if( eType==SQLITE_OPEN_MAIN_DB ){ |
+ p->pUnused = sqlite3_malloc(sizeof(*p->pUnused)); |
+ if (!p->pUnused) { |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ p->pUnused->fd = fd; |
+ p->pUnused->flags = flags; |
+ } |
+ |
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); |
+ if( rc!=SQLITE_OK ){ |
+ sqlite3_free(p->pUnused); |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Open the file zPath. |
+** |
+** Previously, the SQLite OS layer used three functions in place of this |
+** one: |
+** |
+** sqlite3OsOpenReadWrite(); |
+** sqlite3OsOpenReadOnly(); |
+** sqlite3OsOpenExclusive(); |
+** |
+** These calls correspond to the following combinations of flags: |
+** |
+** ReadWrite() -> (READWRITE | CREATE) |
+** ReadOnly() -> (READONLY) |
+** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE) |
+** |
+** The old OpenExclusive() accepted a boolean argument - "delFlag". If |
+** true, the file was configured to be automatically deleted when the |
+** file handle closed. To achieve the same effect using this new |
+** interface, add the DELETEONCLOSE flag to those specified above for |
+** OpenExclusive(). |
+*/ |
+static int unixOpen( |
+ sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */ |
+ const char *zPath, /* Pathname of file to be opened */ |
+ sqlite3_file *pFile, /* The file descriptor to be filled in */ |
+ int flags, /* Input flags to control the opening */ |
+ int *pOutFlags /* Output flags returned to SQLite core */ |
+){ |
+ unixFile *p = (unixFile *)pFile; |
+ int fd = -1; /* File descriptor returned by open() */ |
+ int openFlags = 0; /* Flags to pass to open() */ |
+ int eType = flags&0xFFFFFF00; /* Type of file to open */ |
+ int noLock; /* True to omit locking primitives */ |
+ int rc = SQLITE_OK; /* Function Return Code */ |
+ int ctrlFlags = 0; /* UNIXFILE_* flags */ |
+ |
+ int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); |
+ int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); |
+ int isCreate = (flags & SQLITE_OPEN_CREATE); |
+ int isReadonly = (flags & SQLITE_OPEN_READONLY); |
+ int isReadWrite = (flags & SQLITE_OPEN_READWRITE); |
+#if SQLITE_ENABLE_LOCKING_STYLE |
+ int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY); |
+#endif |
+#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE |
+ struct statfs fsInfo; |
+#endif |
+ |
+ /* If creating a master or main-file journal, this function will open |
+ ** a file-descriptor on the directory too. The first time unixSync() |
+ ** is called the directory file descriptor will be fsync()ed and close()d. |
+ */ |
+ int syncDir = (isCreate && ( |
+ eType==SQLITE_OPEN_MASTER_JOURNAL |
+ || eType==SQLITE_OPEN_MAIN_JOURNAL |
+ || eType==SQLITE_OPEN_WAL |
+ )); |
+ |
+ /* If argument zPath is a NULL pointer, this function is required to open |
+ ** a temporary file. Use this buffer to store the file name in. |
+ */ |
+ char zTmpname[MAX_PATHNAME+2]; |
+ const char *zName = zPath; |
+ |
+ /* Check the following statements are true: |
+ ** |
+ ** (a) Exactly one of the READWRITE and READONLY flags must be set, and |
+ ** (b) if CREATE is set, then READWRITE must also be set, and |
+ ** (c) if EXCLUSIVE is set, then CREATE must also be set. |
+ ** (d) if DELETEONCLOSE is set, then CREATE must also be set. |
+ */ |
+ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); |
+ assert(isCreate==0 || isReadWrite); |
+ assert(isExclusive==0 || isCreate); |
+ assert(isDelete==0 || isCreate); |
+ |
+ /* The main DB, main journal, WAL file and master journal are never |
+ ** automatically deleted. Nor are they ever temporary files. */ |
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); |
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); |
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL ); |
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); |
+ |
+ /* Assert that the upper layer has set one of the "file-type" flags. */ |
+ 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 |
+ ); |
+ |
+ /* Detect a pid change and reset the PRNG. There is a race condition |
+ ** here such that two or more threads all trying to open databases at |
+ ** the same instant might all reset the PRNG. But multiple resets |
+ ** are harmless. |
+ */ |
+ if( randomnessPid!=osGetpid(0) ){ |
+ randomnessPid = osGetpid(0); |
+ sqlite3_randomness(0,0); |
+ } |
+ |
+ /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */ |
+ memset(p, 0, sizeof(unixFile)); |
+ |
+ if( eType==SQLITE_OPEN_MAIN_DB ){ |
+ UnixUnusedFd *pUnused; |
+ pUnused = findReusableFd(zName, flags); |
+ if( pUnused ){ |
+ fd = pUnused->fd; |
+ }else{ |
+ /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */ |
+ pUnused = sqlite3_malloc64(sizeof(*pUnused)); |
+ if( !pUnused ){ |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ } |
+ p->pUnused = pUnused; |
+ |
+ /* Database filenames are double-zero terminated if they are not |
+ ** URIs with parameters. Hence, they can always be passed into |
+ ** sqlite3_uri_parameter(). */ |
+ assert( (flags & SQLITE_OPEN_URI) || zName[strlen(zName)+1]==0 ); |
+ |
+ }else if( !zName ){ |
+ /* If zName is NULL, the upper layer is requesting a temp file. */ |
+ assert(isDelete && !syncDir); |
+ rc = unixGetTempname(pVfs->mxPathname, zTmpname); |
+ if( rc!=SQLITE_OK ){ |
+ return rc; |
+ } |
+ zName = zTmpname; |
+ |
+ /* Generated temporary filenames are always double-zero terminated |
+ ** for use by sqlite3_uri_parameter(). */ |
+ assert( zName[strlen(zName)+1]==0 ); |
+ } |
+ |
+ /* Determine the value of the flags parameter passed to POSIX function |
+ ** open(). These must be calculated even if open() is not called, as |
+ ** they may be stored as part of the file handle and used by the |
+ ** 'conch file' locking functions later on. */ |
+ if( isReadonly ) openFlags |= O_RDONLY; |
+ if( isReadWrite ) openFlags |= O_RDWR; |
+ if( isCreate ) openFlags |= O_CREAT; |
+ if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW); |
+ openFlags |= (O_LARGEFILE|O_BINARY); |
+ |
+ if( fd<0 ){ |
+ mode_t openMode; /* Permissions to create file with */ |
+ uid_t uid; /* Userid for the file */ |
+ gid_t gid; /* Groupid for the file */ |
+ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid); |
+ if( rc!=SQLITE_OK ){ |
+ assert( !p->pUnused ); |
+ assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); |
+ return rc; |
+ } |
+ fd = robust_open(zName, openFlags, openMode); |
+ OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags)); |
+ assert( !isExclusive || (openFlags & O_CREAT)!=0 ); |
+ if( fd<0 && errno!=EISDIR && isReadWrite ){ |
+ /* Failed to open the file for read/write access. Try read-only. */ |
+ flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); |
+ openFlags &= ~(O_RDWR|O_CREAT); |
+ flags |= SQLITE_OPEN_READONLY; |
+ openFlags |= O_RDONLY; |
+ isReadonly = 1; |
+ fd = robust_open(zName, openFlags, openMode); |
+ } |
+ if( fd<0 ){ |
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); |
+ goto open_finished; |
+ } |
+ |
+ /* If this process is running as root and if creating a new rollback |
+ ** journal or WAL file, set the ownership of the journal or WAL to be |
+ ** the same as the original database. |
+ */ |
+ if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ |
+ robustFchown(fd, uid, gid); |
+ } |
+ } |
+ assert( fd>=0 ); |
+ if( pOutFlags ){ |
+ *pOutFlags = flags; |
+ } |
+ |
+ if( p->pUnused ){ |
+ /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */ |
+ p->pUnused->fd = fd; |
+ p->pUnused->flags = flags; |
+ } |
+ |
+ if( isDelete ){ |
+#if OS_VXWORKS |
+ zPath = zName; |
+#elif defined(SQLITE_UNLINK_AFTER_CLOSE) |
+ zPath = sqlite3_mprintf("%s", zName); |
+ if( zPath==0 ){ |
+ robust_close(p, fd, __LINE__); |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+#else |
+ osUnlink(zName); |
+#endif |
+ } |
+#if SQLITE_ENABLE_LOCKING_STYLE |
+ else{ |
+ p->openFlags = openFlags; |
+ } |
+#endif |
+ |
+#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE |
+ if( fstatfs(fd, &fsInfo) == -1 ){ |
+ storeLastErrno(p, errno); |
+ robust_close(p, fd, __LINE__); |
+ return SQLITE_IOERR_ACCESS; |
+ } |
+ if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { |
+ ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; |
+ } |
+ if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) { |
+ ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS; |
+ } |
+#endif |
+ |
+ /* Set up appropriate ctrlFlags */ |
+ if( isDelete ) ctrlFlags |= UNIXFILE_DELETE; |
+ if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY; |
+ noLock = eType!=SQLITE_OPEN_MAIN_DB; |
+ if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK; |
+ if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC; |
+ if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI; |
+ |
+#if SQLITE_ENABLE_LOCKING_STYLE |
+#if SQLITE_PREFER_PROXY_LOCKING |
+ isAutoProxy = 1; |
+#endif |
+ if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){ |
+ char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING"); |
+ int useProxy = 0; |
+ |
+ /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means |
+ ** never use proxy, NULL means use proxy for non-local files only. */ |
+ if( envforce!=NULL ){ |
+ useProxy = atoi(envforce)>0; |
+ }else{ |
+ useProxy = !(fsInfo.f_flags&MNT_LOCAL); |
+ } |
+ if( useProxy ){ |
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); |
+ if( rc==SQLITE_OK ){ |
+ rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); |
+ if( rc!=SQLITE_OK ){ |
+ /* Use unixClose to clean up the resources added in fillInUnixFile |
+ ** and clear all the structure's references. Specifically, |
+ ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op |
+ */ |
+ unixClose(pFile); |
+ return rc; |
+ } |
+ } |
+ goto open_finished; |
+ } |
+ } |
+#endif |
+ |
+ /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */ |
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); |
+ |
+open_finished: |
+ if( rc!=SQLITE_OK ){ |
+ /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */ |
+ sqlite3_free(p->pUnused); |
+ } |
+ return rc; |
+} |
+ |
+ |
+/* |
+** Delete the file at zPath. If the dirSync argument is true, fsync() |
+** the directory after deleting the file. |
+*/ |
+static int unixDelete( |
+ sqlite3_vfs *NotUsed, /* VFS containing this as the xDelete method */ |
+ const char *zPath, /* Name of file to be deleted */ |
+ int dirSync /* If true, fsync() directory after deleting file */ |
+){ |
+ int rc = SQLITE_OK; |
+ UNUSED_PARAMETER(NotUsed); |
+ SimulateIOError(return SQLITE_IOERR_DELETE); |
+ if( osUnlink(zPath)==(-1) ){ |
+ if( errno==ENOENT |
+#if OS_VXWORKS |
+ || osAccess(zPath,0)!=0 |
+#endif |
+ ){ |
+ rc = SQLITE_IOERR_DELETE_NOENT; |
+ }else{ |
+ rc = unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath); |
+ } |
+ return rc; |
+ } |
+#ifndef SQLITE_DISABLE_DIRSYNC |
+ if( (dirSync & 1)!=0 ){ |
+ int fd; |
+ rc = osOpenDirectory(zPath, &fd); |
+ if( rc==SQLITE_OK ){ |
+ if( full_fsync(fd,0,0) ){ |
+ rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); |
+ } |
+ robust_close(0, fd, __LINE__); |
+ }else{ |
+ assert( rc==SQLITE_CANTOPEN ); |
+ rc = SQLITE_OK; |
+ } |
+ } |
+#endif |
+ return rc; |
+} |
+ |
+/* |
+** Test the existence of or access permissions of file zPath. The |
+** test performed depends on the value of flags: |
+** |
+** SQLITE_ACCESS_EXISTS: Return 1 if the file exists |
+** SQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable. |
+** SQLITE_ACCESS_READONLY: Return 1 if the file is readable. |
+** |
+** Otherwise return 0. |
+*/ |
+static int unixAccess( |
+ sqlite3_vfs *NotUsed, /* The VFS containing this xAccess method */ |
+ const char *zPath, /* Path of the file to examine */ |
+ int flags, /* What do we want to learn about the zPath file? */ |
+ int *pResOut /* Write result boolean here */ |
+){ |
+ UNUSED_PARAMETER(NotUsed); |
+ SimulateIOError( return SQLITE_IOERR_ACCESS; ); |
+ assert( pResOut!=0 ); |
+ |
+ /* The spec says there are three possible values for flags. But only |
+ ** two of them are actually used */ |
+ assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE ); |
+ |
+ if( flags==SQLITE_ACCESS_EXISTS ){ |
+ struct stat buf; |
+ *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0); |
+ }else{ |
+ *pResOut = osAccess(zPath, W_OK|R_OK)==0; |
+ } |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** |
+*/ |
+static int mkFullPathname( |
+ const char *zPath, /* Input path */ |
+ char *zOut, /* Output buffer */ |
+ int nOut /* Allocated size of buffer zOut */ |
+){ |
+ int nPath = sqlite3Strlen30(zPath); |
+ int iOff = 0; |
+ if( zPath[0]!='/' ){ |
+ if( osGetcwd(zOut, nOut-2)==0 ){ |
+ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); |
+ } |
+ iOff = sqlite3Strlen30(zOut); |
+ zOut[iOff++] = '/'; |
+ } |
+ if( (iOff+nPath+1)>nOut ){ |
+ /* SQLite assumes that xFullPathname() nul-terminates the output buffer |
+ ** even if it returns an error. */ |
+ zOut[iOff] = '\0'; |
+ return SQLITE_CANTOPEN_BKPT; |
+ } |
+ sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Turn a relative pathname into a full pathname. The relative path |
+** is stored as a nul-terminated string in the buffer pointed to by |
+** zPath. |
+** |
+** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes |
+** (in this case, MAX_PATHNAME bytes). The full-path is written to |
+** this buffer before returning. |
+*/ |
+static int unixFullPathname( |
+ sqlite3_vfs *pVfs, /* Pointer to vfs object */ |
+ const char *zPath, /* Possibly relative input path */ |
+ int nOut, /* Size of output buffer in bytes */ |
+ char *zOut /* Output buffer */ |
+){ |
+#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) |
+ return mkFullPathname(zPath, zOut, nOut); |
+#else |
+ int rc = SQLITE_OK; |
+ int nByte; |
+ int nLink = 1; /* Number of symbolic links followed so far */ |
+ const char *zIn = zPath; /* Input path for each iteration of loop */ |
+ char *zDel = 0; |
+ |
+ assert( pVfs->mxPathname==MAX_PATHNAME ); |
+ UNUSED_PARAMETER(pVfs); |
+ |
+ /* 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. This function could fail if, for example, the |
+ ** current working directory has been unlinked. |
+ */ |
+ SimulateIOError( return SQLITE_ERROR ); |
+ |
+ do { |
+ |
+ /* Call stat() on path zIn. Set bLink to true if the path is a symbolic |
+ ** link, or false otherwise. */ |
+ int bLink = 0; |
+ struct stat buf; |
+ if( osLstat(zIn, &buf)!=0 ){ |
+ if( errno!=ENOENT ){ |
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); |
+ } |
+ }else{ |
+ bLink = S_ISLNK(buf.st_mode); |
+ } |
+ |
+ if( bLink ){ |
+ if( zDel==0 ){ |
+ zDel = sqlite3_malloc(nOut); |
+ if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; |
+ }else if( ++nLink>SQLITE_MAX_SYMLINKS ){ |
+ rc = SQLITE_CANTOPEN_BKPT; |
+ } |
+ |
+ if( rc==SQLITE_OK ){ |
+ nByte = osReadlink(zIn, zDel, nOut-1); |
+ if( nByte<0 ){ |
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); |
+ }else{ |
+ if( zDel[0]!='/' ){ |
+ int n; |
+ for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); |
+ if( nByte+n+1>nOut ){ |
+ rc = SQLITE_CANTOPEN_BKPT; |
+ }else{ |
+ memmove(&zDel[n], zDel, nByte+1); |
+ memcpy(zDel, zIn, n); |
+ nByte += n; |
+ } |
+ } |
+ zDel[nByte] = '\0'; |
+ } |
+ } |
+ |
+ zIn = zDel; |
+ } |
+ |
+ assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); |
+ if( rc==SQLITE_OK && zIn!=zOut ){ |
+ rc = mkFullPathname(zIn, zOut, nOut); |
+ } |
+ if( bLink==0 ) break; |
+ zIn = zOut; |
+ }while( rc==SQLITE_OK ); |
+ |
+ sqlite3_free(zDel); |
+ return rc; |
+#endif /* HAVE_READLINK && HAVE_LSTAT */ |
+} |
+ |
+ |
+#ifndef SQLITE_OMIT_LOAD_EXTENSION |
+/* |
+** Interfaces for opening a shared library, finding entry points |
+** within the shared library, and closing the shared library. |
+*/ |
+#include <dlfcn.h> |
+static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){ |
+ UNUSED_PARAMETER(NotUsed); |
+ return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL); |
+} |
+ |
+/* |
+** SQLite calls this function immediately after a call to unixDlSym() or |
+** unixDlOpen() fails (returns a null pointer). If a more detailed error |
+** message is available, it is written to zBufOut. If no error message |
+** is available, zBufOut is left unmodified and SQLite uses a default |
+** error message. |
+*/ |
+static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){ |
+ const char *zErr; |
+ UNUSED_PARAMETER(NotUsed); |
+ unixEnterMutex(); |
+ zErr = dlerror(); |
+ if( zErr ){ |
+ sqlite3_snprintf(nBuf, zBufOut, "%s", zErr); |
+ } |
+ unixLeaveMutex(); |
+} |
+static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){ |
+ /* |
+ ** GCC with -pedantic-errors says that C90 does not allow a void* to be |
+ ** cast into a pointer to a function. And yet the library dlsym() routine |
+ ** returns a void* which is really a pointer to a function. So how do we |
+ ** use dlsym() with -pedantic-errors? |
+ ** |
+ ** Variable x below is defined to be a pointer to a function taking |
+ ** parameters void* and const char* and returning a pointer to a function. |
+ ** We initialize x by assigning it a pointer to the dlsym() function. |
+ ** (That assignment requires a cast.) Then we call the function that |
+ ** x points to. |
+ ** |
+ ** This work-around is unlikely to work correctly on any system where |
+ ** you really cannot cast a function pointer into void*. But then, on the |
+ ** other hand, dlsym() will not work on such a system either, so we have |
+ ** not really lost anything. |
+ */ |
+ void (*(*x)(void*,const char*))(void); |
+ UNUSED_PARAMETER(NotUsed); |
+ x = (void(*(*)(void*,const char*))(void))dlsym; |
+ return (*x)(p, zSym); |
+} |
+static void unixDlClose(sqlite3_vfs *NotUsed, void *pHandle){ |
+ UNUSED_PARAMETER(NotUsed); |
+ dlclose(pHandle); |
+} |
+#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ |
+ #define unixDlOpen 0 |
+ #define unixDlError 0 |
+ #define unixDlSym 0 |
+ #define unixDlClose 0 |
+#endif |
+ |
+/* |
+** Write nBuf bytes of random data to the supplied buffer zBuf. |
+*/ |
+static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){ |
+ UNUSED_PARAMETER(NotUsed); |
+ assert((size_t)nBuf>=(sizeof(time_t)+sizeof(int))); |
+ |
+ /* We have to initialize zBuf to prevent valgrind from reporting |
+ ** errors. The reports issued by valgrind are incorrect - we would |
+ ** prefer that the randomness be increased by making use of the |
+ ** uninitialized space in zBuf - but valgrind errors tend to worry |
+ ** some users. Rather than argue, it seems easier just to initialize |
+ ** the whole array and silence valgrind, even if that means less randomness |
+ ** in the random seed. |
+ ** |
+ ** When testing, initializing zBuf[] to zero is all we do. That means |
+ ** that we always use the same random number sequence. This makes the |
+ ** tests repeatable. |
+ */ |
+ memset(zBuf, 0, nBuf); |
+ randomnessPid = osGetpid(0); |
+#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) |
+ { |
+ int fd, got; |
+ fd = robust_open("/dev/urandom", O_RDONLY, 0); |
+ if( fd<0 ){ |
+ time_t t; |
+ time(&t); |
+ memcpy(zBuf, &t, sizeof(t)); |
+ memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid)); |
+ assert( sizeof(t)+sizeof(randomnessPid)<=(size_t)nBuf ); |
+ nBuf = sizeof(t) + sizeof(randomnessPid); |
+ }else{ |
+ do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR ); |
+ robust_close(0, fd, __LINE__); |
+ } |
+ } |
+#endif |
+ return nBuf; |
+} |
+ |
+ |
+/* |
+** Sleep for a little while. Return the amount of time slept. |
+** The argument is the number of microseconds we want to sleep. |
+** The return value is the number of microseconds of sleep actually |
+** requested from the underlying operating system, a number which |
+** might be greater than or equal to the argument, but not less |
+** than the argument. |
+*/ |
+static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ |
+#if OS_VXWORKS |
+ struct timespec sp; |
+ |
+ sp.tv_sec = microseconds / 1000000; |
+ sp.tv_nsec = (microseconds % 1000000) * 1000; |
+ nanosleep(&sp, NULL); |
+ UNUSED_PARAMETER(NotUsed); |
+ return microseconds; |
+#elif defined(HAVE_USLEEP) && HAVE_USLEEP |
+ usleep(microseconds); |
+ UNUSED_PARAMETER(NotUsed); |
+ return microseconds; |
+#else |
+ int seconds = (microseconds+999999)/1000000; |
+ sleep(seconds); |
+ UNUSED_PARAMETER(NotUsed); |
+ return seconds*1000000; |
+#endif |
+} |
+ |
+/* |
+** The following variable, if set to a non-zero value, is interpreted as |
+** the number of seconds since 1970 and is used to set the result of |
+** sqlite3OsCurrentTime() during testing. |
+*/ |
+#ifdef SQLITE_TEST |
+SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ |
+#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 SQLITE_OK. Return SQLITE_ERROR if the time and date |
+** cannot be found. |
+*/ |
+static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ |
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; |
+ int rc = SQLITE_OK; |
+#if defined(NO_GETTOD) |
+ time_t t; |
+ time(&t); |
+ *piNow = ((sqlite3_int64)t)*1000 + unixEpoch; |
+#elif OS_VXWORKS |
+ struct timespec sNow; |
+ clock_gettime(CLOCK_REALTIME, &sNow); |
+ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000; |
+#else |
+ struct timeval sNow; |
+ (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */ |
+ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000; |
+#endif |
+ |
+#ifdef SQLITE_TEST |
+ if( sqlite3_current_time ){ |
+ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; |
+ } |
+#endif |
+ UNUSED_PARAMETER(NotUsed); |
+ return rc; |
+} |
+ |
+#ifndef SQLITE_OMIT_DEPRECATED |
+/* |
+** 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 unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){ |
+ sqlite3_int64 i = 0; |
+ int rc; |
+ UNUSED_PARAMETER(NotUsed); |
+ rc = unixCurrentTimeInt64(0, &i); |
+ *prNow = i/86400000.0; |
+ return rc; |
+} |
+#else |
+# define unixCurrentTime 0 |
+#endif |
+ |
+/* |
+** The xGetLastError() method is designed to return a better |
+** low-level error message when operating-system problems come up |
+** during SQLite operation. Only the integer return code is currently |
+** used. |
+*/ |
+static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ |
+ UNUSED_PARAMETER(NotUsed); |
+ UNUSED_PARAMETER(NotUsed2); |
+ UNUSED_PARAMETER(NotUsed3); |
+ return errno; |
+} |
+ |
+ |
+/* |
+************************ End of sqlite3_vfs methods *************************** |
+******************************************************************************/ |
+ |
+/****************************************************************************** |
+************************** Begin Proxy Locking ******************************** |
+** |
+** Proxy locking is a "uber-locking-method" in this sense: It uses the |
+** other locking methods on secondary lock files. Proxy locking is a |
+** meta-layer over top of the primitive locking implemented above. For |
+** this reason, the division that implements of proxy locking is deferred |
+** until late in the file (here) after all of the other I/O methods have |
+** been defined - so that the primitive locking methods are available |
+** as services to help with the implementation of proxy locking. |
+** |
+**** |
+** |
+** The default locking schemes in SQLite use byte-range locks on the |
+** database file to coordinate safe, concurrent access by multiple readers |
+** and writers [http://sqlite.org/lockingv3.html]. The five file locking |
+** states (UNLOCKED, PENDING, SHARED, RESERVED, EXCLUSIVE) are implemented |
+** as POSIX read & write locks over fixed set of locations (via fsctl), |
+** on AFP and SMB only exclusive byte-range locks are available via fsctl |
+** with _IOWR('z', 23, struct ByteRangeLockPB2) to track the same 5 states. |
+** To simulate a F_RDLCK on the shared range, on AFP a randomly selected |
+** address in the shared range is taken for a SHARED lock, the entire |
+** shared range is taken for an EXCLUSIVE lock): |
+** |
+** PENDING_BYTE 0x40000000 |
+** RESERVED_BYTE 0x40000001 |
+** SHARED_RANGE 0x40000002 -> 0x40000200 |
+** |
+** This works well on the local file system, but shows a nearly 100x |
+** slowdown in read performance on AFP because the AFP client disables |
+** the read cache when byte-range locks are present. Enabling the read |
+** cache exposes a cache coherency problem that is present on all OS X |
+** supported network file systems. NFS and AFP both observe the |
+** close-to-open semantics for ensuring cache coherency |
+** [http://nfs.sourceforge.net/#faq_a8], which does not effectively |
+** address the requirements for concurrent database access by multiple |
+** readers and writers |
+** [http://www.nabble.com/SQLite-on-NFS-cache-coherency-td15655701.html]. |
+** |
+** To address the performance and cache coherency issues, proxy file locking |
+** changes the way database access is controlled by limiting access to a |
+** single host at a time and moving file locks off of the database file |
+** and onto a proxy file on the local file system. |
+** |
+** |
+** Using proxy locks |
+** ----------------- |
+** |
+** C APIs |
+** |
+** sqlite3_file_control(db, dbname, SQLITE_FCNTL_SET_LOCKPROXYFILE, |
+** <proxy_path> | ":auto:"); |
+** sqlite3_file_control(db, dbname, SQLITE_FCNTL_GET_LOCKPROXYFILE, |
+** &<proxy_path>); |
+** |
+** |
+** SQL pragmas |
+** |
+** PRAGMA [database.]lock_proxy_file=<proxy_path> | :auto: |
+** PRAGMA [database.]lock_proxy_file |
+** |
+** Specifying ":auto:" means that if there is a conch file with a matching |
+** host ID in it, the proxy path in the conch file will be used, otherwise |
+** a proxy path based on the user's temp dir |
+** (via confstr(_CS_DARWIN_USER_TEMP_DIR,...)) will be used and the |
+** actual proxy file name is generated from the name and path of the |
+** database file. For example: |
+** |
+** For database path "/Users/me/foo.db" |
+** The lock path will be "<tmpdir>/sqliteplocks/_Users_me_foo.db:auto:") |
+** |
+** Once a lock proxy is configured for a database connection, it can not |
+** be removed, however it may be switched to a different proxy path via |
+** the above APIs (assuming the conch file is not being held by another |
+** connection or process). |
+** |
+** |
+** How proxy locking works |
+** ----------------------- |
+** |
+** Proxy file locking relies primarily on two new supporting files: |
+** |
+** * conch file to limit access to the database file to a single host |
+** at a time |
+** |
+** * proxy file to act as a proxy for the advisory locks normally |
+** taken on the database |
+** |
+** The conch file - to use a proxy file, sqlite must first "hold the conch" |
+** by taking an sqlite-style shared lock on the conch file, reading the |
+** contents and comparing the host's unique host ID (see below) and lock |
+** proxy path against the values stored in the conch. The conch file is |
+** stored in the same directory as the database file and the file name |
+** is patterned after the database file name as ".<databasename>-conch". |
+** If the conch file does not exist, or its contents do not match the |
+** host ID and/or proxy path, then the lock is escalated to an exclusive |
+** lock and the conch file contents is updated with the host ID and proxy |
+** path and the lock is downgraded to a shared lock again. If the conch |
+** is held by another process (with a shared lock), the exclusive lock |
+** will fail and SQLITE_BUSY is returned. |
+** |
+** The proxy file - a single-byte file used for all advisory file locks |
+** normally taken on the database file. This allows for safe sharing |
+** of the database file for multiple readers and writers on the same |
+** host (the conch ensures that they all use the same local lock file). |
+** |
+** Requesting the lock proxy does not immediately take the conch, it is |
+** only taken when the first request to lock database file is made. |
+** This matches the semantics of the traditional locking behavior, where |
+** opening a connection to a database file does not take a lock on it. |
+** The shared lock and an open file descriptor are maintained until |
+** the connection to the database is closed. |
+** |
+** The proxy file and the lock file are never deleted so they only need |
+** to be created the first time they are used. |
+** |
+** Configuration options |
+** --------------------- |
+** |
+** SQLITE_PREFER_PROXY_LOCKING |
+** |
+** Database files accessed on non-local file systems are |
+** automatically configured for proxy locking, lock files are |
+** named automatically using the same logic as |
+** PRAGMA lock_proxy_file=":auto:" |
+** |
+** SQLITE_PROXY_DEBUG |
+** |
+** Enables the logging of error messages during host id file |
+** retrieval and creation |
+** |
+** LOCKPROXYDIR |
+** |
+** Overrides the default directory used for lock proxy files that |
+** are named automatically via the ":auto:" setting |
+** |
+** SQLITE_DEFAULT_PROXYDIR_PERMISSIONS |
+** |
+** Permissions to use when creating a directory for storing the |
+** lock proxy files, only used when LOCKPROXYDIR is not set. |
+** |
+** |
+** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING, |
+** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will |
+** force proxy locking to be used for every database file opened, and 0 |
+** will force automatic proxy locking to be disabled for all database |
+** files (explicitly calling the SQLITE_FCNTL_SET_LOCKPROXYFILE pragma or |
+** sqlite_file_control API is not affected by SQLITE_FORCE_PROXY_LOCKING). |
+*/ |
+ |
+/* |
+** Proxy locking is only available on MacOSX |
+*/ |
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+ |
+/* |
+** The proxyLockingContext has the path and file structures for the remote |
+** and local proxy files in it |
+*/ |
+typedef struct proxyLockingContext proxyLockingContext; |
+struct proxyLockingContext { |
+ unixFile *conchFile; /* Open conch file */ |
+ char *conchFilePath; /* Name of the conch file */ |
+ unixFile *lockProxy; /* Open proxy lock file */ |
+ char *lockProxyPath; /* Name of the proxy lock file */ |
+ char *dbPath; /* Name of the open file */ |
+ int conchHeld; /* 1 if the conch is held, -1 if lockless */ |
+ int nFails; /* Number of conch taking failures */ |
+ void *oldLockingContext; /* Original lockingcontext to restore on close */ |
+ sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */ |
+}; |
+ |
+/* |
+** The proxy lock file path for the database at dbPath is written into lPath, |
+** which must point to valid, writable memory large enough for a maxLen length |
+** file path. |
+*/ |
+static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ |
+ int len; |
+ int dbLen; |
+ int i; |
+ |
+#ifdef LOCKPROXYDIR |
+ len = strlcpy(lPath, LOCKPROXYDIR, maxLen); |
+#else |
+# ifdef _CS_DARWIN_USER_TEMP_DIR |
+ { |
+ if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ |
+ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", |
+ lPath, errno, osGetpid(0))); |
+ return SQLITE_IOERR_LOCK; |
+ } |
+ len = strlcat(lPath, "sqliteplocks", maxLen); |
+ } |
+# else |
+ len = strlcpy(lPath, "/tmp/", maxLen); |
+# endif |
+#endif |
+ |
+ if( lPath[len-1]!='/' ){ |
+ len = strlcat(lPath, "/", maxLen); |
+ } |
+ |
+ /* transform the db path to a unique cache name */ |
+ dbLen = (int)strlen(dbPath); |
+ for( i=0; i<dbLen && (i+len+7)<(int)maxLen; i++){ |
+ char c = dbPath[i]; |
+ lPath[i+len] = (c=='/')?'_':c; |
+ } |
+ lPath[i+len]='\0'; |
+ strlcat(lPath, ":auto:", maxLen); |
+ OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, osGetpid(0))); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+ ** Creates the lock file and any missing directories in lockPath |
+ */ |
+static int proxyCreateLockPath(const char *lockPath){ |
+ int i, len; |
+ char buf[MAXPATHLEN]; |
+ int start = 0; |
+ |
+ assert(lockPath!=NULL); |
+ /* try to create all the intermediate directories */ |
+ len = (int)strlen(lockPath); |
+ buf[0] = lockPath[0]; |
+ for( i=1; i<len; i++ ){ |
+ if( lockPath[i] == '/' && (i - start > 0) ){ |
+ /* only mkdir if leaf dir != "." or "/" or ".." */ |
+ if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/') |
+ || (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){ |
+ buf[i]='\0'; |
+ if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ |
+ int err=errno; |
+ if( err!=EEXIST ) { |
+ OSTRACE(("CREATELOCKPATH FAILED creating %s, " |
+ "'%s' proxy lock path=%s pid=%d\n", |
+ buf, strerror(err), lockPath, osGetpid(0))); |
+ return err; |
+ } |
+ } |
+ } |
+ start=i+1; |
+ } |
+ buf[i] = lockPath[i]; |
+ } |
+ OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n",lockPath,osGetpid(0))); |
+ return 0; |
+} |
+ |
+/* |
+** Create a new VFS file descriptor (stored in memory obtained from |
+** sqlite3_malloc) and open the file named "path" in the file descriptor. |
+** |
+** The caller is responsible not only for closing the file descriptor |
+** but also for freeing the memory associated with the file descriptor. |
+*/ |
+static int proxyCreateUnixFile( |
+ const char *path, /* path for the new unixFile */ |
+ unixFile **ppFile, /* unixFile created and returned by ref */ |
+ int islockfile /* if non zero missing dirs will be created */ |
+) { |
+ int fd = -1; |
+ unixFile *pNew; |
+ int rc = SQLITE_OK; |
+ int openFlags = O_RDWR | O_CREAT; |
+ sqlite3_vfs dummyVfs; |
+ int terrno = 0; |
+ UnixUnusedFd *pUnused = NULL; |
+ |
+ /* 1. first try to open/create the file |
+ ** 2. if that fails, and this is a lock file (not-conch), try creating |
+ ** the parent directories and then try again. |
+ ** 3. if that fails, try to open the file read-only |
+ ** otherwise return BUSY (if lock file) or CANTOPEN for the conch file |
+ */ |
+ pUnused = findReusableFd(path, openFlags); |
+ if( pUnused ){ |
+ fd = pUnused->fd; |
+ }else{ |
+ pUnused = sqlite3_malloc64(sizeof(*pUnused)); |
+ if( !pUnused ){ |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ } |
+ if( fd<0 ){ |
+ fd = robust_open(path, openFlags, 0); |
+ terrno = errno; |
+ if( fd<0 && errno==ENOENT && islockfile ){ |
+ if( proxyCreateLockPath(path) == SQLITE_OK ){ |
+ fd = robust_open(path, openFlags, 0); |
+ } |
+ } |
+ } |
+ if( fd<0 ){ |
+ openFlags = O_RDONLY; |
+ fd = robust_open(path, openFlags, 0); |
+ terrno = errno; |
+ } |
+ if( fd<0 ){ |
+ if( islockfile ){ |
+ return SQLITE_BUSY; |
+ } |
+ switch (terrno) { |
+ case EACCES: |
+ return SQLITE_PERM; |
+ case EIO: |
+ return SQLITE_IOERR_LOCK; /* even though it is the conch */ |
+ default: |
+ return SQLITE_CANTOPEN_BKPT; |
+ } |
+ } |
+ |
+ pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew)); |
+ if( pNew==NULL ){ |
+ rc = SQLITE_NOMEM_BKPT; |
+ goto end_create_proxy; |
+ } |
+ memset(pNew, 0, sizeof(unixFile)); |
+ pNew->openFlags = openFlags; |
+ memset(&dummyVfs, 0, sizeof(dummyVfs)); |
+ dummyVfs.pAppData = (void*)&autolockIoFinder; |
+ dummyVfs.zName = "dummy"; |
+ pUnused->fd = fd; |
+ pUnused->flags = openFlags; |
+ pNew->pUnused = pUnused; |
+ |
+ rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0); |
+ if( rc==SQLITE_OK ){ |
+ *ppFile = pNew; |
+ return SQLITE_OK; |
+ } |
+end_create_proxy: |
+ robust_close(pNew, fd, __LINE__); |
+ sqlite3_free(pNew); |
+ sqlite3_free(pUnused); |
+ return rc; |
+} |
+ |
+#ifdef SQLITE_TEST |
+/* simulate multiple hosts by creating unique hostid file paths */ |
+SQLITE_API int sqlite3_hostid_num = 0; |
+#endif |
+ |
+#define PROXY_HOSTIDLEN 16 /* conch file host id length */ |
+ |
+#ifdef HAVE_GETHOSTUUID |
+/* Not always defined in the headers as it ought to be */ |
+extern int gethostuuid(uuid_t id, const struct timespec *wait); |
+#endif |
+ |
+/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN |
+** bytes of writable memory. |
+*/ |
+static int proxyGetHostID(unsigned char *pHostID, int *pError){ |
+ assert(PROXY_HOSTIDLEN == sizeof(uuid_t)); |
+ memset(pHostID, 0, PROXY_HOSTIDLEN); |
+#ifdef HAVE_GETHOSTUUID |
+ { |
+ struct timespec timeout = {1, 0}; /* 1 sec timeout */ |
+ if( gethostuuid(pHostID, &timeout) ){ |
+ int err = errno; |
+ if( pError ){ |
+ *pError = err; |
+ } |
+ return SQLITE_IOERR; |
+ } |
+ } |
+#else |
+ UNUSED_PARAMETER(pError); |
+#endif |
+#ifdef SQLITE_TEST |
+ /* simulate multiple hosts by creating unique hostid file paths */ |
+ if( sqlite3_hostid_num != 0){ |
+ pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF)); |
+ } |
+#endif |
+ |
+ return SQLITE_OK; |
+} |
+ |
+/* The conch file contains the header, host id and lock file path |
+ */ |
+#define PROXY_CONCHVERSION 2 /* 1-byte header, 16-byte host id, path */ |
+#define PROXY_HEADERLEN 1 /* conch file header length */ |
+#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN) |
+#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN) |
+ |
+/* |
+** Takes an open conch file, copies the contents to a new path and then moves |
+** it back. The newly created file's file descriptor is assigned to the |
+** conch file structure and finally the original conch file descriptor is |
+** closed. Returns zero if successful. |
+*/ |
+static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ |
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; |
+ unixFile *conchFile = pCtx->conchFile; |
+ char tPath[MAXPATHLEN]; |
+ char buf[PROXY_MAXCONCHLEN]; |
+ char *cPath = pCtx->conchFilePath; |
+ size_t readLen = 0; |
+ size_t pathLen = 0; |
+ char errmsg[64] = ""; |
+ int fd = -1; |
+ int rc = -1; |
+ UNUSED_PARAMETER(myHostID); |
+ |
+ /* create a new path by replace the trailing '-conch' with '-break' */ |
+ pathLen = strlcpy(tPath, cPath, MAXPATHLEN); |
+ if( pathLen>MAXPATHLEN || pathLen<6 || |
+ (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){ |
+ sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen); |
+ goto end_breaklock; |
+ } |
+ /* read the conch content */ |
+ readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0); |
+ if( readLen<PROXY_PATHINDEX ){ |
+ sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen); |
+ goto end_breaklock; |
+ } |
+ /* write it out to the temporary break file */ |
+ fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), 0); |
+ if( fd<0 ){ |
+ sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno); |
+ goto end_breaklock; |
+ } |
+ if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){ |
+ sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno); |
+ goto end_breaklock; |
+ } |
+ if( rename(tPath, cPath) ){ |
+ sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno); |
+ goto end_breaklock; |
+ } |
+ rc = 0; |
+ fprintf(stderr, "broke stale lock on %s\n", cPath); |
+ robust_close(pFile, conchFile->h, __LINE__); |
+ conchFile->h = fd; |
+ conchFile->openFlags = O_RDWR | O_CREAT; |
+ |
+end_breaklock: |
+ if( rc ){ |
+ if( fd>=0 ){ |
+ osUnlink(tPath); |
+ robust_close(pFile, fd, __LINE__); |
+ } |
+ fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg); |
+ } |
+ return rc; |
+} |
+ |
+/* Take the requested lock on the conch file and break a stale lock if the |
+** host id matches. |
+*/ |
+static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ |
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; |
+ unixFile *conchFile = pCtx->conchFile; |
+ int rc = SQLITE_OK; |
+ int nTries = 0; |
+ struct timespec conchModTime; |
+ |
+ memset(&conchModTime, 0, sizeof(conchModTime)); |
+ do { |
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); |
+ nTries ++; |
+ if( rc==SQLITE_BUSY ){ |
+ /* If the lock failed (busy): |
+ * 1st try: get the mod time of the conch, wait 0.5s and try again. |
+ * 2nd try: fail if the mod time changed or host id is different, wait |
+ * 10 sec and try again |
+ * 3rd try: break the lock unless the mod time has changed. |
+ */ |
+ struct stat buf; |
+ if( osFstat(conchFile->h, &buf) ){ |
+ storeLastErrno(pFile, errno); |
+ return SQLITE_IOERR_LOCK; |
+ } |
+ |
+ if( nTries==1 ){ |
+ conchModTime = buf.st_mtimespec; |
+ usleep(500000); /* wait 0.5 sec and try the lock again*/ |
+ continue; |
+ } |
+ |
+ assert( nTries>1 ); |
+ if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || |
+ conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){ |
+ return SQLITE_BUSY; |
+ } |
+ |
+ if( nTries==2 ){ |
+ char tBuf[PROXY_MAXCONCHLEN]; |
+ int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); |
+ if( len<0 ){ |
+ storeLastErrno(pFile, errno); |
+ return SQLITE_IOERR_LOCK; |
+ } |
+ if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ |
+ /* don't break the lock if the host id doesn't match */ |
+ if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){ |
+ return SQLITE_BUSY; |
+ } |
+ }else{ |
+ /* don't break the lock on short read or a version mismatch */ |
+ return SQLITE_BUSY; |
+ } |
+ usleep(10000000); /* wait 10 sec and try the lock again */ |
+ continue; |
+ } |
+ |
+ assert( nTries==3 ); |
+ if( 0==proxyBreakConchLock(pFile, myHostID) ){ |
+ rc = SQLITE_OK; |
+ if( lockType==EXCLUSIVE_LOCK ){ |
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK); |
+ } |
+ if( !rc ){ |
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); |
+ } |
+ } |
+ } |
+ } while( rc==SQLITE_BUSY && nTries<3 ); |
+ |
+ return rc; |
+} |
+ |
+/* Takes the conch by taking a shared lock and read the contents conch, if |
+** lockPath is non-NULL, the host ID and lock file path must match. A NULL |
+** lockPath means that the lockPath in the conch file will be used if the |
+** host IDs match, or a new lock path will be generated automatically |
+** and written to the conch file. |
+*/ |
+static int proxyTakeConch(unixFile *pFile){ |
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; |
+ |
+ if( pCtx->conchHeld!=0 ){ |
+ return SQLITE_OK; |
+ }else{ |
+ unixFile *conchFile = pCtx->conchFile; |
+ uuid_t myHostID; |
+ int pError = 0; |
+ char readBuf[PROXY_MAXCONCHLEN]; |
+ char lockPath[MAXPATHLEN]; |
+ char *tempLockPath = NULL; |
+ int rc = SQLITE_OK; |
+ int createConch = 0; |
+ int hostIdMatch = 0; |
+ int readLen = 0; |
+ int tryOldLockPath = 0; |
+ int forceNewLockPath = 0; |
+ |
+ OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h, |
+ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), |
+ osGetpid(0))); |
+ |
+ rc = proxyGetHostID(myHostID, &pError); |
+ if( (rc&0xff)==SQLITE_IOERR ){ |
+ storeLastErrno(pFile, pError); |
+ goto end_takeconch; |
+ } |
+ rc = proxyConchLock(pFile, myHostID, SHARED_LOCK); |
+ if( rc!=SQLITE_OK ){ |
+ goto end_takeconch; |
+ } |
+ /* read the existing conch file */ |
+ readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN); |
+ if( readLen<0 ){ |
+ /* I/O error: lastErrno set by seekAndRead */ |
+ storeLastErrno(pFile, conchFile->lastErrno); |
+ rc = SQLITE_IOERR_READ; |
+ goto end_takeconch; |
+ }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || |
+ readBuf[0]!=(char)PROXY_CONCHVERSION ){ |
+ /* a short read or version format mismatch means we need to create a new |
+ ** conch file. |
+ */ |
+ createConch = 1; |
+ } |
+ /* if the host id matches and the lock path already exists in the conch |
+ ** we'll try to use the path there, if we can't open that path, we'll |
+ ** retry with a new auto-generated path |
+ */ |
+ do { /* in case we need to try again for an :auto: named lock file */ |
+ |
+ if( !createConch && !forceNewLockPath ){ |
+ hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID, |
+ PROXY_HOSTIDLEN); |
+ /* if the conch has data compare the contents */ |
+ if( !pCtx->lockProxyPath ){ |
+ /* for auto-named local lock file, just check the host ID and we'll |
+ ** use the local lock file path that's already in there |
+ */ |
+ if( hostIdMatch ){ |
+ size_t pathLen = (readLen - PROXY_PATHINDEX); |
+ |
+ if( pathLen>=MAXPATHLEN ){ |
+ pathLen=MAXPATHLEN-1; |
+ } |
+ memcpy(lockPath, &readBuf[PROXY_PATHINDEX], pathLen); |
+ lockPath[pathLen] = 0; |
+ tempLockPath = lockPath; |
+ tryOldLockPath = 1; |
+ /* create a copy of the lock path if the conch is taken */ |
+ goto end_takeconch; |
+ } |
+ }else if( hostIdMatch |
+ && !strncmp(pCtx->lockProxyPath, &readBuf[PROXY_PATHINDEX], |
+ readLen-PROXY_PATHINDEX) |
+ ){ |
+ /* conch host and lock path match */ |
+ goto end_takeconch; |
+ } |
+ } |
+ |
+ /* if the conch isn't writable and doesn't match, we can't take it */ |
+ if( (conchFile->openFlags&O_RDWR) == 0 ){ |
+ rc = SQLITE_BUSY; |
+ goto end_takeconch; |
+ } |
+ |
+ /* either the conch didn't match or we need to create a new one */ |
+ if( !pCtx->lockProxyPath ){ |
+ proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN); |
+ tempLockPath = lockPath; |
+ /* create a copy of the lock path _only_ if the conch is taken */ |
+ } |
+ |
+ /* update conch with host and path (this will fail if other process |
+ ** has a shared lock already), if the host id matches, use the big |
+ ** stick. |
+ */ |
+ futimes(conchFile->h, NULL); |
+ if( hostIdMatch && !createConch ){ |
+ if( conchFile->pInode && conchFile->pInode->nShared>1 ){ |
+ /* We are trying for an exclusive lock but another thread in this |
+ ** same process is still holding a shared lock. */ |
+ rc = SQLITE_BUSY; |
+ } else { |
+ rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK); |
+ } |
+ }else{ |
+ rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK); |
+ } |
+ if( rc==SQLITE_OK ){ |
+ char writeBuffer[PROXY_MAXCONCHLEN]; |
+ int writeSize = 0; |
+ |
+ writeBuffer[0] = (char)PROXY_CONCHVERSION; |
+ memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN); |
+ if( pCtx->lockProxyPath!=NULL ){ |
+ strlcpy(&writeBuffer[PROXY_PATHINDEX], pCtx->lockProxyPath, |
+ MAXPATHLEN); |
+ }else{ |
+ strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN); |
+ } |
+ writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]); |
+ robust_ftruncate(conchFile->h, writeSize); |
+ rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0); |
+ full_fsync(conchFile->h,0,0); |
+ /* If we created a new conch file (not just updated the contents of a |
+ ** valid conch file), try to match the permissions of the database |
+ */ |
+ if( rc==SQLITE_OK && createConch ){ |
+ struct stat buf; |
+ int err = osFstat(pFile->h, &buf); |
+ if( err==0 ){ |
+ mode_t cmode = buf.st_mode&(S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | |
+ S_IROTH|S_IWOTH); |
+ /* try to match the database file R/W permissions, ignore failure */ |
+#ifndef SQLITE_PROXY_DEBUG |
+ osFchmod(conchFile->h, cmode); |
+#else |
+ do{ |
+ rc = osFchmod(conchFile->h, cmode); |
+ }while( rc==(-1) && errno==EINTR ); |
+ if( rc!=0 ){ |
+ int code = errno; |
+ fprintf(stderr, "fchmod %o FAILED with %d %s\n", |
+ cmode, code, strerror(code)); |
+ } else { |
+ fprintf(stderr, "fchmod %o SUCCEDED\n",cmode); |
+ } |
+ }else{ |
+ int code = errno; |
+ fprintf(stderr, "STAT FAILED[%d] with %d %s\n", |
+ err, code, strerror(code)); |
+#endif |
+ } |
+ } |
+ } |
+ conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK); |
+ |
+ end_takeconch: |
+ OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h)); |
+ if( rc==SQLITE_OK && pFile->openFlags ){ |
+ int fd; |
+ if( pFile->h>=0 ){ |
+ robust_close(pFile, pFile->h, __LINE__); |
+ } |
+ pFile->h = -1; |
+ fd = robust_open(pCtx->dbPath, pFile->openFlags, 0); |
+ OSTRACE(("TRANSPROXY: OPEN %d\n", fd)); |
+ if( fd>=0 ){ |
+ pFile->h = fd; |
+ }else{ |
+ rc=SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called |
+ during locking */ |
+ } |
+ } |
+ if( rc==SQLITE_OK && !pCtx->lockProxy ){ |
+ char *path = tempLockPath ? tempLockPath : pCtx->lockProxyPath; |
+ rc = proxyCreateUnixFile(path, &pCtx->lockProxy, 1); |
+ if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && tryOldLockPath ){ |
+ /* we couldn't create the proxy lock file with the old lock file path |
+ ** so try again via auto-naming |
+ */ |
+ forceNewLockPath = 1; |
+ tryOldLockPath = 0; |
+ continue; /* go back to the do {} while start point, try again */ |
+ } |
+ } |
+ if( rc==SQLITE_OK ){ |
+ /* Need to make a copy of path if we extracted the value |
+ ** from the conch file or the path was allocated on the stack |
+ */ |
+ if( tempLockPath ){ |
+ pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath); |
+ if( !pCtx->lockProxyPath ){ |
+ rc = SQLITE_NOMEM_BKPT; |
+ } |
+ } |
+ } |
+ if( rc==SQLITE_OK ){ |
+ pCtx->conchHeld = 1; |
+ |
+ if( pCtx->lockProxy->pMethod == &afpIoMethods ){ |
+ afpLockingContext *afpCtx; |
+ afpCtx = (afpLockingContext *)pCtx->lockProxy->lockingContext; |
+ afpCtx->dbPath = pCtx->lockProxyPath; |
+ } |
+ } else { |
+ conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); |
+ } |
+ OSTRACE(("TAKECONCH %d %s\n", conchFile->h, |
+ rc==SQLITE_OK?"ok":"failed")); |
+ return rc; |
+ } while (1); /* in case we need to retry the :auto: lock file - |
+ ** we should never get here except via the 'continue' call. */ |
+ } |
+} |
+ |
+/* |
+** If pFile holds a lock on a conch file, then release that lock. |
+*/ |
+static int proxyReleaseConch(unixFile *pFile){ |
+ int rc = SQLITE_OK; /* Subroutine return code */ |
+ proxyLockingContext *pCtx; /* The locking context for the proxy lock */ |
+ unixFile *conchFile; /* Name of the conch file */ |
+ |
+ pCtx = (proxyLockingContext *)pFile->lockingContext; |
+ conchFile = pCtx->conchFile; |
+ OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h, |
+ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), |
+ osGetpid(0))); |
+ if( pCtx->conchHeld>0 ){ |
+ rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); |
+ } |
+ pCtx->conchHeld = 0; |
+ OSTRACE(("RELEASECONCH %d %s\n", conchFile->h, |
+ (rc==SQLITE_OK ? "ok" : "failed"))); |
+ return rc; |
+} |
+ |
+/* |
+** Given the name of a database file, compute the name of its conch file. |
+** Store the conch filename in memory obtained from sqlite3_malloc64(). |
+** Make *pConchPath point to the new name. Return SQLITE_OK on success |
+** or SQLITE_NOMEM if unable to obtain memory. |
+** |
+** The caller is responsible for ensuring that the allocated memory |
+** space is eventually freed. |
+** |
+** *pConchPath is set to NULL if a memory allocation error occurs. |
+*/ |
+static int proxyCreateConchPathname(char *dbPath, char **pConchPath){ |
+ int i; /* Loop counter */ |
+ int len = (int)strlen(dbPath); /* Length of database filename - dbPath */ |
+ char *conchPath; /* buffer in which to construct conch name */ |
+ |
+ /* Allocate space for the conch filename and initialize the name to |
+ ** the name of the original database file. */ |
+ *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8); |
+ if( conchPath==0 ){ |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ memcpy(conchPath, dbPath, len+1); |
+ |
+ /* now insert a "." before the last / character */ |
+ for( i=(len-1); i>=0; i-- ){ |
+ if( conchPath[i]=='/' ){ |
+ i++; |
+ break; |
+ } |
+ } |
+ conchPath[i]='.'; |
+ while ( i<len ){ |
+ conchPath[i+1]=dbPath[i]; |
+ i++; |
+ } |
+ |
+ /* append the "-conch" suffix to the file */ |
+ memcpy(&conchPath[i+1], "-conch", 7); |
+ assert( (int)strlen(conchPath) == len+7 ); |
+ |
+ return SQLITE_OK; |
+} |
+ |
+ |
+/* Takes a fully configured proxy locking-style unix file and switches |
+** the local lock file path |
+*/ |
+static int switchLockProxyPath(unixFile *pFile, const char *path) { |
+ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; |
+ char *oldPath = pCtx->lockProxyPath; |
+ int rc = SQLITE_OK; |
+ |
+ if( pFile->eFileLock!=NO_LOCK ){ |
+ return SQLITE_BUSY; |
+ } |
+ |
+ /* nothing to do if the path is NULL, :auto: or matches the existing path */ |
+ if( !path || path[0]=='\0' || !strcmp(path, ":auto:") || |
+ (oldPath && !strncmp(oldPath, path, MAXPATHLEN)) ){ |
+ return SQLITE_OK; |
+ }else{ |
+ unixFile *lockProxy = pCtx->lockProxy; |
+ pCtx->lockProxy=NULL; |
+ pCtx->conchHeld = 0; |
+ if( lockProxy!=NULL ){ |
+ rc=lockProxy->pMethod->xClose((sqlite3_file *)lockProxy); |
+ if( rc ) return rc; |
+ sqlite3_free(lockProxy); |
+ } |
+ sqlite3_free(oldPath); |
+ pCtx->lockProxyPath = sqlite3DbStrDup(0, path); |
+ } |
+ |
+ return rc; |
+} |
+ |
+/* |
+** pFile is a file that has been opened by a prior xOpen call. dbPath |
+** is a string buffer at least MAXPATHLEN+1 characters in size. |
+** |
+** This routine find the filename associated with pFile and writes it |
+** int dbPath. |
+*/ |
+static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){ |
+#if defined(__APPLE__) |
+ if( pFile->pMethod == &afpIoMethods ){ |
+ /* afp style keeps a reference to the db path in the filePath field |
+ ** of the struct */ |
+ assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); |
+ strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, |
+ MAXPATHLEN); |
+ } else |
+#endif |
+ if( pFile->pMethod == &dotlockIoMethods ){ |
+ /* dot lock style uses the locking context to store the dot lock |
+ ** file path */ |
+ int len = strlen((char *)pFile->lockingContext) - strlen(DOTLOCK_SUFFIX); |
+ memcpy(dbPath, (char *)pFile->lockingContext, len + 1); |
+ }else{ |
+ /* all other styles use the locking context to store the db file path */ |
+ assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); |
+ strlcpy(dbPath, (char *)pFile->lockingContext, MAXPATHLEN); |
+ } |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Takes an already filled in unix file and alters it so all file locking |
+** will be performed on the local proxy lock file. The following fields |
+** are preserved in the locking context so that they can be restored and |
+** the unix structure properly cleaned up at close time: |
+** ->lockingContext |
+** ->pMethod |
+*/ |
+static int proxyTransformUnixFile(unixFile *pFile, const char *path) { |
+ proxyLockingContext *pCtx; |
+ char dbPath[MAXPATHLEN+1]; /* Name of the database file */ |
+ char *lockPath=NULL; |
+ int rc = SQLITE_OK; |
+ |
+ if( pFile->eFileLock!=NO_LOCK ){ |
+ return SQLITE_BUSY; |
+ } |
+ proxyGetDbPathForUnixFile(pFile, dbPath); |
+ if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ){ |
+ lockPath=NULL; |
+ }else{ |
+ lockPath=(char *)path; |
+ } |
+ |
+ OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h, |
+ (lockPath ? lockPath : ":auto:"), osGetpid(0))); |
+ |
+ pCtx = sqlite3_malloc64( sizeof(*pCtx) ); |
+ if( pCtx==0 ){ |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ memset(pCtx, 0, sizeof(*pCtx)); |
+ |
+ rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath); |
+ if( rc==SQLITE_OK ){ |
+ rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile, 0); |
+ if( rc==SQLITE_CANTOPEN && ((pFile->openFlags&O_RDWR) == 0) ){ |
+ /* if (a) the open flags are not O_RDWR, (b) the conch isn't there, and |
+ ** (c) the file system is read-only, then enable no-locking access. |
+ ** Ugh, since O_RDONLY==0x0000 we test for !O_RDWR since unixOpen asserts |
+ ** that openFlags will have only one of O_RDONLY or O_RDWR. |
+ */ |
+ struct statfs fsInfo; |
+ struct stat conchInfo; |
+ int goLockless = 0; |
+ |
+ if( osStat(pCtx->conchFilePath, &conchInfo) == -1 ) { |
+ int err = errno; |
+ if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){ |
+ goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY; |
+ } |
+ } |
+ if( goLockless ){ |
+ pCtx->conchHeld = -1; /* read only FS/ lockless */ |
+ rc = SQLITE_OK; |
+ } |
+ } |
+ } |
+ if( rc==SQLITE_OK && lockPath ){ |
+ pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath); |
+ } |
+ |
+ if( rc==SQLITE_OK ){ |
+ pCtx->dbPath = sqlite3DbStrDup(0, dbPath); |
+ if( pCtx->dbPath==NULL ){ |
+ rc = SQLITE_NOMEM_BKPT; |
+ } |
+ } |
+ if( rc==SQLITE_OK ){ |
+ /* all memory is allocated, proxys are created and assigned, |
+ ** switch the locking context and pMethod then return. |
+ */ |
+ pCtx->oldLockingContext = pFile->lockingContext; |
+ pFile->lockingContext = pCtx; |
+ pCtx->pOldMethod = pFile->pMethod; |
+ pFile->pMethod = &proxyIoMethods; |
+ }else{ |
+ if( pCtx->conchFile ){ |
+ pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile); |
+ sqlite3_free(pCtx->conchFile); |
+ } |
+ sqlite3DbFree(0, pCtx->lockProxyPath); |
+ sqlite3_free(pCtx->conchFilePath); |
+ sqlite3_free(pCtx); |
+ } |
+ OSTRACE(("TRANSPROXY %d %s\n", pFile->h, |
+ (rc==SQLITE_OK ? "ok" : "failed"))); |
+ return rc; |
+} |
+ |
+ |
+/* |
+** This routine handles sqlite3_file_control() calls that are specific |
+** to proxy locking. |
+*/ |
+static int proxyFileControl(sqlite3_file *id, int op, void *pArg){ |
+ switch( op ){ |
+ case SQLITE_FCNTL_GET_LOCKPROXYFILE: { |
+ unixFile *pFile = (unixFile*)id; |
+ if( pFile->pMethod == &proxyIoMethods ){ |
+ proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; |
+ proxyTakeConch(pFile); |
+ if( pCtx->lockProxyPath ){ |
+ *(const char **)pArg = pCtx->lockProxyPath; |
+ }else{ |
+ *(const char **)pArg = ":auto: (not held)"; |
+ } |
+ } else { |
+ *(const char **)pArg = NULL; |
+ } |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_SET_LOCKPROXYFILE: { |
+ unixFile *pFile = (unixFile*)id; |
+ int rc = SQLITE_OK; |
+ int isProxyStyle = (pFile->pMethod == &proxyIoMethods); |
+ if( pArg==NULL || (const char *)pArg==0 ){ |
+ if( isProxyStyle ){ |
+ /* turn off proxy locking - not supported. If support is added for |
+ ** switching proxy locking mode off then it will need to fail if |
+ ** the journal mode is WAL mode. |
+ */ |
+ rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/; |
+ }else{ |
+ /* turn off proxy locking - already off - NOOP */ |
+ rc = SQLITE_OK; |
+ } |
+ }else{ |
+ const char *proxyPath = (const char *)pArg; |
+ if( isProxyStyle ){ |
+ proxyLockingContext *pCtx = |
+ (proxyLockingContext*)pFile->lockingContext; |
+ if( !strcmp(pArg, ":auto:") |
+ || (pCtx->lockProxyPath && |
+ !strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN)) |
+ ){ |
+ rc = SQLITE_OK; |
+ }else{ |
+ rc = switchLockProxyPath(pFile, proxyPath); |
+ } |
+ }else{ |
+ /* turn on proxy file locking */ |
+ rc = proxyTransformUnixFile(pFile, proxyPath); |
+ } |
+ } |
+ return rc; |
+ } |
+ default: { |
+ assert( 0 ); /* The call assures that only valid opcodes are sent */ |
+ } |
+ } |
+ /*NOTREACHED*/ |
+ return SQLITE_ERROR; |
+} |
+ |
+/* |
+** Within this division (the proxying locking implementation) the procedures |
+** above this point are all utilities. The lock-related methods of the |
+** proxy-locking sqlite3_io_method object follow. |
+*/ |
+ |
+ |
+/* |
+** This routine checks if there is a RESERVED lock held on the specified |
+** file by this or any other process. If such a lock is held, set *pResOut |
+** to a non-zero value otherwise *pResOut is set to zero. The return value |
+** is set to SQLITE_OK unless an I/O error occurs during lock checking. |
+*/ |
+static int proxyCheckReservedLock(sqlite3_file *id, int *pResOut) { |
+ unixFile *pFile = (unixFile*)id; |
+ int rc = proxyTakeConch(pFile); |
+ if( rc==SQLITE_OK ){ |
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; |
+ if( pCtx->conchHeld>0 ){ |
+ unixFile *proxy = pCtx->lockProxy; |
+ return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut); |
+ }else{ /* conchHeld < 0 is lockless */ |
+ pResOut=0; |
+ } |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Lock the file with the lock specified by parameter eFileLock - one |
+** of the following: |
+** |
+** (1) SHARED_LOCK |
+** (2) RESERVED_LOCK |
+** (3) PENDING_LOCK |
+** (4) EXCLUSIVE_LOCK |
+** |
+** Sometimes when requesting one lock state, additional lock states |
+** are inserted in between. The locking might fail on one of the later |
+** transitions leaving the lock state different from what it started but |
+** still short of its goal. The following chart shows the allowed |
+** transitions and the inserted intermediate states: |
+** |
+** UNLOCKED -> SHARED |
+** SHARED -> RESERVED |
+** SHARED -> (PENDING) -> EXCLUSIVE |
+** RESERVED -> (PENDING) -> EXCLUSIVE |
+** PENDING -> EXCLUSIVE |
+** |
+** This routine will only increase a lock. Use the sqlite3OsUnlock() |
+** routine to lower a locking level. |
+*/ |
+static int proxyLock(sqlite3_file *id, int eFileLock) { |
+ unixFile *pFile = (unixFile*)id; |
+ int rc = proxyTakeConch(pFile); |
+ if( rc==SQLITE_OK ){ |
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; |
+ if( pCtx->conchHeld>0 ){ |
+ unixFile *proxy = pCtx->lockProxy; |
+ rc = proxy->pMethod->xLock((sqlite3_file*)proxy, eFileLock); |
+ pFile->eFileLock = proxy->eFileLock; |
+ }else{ |
+ /* conchHeld < 0 is lockless */ |
+ } |
+ } |
+ return rc; |
+} |
+ |
+ |
+/* |
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock |
+** must be either NO_LOCK or SHARED_LOCK. |
+** |
+** If the locking level of the file descriptor is already at or below |
+** the requested locking level, this routine is a no-op. |
+*/ |
+static int proxyUnlock(sqlite3_file *id, int eFileLock) { |
+ unixFile *pFile = (unixFile*)id; |
+ int rc = proxyTakeConch(pFile); |
+ if( rc==SQLITE_OK ){ |
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; |
+ if( pCtx->conchHeld>0 ){ |
+ unixFile *proxy = pCtx->lockProxy; |
+ rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, eFileLock); |
+ pFile->eFileLock = proxy->eFileLock; |
+ }else{ |
+ /* conchHeld < 0 is lockless */ |
+ } |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Close a file that uses proxy locks. |
+*/ |
+static int proxyClose(sqlite3_file *id) { |
+ if( ALWAYS(id) ){ |
+ unixFile *pFile = (unixFile*)id; |
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; |
+ unixFile *lockProxy = pCtx->lockProxy; |
+ unixFile *conchFile = pCtx->conchFile; |
+ int rc = SQLITE_OK; |
+ |
+ if( lockProxy ){ |
+ rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK); |
+ if( rc ) return rc; |
+ rc = lockProxy->pMethod->xClose((sqlite3_file*)lockProxy); |
+ if( rc ) return rc; |
+ sqlite3_free(lockProxy); |
+ pCtx->lockProxy = 0; |
+ } |
+ if( conchFile ){ |
+ if( pCtx->conchHeld ){ |
+ rc = proxyReleaseConch(pFile); |
+ if( rc ) return rc; |
+ } |
+ rc = conchFile->pMethod->xClose((sqlite3_file*)conchFile); |
+ if( rc ) return rc; |
+ sqlite3_free(conchFile); |
+ } |
+ sqlite3DbFree(0, pCtx->lockProxyPath); |
+ sqlite3_free(pCtx->conchFilePath); |
+ sqlite3DbFree(0, pCtx->dbPath); |
+ /* restore the original locking context and pMethod then close it */ |
+ pFile->lockingContext = pCtx->oldLockingContext; |
+ pFile->pMethod = pCtx->pOldMethod; |
+ sqlite3_free(pCtx); |
+ return pFile->pMethod->xClose(id); |
+ } |
+ return SQLITE_OK; |
+} |
+ |
+ |
+ |
+#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ |
+/* |
+** The proxy locking style is intended for use with AFP filesystems. |
+** And since AFP is only supported on MacOSX, the proxy locking is also |
+** restricted to MacOSX. |
+** |
+** |
+******************* End of the proxy lock implementation ********************** |
+******************************************************************************/ |
+ |
+/* |
+** Initialize the operating system interface. |
+** |
+** This routine registers all VFS implementations for unix-like operating |
+** systems. This routine, and the sqlite3_os_end() routine that follows, |
+** should be the only routines in this file that are visible from other |
+** files. |
+** |
+** This routine is called once during SQLite initialization and by a |
+** single thread. The memory allocation and mutex subsystems have not |
+** necessarily been initialized when this routine is called, and so they |
+** should not be used. |
+*/ |
+SQLITE_API int sqlite3_os_init(void){ |
+ /* |
+ ** The following macro defines an initializer for an sqlite3_vfs object. |
+ ** The name of the VFS is NAME. The pAppData is a pointer to a pointer |
+ ** to the "finder" function. (pAppData is a pointer to a pointer because |
+ ** silly C90 rules prohibit a void* from being cast to a function pointer |
+ ** and so we have to go through the intermediate pointer to avoid problems |
+ ** when compiling with -pedantic-errors on GCC.) |
+ ** |
+ ** The FINDER parameter to this macro is the name of the pointer to the |
+ ** finder-function. The finder-function returns a pointer to the |
+ ** sqlite_io_methods object that implements the desired locking |
+ ** behaviors. See the division above that contains the IOMETHODS |
+ ** macro for addition information on finder-functions. |
+ ** |
+ ** Most finders simply return a pointer to a fixed sqlite3_io_methods |
+ ** object. But the "autolockIoFinder" available on MacOSX does a little |
+ ** more than that; it looks at the filesystem type that hosts the |
+ ** database file and tries to choose an locking method appropriate for |
+ ** that filesystem time. |
+ */ |
+ #define UNIXVFS(VFSNAME, FINDER) { \ |
+ 3, /* iVersion */ \ |
+ sizeof(unixFile), /* szOsFile */ \ |
+ MAX_PATHNAME, /* mxPathname */ \ |
+ 0, /* pNext */ \ |
+ VFSNAME, /* zName */ \ |
+ (void*)&FINDER, /* pAppData */ \ |
+ unixOpen, /* xOpen */ \ |
+ unixDelete, /* xDelete */ \ |
+ unixAccess, /* xAccess */ \ |
+ unixFullPathname, /* xFullPathname */ \ |
+ unixDlOpen, /* xDlOpen */ \ |
+ unixDlError, /* xDlError */ \ |
+ unixDlSym, /* xDlSym */ \ |
+ unixDlClose, /* xDlClose */ \ |
+ unixRandomness, /* xRandomness */ \ |
+ unixSleep, /* xSleep */ \ |
+ unixCurrentTime, /* xCurrentTime */ \ |
+ unixGetLastError, /* xGetLastError */ \ |
+ unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \ |
+ unixSetSystemCall, /* xSetSystemCall */ \ |
+ unixGetSystemCall, /* xGetSystemCall */ \ |
+ unixNextSystemCall, /* xNextSystemCall */ \ |
+ } |
+ |
+ /* |
+ ** All default VFSes for unix are contained in the following array. |
+ ** |
+ ** Note that the sqlite3_vfs.pNext field of the VFS object is modified |
+ ** by the SQLite core when the VFS is registered. So the following |
+ ** array cannot be const. |
+ */ |
+ static sqlite3_vfs aVfs[] = { |
+#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) |
+ UNIXVFS("unix", autolockIoFinder ), |
+#elif OS_VXWORKS |
+ UNIXVFS("unix", vxworksIoFinder ), |
+#else |
+ UNIXVFS("unix", posixIoFinder ), |
+#endif |
+ UNIXVFS("unix-none", nolockIoFinder ), |
+ UNIXVFS("unix-dotfile", dotlockIoFinder ), |
+ UNIXVFS("unix-excl", posixIoFinder ), |
+#if OS_VXWORKS |
+ UNIXVFS("unix-namedsem", semIoFinder ), |
+#endif |
+#if SQLITE_ENABLE_LOCKING_STYLE || OS_VXWORKS |
+ UNIXVFS("unix-posix", posixIoFinder ), |
+#endif |
+#if SQLITE_ENABLE_LOCKING_STYLE |
+ UNIXVFS("unix-flock", flockIoFinder ), |
+#endif |
+#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)==28 ); |
+ |
+ /* 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; |
+} |
+ |
+/* |
+** Shutdown the operating system interface. |
+** |
+** Some operating systems might need to do some cleanup in this routine, |
+** to release dynamically allocated objects. But not on unix. |
+** This routine is a no-op for unix. |
+*/ |
+SQLITE_API int sqlite3_os_end(void){ |
+ return SQLITE_OK; |
+} |
+ |
+#endif /* SQLITE_OS_UNIX */ |
+ |
+/************** End of os_unix.c *********************************************/ |
+/************** Begin file os_win.c ******************************************/ |
+/* |
+** 2004 May 22 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains code that is specific to Windows. |
+*/ |
+/* #include "sqliteInt.h" */ |
+#if SQLITE_OS_WIN /* This file is used for Windows only */ |
+ |
+/* |
+** Include code that is common to all os_*.c files |
+*/ |
+/************** Include os_common.h in the middle of os_win.c ****************/ |
+/************** Begin file os_common.h ***************************************/ |
+/* |
+** 2004 May 22 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains macros and a little bit of code that is common to |
+** all of the platform-specific files (os_*.c) and is #included into those |
+** files. |
+** |
+** This file should be #included by the os_*.c files only. It is not a |
+** general purpose header file. |
+*/ |
+#ifndef _OS_COMMON_H_ |
+#define _OS_COMMON_H_ |
+ |
+/* |
+** At least two bugs have slipped in because we changed the MEMORY_DEBUG |
+** macro to SQLITE_DEBUG and some older makefiles have not yet made the |
+** switch. The following code should catch this problem at compile-time. |
+*/ |
+#ifdef MEMORY_DEBUG |
+# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." |
+#endif |
+ |
+/* |
+** Macros for performance tracing. Normally turned off. Only works |
+** on i486 hardware. |
+*/ |
+#ifdef SQLITE_PERFORMANCE_TRACE |
+ |
+/* |
+** hwtime.h contains inline assembler code for implementing |
+** high-performance timing routines. |
+*/ |
+/************** Include hwtime.h in the middle of os_common.h ****************/ |
+/************** Begin file hwtime.h ******************************************/ |
+/* |
+** 2008 May 27 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+****************************************************************************** |
+** |
+** This file contains inline asm code for retrieving "high-performance" |
+** counters for x86 class CPUs. |
+*/ |
+#ifndef SQLITE_HWTIME_H |
+#define SQLITE_HWTIME_H |
+ |
+/* |
+** The following routine only works on pentium-class (or newer) processors. |
+** It uses the RDTSC opcode to read the cycle count value out of the |
+** processor and returns that value. This can be used for high-res |
+** profiling. |
+*/ |
+#if (defined(__GNUC__) || defined(_MSC_VER)) && \ |
+ (defined(i386) || defined(__i386__) || defined(_M_IX86)) |
+ |
+ #if defined(__GNUC__) |
+ |
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
+ unsigned int lo, hi; |
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); |
+ return (sqlite_uint64)hi << 32 | lo; |
+ } |
+ |
+ #elif defined(_MSC_VER) |
+ |
+ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ |
+ __asm { |
+ rdtsc |
+ ret ; return value at EDX:EAX |
+ } |
+ } |
+ |
+ #endif |
+ |
+#elif (defined(__GNUC__) && defined(__x86_64__)) |
+ |
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
+ unsigned long val; |
+ __asm__ __volatile__ ("rdtsc" : "=A" (val)); |
+ return val; |
+ } |
+ |
+#elif (defined(__GNUC__) && defined(__ppc__)) |
+ |
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){ |
+ unsigned long long retval; |
+ unsigned long junk; |
+ __asm__ __volatile__ ("\n\ |
+ 1: mftbu %1\n\ |
+ mftb %L0\n\ |
+ mftbu %0\n\ |
+ cmpw %0,%1\n\ |
+ bne 1b" |
+ : "=r" (retval), "=r" (junk)); |
+ return retval; |
+ } |
+ |
+#else |
+ |
+ #error Need implementation of sqlite3Hwtime() for your platform. |
+ |
+ /* |
+ ** To compile without implementing sqlite3Hwtime() for your platform, |
+ ** you can remove the above #error and use the following |
+ ** stub function. You will lose timing support for many |
+ ** of the debugging and testing utilities, but it should at |
+ ** least compile and run. |
+ */ |
+SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } |
+ |
+#endif |
+ |
+#endif /* !defined(SQLITE_HWTIME_H) */ |
+ |
+/************** End of hwtime.h **********************************************/ |
+/************** Continuing where we left off in os_common.h ******************/ |
+ |
+static sqlite_uint64 g_start; |
+static sqlite_uint64 g_elapsed; |
+#define TIMER_START g_start=sqlite3Hwtime() |
+#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start |
+#define TIMER_ELAPSED g_elapsed |
+#else |
+#define TIMER_START |
+#define TIMER_END |
+#define TIMER_ELAPSED ((sqlite_uint64)0) |
+#endif |
+ |
+/* |
+** If we compile with the SQLITE_TEST macro set, then the following block |
+** of code will give us the ability to simulate a disk I/O error. This |
+** is used for testing the I/O recovery logic. |
+*/ |
+#if defined(SQLITE_TEST) |
+SQLITE_API extern int sqlite3_io_error_hit; |
+SQLITE_API extern int sqlite3_io_error_hardhit; |
+SQLITE_API extern int sqlite3_io_error_pending; |
+SQLITE_API extern int sqlite3_io_error_persist; |
+SQLITE_API extern int sqlite3_io_error_benign; |
+SQLITE_API extern int sqlite3_diskfull_pending; |
+SQLITE_API extern int sqlite3_diskfull; |
+#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) |
+#define SimulateIOError(CODE) \ |
+ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ |
+ || sqlite3_io_error_pending-- == 1 ) \ |
+ { local_ioerr(); CODE; } |
+static void local_ioerr(){ |
+ IOTRACE(("IOERR\n")); |
+ sqlite3_io_error_hit++; |
+ if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; |
+} |
+#define SimulateDiskfullError(CODE) \ |
+ if( sqlite3_diskfull_pending ){ \ |
+ if( sqlite3_diskfull_pending == 1 ){ \ |
+ local_ioerr(); \ |
+ sqlite3_diskfull = 1; \ |
+ sqlite3_io_error_hit = 1; \ |
+ CODE; \ |
+ }else{ \ |
+ sqlite3_diskfull_pending--; \ |
+ } \ |
+ } |
+#else |
+#define SimulateIOErrorBenign(X) |
+#define SimulateIOError(A) |
+#define SimulateDiskfullError(A) |
+#endif /* defined(SQLITE_TEST) */ |
+ |
+/* |
+** When testing, keep a count of the number of open files. |
+*/ |
+#if defined(SQLITE_TEST) |
+SQLITE_API extern int sqlite3_open_file_count; |
+#define OpenCounter(X) sqlite3_open_file_count+=(X) |
+#else |
+#define OpenCounter(X) |
+#endif /* defined(SQLITE_TEST) */ |
+ |
+#endif /* !defined(_OS_COMMON_H_) */ |
+ |
+/************** End of os_common.h *******************************************/ |
+/************** Continuing where we left off in os_win.c *********************/ |
+ |
+/* |
+** Include the header file for the Windows VFS. |
+*/ |
+/* #include "os_win.h" */ |
+ |
+/* |
+** Compiling and using WAL mode requires several APIs that are only |
+** available in Windows platforms based on the NT kernel. |
+*/ |
+#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL) |
+# error "WAL mode requires support from the Windows NT kernel, compile\ |
+ with SQLITE_OMIT_WAL." |
+#endif |
+ |
+#if !SQLITE_OS_WINNT && SQLITE_MAX_MMAP_SIZE>0 |
+# error "Memory mapped files require support from the Windows NT kernel,\ |
+ compile with SQLITE_MAX_MMAP_SIZE=0." |
+#endif |
+ |
+/* |
+** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions |
+** based on the sub-platform)? |
+*/ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(SQLITE_WIN32_NO_ANSI) |
+# define SQLITE_WIN32_HAS_ANSI |
+#endif |
+ |
+/* |
+** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions |
+** based on the sub-platform)? |
+*/ |
+#if (SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT) && \ |
+ !defined(SQLITE_WIN32_NO_WIDE) |
+# define SQLITE_WIN32_HAS_WIDE |
+#endif |
+ |
+/* |
+** Make sure at least one set of Win32 APIs is available. |
+*/ |
+#if !defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_WIN32_HAS_WIDE) |
+# error "At least one of SQLITE_WIN32_HAS_ANSI and SQLITE_WIN32_HAS_WIDE\ |
+ must be defined." |
+#endif |
+ |
+/* |
+** Define the required Windows SDK version constants if they are not |
+** already available. |
+*/ |
+#ifndef NTDDI_WIN8 |
+# define NTDDI_WIN8 0x06020000 |
+#endif |
+ |
+#ifndef NTDDI_WINBLUE |
+# define NTDDI_WINBLUE 0x06030000 |
+#endif |
+ |
+#ifndef NTDDI_WINTHRESHOLD |
+# define NTDDI_WINTHRESHOLD 0x06040000 |
+#endif |
+ |
+/* |
+** Check to see if the GetVersionEx[AW] functions are deprecated on the |
+** target system. GetVersionEx was first deprecated in Win8.1. |
+*/ |
+#ifndef SQLITE_WIN32_GETVERSIONEX |
+# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE |
+# define SQLITE_WIN32_GETVERSIONEX 0 /* GetVersionEx() is deprecated */ |
+# else |
+# define SQLITE_WIN32_GETVERSIONEX 1 /* GetVersionEx() is current */ |
+# endif |
+#endif |
+ |
+/* |
+** Check to see if the CreateFileMappingA function is supported on the |
+** target system. It is unavailable when using "mincore.lib" on Win10. |
+** When compiling for Windows 10, always assume "mincore.lib" is in use. |
+*/ |
+#ifndef SQLITE_WIN32_CREATEFILEMAPPINGA |
+# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINTHRESHOLD |
+# define SQLITE_WIN32_CREATEFILEMAPPINGA 0 |
+# else |
+# define SQLITE_WIN32_CREATEFILEMAPPINGA 1 |
+# endif |
+#endif |
+ |
+/* |
+** This constant should already be defined (in the "WinDef.h" SDK file). |
+*/ |
+#ifndef MAX_PATH |
+# define MAX_PATH (260) |
+#endif |
+ |
+/* |
+** Maximum pathname length (in chars) for Win32. This should normally be |
+** MAX_PATH. |
+*/ |
+#ifndef SQLITE_WIN32_MAX_PATH_CHARS |
+# define SQLITE_WIN32_MAX_PATH_CHARS (MAX_PATH) |
+#endif |
+ |
+/* |
+** This constant should already be defined (in the "WinNT.h" SDK file). |
+*/ |
+#ifndef UNICODE_STRING_MAX_CHARS |
+# define UNICODE_STRING_MAX_CHARS (32767) |
+#endif |
+ |
+/* |
+** Maximum pathname length (in chars) for WinNT. This should normally be |
+** UNICODE_STRING_MAX_CHARS. |
+*/ |
+#ifndef SQLITE_WINNT_MAX_PATH_CHARS |
+# define SQLITE_WINNT_MAX_PATH_CHARS (UNICODE_STRING_MAX_CHARS) |
+#endif |
+ |
+/* |
+** Maximum pathname length (in bytes) for Win32. The MAX_PATH macro is in |
+** characters, so we allocate 4 bytes per character assuming worst-case of |
+** 4-bytes-per-character for UTF8. |
+*/ |
+#ifndef SQLITE_WIN32_MAX_PATH_BYTES |
+# define SQLITE_WIN32_MAX_PATH_BYTES (SQLITE_WIN32_MAX_PATH_CHARS*4) |
+#endif |
+ |
+/* |
+** Maximum pathname length (in bytes) for WinNT. This should normally be |
+** UNICODE_STRING_MAX_CHARS * sizeof(WCHAR). |
+*/ |
+#ifndef SQLITE_WINNT_MAX_PATH_BYTES |
+# define SQLITE_WINNT_MAX_PATH_BYTES \ |
+ (sizeof(WCHAR) * SQLITE_WINNT_MAX_PATH_CHARS) |
+#endif |
+ |
+/* |
+** Maximum error message length (in chars) for WinRT. |
+*/ |
+#ifndef SQLITE_WIN32_MAX_ERRMSG_CHARS |
+# define SQLITE_WIN32_MAX_ERRMSG_CHARS (1024) |
+#endif |
+ |
+/* |
+** Returns non-zero if the character should be treated as a directory |
+** separator. |
+*/ |
+#ifndef winIsDirSep |
+# define winIsDirSep(a) (((a) == '/') || ((a) == '\\')) |
+#endif |
+ |
+/* |
+** This macro is used when a local variable is set to a value that is |
+** [sometimes] not used by the code (e.g. via conditional compilation). |
+*/ |
+#ifndef UNUSED_VARIABLE_VALUE |
+# define UNUSED_VARIABLE_VALUE(x) (void)(x) |
+#endif |
+ |
+/* |
+** Returns the character that should be used as the directory separator. |
+*/ |
+#ifndef winGetDirSep |
+# define winGetDirSep() '\\' |
+#endif |
+ |
+/* |
+** Do we need to manually define the Win32 file mapping APIs for use with WAL |
+** mode or memory mapped files (e.g. these APIs are available in the Windows |
+** CE SDK; however, they are not present in the header file)? |
+*/ |
+#if SQLITE_WIN32_FILEMAPPING_API && \ |
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) |
+/* |
+** Two of the file mapping APIs are different under WinRT. Figure out which |
+** set we need. |
+*/ |
+#if SQLITE_OS_WINRT |
+WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \ |
+ LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR); |
+ |
+WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T); |
+#else |
+#if defined(SQLITE_WIN32_HAS_ANSI) |
+WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \ |
+ DWORD, DWORD, DWORD, LPCSTR); |
+#endif /* defined(SQLITE_WIN32_HAS_ANSI) */ |
+ |
+#if defined(SQLITE_WIN32_HAS_WIDE) |
+WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \ |
+ DWORD, DWORD, DWORD, LPCWSTR); |
+#endif /* defined(SQLITE_WIN32_HAS_WIDE) */ |
+ |
+WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); |
+#endif /* SQLITE_OS_WINRT */ |
+ |
+/* |
+** These file mapping APIs are common to both Win32 and WinRT. |
+*/ |
+ |
+WINBASEAPI BOOL WINAPI FlushViewOfFile(LPCVOID, SIZE_T); |
+WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID); |
+#endif /* SQLITE_WIN32_FILEMAPPING_API */ |
+ |
+/* |
+** Some Microsoft compilers lack this definition. |
+*/ |
+#ifndef INVALID_FILE_ATTRIBUTES |
+# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) |
+#endif |
+ |
+#ifndef FILE_FLAG_MASK |
+# define FILE_FLAG_MASK (0xFF3C0000) |
+#endif |
+ |
+#ifndef FILE_ATTRIBUTE_MASK |
+# define FILE_ATTRIBUTE_MASK (0x0003FFF7) |
+#endif |
+ |
+#ifndef SQLITE_OMIT_WAL |
+/* Forward references to structures used for WAL */ |
+typedef struct winShm winShm; /* A connection to shared-memory */ |
+typedef struct winShmNode winShmNode; /* A region of shared-memory */ |
+#endif |
+ |
+/* |
+** WinCE lacks native support for file locking so we have to fake it |
+** with some code of our own. |
+*/ |
+#if SQLITE_OS_WINCE |
+typedef struct winceLock { |
+ int nReaders; /* Number of reader locks obtained */ |
+ BOOL bPending; /* Indicates a pending lock has been obtained */ |
+ BOOL bReserved; /* Indicates a reserved lock has been obtained */ |
+ BOOL bExclusive; /* Indicates an exclusive lock has been obtained */ |
+} winceLock; |
+#endif |
+ |
+/* |
+** The winFile structure is a subclass of sqlite3_file* specific to the win32 |
+** portability layer. |
+*/ |
+typedef struct winFile winFile; |
+struct winFile { |
+ const sqlite3_io_methods *pMethod; /*** Must be first ***/ |
+ sqlite3_vfs *pVfs; /* The VFS used to open this file */ |
+ HANDLE h; /* Handle for accessing the file */ |
+ u8 locktype; /* Type of lock currently held on this file */ |
+ short sharedLockByte; /* Randomly chosen byte used as a shared lock */ |
+ u8 ctrlFlags; /* Flags. See WINFILE_* below */ |
+ DWORD lastErrno; /* The Windows errno from the last I/O error */ |
+#ifndef SQLITE_OMIT_WAL |
+ winShm *pShm; /* Instance of shared memory on this file */ |
+#endif |
+ const char *zPath; /* Full pathname of this file */ |
+ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ |
+#if SQLITE_OS_WINCE |
+ LPWSTR 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 |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ int nFetchOut; /* Number of outstanding xFetch references */ |
+ HANDLE hMap; /* Handle for accessing memory mapping */ |
+ void *pMapRegion; /* Area memory mapped */ |
+ sqlite3_int64 mmapSize; /* Usable size of mapped region */ |
+ sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ |
+ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ |
+#endif |
+}; |
+ |
+/* |
+** The winVfsAppData structure is used for the pAppData member for all of the |
+** Win32 VFS variants. |
+*/ |
+typedef struct winVfsAppData winVfsAppData; |
+struct winVfsAppData { |
+ const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */ |
+ void *pAppData; /* The extra pAppData, if any. */ |
+ BOOL bNoLock; /* Non-zero if locking is disabled. */ |
+}; |
+ |
+/* |
+** Allowed values for winFile.ctrlFlags |
+*/ |
+#define WINFILE_RDONLY 0x02 /* Connection is read only */ |
+#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ |
+#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ |
+ |
+/* |
+ * The size of the buffer used by sqlite3_win32_write_debug(). |
+ */ |
+#ifndef SQLITE_WIN32_DBG_BUF_SIZE |
+# define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD))) |
+#endif |
+ |
+/* |
+ * The value used with sqlite3_win32_set_directory() to specify that |
+ * the data directory should be changed. |
+ */ |
+#ifndef SQLITE_WIN32_DATA_DIRECTORY_TYPE |
+# define SQLITE_WIN32_DATA_DIRECTORY_TYPE (1) |
+#endif |
+ |
+/* |
+ * The value used with sqlite3_win32_set_directory() to specify that |
+ * the temporary directory should be changed. |
+ */ |
+#ifndef SQLITE_WIN32_TEMP_DIRECTORY_TYPE |
+# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE (2) |
+#endif |
+ |
+/* |
+ * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the |
+ * various Win32 API heap functions instead of our own. |
+ */ |
+#ifdef SQLITE_WIN32_MALLOC |
+ |
+/* |
+ * If this is non-zero, an isolated heap will be created by the native Win32 |
+ * allocator subsystem; otherwise, the default process heap will be used. This |
+ * setting has no effect when compiling for WinRT. By default, this is enabled |
+ * and an isolated heap will be created to store all allocated data. |
+ * |
+ ****************************************************************************** |
+ * WARNING: It is important to note that when this setting is non-zero and the |
+ * winMemShutdown function is called (e.g. by the sqlite3_shutdown |
+ * function), all data that was allocated using the isolated heap will |
+ * be freed immediately and any attempt to access any of that freed |
+ * data will almost certainly result in an immediate access violation. |
+ ****************************************************************************** |
+ */ |
+#ifndef SQLITE_WIN32_HEAP_CREATE |
+# define SQLITE_WIN32_HEAP_CREATE (TRUE) |
+#endif |
+ |
+/* |
+ * This is cache size used in the calculation of the initial size of the |
+ * Win32-specific heap. It cannot be negative. |
+ */ |
+#ifndef SQLITE_WIN32_CACHE_SIZE |
+# if SQLITE_DEFAULT_CACHE_SIZE>=0 |
+# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE) |
+# else |
+# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE)) |
+# endif |
+#endif |
+ |
+/* |
+ * The initial size of the Win32-specific heap. This value may be zero. |
+ */ |
+#ifndef SQLITE_WIN32_HEAP_INIT_SIZE |
+# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \ |
+ (SQLITE_DEFAULT_PAGE_SIZE) + 4194304) |
+#endif |
+ |
+/* |
+ * The maximum size of the Win32-specific heap. This value may be zero. |
+ */ |
+#ifndef SQLITE_WIN32_HEAP_MAX_SIZE |
+# define SQLITE_WIN32_HEAP_MAX_SIZE (0) |
+#endif |
+ |
+/* |
+ * The extra flags to use in calls to the Win32 heap APIs. This value may be |
+ * zero for the default behavior. |
+ */ |
+#ifndef SQLITE_WIN32_HEAP_FLAGS |
+# define SQLITE_WIN32_HEAP_FLAGS (0) |
+#endif |
+ |
+ |
+/* |
+** The winMemData structure stores information required by the Win32-specific |
+** sqlite3_mem_methods implementation. |
+*/ |
+typedef struct winMemData winMemData; |
+struct winMemData { |
+#ifndef NDEBUG |
+ u32 magic1; /* Magic number to detect structure corruption. */ |
+#endif |
+ HANDLE hHeap; /* The handle to our heap. */ |
+ BOOL bOwned; /* Do we own the heap (i.e. destroy it on shutdown)? */ |
+#ifndef NDEBUG |
+ u32 magic2; /* Magic number to detect structure corruption. */ |
+#endif |
+}; |
+ |
+#ifndef NDEBUG |
+#define WINMEM_MAGIC1 0x42b2830b |
+#define WINMEM_MAGIC2 0xbd4d7cf4 |
+#endif |
+ |
+static struct winMemData win_mem_data = { |
+#ifndef NDEBUG |
+ WINMEM_MAGIC1, |
+#endif |
+ NULL, FALSE |
+#ifndef NDEBUG |
+ ,WINMEM_MAGIC2 |
+#endif |
+}; |
+ |
+#ifndef NDEBUG |
+#define winMemAssertMagic1() assert( win_mem_data.magic1==WINMEM_MAGIC1 ) |
+#define winMemAssertMagic2() assert( win_mem_data.magic2==WINMEM_MAGIC2 ) |
+#define winMemAssertMagic() winMemAssertMagic1(); winMemAssertMagic2(); |
+#else |
+#define winMemAssertMagic() |
+#endif |
+ |
+#define winMemGetDataPtr() &win_mem_data |
+#define winMemGetHeap() win_mem_data.hHeap |
+#define winMemGetOwned() win_mem_data.bOwned |
+ |
+static void *winMemMalloc(int nBytes); |
+static void winMemFree(void *pPrior); |
+static void *winMemRealloc(void *pPrior, int nBytes); |
+static int winMemSize(void *p); |
+static int winMemRoundup(int n); |
+static int winMemInit(void *pAppData); |
+static void winMemShutdown(void *pAppData); |
+ |
+SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void); |
+#endif /* SQLITE_WIN32_MALLOC */ |
+ |
+/* |
+** The following variable is (normally) set once and never changes |
+** thereafter. It records whether the operating system is Win9x |
+** or WinNT. |
+** |
+** 0: Operating system unknown. |
+** 1: Operating system is Win9x. |
+** 2: Operating system is WinNT. |
+** |
+** In order to facilitate testing on a WinNT system, the test fixture |
+** can manually set this value to 1 to emulate Win98 behavior. |
+*/ |
+#ifdef SQLITE_TEST |
+SQLITE_API LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; |
+#else |
+static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; |
+#endif |
+ |
+#ifndef SYSCALL |
+# define SYSCALL sqlite3_syscall_ptr |
+#endif |
+ |
+/* |
+** This function is not available on Windows CE or WinRT. |
+ */ |
+ |
+#if SQLITE_OS_WINCE || SQLITE_OS_WINRT |
+# define osAreFileApisANSI() 1 |
+#endif |
+ |
+/* |
+** Many system calls are accessed through pointer-to-functions so that |
+** they may be overridden at runtime to facilitate fault injection during |
+** testing and sandboxing. The following array holds the names and pointers |
+** to all overrideable system calls. |
+*/ |
+static struct win_syscall { |
+ const char *zName; /* Name of the system call */ |
+ sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ |
+ sqlite3_syscall_ptr pDefault; /* Default value */ |
+} aSyscall[] = { |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT |
+ { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 }, |
+#else |
+ { "AreFileApisANSI", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#ifndef osAreFileApisANSI |
+#define osAreFileApisANSI ((BOOL(WINAPI*)(VOID))aSyscall[0].pCurrent) |
+#endif |
+ |
+#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) |
+ { "CharLowerW", (SYSCALL)CharLowerW, 0 }, |
+#else |
+ { "CharLowerW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCharLowerW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[1].pCurrent) |
+ |
+#if SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) |
+ { "CharUpperW", (SYSCALL)CharUpperW, 0 }, |
+#else |
+ { "CharUpperW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCharUpperW ((LPWSTR(WINAPI*)(LPWSTR))aSyscall[2].pCurrent) |
+ |
+ { "CloseHandle", (SYSCALL)CloseHandle, 0 }, |
+ |
+#define osCloseHandle ((BOOL(WINAPI*)(HANDLE))aSyscall[3].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_ANSI) |
+ { "CreateFileA", (SYSCALL)CreateFileA, 0 }, |
+#else |
+ { "CreateFileA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \ |
+ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) |
+ { "CreateFileW", (SYSCALL)CreateFileW, 0 }, |
+#else |
+ { "CreateFileW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ |
+ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ |
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \ |
+ SQLITE_WIN32_CREATEFILEMAPPINGA |
+ { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, |
+#else |
+ { "CreateFileMappingA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ |
+ DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent) |
+ |
+#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ |
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) |
+ { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, |
+#else |
+ { "CreateFileMappingW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ |
+ DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) |
+ { "CreateMutexW", (SYSCALL)CreateMutexW, 0 }, |
+#else |
+ { "CreateMutexW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCreateMutexW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,BOOL, \ |
+ LPCWSTR))aSyscall[8].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_ANSI) |
+ { "DeleteFileA", (SYSCALL)DeleteFileA, 0 }, |
+#else |
+ { "DeleteFileA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osDeleteFileA ((BOOL(WINAPI*)(LPCSTR))aSyscall[9].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_WIDE) |
+ { "DeleteFileW", (SYSCALL)DeleteFileW, 0 }, |
+#else |
+ { "DeleteFileW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osDeleteFileW ((BOOL(WINAPI*)(LPCWSTR))aSyscall[10].pCurrent) |
+ |
+#if SQLITE_OS_WINCE |
+ { "FileTimeToLocalFileTime", (SYSCALL)FileTimeToLocalFileTime, 0 }, |
+#else |
+ { "FileTimeToLocalFileTime", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \ |
+ LPFILETIME))aSyscall[11].pCurrent) |
+ |
+#if SQLITE_OS_WINCE |
+ { "FileTimeToSystemTime", (SYSCALL)FileTimeToSystemTime, 0 }, |
+#else |
+ { "FileTimeToSystemTime", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \ |
+ LPSYSTEMTIME))aSyscall[12].pCurrent) |
+ |
+ { "FlushFileBuffers", (SYSCALL)FlushFileBuffers, 0 }, |
+ |
+#define osFlushFileBuffers ((BOOL(WINAPI*)(HANDLE))aSyscall[13].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_ANSI) |
+ { "FormatMessageA", (SYSCALL)FormatMessageA, 0 }, |
+#else |
+ { "FormatMessageA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osFormatMessageA ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPSTR, \ |
+ DWORD,va_list*))aSyscall[14].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_WIDE) |
+ { "FormatMessageW", (SYSCALL)FormatMessageW, 0 }, |
+#else |
+ { "FormatMessageW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \ |
+ DWORD,va_list*))aSyscall[15].pCurrent) |
+ |
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) |
+ { "FreeLibrary", (SYSCALL)FreeLibrary, 0 }, |
+#else |
+ { "FreeLibrary", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent) |
+ |
+ { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 }, |
+ |
+#define osGetCurrentProcessId ((DWORD(WINAPI*)(VOID))aSyscall[17].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) |
+ { "GetDiskFreeSpaceA", (SYSCALL)GetDiskFreeSpaceA, 0 }, |
+#else |
+ { "GetDiskFreeSpaceA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \ |
+ LPDWORD))aSyscall[18].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) |
+ { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 }, |
+#else |
+ { "GetDiskFreeSpaceW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetDiskFreeSpaceW ((BOOL(WINAPI*)(LPCWSTR,LPDWORD,LPDWORD,LPDWORD, \ |
+ LPDWORD))aSyscall[19].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_ANSI) |
+ { "GetFileAttributesA", (SYSCALL)GetFileAttributesA, 0 }, |
+#else |
+ { "GetFileAttributesA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) |
+ { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 }, |
+#else |
+ { "GetFileAttributesW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetFileAttributesW ((DWORD(WINAPI*)(LPCWSTR))aSyscall[21].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_WIDE) |
+ { "GetFileAttributesExW", (SYSCALL)GetFileAttributesExW, 0 }, |
+#else |
+ { "GetFileAttributesExW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \ |
+ LPVOID))aSyscall[22].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "GetFileSize", (SYSCALL)GetFileSize, 0 }, |
+#else |
+ { "GetFileSize", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_ANSI) |
+ { "GetFullPathNameA", (SYSCALL)GetFullPathNameA, 0 }, |
+#else |
+ { "GetFullPathNameA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \ |
+ LPSTR*))aSyscall[24].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) |
+ { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 }, |
+#else |
+ { "GetFullPathNameW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \ |
+ LPWSTR*))aSyscall[25].pCurrent) |
+ |
+ { "GetLastError", (SYSCALL)GetLastError, 0 }, |
+ |
+#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent) |
+ |
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) |
+#if SQLITE_OS_WINCE |
+ /* The GetProcAddressA() routine is only available on Windows CE. */ |
+ { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 }, |
+#else |
+ /* All other Windows platforms expect GetProcAddress() to take |
+ ** an ANSI string regardless of the _UNICODE setting */ |
+ { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 }, |
+#endif |
+#else |
+ { "GetProcAddressA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \ |
+ LPCSTR))aSyscall[27].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 }, |
+#else |
+ { "GetSystemInfo", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent) |
+ |
+ { "GetSystemTime", (SYSCALL)GetSystemTime, 0 }, |
+ |
+#define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE |
+ { "GetSystemTimeAsFileTime", (SYSCALL)GetSystemTimeAsFileTime, 0 }, |
+#else |
+ { "GetSystemTimeAsFileTime", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetSystemTimeAsFileTime ((VOID(WINAPI*)( \ |
+ LPFILETIME))aSyscall[30].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_ANSI) |
+ { "GetTempPathA", (SYSCALL)GetTempPathA, 0 }, |
+#else |
+ { "GetTempPathA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) |
+ { "GetTempPathW", (SYSCALL)GetTempPathW, 0 }, |
+#else |
+ { "GetTempPathW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "GetTickCount", (SYSCALL)GetTickCount, 0 }, |
+#else |
+ { "GetTickCount", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_GETVERSIONEX |
+ { "GetVersionExA", (SYSCALL)GetVersionExA, 0 }, |
+#else |
+ { "GetVersionExA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetVersionExA ((BOOL(WINAPI*)( \ |
+ LPOSVERSIONINFOA))aSyscall[34].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ |
+ SQLITE_WIN32_GETVERSIONEX |
+ { "GetVersionExW", (SYSCALL)GetVersionExW, 0 }, |
+#else |
+ { "GetVersionExW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetVersionExW ((BOOL(WINAPI*)( \ |
+ LPOSVERSIONINFOW))aSyscall[35].pCurrent) |
+ |
+ { "HeapAlloc", (SYSCALL)HeapAlloc, 0 }, |
+ |
+#define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \ |
+ SIZE_T))aSyscall[36].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "HeapCreate", (SYSCALL)HeapCreate, 0 }, |
+#else |
+ { "HeapCreate", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \ |
+ SIZE_T))aSyscall[37].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "HeapDestroy", (SYSCALL)HeapDestroy, 0 }, |
+#else |
+ { "HeapDestroy", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent) |
+ |
+ { "HeapFree", (SYSCALL)HeapFree, 0 }, |
+ |
+#define osHeapFree ((BOOL(WINAPI*)(HANDLE,DWORD,LPVOID))aSyscall[39].pCurrent) |
+ |
+ { "HeapReAlloc", (SYSCALL)HeapReAlloc, 0 }, |
+ |
+#define osHeapReAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD,LPVOID, \ |
+ SIZE_T))aSyscall[40].pCurrent) |
+ |
+ { "HeapSize", (SYSCALL)HeapSize, 0 }, |
+ |
+#define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \ |
+ LPCVOID))aSyscall[41].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "HeapValidate", (SYSCALL)HeapValidate, 0 }, |
+#else |
+ { "HeapValidate", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ |
+ LPCVOID))aSyscall[42].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT |
+ { "HeapCompact", (SYSCALL)HeapCompact, 0 }, |
+#else |
+ { "HeapCompact", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osHeapCompact ((UINT(WINAPI*)(HANDLE,DWORD))aSyscall[43].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION) |
+ { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 }, |
+#else |
+ { "LoadLibraryA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[44].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ |
+ !defined(SQLITE_OMIT_LOAD_EXTENSION) |
+ { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 }, |
+#else |
+ { "LoadLibraryW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[45].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "LocalFree", (SYSCALL)LocalFree, 0 }, |
+#else |
+ { "LocalFree", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT |
+ { "LockFile", (SYSCALL)LockFile, 0 }, |
+#else |
+ { "LockFile", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#ifndef osLockFile |
+#define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ |
+ DWORD))aSyscall[47].pCurrent) |
+#endif |
+ |
+#if !SQLITE_OS_WINCE |
+ { "LockFileEx", (SYSCALL)LockFileEx, 0 }, |
+#else |
+ { "LockFileEx", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#ifndef osLockFileEx |
+#define osLockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD,DWORD, \ |
+ LPOVERLAPPED))aSyscall[48].pCurrent) |
+#endif |
+ |
+#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \ |
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) |
+ { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, |
+#else |
+ { "MapViewOfFile", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osMapViewOfFile ((LPVOID(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ |
+ SIZE_T))aSyscall[49].pCurrent) |
+ |
+ { "MultiByteToWideChar", (SYSCALL)MultiByteToWideChar, 0 }, |
+ |
+#define osMultiByteToWideChar ((int(WINAPI*)(UINT,DWORD,LPCSTR,int,LPWSTR, \ |
+ int))aSyscall[50].pCurrent) |
+ |
+ { "QueryPerformanceCounter", (SYSCALL)QueryPerformanceCounter, 0 }, |
+ |
+#define osQueryPerformanceCounter ((BOOL(WINAPI*)( \ |
+ LARGE_INTEGER*))aSyscall[51].pCurrent) |
+ |
+ { "ReadFile", (SYSCALL)ReadFile, 0 }, |
+ |
+#define osReadFile ((BOOL(WINAPI*)(HANDLE,LPVOID,DWORD,LPDWORD, \ |
+ LPOVERLAPPED))aSyscall[52].pCurrent) |
+ |
+ { "SetEndOfFile", (SYSCALL)SetEndOfFile, 0 }, |
+ |
+#define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[53].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "SetFilePointer", (SYSCALL)SetFilePointer, 0 }, |
+#else |
+ { "SetFilePointer", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \ |
+ DWORD))aSyscall[54].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "Sleep", (SYSCALL)Sleep, 0 }, |
+#else |
+ { "Sleep", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent) |
+ |
+ { "SystemTimeToFileTime", (SYSCALL)SystemTimeToFileTime, 0 }, |
+ |
+#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \ |
+ LPFILETIME))aSyscall[56].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT |
+ { "UnlockFile", (SYSCALL)UnlockFile, 0 }, |
+#else |
+ { "UnlockFile", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#ifndef osUnlockFile |
+#define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ |
+ DWORD))aSyscall[57].pCurrent) |
+#endif |
+ |
+#if !SQLITE_OS_WINCE |
+ { "UnlockFileEx", (SYSCALL)UnlockFileEx, 0 }, |
+#else |
+ { "UnlockFileEx", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osUnlockFileEx ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \ |
+ LPOVERLAPPED))aSyscall[58].pCurrent) |
+ |
+#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 |
+ { "UnmapViewOfFile", (SYSCALL)UnmapViewOfFile, 0 }, |
+#else |
+ { "UnmapViewOfFile", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osUnmapViewOfFile ((BOOL(WINAPI*)(LPCVOID))aSyscall[59].pCurrent) |
+ |
+ { "WideCharToMultiByte", (SYSCALL)WideCharToMultiByte, 0 }, |
+ |
+#define osWideCharToMultiByte ((int(WINAPI*)(UINT,DWORD,LPCWSTR,int,LPSTR,int, \ |
+ LPCSTR,LPBOOL))aSyscall[60].pCurrent) |
+ |
+ { "WriteFile", (SYSCALL)WriteFile, 0 }, |
+ |
+#define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \ |
+ LPOVERLAPPED))aSyscall[61].pCurrent) |
+ |
+#if SQLITE_OS_WINRT |
+ { "CreateEventExW", (SYSCALL)CreateEventExW, 0 }, |
+#else |
+ { "CreateEventExW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \ |
+ DWORD,DWORD))aSyscall[62].pCurrent) |
+ |
+#if !SQLITE_OS_WINRT |
+ { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, |
+#else |
+ { "WaitForSingleObject", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ |
+ DWORD))aSyscall[63].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE |
+ { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, |
+#else |
+ { "WaitForSingleObjectEx", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ |
+ BOOL))aSyscall[64].pCurrent) |
+ |
+#if SQLITE_OS_WINRT |
+ { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, |
+#else |
+ { "SetFilePointerEx", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \ |
+ PLARGE_INTEGER,DWORD))aSyscall[65].pCurrent) |
+ |
+#if SQLITE_OS_WINRT |
+ { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 }, |
+#else |
+ { "GetFileInformationByHandleEx", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ |
+ FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent) |
+ |
+#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) |
+ { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, |
+#else |
+ { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \ |
+ SIZE_T))aSyscall[67].pCurrent) |
+ |
+#if SQLITE_OS_WINRT |
+ { "CreateFile2", (SYSCALL)CreateFile2, 0 }, |
+#else |
+ { "CreateFile2", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \ |
+ LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[68].pCurrent) |
+ |
+#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION) |
+ { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 }, |
+#else |
+ { "LoadPackagedLibrary", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \ |
+ DWORD))aSyscall[69].pCurrent) |
+ |
+#if SQLITE_OS_WINRT |
+ { "GetTickCount64", (SYSCALL)GetTickCount64, 0 }, |
+#else |
+ { "GetTickCount64", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[70].pCurrent) |
+ |
+#if SQLITE_OS_WINRT |
+ { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 }, |
+#else |
+ { "GetNativeSystemInfo", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osGetNativeSystemInfo ((VOID(WINAPI*)( \ |
+ LPSYSTEM_INFO))aSyscall[71].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_ANSI) |
+ { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, |
+#else |
+ { "OutputDebugStringA", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[72].pCurrent) |
+ |
+#if defined(SQLITE_WIN32_HAS_WIDE) |
+ { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 }, |
+#else |
+ { "OutputDebugStringW", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[73].pCurrent) |
+ |
+ { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, |
+ |
+#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent) |
+ |
+#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) |
+ { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, |
+#else |
+ { "CreateFileMappingFromApp", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ |
+ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) |
+ |
+/* |
+** NOTE: On some sub-platforms, the InterlockedCompareExchange "function" |
+** is really just a macro that uses a compiler intrinsic (e.g. x64). |
+** So do not try to make this is into a redefinable interface. |
+*/ |
+#if defined(InterlockedCompareExchange) |
+ { "InterlockedCompareExchange", (SYSCALL)0, 0 }, |
+ |
+#define osInterlockedCompareExchange InterlockedCompareExchange |
+#else |
+ { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, |
+ |
+#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \ |
+ SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent) |
+#endif /* defined(InterlockedCompareExchange) */ |
+ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID |
+ { "UuidCreate", (SYSCALL)UuidCreate, 0 }, |
+#else |
+ { "UuidCreate", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent) |
+ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID |
+ { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 }, |
+#else |
+ { "UuidCreateSequential", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osUuidCreateSequential \ |
+ ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent) |
+ |
+#if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0 |
+ { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 }, |
+#else |
+ { "FlushViewOfFile", (SYSCALL)0, 0 }, |
+#endif |
+ |
+#define osFlushViewOfFile \ |
+ ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent) |
+ |
+}; /* End of the overrideable system calls */ |
+ |
+/* |
+** This is the xSetSystemCall() method of sqlite3_vfs for all of the |
+** "win32" VFSes. Return SQLITE_OK opon successfully updating the |
+** system call pointer, or SQLITE_NOTFOUND if there is no configurable |
+** system call named zName. |
+*/ |
+static int winSetSystemCall( |
+ sqlite3_vfs *pNotUsed, /* The VFS pointer. Not used */ |
+ const char *zName, /* Name of system call to override */ |
+ sqlite3_syscall_ptr pNewFunc /* Pointer to new system call value */ |
+){ |
+ unsigned int i; |
+ int rc = SQLITE_NOTFOUND; |
+ |
+ UNUSED_PARAMETER(pNotUsed); |
+ if( zName==0 ){ |
+ /* If no zName is given, restore all system calls to their default |
+ ** settings and return NULL |
+ */ |
+ rc = SQLITE_OK; |
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ |
+ if( aSyscall[i].pDefault ){ |
+ aSyscall[i].pCurrent = aSyscall[i].pDefault; |
+ } |
+ } |
+ }else{ |
+ /* If zName is specified, operate on only the one system call |
+ ** specified. |
+ */ |
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ |
+ if( strcmp(zName, aSyscall[i].zName)==0 ){ |
+ if( aSyscall[i].pDefault==0 ){ |
+ aSyscall[i].pDefault = aSyscall[i].pCurrent; |
+ } |
+ rc = SQLITE_OK; |
+ if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault; |
+ aSyscall[i].pCurrent = pNewFunc; |
+ break; |
+ } |
+ } |
+ } |
+ return rc; |
+} |
+ |
+/* |
+** Return the value of a system call. Return NULL if zName is not a |
+** recognized system call name. NULL is also returned if the system call |
+** is currently undefined. |
+*/ |
+static sqlite3_syscall_ptr winGetSystemCall( |
+ sqlite3_vfs *pNotUsed, |
+ const char *zName |
+){ |
+ unsigned int i; |
+ |
+ UNUSED_PARAMETER(pNotUsed); |
+ for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ |
+ if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent; |
+ } |
+ return 0; |
+} |
+ |
+/* |
+** Return the name of the first system call after zName. If zName==NULL |
+** then return the name of the first system call. Return NULL if zName |
+** is the last system call or if zName is not the name of a valid |
+** system call. |
+*/ |
+static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){ |
+ int i = -1; |
+ |
+ UNUSED_PARAMETER(p); |
+ if( zName ){ |
+ for(i=0; i<ArraySize(aSyscall)-1; i++){ |
+ if( strcmp(zName, aSyscall[i].zName)==0 ) break; |
+ } |
+ } |
+ for(i++; i<ArraySize(aSyscall); i++){ |
+ if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName; |
+ } |
+ return 0; |
+} |
+ |
+#ifdef SQLITE_WIN32_MALLOC |
+/* |
+** If a Win32 native heap has been configured, this function will attempt to |
+** compact it. Upon success, SQLITE_OK will be returned. Upon failure, one |
+** of SQLITE_NOMEM, SQLITE_ERROR, or SQLITE_NOTFOUND will be returned. The |
+** "pnLargest" argument, if non-zero, will be used to return the size of the |
+** largest committed free block in the heap, in bytes. |
+*/ |
+SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){ |
+ int rc = SQLITE_OK; |
+ UINT nLargest = 0; |
+ HANDLE hHeap; |
+ |
+ winMemAssertMagic(); |
+ hHeap = winMemGetHeap(); |
+ assert( hHeap!=0 ); |
+ assert( hHeap!=INVALID_HANDLE_VALUE ); |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) |
+ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); |
+#endif |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT |
+ if( (nLargest=osHeapCompact(hHeap, SQLITE_WIN32_HEAP_FLAGS))==0 ){ |
+ DWORD lastErrno = osGetLastError(); |
+ if( lastErrno==NO_ERROR ){ |
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p", |
+ (void*)hHeap); |
+ rc = SQLITE_NOMEM_BKPT; |
+ }else{ |
+ sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p", |
+ osGetLastError(), (void*)hHeap); |
+ rc = SQLITE_ERROR; |
+ } |
+ } |
+#else |
+ sqlite3_log(SQLITE_NOTFOUND, "failed to HeapCompact, heap=%p", |
+ (void*)hHeap); |
+ rc = SQLITE_NOTFOUND; |
+#endif |
+ if( pnLargest ) *pnLargest = nLargest; |
+ return rc; |
+} |
+ |
+/* |
+** If a Win32 native heap has been configured, this function will attempt to |
+** destroy and recreate it. If the Win32 native heap is not isolated and/or |
+** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will |
+** be returned and no changes will be made to the Win32 native heap. |
+*/ |
+SQLITE_API int sqlite3_win32_reset_heap(){ |
+ int rc; |
+ MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */ |
+ MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */ |
+ MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) |
+ MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); ) |
+ sqlite3_mutex_enter(pMaster); |
+ sqlite3_mutex_enter(pMem); |
+ winMemAssertMagic(); |
+ if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){ |
+ /* |
+ ** At this point, there should be no outstanding memory allocations on |
+ ** the heap. Also, since both the master and memsys locks are currently |
+ ** being held by us, no other function (i.e. from another thread) should |
+ ** be able to even access the heap. Attempt to destroy and recreate our |
+ ** isolated Win32 native heap now. |
+ */ |
+ assert( winMemGetHeap()!=NULL ); |
+ assert( winMemGetOwned() ); |
+ assert( sqlite3_memory_used()==0 ); |
+ winMemShutdown(winMemGetDataPtr()); |
+ assert( winMemGetHeap()==NULL ); |
+ assert( !winMemGetOwned() ); |
+ assert( sqlite3_memory_used()==0 ); |
+ rc = winMemInit(winMemGetDataPtr()); |
+ assert( rc!=SQLITE_OK || winMemGetHeap()!=NULL ); |
+ assert( rc!=SQLITE_OK || winMemGetOwned() ); |
+ assert( rc!=SQLITE_OK || sqlite3_memory_used()==0 ); |
+ }else{ |
+ /* |
+ ** The Win32 native heap cannot be modified because it may be in use. |
+ */ |
+ rc = SQLITE_BUSY; |
+ } |
+ sqlite3_mutex_leave(pMem); |
+ sqlite3_mutex_leave(pMaster); |
+ return rc; |
+} |
+#endif /* SQLITE_WIN32_MALLOC */ |
+ |
+/* |
+** This function outputs the specified (ANSI) string to the Win32 debugger |
+** (if available). |
+*/ |
+ |
+SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ |
+ char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE]; |
+ int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */ |
+ if( nMin<-1 ) nMin = -1; /* all negative values become -1. */ |
+ assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE ); |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( !zBuf ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return; |
+ } |
+#endif |
+#if defined(SQLITE_WIN32_HAS_ANSI) |
+ if( nMin>0 ){ |
+ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); |
+ memcpy(zDbgBuf, zBuf, nMin); |
+ osOutputDebugStringA(zDbgBuf); |
+ }else{ |
+ osOutputDebugStringA(zBuf); |
+ } |
+#elif defined(SQLITE_WIN32_HAS_WIDE) |
+ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); |
+ if ( osMultiByteToWideChar( |
+ osAreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, zBuf, |
+ nMin, (LPWSTR)zDbgBuf, SQLITE_WIN32_DBG_BUF_SIZE/sizeof(WCHAR))<=0 ){ |
+ return; |
+ } |
+ osOutputDebugStringW((LPCWSTR)zDbgBuf); |
+#else |
+ if( nMin>0 ){ |
+ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); |
+ memcpy(zDbgBuf, zBuf, nMin); |
+ fprintf(stderr, "%s", zDbgBuf); |
+ }else{ |
+ fprintf(stderr, "%s", zBuf); |
+ } |
+#endif |
+} |
+ |
+/* |
+** The following routine suspends the current thread for at least ms |
+** milliseconds. This is equivalent to the Win32 Sleep() interface. |
+*/ |
+#if SQLITE_OS_WINRT |
+static HANDLE sleepObj = NULL; |
+#endif |
+ |
+SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ |
+#if SQLITE_OS_WINRT |
+ if ( sleepObj==NULL ){ |
+ sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET, |
+ SYNCHRONIZE); |
+ } |
+ assert( sleepObj!=NULL ); |
+ osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE); |
+#else |
+ osSleep(milliseconds); |
+#endif |
+} |
+ |
+#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ |
+ SQLITE_THREADSAFE>0 |
+SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ |
+ DWORD rc; |
+ while( (rc = osWaitForSingleObjectEx(hObject, INFINITE, |
+ TRUE))==WAIT_IO_COMPLETION ){} |
+ return rc; |
+} |
+#endif |
+ |
+/* |
+** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, |
+** or WinCE. Return false (zero) for Win95, Win98, or WinME. |
+** |
+** Here is an interesting observation: Win95, Win98, and WinME lack |
+** the LockFileEx() API. But we can still statically link against that |
+** API as long as we don't call it when running Win95/98/ME. A call to |
+** this routine is used to determine if the host is Win95/98/ME or |
+** WinNT/2K/XP so that we will know whether or not we can safely call |
+** the LockFileEx() API. |
+*/ |
+ |
+#if !SQLITE_WIN32_GETVERSIONEX |
+# define osIsNT() (1) |
+#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) |
+# define osIsNT() (1) |
+#elif !defined(SQLITE_WIN32_HAS_WIDE) |
+# define osIsNT() (0) |
+#else |
+# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt()) |
+#endif |
+ |
+/* |
+** This function determines if the machine is running a version of Windows |
+** based on the NT kernel. |
+*/ |
+SQLITE_API int sqlite3_win32_is_nt(void){ |
+#if SQLITE_OS_WINRT |
+ /* |
+ ** NOTE: The WinRT sub-platform is always assumed to be based on the NT |
+ ** kernel. |
+ */ |
+ return 1; |
+#elif SQLITE_WIN32_GETVERSIONEX |
+ if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ |
+#if defined(SQLITE_WIN32_HAS_ANSI) |
+ OSVERSIONINFOA sInfo; |
+ sInfo.dwOSVersionInfoSize = sizeof(sInfo); |
+ osGetVersionExA(&sInfo); |
+ osInterlockedCompareExchange(&sqlite3_os_type, |
+ (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); |
+#elif defined(SQLITE_WIN32_HAS_WIDE) |
+ OSVERSIONINFOW sInfo; |
+ sInfo.dwOSVersionInfoSize = sizeof(sInfo); |
+ osGetVersionExW(&sInfo); |
+ osInterlockedCompareExchange(&sqlite3_os_type, |
+ (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); |
+#endif |
+ } |
+ return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; |
+#elif SQLITE_TEST |
+ return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; |
+#else |
+ /* |
+ ** NOTE: All sub-platforms where the GetVersionEx[AW] functions are |
+ ** deprecated are always assumed to be based on the NT kernel. |
+ */ |
+ return 1; |
+#endif |
+} |
+ |
+#ifdef SQLITE_WIN32_MALLOC |
+/* |
+** Allocate nBytes of memory. |
+*/ |
+static void *winMemMalloc(int nBytes){ |
+ HANDLE hHeap; |
+ void *p; |
+ |
+ winMemAssertMagic(); |
+ hHeap = winMemGetHeap(); |
+ assert( hHeap!=0 ); |
+ assert( hHeap!=INVALID_HANDLE_VALUE ); |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) |
+ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); |
+#endif |
+ assert( nBytes>=0 ); |
+ p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); |
+ if( !p ){ |
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%lu), heap=%p", |
+ nBytes, osGetLastError(), (void*)hHeap); |
+ } |
+ return p; |
+} |
+ |
+/* |
+** Free memory. |
+*/ |
+static void winMemFree(void *pPrior){ |
+ HANDLE hHeap; |
+ |
+ winMemAssertMagic(); |
+ hHeap = winMemGetHeap(); |
+ assert( hHeap!=0 ); |
+ assert( hHeap!=INVALID_HANDLE_VALUE ); |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) |
+ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); |
+#endif |
+ if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */ |
+ if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){ |
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%lu), heap=%p", |
+ pPrior, osGetLastError(), (void*)hHeap); |
+ } |
+} |
+ |
+/* |
+** Change the size of an existing memory allocation |
+*/ |
+static void *winMemRealloc(void *pPrior, int nBytes){ |
+ HANDLE hHeap; |
+ void *p; |
+ |
+ winMemAssertMagic(); |
+ hHeap = winMemGetHeap(); |
+ assert( hHeap!=0 ); |
+ assert( hHeap!=INVALID_HANDLE_VALUE ); |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) |
+ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); |
+#endif |
+ assert( nBytes>=0 ); |
+ if( !pPrior ){ |
+ p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes); |
+ }else{ |
+ p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes); |
+ } |
+ if( !p ){ |
+ sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%lu), heap=%p", |
+ pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(), |
+ (void*)hHeap); |
+ } |
+ return p; |
+} |
+ |
+/* |
+** Return the size of an outstanding allocation, in bytes. |
+*/ |
+static int winMemSize(void *p){ |
+ HANDLE hHeap; |
+ SIZE_T n; |
+ |
+ winMemAssertMagic(); |
+ hHeap = winMemGetHeap(); |
+ assert( hHeap!=0 ); |
+ assert( hHeap!=INVALID_HANDLE_VALUE ); |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) |
+ assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, p) ); |
+#endif |
+ if( !p ) return 0; |
+ n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p); |
+ if( n==(SIZE_T)-1 ){ |
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%lu), heap=%p", |
+ p, osGetLastError(), (void*)hHeap); |
+ return 0; |
+ } |
+ return (int)n; |
+} |
+ |
+/* |
+** Round up a request size to the next valid allocation size. |
+*/ |
+static int winMemRoundup(int n){ |
+ return n; |
+} |
+ |
+/* |
+** Initialize this module. |
+*/ |
+static int winMemInit(void *pAppData){ |
+ winMemData *pWinMemData = (winMemData *)pAppData; |
+ |
+ if( !pWinMemData ) return SQLITE_ERROR; |
+ assert( pWinMemData->magic1==WINMEM_MAGIC1 ); |
+ assert( pWinMemData->magic2==WINMEM_MAGIC2 ); |
+ |
+#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE |
+ if( !pWinMemData->hHeap ){ |
+ DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE; |
+ DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap; |
+ if( dwMaximumSize==0 ){ |
+ dwMaximumSize = SQLITE_WIN32_HEAP_MAX_SIZE; |
+ }else if( dwInitialSize>dwMaximumSize ){ |
+ dwInitialSize = dwMaximumSize; |
+ } |
+ pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS, |
+ dwInitialSize, dwMaximumSize); |
+ if( !pWinMemData->hHeap ){ |
+ sqlite3_log(SQLITE_NOMEM, |
+ "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu", |
+ osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize, |
+ dwMaximumSize); |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ pWinMemData->bOwned = TRUE; |
+ assert( pWinMemData->bOwned ); |
+ } |
+#else |
+ pWinMemData->hHeap = osGetProcessHeap(); |
+ if( !pWinMemData->hHeap ){ |
+ sqlite3_log(SQLITE_NOMEM, |
+ "failed to GetProcessHeap (%lu)", osGetLastError()); |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ pWinMemData->bOwned = FALSE; |
+ assert( !pWinMemData->bOwned ); |
+#endif |
+ assert( pWinMemData->hHeap!=0 ); |
+ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) |
+ assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); |
+#endif |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Deinitialize this module. |
+*/ |
+static void winMemShutdown(void *pAppData){ |
+ winMemData *pWinMemData = (winMemData *)pAppData; |
+ |
+ if( !pWinMemData ) return; |
+ assert( pWinMemData->magic1==WINMEM_MAGIC1 ); |
+ assert( pWinMemData->magic2==WINMEM_MAGIC2 ); |
+ |
+ if( pWinMemData->hHeap ){ |
+ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); |
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) |
+ assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); |
+#endif |
+ if( pWinMemData->bOwned ){ |
+ if( !osHeapDestroy(pWinMemData->hHeap) ){ |
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%lu), heap=%p", |
+ osGetLastError(), (void*)pWinMemData->hHeap); |
+ } |
+ pWinMemData->bOwned = FALSE; |
+ } |
+ pWinMemData->hHeap = NULL; |
+ } |
+} |
+ |
+/* |
+** Populate the low-level memory allocation function pointers in |
+** sqlite3GlobalConfig.m with pointers to the routines in this file. The |
+** arguments specify the block of memory to manage. |
+** |
+** This routine is only called by sqlite3_config(), and therefore |
+** is not required to be threadsafe (it is not). |
+*/ |
+SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void){ |
+ static const sqlite3_mem_methods winMemMethods = { |
+ winMemMalloc, |
+ winMemFree, |
+ winMemRealloc, |
+ winMemSize, |
+ winMemRoundup, |
+ winMemInit, |
+ winMemShutdown, |
+ &win_mem_data |
+ }; |
+ return &winMemMethods; |
+} |
+ |
+SQLITE_PRIVATE void sqlite3MemSetDefault(void){ |
+ sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32()); |
+} |
+#endif /* SQLITE_WIN32_MALLOC */ |
+ |
+/* |
+** Convert a UTF-8 string to Microsoft Unicode. |
+** |
+** Space to hold the returned string is obtained from sqlite3_malloc(). |
+*/ |
+static LPWSTR winUtf8ToUnicode(const char *zText){ |
+ int nChar; |
+ LPWSTR zWideText; |
+ |
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0); |
+ if( nChar==0 ){ |
+ return 0; |
+ } |
+ zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) ); |
+ if( zWideText==0 ){ |
+ return 0; |
+ } |
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText, |
+ nChar); |
+ if( nChar==0 ){ |
+ sqlite3_free(zWideText); |
+ zWideText = 0; |
+ } |
+ return zWideText; |
+} |
+ |
+/* |
+** Convert a Microsoft Unicode string to UTF-8. |
+** |
+** Space to hold the returned string is obtained from sqlite3_malloc(). |
+*/ |
+static char *winUnicodeToUtf8(LPCWSTR zWideText){ |
+ int nByte; |
+ char *zText; |
+ |
+ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0); |
+ if( nByte == 0 ){ |
+ return 0; |
+ } |
+ zText = sqlite3MallocZero( nByte ); |
+ if( zText==0 ){ |
+ return 0; |
+ } |
+ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte, |
+ 0, 0); |
+ if( nByte == 0 ){ |
+ sqlite3_free(zText); |
+ zText = 0; |
+ } |
+ return zText; |
+} |
+ |
+/* |
+** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM |
+** code page. |
+** |
+** Space to hold the returned string is obtained from sqlite3_malloc(). |
+*/ |
+static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){ |
+ int nByte; |
+ LPWSTR zMbcsText; |
+ int codepage = useAnsi ? CP_ACP : CP_OEMCP; |
+ |
+ nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL, |
+ 0)*sizeof(WCHAR); |
+ if( nByte==0 ){ |
+ return 0; |
+ } |
+ zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) ); |
+ if( zMbcsText==0 ){ |
+ return 0; |
+ } |
+ nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText, |
+ nByte); |
+ if( nByte==0 ){ |
+ sqlite3_free(zMbcsText); |
+ zMbcsText = 0; |
+ } |
+ return zMbcsText; |
+} |
+ |
+/* |
+** Convert a Microsoft Unicode string to a multi-byte character string, |
+** using the ANSI or OEM code page. |
+** |
+** Space to hold the returned string is obtained from sqlite3_malloc(). |
+*/ |
+static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){ |
+ int nByte; |
+ char *zText; |
+ int codepage = useAnsi ? CP_ACP : CP_OEMCP; |
+ |
+ nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0); |
+ if( nByte == 0 ){ |
+ return 0; |
+ } |
+ zText = sqlite3MallocZero( nByte ); |
+ if( zText==0 ){ |
+ return 0; |
+ } |
+ nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, zText, |
+ nByte, 0, 0); |
+ if( nByte == 0 ){ |
+ sqlite3_free(zText); |
+ zText = 0; |
+ } |
+ return zText; |
+} |
+ |
+/* |
+** Convert a multi-byte character string to UTF-8. |
+** |
+** Space to hold the returned string is obtained from sqlite3_malloc(). |
+*/ |
+static char *winMbcsToUtf8(const char *zText, int useAnsi){ |
+ char *zTextUtf8; |
+ LPWSTR zTmpWide; |
+ |
+ zTmpWide = winMbcsToUnicode(zText, useAnsi); |
+ if( zTmpWide==0 ){ |
+ return 0; |
+ } |
+ zTextUtf8 = winUnicodeToUtf8(zTmpWide); |
+ sqlite3_free(zTmpWide); |
+ return zTextUtf8; |
+} |
+ |
+/* |
+** Convert a UTF-8 string to a multi-byte character string. |
+** |
+** Space to hold the returned string is obtained from sqlite3_malloc(). |
+*/ |
+static char *winUtf8ToMbcs(const char *zText, int useAnsi){ |
+ char *zTextMbcs; |
+ LPWSTR zTmpWide; |
+ |
+ zTmpWide = winUtf8ToUnicode(zText); |
+ if( zTmpWide==0 ){ |
+ return 0; |
+ } |
+ zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi); |
+ sqlite3_free(zTmpWide); |
+ return zTextMbcs; |
+} |
+ |
+/* |
+** This is a public wrapper for the winUtf8ToUnicode() function. |
+*/ |
+SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText){ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( !zText ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ return winUtf8ToUnicode(zText); |
+} |
+ |
+/* |
+** This is a public wrapper for the winUnicodeToUtf8() function. |
+*/ |
+SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( !zWideText ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ return winUnicodeToUtf8(zWideText); |
+} |
+ |
+/* |
+** This is a public wrapper for the winMbcsToUtf8() function. |
+*/ |
+SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( !zText ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ return winMbcsToUtf8(zText, osAreFileApisANSI()); |
+} |
+ |
+/* |
+** This is a public wrapper for the winMbcsToUtf8() function. |
+*/ |
+SQLITE_API char *sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( !zText ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ return winMbcsToUtf8(zText, useAnsi); |
+} |
+ |
+/* |
+** This is a public wrapper for the winUtf8ToMbcs() function. |
+*/ |
+SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zText){ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( !zText ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ return winUtf8ToMbcs(zText, osAreFileApisANSI()); |
+} |
+ |
+/* |
+** This is a public wrapper for the winUtf8ToMbcs() function. |
+*/ |
+SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){ |
+#ifdef SQLITE_ENABLE_API_ARMOR |
+ if( !zText ){ |
+ (void)SQLITE_MISUSE_BKPT; |
+ return 0; |
+ } |
+#endif |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ if( sqlite3_initialize() ) return 0; |
+#endif |
+ return winUtf8ToMbcs(zText, useAnsi); |
+} |
+ |
+/* |
+** This function sets the data directory or the temporary directory based on |
+** the provided arguments. The type argument must be 1 in order to set the |
+** data directory or 2 in order to set the temporary directory. The zValue |
+** argument is the name of the directory to use. The return value will be |
+** SQLITE_OK if successful. |
+*/ |
+SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ |
+ char **ppDirectory = 0; |
+#ifndef SQLITE_OMIT_AUTOINIT |
+ int rc = sqlite3_initialize(); |
+ if( rc ) return rc; |
+#endif |
+ if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){ |
+ ppDirectory = &sqlite3_data_directory; |
+ }else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){ |
+ ppDirectory = &sqlite3_temp_directory; |
+ } |
+ assert( !ppDirectory || type==SQLITE_WIN32_DATA_DIRECTORY_TYPE |
+ || type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE |
+ ); |
+ assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) ); |
+ if( ppDirectory ){ |
+ char *zValueUtf8 = 0; |
+ if( zValue && zValue[0] ){ |
+ zValueUtf8 = winUnicodeToUtf8(zValue); |
+ if ( zValueUtf8==0 ){ |
+ return SQLITE_NOMEM_BKPT; |
+ } |
+ } |
+ sqlite3_free(*ppDirectory); |
+ *ppDirectory = zValueUtf8; |
+ return SQLITE_OK; |
+ } |
+ return SQLITE_ERROR; |
+} |
+ |
+/* |
+** The return value of winGetLastErrorMsg |
+** is zero if the error message fits in the buffer, or non-zero |
+** otherwise (if the message was truncated). |
+*/ |
+static int winGetLastErrorMsg(DWORD lastErrno, 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 dwLen = 0; |
+ char *zOut = 0; |
+ |
+ if( osIsNT() ){ |
+#if SQLITE_OS_WINRT |
+ WCHAR zTempWide[SQLITE_WIN32_MAX_ERRMSG_CHARS+1]; |
+ dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | |
+ FORMAT_MESSAGE_IGNORE_INSERTS, |
+ NULL, |
+ lastErrno, |
+ 0, |
+ zTempWide, |
+ SQLITE_WIN32_MAX_ERRMSG_CHARS, |
+ 0); |
+#else |
+ LPWSTR zTempWide = NULL; |
+ dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | |
+ FORMAT_MESSAGE_FROM_SYSTEM | |
+ FORMAT_MESSAGE_IGNORE_INSERTS, |
+ NULL, |
+ lastErrno, |
+ 0, |
+ (LPWSTR) &zTempWide, |
+ 0, |
+ 0); |
+#endif |
+ if( dwLen > 0 ){ |
+ /* allocate a buffer and convert to UTF8 */ |
+ sqlite3BeginBenignMalloc(); |
+ zOut = winUnicodeToUtf8(zTempWide); |
+ sqlite3EndBenignMalloc(); |
+#if !SQLITE_OS_WINRT |
+ /* free the system buffer allocated by FormatMessage */ |
+ osLocalFree(zTempWide); |
+#endif |
+ } |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ char *zTemp = NULL; |
+ dwLen = osFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | |
+ FORMAT_MESSAGE_FROM_SYSTEM | |
+ FORMAT_MESSAGE_IGNORE_INSERTS, |
+ NULL, |
+ lastErrno, |
+ 0, |
+ (LPSTR) &zTemp, |
+ 0, |
+ 0); |
+ if( dwLen > 0 ){ |
+ /* allocate a buffer and convert to UTF8 */ |
+ sqlite3BeginBenignMalloc(); |
+ zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); |
+ sqlite3EndBenignMalloc(); |
+ /* free the system buffer allocated by FormatMessage */ |
+ osLocalFree(zTemp); |
+ } |
+ } |
+#endif |
+ if( 0 == dwLen ){ |
+ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno); |
+ }else{ |
+ /* copy a maximum of nBuf chars to output buffer */ |
+ sqlite3_snprintf(nBuf, zBuf, "%s", zOut); |
+ /* free the UTF8 buffer */ |
+ sqlite3_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 associated file-system path, if any. |
+*/ |
+#define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__) |
+static int winLogErrorAtLine( |
+ int errcode, /* SQLite error code */ |
+ DWORD lastErrno, /* Win32 last error */ |
+ 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 */ |
+ |
+ zMsg[0] = 0; |
+ winGetLastErrorMsg(lastErrno, 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: (%lu) %s(%s) - %s", |
+ iLine, lastErrno, zFunc, zPath, zMsg |
+ ); |
+ |
+ return errcode; |
+} |
+ |
+/* |
+** The number of times that a ReadFile(), WriteFile(), and DeleteFile() |
+** will be retried following a locking error - probably caused by |
+** antivirus software. Also the initial delay before the first retry. |
+** The delay increases linearly with each retry. |
+*/ |
+#ifndef SQLITE_WIN32_IOERR_RETRY |
+# define SQLITE_WIN32_IOERR_RETRY 10 |
+#endif |
+#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY |
+# define SQLITE_WIN32_IOERR_RETRY_DELAY 25 |
+#endif |
+static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY; |
+static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY; |
+ |
+/* |
+** The "winIoerrCanRetry1" macro is used to determine if a particular I/O |
+** error code obtained via GetLastError() is eligible to be retried. It |
+** must accept the error code DWORD as its only argument and should return |
+** non-zero if the error code is transient in nature and the operation |
+** responsible for generating the original error might succeed upon being |
+** retried. The argument to this macro should be a variable. |
+** |
+** Additionally, a macro named "winIoerrCanRetry2" may be defined. If it |
+** is defined, it will be consulted only when the macro "winIoerrCanRetry1" |
+** returns zero. The "winIoerrCanRetry2" macro is completely optional and |
+** may be used to include additional error codes in the set that should |
+** result in the failing I/O operation being retried by the caller. If |
+** defined, the "winIoerrCanRetry2" macro must exhibit external semantics |
+** identical to those of the "winIoerrCanRetry1" macro. |
+*/ |
+#if !defined(winIoerrCanRetry1) |
+#define winIoerrCanRetry1(a) (((a)==ERROR_ACCESS_DENIED) || \ |
+ ((a)==ERROR_SHARING_VIOLATION) || \ |
+ ((a)==ERROR_LOCK_VIOLATION) || \ |
+ ((a)==ERROR_DEV_NOT_EXIST) || \ |
+ ((a)==ERROR_NETNAME_DELETED) || \ |
+ ((a)==ERROR_SEM_TIMEOUT) || \ |
+ ((a)==ERROR_NETWORK_UNREACHABLE)) |
+#endif |
+ |
+/* |
+** If a ReadFile() or WriteFile() error occurs, invoke this routine |
+** to see if it should be retried. Return TRUE to retry. Return FALSE |
+** to give up with an error. |
+*/ |
+static int winRetryIoerr(int *pnRetry, DWORD *pError){ |
+ DWORD e = osGetLastError(); |
+ if( *pnRetry>=winIoerrRetry ){ |
+ if( pError ){ |
+ *pError = e; |
+ } |
+ return 0; |
+ } |
+ if( winIoerrCanRetry1(e) ){ |
+ sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); |
+ ++*pnRetry; |
+ return 1; |
+ } |
+#if defined(winIoerrCanRetry2) |
+ else if( winIoerrCanRetry2(e) ){ |
+ sqlite3_win32_sleep(winIoerrRetryDelay*(1+*pnRetry)); |
+ ++*pnRetry; |
+ return 1; |
+ } |
+#endif |
+ if( pError ){ |
+ *pError = e; |
+ } |
+ return 0; |
+} |
+ |
+/* |
+** Log a I/O error retry episode. |
+*/ |
+static void winLogIoerr(int nRetry, int lineno){ |
+ if( nRetry ){ |
+ sqlite3_log(SQLITE_NOTICE, |
+ "delayed %dms for lock/sharing conflict at line %d", |
+ winIoerrRetryDelay*nRetry*(nRetry+1)/2, lineno |
+ ); |
+ } |
+} |
+ |
+/* |
+** This #if does not rely on the SQLITE_OS_WINCE define because the |
+** corresponding section in "date.c" cannot use it. |
+*/ |
+#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \ |
+ (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API) |
+/* |
+** The MSVC CRT on Windows CE may not have a localtime() function. |
+** So define a substitute. |
+*/ |
+/* # include <time.h> */ |
+struct tm *__cdecl localtime(const time_t *t) |
+{ |
+ static struct tm y; |
+ FILETIME uTm, lTm; |
+ SYSTEMTIME pTm; |
+ sqlite3_int64 t64; |
+ t64 = *t; |
+ t64 = (t64 + 11644473600)*10000000; |
+ uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF); |
+ uTm.dwHighDateTime= (DWORD)(t64 >> 32); |
+ osFileTimeToLocalFileTime(&uTm,&lTm); |
+ osFileTimeToSystemTime(&lTm,&pTm); |
+ y.tm_year = pTm.wYear - 1900; |
+ y.tm_mon = pTm.wMonth - 1; |
+ y.tm_wday = pTm.wDayOfWeek; |
+ y.tm_mday = pTm.wDay; |
+ y.tm_hour = pTm.wHour; |
+ y.tm_min = pTm.wMinute; |
+ y.tm_sec = pTm.wSecond; |
+ return &y; |
+} |
+#endif |
+ |
+#if SQLITE_OS_WINCE |
+/************************************************************************* |
+** This section contains code for WinCE only. |
+*/ |
+#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)] |
+ |
+/* |
+** Acquire a lock on the handle h |
+*/ |
+static void winceMutexAcquire(HANDLE h){ |
+ DWORD dwErr; |
+ do { |
+ dwErr = osWaitForSingleObject(h, INFINITE); |
+ } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED); |
+} |
+/* |
+** Release a lock acquired by winceMutexAcquire() |
+*/ |
+#define winceMutexRelease(h) ReleaseMutex(h) |
+ |
+/* |
+** Create the mutex and shared memory used for locking in the file |
+** descriptor pFile |
+*/ |
+static int winceCreateLock(const char *zFilename, winFile *pFile){ |
+ LPWSTR zTok; |
+ LPWSTR zName; |
+ DWORD lastErrno; |
+ BOOL bLogged = FALSE; |
+ BOOL bInit = TRUE; |
+ |
+ zName = winUtf8ToUnicode(zFilename); |
+ if( zName==0 ){ |
+ /* out of memory */ |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ |
+ /* Initialize the local lockdata */ |
+ memset(&pFile->local, 0, sizeof(pFile->local)); |
+ |
+ /* Replace the backslashes from the filename and lowercase it |
+ ** to derive a mutex name. */ |
+ zTok = osCharLowerW(zName); |
+ for (;*zTok;zTok++){ |
+ if (*zTok == '\\') *zTok = '_'; |
+ } |
+ |
+ /* Create/open the named mutex */ |
+ pFile->hMutex = osCreateMutexW(NULL, FALSE, zName); |
+ if (!pFile->hMutex){ |
+ pFile->lastErrno = osGetLastError(); |
+ sqlite3_free(zName); |
+ return winLogError(SQLITE_IOERR, pFile->lastErrno, |
+ "winceCreateLock1", zFilename); |
+ } |
+ |
+ /* Acquire the mutex before continuing */ |
+ winceMutexAcquire(pFile->hMutex); |
+ |
+ /* Since the names of named mutexes, semaphores, file mappings etc are |
+ ** case-sensitive, take advantage of that by uppercasing the mutex name |
+ ** and using that as the shared filemapping name. |
+ */ |
+ osCharUpperW(zName); |
+ pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL, |
+ PAGE_READWRITE, 0, sizeof(winceLock), |
+ zName); |
+ |
+ /* Set a flag that indicates we're the first to create the memory so it |
+ ** must be zero-initialized */ |
+ lastErrno = osGetLastError(); |
+ if (lastErrno == ERROR_ALREADY_EXISTS){ |
+ bInit = FALSE; |
+ } |
+ |
+ sqlite3_free(zName); |
+ |
+ /* If we succeeded in making the shared memory handle, map it. */ |
+ if( pFile->hShared ){ |
+ pFile->shared = (winceLock*)osMapViewOfFile(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 = osGetLastError(); |
+ winLogError(SQLITE_IOERR, pFile->lastErrno, |
+ "winceCreateLock2", zFilename); |
+ bLogged = TRUE; |
+ osCloseHandle(pFile->hShared); |
+ pFile->hShared = NULL; |
+ } |
+ } |
+ |
+ /* If shared memory could not be created, then close the mutex and fail */ |
+ if( pFile->hShared==NULL ){ |
+ if( !bLogged ){ |
+ pFile->lastErrno = lastErrno; |
+ winLogError(SQLITE_IOERR, pFile->lastErrno, |
+ "winceCreateLock3", zFilename); |
+ bLogged = TRUE; |
+ } |
+ winceMutexRelease(pFile->hMutex); |
+ osCloseHandle(pFile->hMutex); |
+ pFile->hMutex = NULL; |
+ return SQLITE_IOERR; |
+ } |
+ |
+ /* Initialize the shared memory if we're supposed to */ |
+ if( bInit ){ |
+ memset(pFile->shared, 0, sizeof(winceLock)); |
+ } |
+ |
+ winceMutexRelease(pFile->hMutex); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Destroy the part of winFile that deals with wince locks |
+*/ |
+static void winceDestroyLock(winFile *pFile){ |
+ if (pFile->hMutex){ |
+ /* Acquire the mutex */ |
+ winceMutexAcquire(pFile->hMutex); |
+ |
+ /* The following blocks should probably assert in debug mode, but they |
+ are to cleanup in case any locks remained open */ |
+ if (pFile->local.nReaders){ |
+ pFile->shared->nReaders --; |
+ } |
+ if (pFile->local.bReserved){ |
+ pFile->shared->bReserved = FALSE; |
+ } |
+ if (pFile->local.bPending){ |
+ pFile->shared->bPending = FALSE; |
+ } |
+ if (pFile->local.bExclusive){ |
+ pFile->shared->bExclusive = FALSE; |
+ } |
+ |
+ /* De-reference and close our copy of the shared memory handle */ |
+ osUnmapViewOfFile(pFile->shared); |
+ osCloseHandle(pFile->hShared); |
+ |
+ /* Done with the mutex */ |
+ winceMutexRelease(pFile->hMutex); |
+ osCloseHandle(pFile->hMutex); |
+ pFile->hMutex = NULL; |
+ } |
+} |
+ |
+/* |
+** An implementation of the LockFile() API of Windows for CE |
+*/ |
+static BOOL winceLockFile( |
+ LPHANDLE phFile, |
+ DWORD dwFileOffsetLow, |
+ DWORD dwFileOffsetHigh, |
+ DWORD nNumberOfBytesToLockLow, |
+ DWORD nNumberOfBytesToLockHigh |
+){ |
+ winFile *pFile = HANDLE_TO_WINFILE(phFile); |
+ BOOL bReturn = FALSE; |
+ |
+ UNUSED_PARAMETER(dwFileOffsetHigh); |
+ UNUSED_PARAMETER(nNumberOfBytesToLockHigh); |
+ |
+ if (!pFile->hMutex) return TRUE; |
+ winceMutexAcquire(pFile->hMutex); |
+ |
+ /* Wanting an exclusive lock? */ |
+ if (dwFileOffsetLow == (DWORD)SHARED_FIRST |
+ && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){ |
+ if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){ |
+ pFile->shared->bExclusive = TRUE; |
+ pFile->local.bExclusive = TRUE; |
+ bReturn = TRUE; |
+ } |
+ } |
+ |
+ /* Want a read-only lock? */ |
+ else if (dwFileOffsetLow == (DWORD)SHARED_FIRST && |
+ nNumberOfBytesToLockLow == 1){ |
+ if (pFile->shared->bExclusive == 0){ |
+ pFile->local.nReaders ++; |
+ if (pFile->local.nReaders == 1){ |
+ pFile->shared->nReaders ++; |
+ } |
+ bReturn = TRUE; |
+ } |
+ } |
+ |
+ /* Want a pending lock? */ |
+ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE |
+ && nNumberOfBytesToLockLow == 1){ |
+ /* If no pending lock has been acquired, then acquire it */ |
+ if (pFile->shared->bPending == 0) { |
+ pFile->shared->bPending = TRUE; |
+ pFile->local.bPending = TRUE; |
+ bReturn = TRUE; |
+ } |
+ } |
+ |
+ /* Want a reserved lock? */ |
+ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE |
+ && nNumberOfBytesToLockLow == 1){ |
+ if (pFile->shared->bReserved == 0) { |
+ pFile->shared->bReserved = TRUE; |
+ pFile->local.bReserved = TRUE; |
+ bReturn = TRUE; |
+ } |
+ } |
+ |
+ winceMutexRelease(pFile->hMutex); |
+ return bReturn; |
+} |
+ |
+/* |
+** An implementation of the UnlockFile API of Windows for CE |
+*/ |
+static BOOL winceUnlockFile( |
+ LPHANDLE phFile, |
+ DWORD dwFileOffsetLow, |
+ DWORD dwFileOffsetHigh, |
+ DWORD nNumberOfBytesToUnlockLow, |
+ DWORD nNumberOfBytesToUnlockHigh |
+){ |
+ winFile *pFile = HANDLE_TO_WINFILE(phFile); |
+ BOOL bReturn = FALSE; |
+ |
+ UNUSED_PARAMETER(dwFileOffsetHigh); |
+ UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh); |
+ |
+ if (!pFile->hMutex) return TRUE; |
+ winceMutexAcquire(pFile->hMutex); |
+ |
+ /* Releasing a reader lock or an exclusive lock */ |
+ if (dwFileOffsetLow == (DWORD)SHARED_FIRST){ |
+ /* Did we have an exclusive lock? */ |
+ if (pFile->local.bExclusive){ |
+ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE); |
+ pFile->local.bExclusive = FALSE; |
+ pFile->shared->bExclusive = FALSE; |
+ bReturn = TRUE; |
+ } |
+ |
+ /* Did we just have a reader lock? */ |
+ else if (pFile->local.nReaders){ |
+ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE |
+ || nNumberOfBytesToUnlockLow == 1); |
+ pFile->local.nReaders --; |
+ if (pFile->local.nReaders == 0) |
+ { |
+ pFile->shared->nReaders --; |
+ } |
+ bReturn = TRUE; |
+ } |
+ } |
+ |
+ /* Releasing a pending lock */ |
+ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE |
+ && nNumberOfBytesToUnlockLow == 1){ |
+ if (pFile->local.bPending){ |
+ pFile->local.bPending = FALSE; |
+ pFile->shared->bPending = FALSE; |
+ bReturn = TRUE; |
+ } |
+ } |
+ /* Releasing a reserved lock */ |
+ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE |
+ && nNumberOfBytesToUnlockLow == 1){ |
+ if (pFile->local.bReserved) { |
+ pFile->local.bReserved = FALSE; |
+ pFile->shared->bReserved = FALSE; |
+ bReturn = TRUE; |
+ } |
+ } |
+ |
+ winceMutexRelease(pFile->hMutex); |
+ return bReturn; |
+} |
+/* |
+** End of the special code for wince |
+*****************************************************************************/ |
+#endif /* SQLITE_OS_WINCE */ |
+ |
+/* |
+** Lock a file region. |
+*/ |
+static BOOL winLockFile( |
+ LPHANDLE phFile, |
+ DWORD flags, |
+ DWORD offsetLow, |
+ DWORD offsetHigh, |
+ DWORD numBytesLow, |
+ DWORD numBytesHigh |
+){ |
+#if SQLITE_OS_WINCE |
+ /* |
+ ** NOTE: Windows CE is handled differently here due its lack of the Win32 |
+ ** API LockFile. |
+ */ |
+ return winceLockFile(phFile, offsetLow, offsetHigh, |
+ numBytesLow, numBytesHigh); |
+#else |
+ if( osIsNT() ){ |
+ OVERLAPPED ovlp; |
+ memset(&ovlp, 0, sizeof(OVERLAPPED)); |
+ ovlp.Offset = offsetLow; |
+ ovlp.OffsetHigh = offsetHigh; |
+ return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp); |
+ }else{ |
+ return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow, |
+ numBytesHigh); |
+ } |
+#endif |
+} |
+ |
+/* |
+** Unlock a file region. |
+ */ |
+static BOOL winUnlockFile( |
+ LPHANDLE phFile, |
+ DWORD offsetLow, |
+ DWORD offsetHigh, |
+ DWORD numBytesLow, |
+ DWORD numBytesHigh |
+){ |
+#if SQLITE_OS_WINCE |
+ /* |
+ ** NOTE: Windows CE is handled differently here due its lack of the Win32 |
+ ** API UnlockFile. |
+ */ |
+ return winceUnlockFile(phFile, offsetLow, offsetHigh, |
+ numBytesLow, numBytesHigh); |
+#else |
+ if( osIsNT() ){ |
+ OVERLAPPED ovlp; |
+ memset(&ovlp, 0, sizeof(OVERLAPPED)); |
+ ovlp.Offset = offsetLow; |
+ ovlp.OffsetHigh = offsetHigh; |
+ return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp); |
+ }else{ |
+ return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow, |
+ numBytesHigh); |
+ } |
+#endif |
+} |
+ |
+/***************************************************************************** |
+** The next group of routines implement the I/O methods specified |
+** by the sqlite3_io_methods object. |
+******************************************************************************/ |
+ |
+/* |
+** Some Microsoft compilers lack this definition. |
+*/ |
+#ifndef INVALID_SET_FILE_POINTER |
+# define INVALID_SET_FILE_POINTER ((DWORD)-1) |
+#endif |
+ |
+/* |
+** Move the current position of the file handle passed as the first |
+** argument to offset iOffset within the file. If successful, return 0. |
+** Otherwise, set pFile->lastErrno and return non-zero. |
+*/ |
+static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){ |
+#if !SQLITE_OS_WINRT |
+ LONG upperBits; /* Most sig. 32 bits of new offset */ |
+ LONG lowerBits; /* Least sig. 32 bits of new offset */ |
+ DWORD dwRet; /* Value returned by SetFilePointer() */ |
+ DWORD lastErrno; /* Value returned by GetLastError() */ |
+ |
+ OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset)); |
+ |
+ upperBits = (LONG)((iOffset>>32) & 0x7fffffff); |
+ lowerBits = (LONG)(iOffset & 0xffffffff); |
+ |
+ /* API oddity: If successful, SetFilePointer() returns a dword |
+ ** containing the lower 32-bits of the new file-offset. Or, if it fails, |
+ ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, |
+ ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine |
+ ** whether an error has actually occurred, it is also necessary to call |
+ ** GetLastError(). |
+ */ |
+ dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); |
+ |
+ if( (dwRet==INVALID_SET_FILE_POINTER |
+ && ((lastErrno = osGetLastError())!=NO_ERROR)) ){ |
+ pFile->lastErrno = lastErrno; |
+ winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, |
+ "winSeekFile", pFile->zPath); |
+ OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); |
+ return 1; |
+ } |
+ |
+ OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return 0; |
+#else |
+ /* |
+ ** Same as above, except that this implementation works for WinRT. |
+ */ |
+ |
+ LARGE_INTEGER x; /* The new offset */ |
+ BOOL bRet; /* Value returned by SetFilePointerEx() */ |
+ |
+ x.QuadPart = iOffset; |
+ bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN); |
+ |
+ if(!bRet){ |
+ pFile->lastErrno = osGetLastError(); |
+ winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, |
+ "winSeekFile", pFile->zPath); |
+ OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h)); |
+ return 1; |
+ } |
+ |
+ OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return 0; |
+#endif |
+} |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+/* Forward references to VFS helper methods used for memory mapped files */ |
+static int winMapfile(winFile*, sqlite3_int64); |
+static int winUnmapfile(winFile*); |
+#endif |
+ |
+/* |
+** Close a file. |
+** |
+** It is reported that an attempt to close a handle might sometimes |
+** fail. This is a very unreasonable result, but Windows is notorious |
+** for being unreasonable so I do not doubt that it might happen. If |
+** the close fails, we pause for 100 milliseconds and try again. As |
+** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before |
+** giving up and returning an error. |
+*/ |
+#define MX_CLOSE_ATTEMPT 3 |
+static int winClose(sqlite3_file *id){ |
+ int rc, cnt = 0; |
+ winFile *pFile = (winFile*)id; |
+ |
+ assert( id!=0 ); |
+#ifndef SQLITE_OMIT_WAL |
+ assert( pFile->pShm==0 ); |
+#endif |
+ assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE ); |
+ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ winUnmapfile(pFile); |
+#endif |
+ |
+ do{ |
+ rc = osCloseHandle(pFile->h); |
+ /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ |
+ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); |
+#if SQLITE_OS_WINCE |
+#define WINCE_DELETION_ATTEMPTS 3 |
+ { |
+ winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData; |
+ if( pAppData==NULL || !pAppData->bNoLock ){ |
+ winceDestroyLock(pFile); |
+ } |
+ } |
+ if( pFile->zDeleteOnClose ){ |
+ int cnt = 0; |
+ while( |
+ osDeleteFileW(pFile->zDeleteOnClose)==0 |
+ && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff |
+ && cnt++ < WINCE_DELETION_ATTEMPTS |
+ ){ |
+ sqlite3_win32_sleep(100); /* Wait a little before trying again */ |
+ } |
+ sqlite3_free(pFile->zDeleteOnClose); |
+ } |
+#endif |
+ if( rc ){ |
+ pFile->h = NULL; |
+ } |
+ OpenCounter(-1); |
+ OSTRACE(("CLOSE pid=%lu, pFile=%p, file=%p, rc=%s\n", |
+ osGetCurrentProcessId(), pFile, pFile->h, rc ? "ok" : "failed")); |
+ return rc ? SQLITE_OK |
+ : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(), |
+ "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. |
+*/ |
+static int winRead( |
+ sqlite3_file *id, /* File to read from */ |
+ void *pBuf, /* Write content into this buffer */ |
+ int amt, /* Number of bytes to read */ |
+ sqlite3_int64 offset /* Begin reading at this offset */ |
+){ |
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) |
+ OVERLAPPED overlapped; /* The offset for ReadFile. */ |
+#endif |
+ winFile *pFile = (winFile*)id; /* file handle */ |
+ DWORD nRead; /* Number of bytes actually read from file */ |
+ int nRetry = 0; /* Number of retrys */ |
+ |
+ assert( id!=0 ); |
+ assert( amt>0 ); |
+ assert( offset>=0 ); |
+ SimulateIOError(return SQLITE_IOERR_READ); |
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, " |
+ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, |
+ pFile->h, pBuf, amt, offset, pFile->locktype)); |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ /* Deal with as much of this read request as possible by transfering |
+ ** data from the memory mapping using memcpy(). */ |
+ if( offset<pFile->mmapSize ){ |
+ if( offset+amt <= pFile->mmapSize ){ |
+ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt); |
+ OSTRACE(("READ-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return SQLITE_OK; |
+ }else{ |
+ int nCopy = (int)(pFile->mmapSize - offset); |
+ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy); |
+ pBuf = &((u8 *)pBuf)[nCopy]; |
+ amt -= nCopy; |
+ offset += nCopy; |
+ } |
+ } |
+#endif |
+ |
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) |
+ if( winSeekFile(pFile, offset) ){ |
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return SQLITE_FULL; |
+ } |
+ while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ |
+#else |
+ memset(&overlapped, 0, sizeof(OVERLAPPED)); |
+ overlapped.Offset = (LONG)(offset & 0xffffffff); |
+ overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); |
+ while( !osReadFile(pFile->h, pBuf, amt, &nRead, &overlapped) && |
+ osGetLastError()!=ERROR_HANDLE_EOF ){ |
+#endif |
+ DWORD lastErrno; |
+ if( winRetryIoerr(&nRetry, &lastErrno) ) continue; |
+ pFile->lastErrno = lastErrno; |
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_READ\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return winLogError(SQLITE_IOERR_READ, pFile->lastErrno, |
+ "winRead", pFile->zPath); |
+ } |
+ winLogIoerr(nRetry, __LINE__); |
+ if( nRead<(DWORD)amt ){ |
+ /* Unread parts of the buffer must be zero-filled */ |
+ memset(&((char*)pBuf)[nRead], 0, amt-nRead); |
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_SHORT_READ\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return SQLITE_IOERR_SHORT_READ; |
+ } |
+ |
+ OSTRACE(("READ pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Write data from a buffer into a file. Return SQLITE_OK on success |
+** or some other error code on failure. |
+*/ |
+static int winWrite( |
+ sqlite3_file *id, /* File to write into */ |
+ const void *pBuf, /* The bytes to be written */ |
+ int amt, /* Number of bytes to write */ |
+ sqlite3_int64 offset /* Offset into the file to begin writing at */ |
+){ |
+ int rc = 0; /* True if error has occurred, else false */ |
+ winFile *pFile = (winFile*)id; /* File handle */ |
+ int nRetry = 0; /* Number of retries */ |
+ |
+ assert( amt>0 ); |
+ assert( pFile ); |
+ SimulateIOError(return SQLITE_IOERR_WRITE); |
+ SimulateDiskfullError(return SQLITE_FULL); |
+ |
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, buffer=%p, amount=%d, " |
+ "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, |
+ pFile->h, pBuf, amt, offset, pFile->locktype)); |
+ |
+#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0 |
+ /* Deal with as much of this write request as possible by transfering |
+ ** data from the memory mapping using memcpy(). */ |
+ if( offset<pFile->mmapSize ){ |
+ if( offset+amt <= pFile->mmapSize ){ |
+ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); |
+ OSTRACE(("WRITE-MMAP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return SQLITE_OK; |
+ }else{ |
+ int nCopy = (int)(pFile->mmapSize - offset); |
+ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy); |
+ pBuf = &((u8 *)pBuf)[nCopy]; |
+ amt -= nCopy; |
+ offset += nCopy; |
+ } |
+ } |
+#endif |
+ |
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) |
+ rc = winSeekFile(pFile, offset); |
+ if( rc==0 ){ |
+#else |
+ { |
+#endif |
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) |
+ OVERLAPPED overlapped; /* The offset for WriteFile. */ |
+#endif |
+ u8 *aRem = (u8 *)pBuf; /* Data yet to be written */ |
+ int nRem = amt; /* Number of bytes yet to be written */ |
+ DWORD nWrite; /* Bytes written by each WriteFile() call */ |
+ DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */ |
+ |
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) |
+ memset(&overlapped, 0, sizeof(OVERLAPPED)); |
+ overlapped.Offset = (LONG)(offset & 0xffffffff); |
+ overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); |
+#endif |
+ |
+ while( nRem>0 ){ |
+#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED) |
+ if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){ |
+#else |
+ if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){ |
+#endif |
+ if( winRetryIoerr(&nRetry, &lastErrno) ) continue; |
+ break; |
+ } |
+ assert( nWrite==0 || nWrite<=(DWORD)nRem ); |
+ if( nWrite==0 || nWrite>(DWORD)nRem ){ |
+ lastErrno = osGetLastError(); |
+ break; |
+ } |
+#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED) |
+ offset += nWrite; |
+ overlapped.Offset = (LONG)(offset & 0xffffffff); |
+ overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff); |
+#endif |
+ aRem += nWrite; |
+ nRem -= nWrite; |
+ } |
+ if( nRem>0 ){ |
+ pFile->lastErrno = lastErrno; |
+ rc = 1; |
+ } |
+ } |
+ |
+ if( rc ){ |
+ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ) |
+ || ( pFile->lastErrno==ERROR_DISK_FULL )){ |
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_FULL\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return winLogError(SQLITE_FULL, pFile->lastErrno, |
+ "winWrite1", pFile->zPath); |
+ } |
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_WRITE\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno, |
+ "winWrite2", pFile->zPath); |
+ }else{ |
+ winLogIoerr(nRetry, __LINE__); |
+ } |
+ OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Truncate an open file to a specified size |
+*/ |
+static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ |
+ winFile *pFile = (winFile*)id; /* File handle object */ |
+ int rc = SQLITE_OK; /* Return code for this function */ |
+ DWORD lastErrno; |
+ |
+ assert( pFile ); |
+ SimulateIOError(return SQLITE_IOERR_TRUNCATE); |
+ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n", |
+ osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype)); |
+ |
+ /* 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>0 ){ |
+ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; |
+ } |
+ |
+ /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ |
+ if( winSeekFile(pFile, nByte) ){ |
+ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, |
+ "winTruncate1", pFile->zPath); |
+ }else if( 0==osSetEndOfFile(pFile->h) && |
+ ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){ |
+ pFile->lastErrno = lastErrno; |
+ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, |
+ "winTruncate2", pFile->zPath); |
+ } |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ /* If the file was truncated to a size smaller than the currently |
+ ** mapped region, reduce the effective mapping size as well. SQLite will |
+ ** use read() and write() to access data beyond this point from now on. |
+ */ |
+ if( pFile->pMapRegion && nByte<pFile->mmapSize ){ |
+ pFile->mmapSize = nByte; |
+ } |
+#endif |
+ |
+ OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n", |
+ osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc))); |
+ return rc; |
+} |
+ |
+#ifdef SQLITE_TEST |
+/* |
+** Count the number of fullsyncs and normal syncs. This is used to test |
+** that syncs and fullsyncs are occuring at the right times. |
+*/ |
+SQLITE_API int sqlite3_sync_count = 0; |
+SQLITE_API int sqlite3_fullsync_count = 0; |
+#endif |
+ |
+/* |
+** Make sure all writes to a particular file are committed to disk. |
+*/ |
+static int winSync(sqlite3_file *id, int flags){ |
+#ifndef SQLITE_NO_SYNC |
+ /* |
+ ** Used only when SQLITE_NO_SYNC is not defined. |
+ */ |
+ BOOL rc; |
+#endif |
+#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || \ |
+ defined(SQLITE_HAVE_OS_TRACE) |
+ /* |
+ ** Used when SQLITE_NO_SYNC is not defined and by the assert() and/or |
+ ** OSTRACE() macros. |
+ */ |
+ 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 |
+ ); |
+ |
+ /* 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 ); |
+ |
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, flags=%x, lock=%d\n", |
+ osGetCurrentProcessId(), pFile, pFile->h, flags, |
+ pFile->locktype)); |
+ |
+#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 |
+ OSTRACE(("SYNC-NOP pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return SQLITE_OK; |
+#else |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ if( pFile->pMapRegion ){ |
+ if( osFlushViewOfFile(pFile->pMapRegion, 0) ){ |
+ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, " |
+ "rc=SQLITE_OK\n", osGetCurrentProcessId(), |
+ pFile, pFile->pMapRegion)); |
+ }else{ |
+ pFile->lastErrno = osGetLastError(); |
+ OSTRACE(("SYNC-MMAP pid=%lu, pFile=%p, pMapRegion=%p, " |
+ "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), |
+ pFile, pFile->pMapRegion)); |
+ return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, |
+ "winSync1", pFile->zPath); |
+ } |
+ } |
+#endif |
+ rc = osFlushFileBuffers(pFile->h); |
+ SimulateIOError( rc=FALSE ); |
+ if( rc ){ |
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return SQLITE_OK; |
+ }else{ |
+ pFile->lastErrno = osGetLastError(); |
+ OSTRACE(("SYNC pid=%lu, pFile=%p, file=%p, rc=SQLITE_IOERR_FSYNC\n", |
+ osGetCurrentProcessId(), pFile, pFile->h)); |
+ return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno, |
+ "winSync2", pFile->zPath); |
+ } |
+#endif |
+} |
+ |
+/* |
+** Determine the current size of a file in bytes |
+*/ |
+static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ |
+ winFile *pFile = (winFile*)id; |
+ int rc = SQLITE_OK; |
+ |
+ assert( id!=0 ); |
+ assert( pSize!=0 ); |
+ SimulateIOError(return SQLITE_IOERR_FSTAT); |
+ OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize)); |
+ |
+#if SQLITE_OS_WINRT |
+ { |
+ FILE_STANDARD_INFO info; |
+ if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo, |
+ &info, sizeof(info)) ){ |
+ *pSize = info.EndOfFile.QuadPart; |
+ }else{ |
+ pFile->lastErrno = osGetLastError(); |
+ rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, |
+ "winFileSize", pFile->zPath); |
+ } |
+ } |
+#else |
+ { |
+ DWORD upperBits; |
+ DWORD lowerBits; |
+ DWORD lastErrno; |
+ |
+ lowerBits = osGetFileSize(pFile->h, &upperBits); |
+ *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; |
+ if( (lowerBits == INVALID_FILE_SIZE) |
+ && ((lastErrno = osGetLastError())!=NO_ERROR) ){ |
+ pFile->lastErrno = lastErrno; |
+ rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, |
+ "winFileSize", pFile->zPath); |
+ } |
+ } |
+#endif |
+ OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n", |
+ pFile->h, pSize, *pSize, sqlite3ErrName(rc))); |
+ return rc; |
+} |
+ |
+/* |
+** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. |
+*/ |
+#ifndef LOCKFILE_FAIL_IMMEDIATELY |
+# define LOCKFILE_FAIL_IMMEDIATELY 1 |
+#endif |
+ |
+#ifndef LOCKFILE_EXCLUSIVE_LOCK |
+# define LOCKFILE_EXCLUSIVE_LOCK 2 |
+#endif |
+ |
+/* |
+** Historically, SQLite has used both the LockFile and LockFileEx functions. |
+** When the LockFile function was used, it was always expected to fail |
+** immediately if the lock could not be obtained. Also, it always expected to |
+** obtain an exclusive lock. These flags are used with the LockFileEx function |
+** and reflect those expectations; therefore, they should not be changed. |
+*/ |
+#ifndef SQLITE_LOCKFILE_FLAGS |
+# define SQLITE_LOCKFILE_FLAGS (LOCKFILE_FAIL_IMMEDIATELY | \ |
+ LOCKFILE_EXCLUSIVE_LOCK) |
+#endif |
+ |
+/* |
+** Currently, SQLite never calls the LockFileEx function without wanting the |
+** call to fail immediately if the lock cannot be obtained. |
+*/ |
+#ifndef SQLITE_LOCKFILEEX_FLAGS |
+# define SQLITE_LOCKFILEEX_FLAGS (LOCKFILE_FAIL_IMMEDIATELY) |
+#endif |
+ |
+/* |
+** Acquire a reader lock. |
+** Different API routines are called depending on whether or not this |
+** is Win9x or WinNT. |
+*/ |
+static int winGetReadLock(winFile *pFile){ |
+ int res; |
+ OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); |
+ if( osIsNT() ){ |
+#if SQLITE_OS_WINCE |
+ /* |
+ ** NOTE: Windows CE is handled differently here due its lack of the Win32 |
+ ** API LockFileEx. |
+ */ |
+ res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0); |
+#else |
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0, |
+ SHARED_SIZE, 0); |
+#endif |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ int lk; |
+ sqlite3_randomness(sizeof(lk), &lk); |
+ pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1)); |
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, |
+ SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); |
+ } |
+#endif |
+ if( res == 0 ){ |
+ pFile->lastErrno = osGetLastError(); |
+ /* No need to log a failure to lock */ |
+ } |
+ OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res)); |
+ return res; |
+} |
+ |
+/* |
+** Undo a readlock |
+*/ |
+static int winUnlockReadLock(winFile *pFile){ |
+ int res; |
+ DWORD lastErrno; |
+ OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype)); |
+ if( osIsNT() ){ |
+ res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ res = winUnlockFile(&pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); |
+ } |
+#endif |
+ if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){ |
+ pFile->lastErrno = lastErrno; |
+ winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, |
+ "winUnlockReadLock", pFile->zPath); |
+ } |
+ OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res)); |
+ return res; |
+} |
+ |
+/* |
+** Lock the file with the lock specified by parameter locktype - one |
+** of the following: |
+** |
+** (1) SHARED_LOCK |
+** (2) RESERVED_LOCK |
+** (3) PENDING_LOCK |
+** (4) EXCLUSIVE_LOCK |
+** |
+** Sometimes when requesting one lock state, additional lock states |
+** are inserted in between. The locking might fail on one of the later |
+** transitions leaving the lock state different from what it started but |
+** still short of its goal. The following chart shows the allowed |
+** transitions and the inserted intermediate states: |
+** |
+** UNLOCKED -> SHARED |
+** SHARED -> RESERVED |
+** SHARED -> (PENDING) -> EXCLUSIVE |
+** RESERVED -> (PENDING) -> EXCLUSIVE |
+** PENDING -> EXCLUSIVE |
+** |
+** This routine will only increase a lock. The winUnlock() routine |
+** erases all locks at once and returns us immediately to locking level 0. |
+** It is not possible to lower the locking level one step at a time. You |
+** must go straight to locking level 0. |
+*/ |
+static int winLock(sqlite3_file *id, int locktype){ |
+ int rc = SQLITE_OK; /* Return code from subroutines */ |
+ int res = 1; /* Result of a Windows lock call */ |
+ int newLocktype; /* Set pFile->locktype to this value before exiting */ |
+ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ |
+ winFile *pFile = (winFile*)id; |
+ DWORD lastErrno = NO_ERROR; |
+ |
+ assert( id!=0 ); |
+ OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n", |
+ pFile->h, pFile->locktype, pFile->sharedLockByte, locktype)); |
+ |
+ /* If there is already a lock of this type or more restrictive on the |
+ ** OsFile, do nothing. Don't use the end_lock: exit path, as |
+ ** sqlite3OsEnterMutex() hasn't been called yet. |
+ */ |
+ if( pFile->locktype>=locktype ){ |
+ OSTRACE(("LOCK-HELD file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+ |
+ /* Do not allow any kind of write-lock on a read-only database |
+ */ |
+ if( (pFile->ctrlFlags & WINFILE_RDONLY)!=0 && locktype>=RESERVED_LOCK ){ |
+ return SQLITE_IOERR_LOCK; |
+ } |
+ |
+ /* Make sure the locking sequence is correct |
+ */ |
+ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); |
+ assert( locktype!=PENDING_LOCK ); |
+ assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); |
+ |
+ /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or |
+ ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of |
+ ** the PENDING_LOCK byte is temporary. |
+ */ |
+ newLocktype = pFile->locktype; |
+ if( pFile->locktype==NO_LOCK |
+ || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK) |
+ ){ |
+ int cnt = 3; |
+ while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, |
+ PENDING_BYTE, 0, 1, 0))==0 ){ |
+ /* Try 3 times to get the pending lock. This is needed to work |
+ ** around problems caused by indexing and/or anti-virus software on |
+ ** Windows systems. |
+ ** If you are using this code as a model for alternative VFSes, do not |
+ ** copy this retry logic. It is a hack intended for Windows only. |
+ */ |
+ lastErrno = osGetLastError(); |
+ OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n", |
+ pFile->h, cnt, res)); |
+ if( lastErrno==ERROR_INVALID_HANDLE ){ |
+ pFile->lastErrno = lastErrno; |
+ rc = SQLITE_IOERR_LOCK; |
+ OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n", |
+ pFile->h, cnt, sqlite3ErrName(rc))); |
+ return rc; |
+ } |
+ if( cnt ) sqlite3_win32_sleep(1); |
+ } |
+ gotPendingLock = res; |
+ if( !res ){ |
+ lastErrno = osGetLastError(); |
+ } |
+ } |
+ |
+ /* Acquire a shared lock |
+ */ |
+ if( locktype==SHARED_LOCK && res ){ |
+ assert( pFile->locktype==NO_LOCK ); |
+ res = winGetReadLock(pFile); |
+ if( res ){ |
+ newLocktype = SHARED_LOCK; |
+ }else{ |
+ lastErrno = osGetLastError(); |
+ } |
+ } |
+ |
+ /* Acquire a RESERVED lock |
+ */ |
+ if( locktype==RESERVED_LOCK && res ){ |
+ assert( pFile->locktype==SHARED_LOCK ); |
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, RESERVED_BYTE, 0, 1, 0); |
+ if( res ){ |
+ newLocktype = RESERVED_LOCK; |
+ }else{ |
+ lastErrno = osGetLastError(); |
+ } |
+ } |
+ |
+ /* Acquire a PENDING lock |
+ */ |
+ if( locktype==EXCLUSIVE_LOCK && res ){ |
+ newLocktype = PENDING_LOCK; |
+ gotPendingLock = 0; |
+ } |
+ |
+ /* Acquire an EXCLUSIVE lock |
+ */ |
+ if( locktype==EXCLUSIVE_LOCK && res ){ |
+ assert( pFile->locktype>=SHARED_LOCK ); |
+ res = winUnlockReadLock(pFile); |
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0, |
+ SHARED_SIZE, 0); |
+ if( res ){ |
+ newLocktype = EXCLUSIVE_LOCK; |
+ }else{ |
+ lastErrno = osGetLastError(); |
+ winGetReadLock(pFile); |
+ } |
+ } |
+ |
+ /* If we are holding a PENDING lock that ought to be released, then |
+ ** release it now. |
+ */ |
+ if( gotPendingLock && locktype==SHARED_LOCK ){ |
+ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); |
+ } |
+ |
+ /* Update the state of the lock has held in the file descriptor then |
+ ** return the appropriate result code. |
+ */ |
+ if( res ){ |
+ rc = SQLITE_OK; |
+ }else{ |
+ pFile->lastErrno = lastErrno; |
+ rc = SQLITE_BUSY; |
+ OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n", |
+ pFile->h, locktype, newLocktype)); |
+ } |
+ pFile->locktype = (u8)newLocktype; |
+ OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n", |
+ pFile->h, pFile->locktype, sqlite3ErrName(rc))); |
+ return rc; |
+} |
+ |
+/* |
+** This routine checks if there is a RESERVED lock held on the specified |
+** file by this or any other process. If such a lock is held, return |
+** non-zero, otherwise zero. |
+*/ |
+static int winCheckReservedLock(sqlite3_file *id, int *pResOut){ |
+ int res; |
+ winFile *pFile = (winFile*)id; |
+ |
+ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); |
+ OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut)); |
+ |
+ assert( id!=0 ); |
+ if( pFile->locktype>=RESERVED_LOCK ){ |
+ res = 1; |
+ OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res)); |
+ }else{ |
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE,0,1,0); |
+ if( res ){ |
+ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); |
+ } |
+ res = !res; |
+ OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res)); |
+ } |
+ *pResOut = res; |
+ OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", |
+ pFile->h, pResOut, *pResOut)); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Lower the locking level on file descriptor id to locktype. locktype |
+** must be either NO_LOCK or SHARED_LOCK. |
+** |
+** If the locking level of the file descriptor is already at or below |
+** the requested locking level, this routine is a no-op. |
+** |
+** It is not possible for this routine to fail if the second argument |
+** is NO_LOCK. If the second argument is SHARED_LOCK then this routine |
+** might return SQLITE_IOERR; |
+*/ |
+static int winUnlock(sqlite3_file *id, int locktype){ |
+ int type; |
+ winFile *pFile = (winFile*)id; |
+ int rc = SQLITE_OK; |
+ assert( pFile!=0 ); |
+ assert( locktype<=SHARED_LOCK ); |
+ OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n", |
+ pFile->h, pFile->locktype, pFile->sharedLockByte, locktype)); |
+ type = pFile->locktype; |
+ if( type>=EXCLUSIVE_LOCK ){ |
+ winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); |
+ if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){ |
+ /* This should never happen. We should always be able to |
+ ** reacquire the read lock */ |
+ rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(), |
+ "winUnlock", pFile->zPath); |
+ } |
+ } |
+ if( type>=RESERVED_LOCK ){ |
+ winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0); |
+ } |
+ if( locktype==NO_LOCK && type>=SHARED_LOCK ){ |
+ winUnlockReadLock(pFile); |
+ } |
+ if( type>=PENDING_LOCK ){ |
+ winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0); |
+ } |
+ pFile->locktype = (u8)locktype; |
+ OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n", |
+ pFile->h, pFile->locktype, sqlite3ErrName(rc))); |
+ return rc; |
+} |
+ |
+/****************************************************************************** |
+****************************** No-op Locking ********************************** |
+** |
+** Of the various locking implementations available, this is by far the |
+** simplest: locking is ignored. No attempt is made to lock the database |
+** file for reading or writing. |
+** |
+** This locking mode is appropriate for use on read-only databases |
+** (ex: databases that are burned into CD-ROM, for example.) It can |
+** also be used if the application employs some external mechanism to |
+** prevent simultaneous access of the same database by two or more |
+** database connections. But there is a serious risk of database |
+** corruption if this locking mode is used in situations where multiple |
+** database connections are accessing the same database file at the same |
+** time and one or more of those connections are writing. |
+*/ |
+ |
+static int winNolockLock(sqlite3_file *id, int locktype){ |
+ UNUSED_PARAMETER(id); |
+ UNUSED_PARAMETER(locktype); |
+ return SQLITE_OK; |
+} |
+ |
+static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){ |
+ UNUSED_PARAMETER(id); |
+ UNUSED_PARAMETER(pResOut); |
+ return SQLITE_OK; |
+} |
+ |
+static int winNolockUnlock(sqlite3_file *id, int locktype){ |
+ UNUSED_PARAMETER(id); |
+ UNUSED_PARAMETER(locktype); |
+ return SQLITE_OK; |
+} |
+ |
+/******************* End of the no-op lock implementation ********************* |
+******************************************************************************/ |
+ |
+/* |
+** If *pArg is initially negative then this is a query. Set *pArg to |
+** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. |
+** |
+** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. |
+*/ |
+static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ |
+ if( *pArg<0 ){ |
+ *pArg = (pFile->ctrlFlags & mask)!=0; |
+ }else if( (*pArg)==0 ){ |
+ pFile->ctrlFlags &= ~mask; |
+ }else{ |
+ pFile->ctrlFlags |= mask; |
+ } |
+} |
+ |
+/* Forward references to VFS helper methods used for temporary files */ |
+static int winGetTempname(sqlite3_vfs *, char **); |
+static int winIsDir(const void *); |
+static BOOL winIsDriveLetterAndColon(const char *); |
+ |
+/* |
+** Control and query of the open file handle. |
+*/ |
+static int winFileControl(sqlite3_file *id, int op, void *pArg){ |
+ winFile *pFile = (winFile*)id; |
+ OSTRACE(("FCNTL file=%p, op=%d, pArg=%p\n", pFile->h, op, pArg)); |
+ switch( op ){ |
+ case SQLITE_FCNTL_LOCKSTATE: { |
+ *(int*)pArg = pFile->locktype; |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_LAST_ERRNO: { |
+ *(int*)pArg = (int)pFile->lastErrno; |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_CHUNK_SIZE: { |
+ pFile->szChunk = *(int *)pArg; |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_SIZE_HINT: { |
+ if( pFile->szChunk>0 ){ |
+ sqlite3_int64 oldSz; |
+ int rc = winFileSize(id, &oldSz); |
+ if( rc==SQLITE_OK ){ |
+ sqlite3_int64 newSz = *(sqlite3_int64*)pArg; |
+ if( newSz>oldSz ){ |
+ SimulateIOErrorBenign(1); |
+ rc = winTruncate(id, newSz); |
+ SimulateIOErrorBenign(0); |
+ } |
+ } |
+ OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); |
+ return rc; |
+ } |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_PERSIST_WAL: { |
+ winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg); |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { |
+ winModeBit(pFile, WINFILE_PSOW, (int*)pArg); |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_VFSNAME: { |
+ *(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName); |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_WIN32_AV_RETRY: { |
+ int *a = (int*)pArg; |
+ if( a[0]>0 ){ |
+ winIoerrRetry = a[0]; |
+ }else{ |
+ a[0] = winIoerrRetry; |
+ } |
+ if( a[1]>0 ){ |
+ winIoerrRetryDelay = a[1]; |
+ }else{ |
+ a[1] = winIoerrRetryDelay; |
+ } |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+ case SQLITE_FCNTL_WIN32_GET_HANDLE: { |
+ LPHANDLE phFile = (LPHANDLE)pArg; |
+ *phFile = pFile->h; |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h)); |
+ return SQLITE_OK; |
+ } |
+#ifdef SQLITE_TEST |
+ case SQLITE_FCNTL_WIN32_SET_HANDLE: { |
+ LPHANDLE phFile = (LPHANDLE)pArg; |
+ HANDLE hOldFile = pFile->h; |
+ pFile->h = *phFile; |
+ *phFile = hOldFile; |
+ OSTRACE(("FCNTL oldFile=%p, newFile=%p, rc=SQLITE_OK\n", |
+ hOldFile, pFile->h)); |
+ return SQLITE_OK; |
+ } |
+#endif |
+ case SQLITE_FCNTL_TEMPFILENAME: { |
+ char *zTFile = 0; |
+ int rc = winGetTempname(pFile->pVfs, &zTFile); |
+ if( rc==SQLITE_OK ){ |
+ *(char**)pArg = zTFile; |
+ } |
+ OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); |
+ return rc; |
+ } |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ case SQLITE_FCNTL_MMAP_SIZE: { |
+ i64 newLimit = *(i64*)pArg; |
+ int rc = SQLITE_OK; |
+ if( newLimit>sqlite3GlobalConfig.mxMmap ){ |
+ newLimit = sqlite3GlobalConfig.mxMmap; |
+ } |
+ *(i64*)pArg = pFile->mmapSizeMax; |
+ if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ |
+ pFile->mmapSizeMax = newLimit; |
+ if( pFile->mmapSize>0 ){ |
+ winUnmapfile(pFile); |
+ rc = winMapfile(pFile, -1); |
+ } |
+ } |
+ OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc))); |
+ return rc; |
+ } |
+#endif |
+ } |
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h)); |
+ 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 |
+** larger for some devices. |
+** |
+** 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 winSectorSize(sqlite3_file *id){ |
+ (void)id; |
+ return SQLITE_DEFAULT_SECTOR_SIZE; |
+} |
+ |
+/* |
+** Return a vector of device characteristics. |
+*/ |
+static int winDeviceCharacteristics(sqlite3_file *id){ |
+ winFile *p = (winFile*)id; |
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | |
+ ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0); |
+} |
+ |
+/* |
+** Windows will only let you create file view mappings |
+** on allocation size granularity boundaries. |
+** During sqlite3_os_init() we do a GetSystemInfo() |
+** to get the granularity size. |
+*/ |
+static SYSTEM_INFO winSysInfo; |
+ |
+#ifndef SQLITE_OMIT_WAL |
+ |
+/* |
+** Helper functions to obtain and relinquish the global mutex. The |
+** global mutex is used to protect the winLockInfo objects used by |
+** this file, all of which may be shared by multiple threads. |
+** |
+** Function winShmMutexHeld() is used to assert() that the global mutex |
+** is held when required. This function is only used as part of assert() |
+** statements. e.g. |
+** |
+** winShmEnterMutex() |
+** assert( winShmMutexHeld() ); |
+** winShmLeaveMutex() |
+*/ |
+static void winShmEnterMutex(void){ |
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); |
+} |
+static void winShmLeaveMutex(void){ |
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); |
+} |
+#ifndef NDEBUG |
+static int winShmMutexHeld(void) { |
+ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); |
+} |
+#endif |
+ |
+/* |
+** Object used to represent a single file opened and mmapped to provide |
+** shared memory. When multiple threads all reference the same |
+** log-summary, each thread has its own winFile object, but they all |
+** point to a single instance of this object. In other words, each |
+** log-summary is opened only once per process. |
+** |
+** winShmMutexHeld() 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: |
+** |
+** fid |
+** zFilename |
+** |
+** Either winShmNode.mutex must be held or winShmNode.nRef==0 and |
+** winShmMutexHeld() is true when reading or writing any other field |
+** in this structure. |
+** |
+*/ |
+struct winShmNode { |
+ sqlite3_mutex *mutex; /* Mutex to access this object */ |
+ char *zFilename; /* Name of the file */ |
+ winFile hFile; /* File handle from winOpen */ |
+ |
+ int szRegion; /* Size of shared-memory regions */ |
+ int nRegion; /* Size of array apRegion */ |
+ struct ShmRegion { |
+ HANDLE hMap; /* File handle from CreateFileMapping */ |
+ void *pMap; |
+ } *aRegion; |
+ DWORD lastErrno; /* The Windows errno from the last I/O error */ |
+ |
+ int nRef; /* Number of winShm objects pointing to this */ |
+ winShm *pFirst; /* All winShm objects pointing to this */ |
+ winShmNode *pNext; /* Next in list of all winShmNode objects */ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) |
+ u8 nextShmId; /* Next available winShm.id value */ |
+#endif |
+}; |
+ |
+/* |
+** A global array of all winShmNode objects. |
+** |
+** The winShmMutexHeld() must be true while reading or writing this list. |
+*/ |
+static winShmNode *winShmNodeList = 0; |
+ |
+/* |
+** 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: |
+** |
+** winShm.pShmNode |
+** winShm.id |
+** |
+** All other fields are read/write. The winShm.pShmNode->mutex must be held |
+** while accessing any read/write fields. |
+*/ |
+struct winShm { |
+ winShmNode *pShmNode; /* The underlying winShmNode object */ |
+ winShm *pNext; /* Next winShm with the same winShmNode */ |
+ u8 hasMutex; /* True if holding the winShmNode mutex */ |
+ u16 sharedMask; /* Mask of shared locks held */ |
+ u16 exclMask; /* Mask of exclusive locks held */ |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) |
+ u8 id; /* Id of this connection with its winShmNode */ |
+#endif |
+}; |
+ |
+/* |
+** Constants used for locking |
+*/ |
+#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ |
+#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ |
+ |
+/* |
+** Apply advisory locks for all n bytes beginning at ofst. |
+*/ |
+#define WINSHM_UNLCK 1 |
+#define WINSHM_RDLCK 2 |
+#define WINSHM_WRLCK 3 |
+static int winShmSystemLock( |
+ winShmNode *pFile, /* Apply locks to this open shared-memory segment */ |
+ int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */ |
+ int ofst, /* Offset to first byte to be locked/unlocked */ |
+ int nByte /* Number of bytes to lock or unlock */ |
+){ |
+ int rc = 0; /* Result code form Lock/UnlockFileEx() */ |
+ |
+ /* Access to the winShmNode object is serialized by the caller */ |
+ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 ); |
+ |
+ OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", |
+ pFile->hFile.h, lockType, ofst, nByte)); |
+ |
+ /* Release/Acquire the system-level lock */ |
+ if( lockType==WINSHM_UNLCK ){ |
+ rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); |
+ }else{ |
+ /* Initialize the locking parameters */ |
+ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; |
+ if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; |
+ rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); |
+ } |
+ |
+ if( rc!= 0 ){ |
+ rc = SQLITE_OK; |
+ }else{ |
+ pFile->lastErrno = osGetLastError(); |
+ rc = SQLITE_BUSY; |
+ } |
+ |
+ OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", |
+ pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" : |
+ "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); |
+ |
+ return rc; |
+} |
+ |
+/* Forward references to VFS methods */ |
+static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*); |
+static int winDelete(sqlite3_vfs *,const char*,int); |
+ |
+/* |
+** Purge the winShmNodeList list of all entries with winShmNode.nRef==0. |
+** |
+** This is not a VFS shared-memory method; it is a utility function called |
+** by VFS shared-memory methods. |
+*/ |
+static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ |
+ winShmNode **pp; |
+ winShmNode *p; |
+ assert( winShmMutexHeld() ); |
+ OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n", |
+ osGetCurrentProcessId(), deleteFlag)); |
+ pp = &winShmNodeList; |
+ while( (p = *pp)!=0 ){ |
+ if( p->nRef==0 ){ |
+ int i; |
+ if( p->mutex ){ sqlite3_mutex_free(p->mutex); } |
+ for(i=0; i<p->nRegion; i++){ |
+ BOOL bRc = osUnmapViewOfFile(p->aRegion[i].pMap); |
+ OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n", |
+ osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); |
+ UNUSED_VARIABLE_VALUE(bRc); |
+ bRc = osCloseHandle(p->aRegion[i].hMap); |
+ OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n", |
+ osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); |
+ UNUSED_VARIABLE_VALUE(bRc); |
+ } |
+ if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ |
+ SimulateIOErrorBenign(1); |
+ winClose((sqlite3_file *)&p->hFile); |
+ SimulateIOErrorBenign(0); |
+ } |
+ if( deleteFlag ){ |
+ SimulateIOErrorBenign(1); |
+ sqlite3BeginBenignMalloc(); |
+ winDelete(pVfs, p->zFilename, 0); |
+ sqlite3EndBenignMalloc(); |
+ SimulateIOErrorBenign(0); |
+ } |
+ *pp = p->pNext; |
+ sqlite3_free(p->aRegion); |
+ sqlite3_free(p); |
+ }else{ |
+ pp = &p->pNext; |
+ } |
+ } |
+} |
+ |
+/* |
+** Open the shared-memory area associated with database file pDbFd. |
+** |
+** When opening a new shared-memory file, if no other instances of that |
+** file are currently open, in this process or in other processes, then |
+** the file must be truncated to zero length or have its header cleared. |
+*/ |
+static int winOpenSharedMemory(winFile *pDbFd){ |
+ struct winShm *p; /* The connection to be opened */ |
+ struct winShmNode *pShmNode = 0; /* The underlying mmapped file */ |
+ int rc; /* Result code */ |
+ struct winShmNode *pNew; /* Newly allocated winShmNode */ |
+ int nName; /* Size of zName in bytes */ |
+ |
+ assert( pDbFd->pShm==0 ); /* Not previously opened */ |
+ |
+ /* Allocate space for the new sqlite3_shm object. Also speculatively |
+ ** allocate space for a new winShmNode and filename. |
+ */ |
+ p = sqlite3MallocZero( sizeof(*p) ); |
+ if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT; |
+ nName = sqlite3Strlen30(pDbFd->zPath); |
+ pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 ); |
+ if( pNew==0 ){ |
+ sqlite3_free(p); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ pNew->zFilename = (char*)&pNew[1]; |
+ sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); |
+ sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); |
+ |
+ /* Look to see if there is an existing winShmNode that can be used. |
+ ** If no matching winShmNode currently exists, create a new one. |
+ */ |
+ winShmEnterMutex(); |
+ for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){ |
+ /* TBD need to come up with better match here. Perhaps |
+ ** use FILE_ID_BOTH_DIR_INFO Structure. |
+ */ |
+ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break; |
+ } |
+ if( pShmNode ){ |
+ sqlite3_free(pNew); |
+ }else{ |
+ pShmNode = pNew; |
+ pNew = 0; |
+ ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE; |
+ pShmNode->pNext = winShmNodeList; |
+ winShmNodeList = pShmNode; |
+ |
+ if( sqlite3GlobalConfig.bCoreMutex ){ |
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
+ if( pShmNode->mutex==0 ){ |
+ rc = SQLITE_IOERR_NOMEM_BKPT; |
+ goto shm_open_err; |
+ } |
+ } |
+ |
+ rc = winOpen(pDbFd->pVfs, |
+ pShmNode->zFilename, /* Name of the file (UTF-8) */ |
+ (sqlite3_file*)&pShmNode->hFile, /* File handle here */ |
+ SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, |
+ 0); |
+ if( SQLITE_OK!=rc ){ |
+ goto shm_open_err; |
+ } |
+ |
+ /* Check to see if another process is holding the dead-man switch. |
+ ** If not, truncate the file to zero length. |
+ */ |
+ if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ |
+ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); |
+ if( rc!=SQLITE_OK ){ |
+ rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), |
+ "winOpenShm", pDbFd->zPath); |
+ } |
+ } |
+ if( rc==SQLITE_OK ){ |
+ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); |
+ rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); |
+ } |
+ if( rc ) goto shm_open_err; |
+ } |
+ |
+ /* Make the new connection a child of the winShmNode */ |
+ p->pShmNode = pShmNode; |
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) |
+ p->id = pShmNode->nextShmId++; |
+#endif |
+ pShmNode->nRef++; |
+ pDbFd->pShm = p; |
+ winShmLeaveMutex(); |
+ |
+ /* The reference count on pShmNode has already been incremented under |
+ ** the cover of the winShmEnterMutex() mutex and the pointer from the |
+ ** new (struct winShm) object to the pShmNode has been set. All that is |
+ ** left to do is to link the new object into the linked list starting |
+ ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex |
+ ** mutex. |
+ */ |
+ sqlite3_mutex_enter(pShmNode->mutex); |
+ p->pNext = pShmNode->pFirst; |
+ pShmNode->pFirst = p; |
+ sqlite3_mutex_leave(pShmNode->mutex); |
+ return SQLITE_OK; |
+ |
+ /* Jump here on any error */ |
+shm_open_err: |
+ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); |
+ winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */ |
+ sqlite3_free(p); |
+ sqlite3_free(pNew); |
+ winShmLeaveMutex(); |
+ return rc; |
+} |
+ |
+/* |
+** Close a connection to shared-memory. Delete the underlying |
+** storage if deleteFlag is true. |
+*/ |
+static int winShmUnmap( |
+ sqlite3_file *fd, /* Database holding shared memory */ |
+ int deleteFlag /* Delete after closing if true */ |
+){ |
+ winFile *pDbFd; /* Database holding shared-memory */ |
+ winShm *p; /* The connection to be closed */ |
+ winShmNode *pShmNode; /* The underlying shared-memory file */ |
+ winShm **pp; /* For looping over sibling connections */ |
+ |
+ pDbFd = (winFile*)fd; |
+ p = pDbFd->pShm; |
+ if( p==0 ) return SQLITE_OK; |
+ pShmNode = p->pShmNode; |
+ |
+ /* Remove connection p from the set of connections associated |
+ ** with pShmNode */ |
+ sqlite3_mutex_enter(pShmNode->mutex); |
+ for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} |
+ *pp = p->pNext; |
+ |
+ /* Free the connection p */ |
+ sqlite3_free(p); |
+ pDbFd->pShm = 0; |
+ sqlite3_mutex_leave(pShmNode->mutex); |
+ |
+ /* If pShmNode->nRef has reached 0, then close the underlying |
+ ** shared-memory file, too */ |
+ winShmEnterMutex(); |
+ assert( pShmNode->nRef>0 ); |
+ pShmNode->nRef--; |
+ if( pShmNode->nRef==0 ){ |
+ winShmPurge(pDbFd->pVfs, deleteFlag); |
+ } |
+ winShmLeaveMutex(); |
+ |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Change the lock state for a shared-memory segment. |
+*/ |
+static int winShmLock( |
+ sqlite3_file *fd, /* 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 */ |
+){ |
+ winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ |
+ winShm *p = pDbFd->pShm; /* The shared memory being locked */ |
+ winShm *pX; /* For looping over all siblings */ |
+ winShmNode *pShmNode = p->pShmNode; |
+ int rc = SQLITE_OK; /* Result code */ |
+ u16 mask; /* Mask of locks to take or release */ |
+ |
+ 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 = (u16)((1U<<(ofst+n)) - (1U<<ofst)); |
+ assert( n>1 || mask==(1<<ofst) ); |
+ sqlite3_mutex_enter(pShmNode->mutex); |
+ if( flags & SQLITE_SHM_UNLOCK ){ |
+ u16 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 = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_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 ){ |
+ u16 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 = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_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 = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n); |
+ if( rc==SQLITE_OK ){ |
+ assert( (p->sharedMask & mask)==0 ); |
+ p->exclMask |= mask; |
+ } |
+ } |
+ } |
+ sqlite3_mutex_leave(pShmNode->mutex); |
+ OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n", |
+ osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask, |
+ sqlite3ErrName(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 winShmBarrier( |
+ sqlite3_file *fd /* Database holding the shared memory */ |
+){ |
+ UNUSED_PARAMETER(fd); |
+ sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ |
+ winShmEnterMutex(); /* Also mutex, for redundancy */ |
+ winShmLeaveMutex(); |
+} |
+ |
+/* |
+** This function is called to obtain a pointer to region iRegion of the |
+** shared-memory associated with the database file fd. 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 isWrite 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 |
+** isWrite 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 winShmMap( |
+ sqlite3_file *fd, /* Handle open on database file */ |
+ int iRegion, /* Region to retrieve */ |
+ int szRegion, /* Size of regions */ |
+ int isWrite, /* True to extend file if necessary */ |
+ void volatile **pp /* OUT: Mapped memory */ |
+){ |
+ winFile *pDbFd = (winFile*)fd; |
+ winShm *pShm = pDbFd->pShm; |
+ winShmNode *pShmNode; |
+ int rc = SQLITE_OK; |
+ |
+ if( !pShm ){ |
+ rc = winOpenSharedMemory(pDbFd); |
+ if( rc!=SQLITE_OK ) return rc; |
+ pShm = pDbFd->pShm; |
+ } |
+ pShmNode = pShm->pShmNode; |
+ |
+ sqlite3_mutex_enter(pShmNode->mutex); |
+ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); |
+ |
+ if( pShmNode->nRegion<=iRegion ){ |
+ struct ShmRegion *apNew; /* New aRegion[] array */ |
+ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */ |
+ sqlite3_int64 sz; /* Current size of wal-index file */ |
+ |
+ pShmNode->szRegion = szRegion; |
+ |
+ /* 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, osGetLastError(), |
+ "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, osGetLastError(), |
+ "winShmMap2", pDbFd->zPath); |
+ goto shmpage_out; |
+ } |
+ } |
+ |
+ /* Map the requested memory region into this processes address space. */ |
+ apNew = (struct ShmRegion *)sqlite3_realloc64( |
+ pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0]) |
+ ); |
+ if( !apNew ){ |
+ rc = SQLITE_IOERR_NOMEM_BKPT; |
+ goto shmpage_out; |
+ } |
+ pShmNode->aRegion = apNew; |
+ |
+ while( pShmNode->nRegion<=iRegion ){ |
+ HANDLE hMap = NULL; /* file-mapping handle */ |
+ void *pMap = 0; /* Mapped memory region */ |
+ |
+#if SQLITE_OS_WINRT |
+ hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, |
+ NULL, PAGE_READWRITE, nByte, NULL |
+ ); |
+#elif defined(SQLITE_WIN32_HAS_WIDE) |
+ hMap = osCreateFileMappingW(pShmNode->hFile.h, |
+ NULL, PAGE_READWRITE, 0, nByte, NULL |
+ ); |
+#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA |
+ hMap = osCreateFileMappingA(pShmNode->hFile.h, |
+ NULL, PAGE_READWRITE, 0, nByte, NULL |
+ ); |
+#endif |
+ OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n", |
+ osGetCurrentProcessId(), pShmNode->nRegion, nByte, |
+ hMap ? "ok" : "failed")); |
+ if( hMap ){ |
+ int iOffset = pShmNode->nRegion*szRegion; |
+ int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; |
+#if SQLITE_OS_WINRT |
+ pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ, |
+ iOffset - iOffsetShift, szRegion + iOffsetShift |
+ ); |
+#else |
+ pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, |
+ 0, iOffset - iOffsetShift, szRegion + iOffsetShift |
+ ); |
+#endif |
+ OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n", |
+ osGetCurrentProcessId(), pShmNode->nRegion, iOffset, |
+ szRegion, pMap ? "ok" : "failed")); |
+ } |
+ if( !pMap ){ |
+ pShmNode->lastErrno = osGetLastError(); |
+ rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno, |
+ "winShmMap3", pDbFd->zPath); |
+ if( hMap ) osCloseHandle(hMap); |
+ goto shmpage_out; |
+ } |
+ |
+ pShmNode->aRegion[pShmNode->nRegion].pMap = pMap; |
+ pShmNode->aRegion[pShmNode->nRegion].hMap = hMap; |
+ pShmNode->nRegion++; |
+ } |
+ } |
+ |
+shmpage_out: |
+ if( pShmNode->nRegion>iRegion ){ |
+ int iOffset = iRegion*szRegion; |
+ int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; |
+ char *p = (char *)pShmNode->aRegion[iRegion].pMap; |
+ *pp = (void *)&p[iOffsetShift]; |
+ }else{ |
+ *pp = 0; |
+ } |
+ sqlite3_mutex_leave(pShmNode->mutex); |
+ return rc; |
+} |
+ |
+#else |
+# define winShmMap 0 |
+# define winShmLock 0 |
+# define winShmBarrier 0 |
+# define winShmUnmap 0 |
+#endif /* #ifndef SQLITE_OMIT_WAL */ |
+ |
+/* |
+** Cleans up the mapped region of the specified file, if any. |
+*/ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+static int winUnmapfile(winFile *pFile){ |
+ assert( pFile!=0 ); |
+ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, " |
+ "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n", |
+ osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion, |
+ pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax)); |
+ if( pFile->pMapRegion ){ |
+ if( !osUnmapViewOfFile(pFile->pMapRegion) ){ |
+ pFile->lastErrno = osGetLastError(); |
+ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, " |
+ "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile, |
+ pFile->pMapRegion)); |
+ return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, |
+ "winUnmapfile1", pFile->zPath); |
+ } |
+ pFile->pMapRegion = 0; |
+ pFile->mmapSize = 0; |
+ pFile->mmapSizeActual = 0; |
+ } |
+ if( pFile->hMap!=NULL ){ |
+ if( !osCloseHandle(pFile->hMap) ){ |
+ pFile->lastErrno = osGetLastError(); |
+ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n", |
+ osGetCurrentProcessId(), pFile, pFile->hMap)); |
+ return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno, |
+ "winUnmapfile2", pFile->zPath); |
+ } |
+ pFile->hMap = NULL; |
+ } |
+ OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), pFile)); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Memory map or remap the file opened by file-descriptor pFd (if the file |
+** is already mapped, the existing mapping is replaced by the new). Or, if |
+** there already exists a mapping for this file, and there are still |
+** outstanding xFetch() references to it, this function is a no-op. |
+** |
+** If parameter nByte is non-negative, then it is the requested size of |
+** the mapping to create. Otherwise, if nByte is less than zero, then the |
+** requested size is the size of the file on disk. The actual size of the |
+** created mapping is either the requested size or the value configured |
+** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller. |
+** |
+** SQLITE_OK is returned if no error occurs (even if the mapping is not |
+** recreated as a result of outstanding references) or an SQLite error |
+** code otherwise. |
+*/ |
+static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ |
+ sqlite3_int64 nMap = nByte; |
+ int rc; |
+ |
+ assert( nMap>=0 || pFd->nFetchOut==0 ); |
+ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n", |
+ osGetCurrentProcessId(), pFd, nByte)); |
+ |
+ if( pFd->nFetchOut>0 ) return SQLITE_OK; |
+ |
+ if( nMap<0 ){ |
+ rc = winFileSize((sqlite3_file*)pFd, &nMap); |
+ if( rc ){ |
+ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n", |
+ osGetCurrentProcessId(), pFd)); |
+ return SQLITE_IOERR_FSTAT; |
+ } |
+ } |
+ if( nMap>pFd->mmapSizeMax ){ |
+ nMap = pFd->mmapSizeMax; |
+ } |
+ nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1); |
+ |
+ if( nMap==0 && pFd->mmapSize>0 ){ |
+ winUnmapfile(pFd); |
+ } |
+ if( nMap!=pFd->mmapSize ){ |
+ void *pNew = 0; |
+ DWORD protect = PAGE_READONLY; |
+ DWORD flags = FILE_MAP_READ; |
+ |
+ winUnmapfile(pFd); |
+#ifdef SQLITE_MMAP_READWRITE |
+ if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){ |
+ protect = PAGE_READWRITE; |
+ flags |= FILE_MAP_WRITE; |
+ } |
+#endif |
+#if SQLITE_OS_WINRT |
+ pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL); |
+#elif defined(SQLITE_WIN32_HAS_WIDE) |
+ pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect, |
+ (DWORD)((nMap>>32) & 0xffffffff), |
+ (DWORD)(nMap & 0xffffffff), NULL); |
+#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA |
+ pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect, |
+ (DWORD)((nMap>>32) & 0xffffffff), |
+ (DWORD)(nMap & 0xffffffff), NULL); |
+#endif |
+ if( pFd->hMap==NULL ){ |
+ pFd->lastErrno = osGetLastError(); |
+ rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, |
+ "winMapfile1", pFd->zPath); |
+ /* Log the error, but continue normal operation using xRead/xWrite */ |
+ OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=%s\n", |
+ osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); |
+ return SQLITE_OK; |
+ } |
+ assert( (nMap % winSysInfo.dwPageSize)==0 ); |
+ assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); |
+#if SQLITE_OS_WINRT |
+ pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap); |
+#else |
+ pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap); |
+#endif |
+ if( pNew==NULL ){ |
+ osCloseHandle(pFd->hMap); |
+ pFd->hMap = NULL; |
+ pFd->lastErrno = osGetLastError(); |
+ rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno, |
+ "winMapfile2", pFd->zPath); |
+ /* Log the error, but continue normal operation using xRead/xWrite */ |
+ OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=%s\n", |
+ osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); |
+ return SQLITE_OK; |
+ } |
+ pFd->pMapRegion = pNew; |
+ pFd->mmapSize = nMap; |
+ pFd->mmapSizeActual = nMap; |
+ } |
+ |
+ OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), pFd)); |
+ return SQLITE_OK; |
+} |
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */ |
+ |
+/* |
+** If possible, return a pointer to a mapping of file fd starting at offset |
+** iOff. The mapping must be valid for at least nAmt bytes. |
+** |
+** If such a pointer can be obtained, store it in *pp and return SQLITE_OK. |
+** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK. |
+** Finally, if an error does occur, return an SQLite error code. The final |
+** value of *pp is undefined in this case. |
+** |
+** If this function does return a pointer, the caller must eventually |
+** release the reference by calling winUnfetch(). |
+*/ |
+static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ winFile *pFd = (winFile*)fd; /* The underlying database file */ |
+#endif |
+ *pp = 0; |
+ |
+ OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n", |
+ osGetCurrentProcessId(), fd, iOff, nAmt, pp)); |
+ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ if( pFd->mmapSizeMax>0 ){ |
+ if( pFd->pMapRegion==0 ){ |
+ int rc = winMapfile(pFd, -1); |
+ if( rc!=SQLITE_OK ){ |
+ OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n", |
+ osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); |
+ return rc; |
+ } |
+ } |
+ if( pFd->mmapSize >= iOff+nAmt ){ |
+ *pp = &((u8 *)pFd->pMapRegion)[iOff]; |
+ pFd->nFetchOut++; |
+ } |
+ } |
+#endif |
+ |
+ OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), fd, pp, *pp)); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** If the third argument is non-NULL, then this function releases a |
+** reference obtained by an earlier call to winFetch(). The second |
+** argument passed to this function must be the same as the corresponding |
+** argument that was passed to the winFetch() invocation. |
+** |
+** Or, if the third argument is NULL, then this function is being called |
+** to inform the VFS layer that, according to POSIX, any existing mapping |
+** may now be invalid and should be unmapped. |
+*/ |
+static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){ |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ winFile *pFd = (winFile*)fd; /* The underlying database file */ |
+ |
+ /* If p==0 (unmap the entire file) then there must be no outstanding |
+ ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), |
+ ** then there must be at least one outstanding. */ |
+ assert( (p==0)==(pFd->nFetchOut==0) ); |
+ |
+ /* If p!=0, it must match the iOff value. */ |
+ assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] ); |
+ |
+ OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n", |
+ osGetCurrentProcessId(), pFd, iOff, p)); |
+ |
+ if( p ){ |
+ pFd->nFetchOut--; |
+ }else{ |
+ /* FIXME: If Windows truly always prevents truncating or deleting a |
+ ** file while a mapping is held, then the following winUnmapfile() call |
+ ** is unnecessary can be omitted - potentially improving |
+ ** performance. */ |
+ winUnmapfile(pFd); |
+ } |
+ |
+ assert( pFd->nFetchOut>=0 ); |
+#endif |
+ |
+ OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n", |
+ osGetCurrentProcessId(), fd)); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Here ends the implementation of all sqlite3_file methods. |
+** |
+********************** End sqlite3_file Methods ******************************* |
+******************************************************************************/ |
+ |
+/* |
+** This vector defines all the methods that can operate on an |
+** sqlite3_file for win32. |
+*/ |
+static const sqlite3_io_methods winIoMethod = { |
+ 3, /* iVersion */ |
+ winClose, /* xClose */ |
+ winRead, /* xRead */ |
+ winWrite, /* xWrite */ |
+ winTruncate, /* xTruncate */ |
+ winSync, /* xSync */ |
+ winFileSize, /* xFileSize */ |
+ winLock, /* xLock */ |
+ winUnlock, /* xUnlock */ |
+ winCheckReservedLock, /* xCheckReservedLock */ |
+ winFileControl, /* xFileControl */ |
+ winSectorSize, /* xSectorSize */ |
+ winDeviceCharacteristics, /* xDeviceCharacteristics */ |
+ winShmMap, /* xShmMap */ |
+ winShmLock, /* xShmLock */ |
+ winShmBarrier, /* xShmBarrier */ |
+ winShmUnmap, /* xShmUnmap */ |
+ winFetch, /* xFetch */ |
+ winUnfetch /* xUnfetch */ |
+}; |
+ |
+/* |
+** This vector defines all the methods that can operate on an |
+** sqlite3_file for win32 without performing any locking. |
+*/ |
+static const sqlite3_io_methods winIoNolockMethod = { |
+ 3, /* iVersion */ |
+ winClose, /* xClose */ |
+ winRead, /* xRead */ |
+ winWrite, /* xWrite */ |
+ winTruncate, /* xTruncate */ |
+ winSync, /* xSync */ |
+ winFileSize, /* xFileSize */ |
+ winNolockLock, /* xLock */ |
+ winNolockUnlock, /* xUnlock */ |
+ winNolockCheckReservedLock, /* xCheckReservedLock */ |
+ winFileControl, /* xFileControl */ |
+ winSectorSize, /* xSectorSize */ |
+ winDeviceCharacteristics, /* xDeviceCharacteristics */ |
+ winShmMap, /* xShmMap */ |
+ winShmLock, /* xShmLock */ |
+ winShmBarrier, /* xShmBarrier */ |
+ winShmUnmap, /* xShmUnmap */ |
+ winFetch, /* xFetch */ |
+ winUnfetch /* xUnfetch */ |
+}; |
+ |
+static winVfsAppData winAppData = { |
+ &winIoMethod, /* pMethod */ |
+ 0, /* pAppData */ |
+ 0 /* bNoLock */ |
+}; |
+ |
+static winVfsAppData winNolockAppData = { |
+ &winIoNolockMethod, /* pMethod */ |
+ 0, /* pAppData */ |
+ 1 /* bNoLock */ |
+}; |
+ |
+/**************************************************************************** |
+**************************** sqlite3_vfs methods **************************** |
+** |
+** This division contains the implementation of methods on the |
+** sqlite3_vfs object. |
+*/ |
+ |
+#if defined(__CYGWIN__) |
+/* |
+** Convert a filename from whatever the underlying operating system |
+** supports for filenames into UTF-8. Space to hold the result is |
+** obtained from malloc and must be freed by the calling function. |
+*/ |
+static char *winConvertToUtf8Filename(const void *zFilename){ |
+ char *zConverted = 0; |
+ if( osIsNT() ){ |
+ zConverted = winUnicodeToUtf8(zFilename); |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI()); |
+ } |
+#endif |
+ /* caller will handle out of memory */ |
+ return zConverted; |
+} |
+#endif |
+ |
+/* |
+** Convert a UTF-8 filename into whatever form the underlying |
+** operating system wants filenames in. Space to hold the result |
+** is obtained from malloc and must be freed by the calling |
+** function. |
+*/ |
+static void *winConvertFromUtf8Filename(const char *zFilename){ |
+ void *zConverted = 0; |
+ if( osIsNT() ){ |
+ zConverted = winUtf8ToUnicode(zFilename); |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI()); |
+ } |
+#endif |
+ /* caller will handle out of memory */ |
+ return zConverted; |
+} |
+ |
+/* |
+** This function returns non-zero if the specified UTF-8 string buffer |
+** ends with a directory separator character or one was successfully |
+** added to it. |
+*/ |
+static int winMakeEndInDirSep(int nBuf, char *zBuf){ |
+ if( zBuf ){ |
+ int nLen = sqlite3Strlen30(zBuf); |
+ if( nLen>0 ){ |
+ if( winIsDirSep(zBuf[nLen-1]) ){ |
+ return 1; |
+ }else if( nLen+1<nBuf ){ |
+ zBuf[nLen] = winGetDirSep(); |
+ zBuf[nLen+1] = '\0'; |
+ return 1; |
+ } |
+ } |
+ } |
+ return 0; |
+} |
+ |
+/* |
+** Create a temporary file name and store the resulting pointer into pzBuf. |
+** The pointer returned in pzBuf must be freed via sqlite3_free(). |
+*/ |
+static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ |
+ static char zChars[] = |
+ "abcdefghijklmnopqrstuvwxyz" |
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
+ "0123456789"; |
+ size_t i, j; |
+ int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX); |
+ int nMax, nBuf, nDir, nLen; |
+ char *zBuf; |
+ |
+ /* 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 ); |
+ |
+ /* Allocate a temporary buffer to store the fully qualified file |
+ ** name for the temporary file. If this fails, we cannot continue. |
+ */ |
+ nMax = pVfs->mxPathname; nBuf = nMax + 2; |
+ zBuf = sqlite3MallocZero( nBuf ); |
+ if( !zBuf ){ |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ |
+ /* Figure out the effective temporary directory. First, check if one |
+ ** has been explicitly set by the application; otherwise, use the one |
+ ** configured by the operating system. |
+ */ |
+ nDir = nMax - (nPre + 15); |
+ assert( nDir>0 ); |
+ if( sqlite3_temp_directory ){ |
+ int nDirLen = sqlite3Strlen30(sqlite3_temp_directory); |
+ if( nDirLen>0 ){ |
+ if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){ |
+ nDirLen++; |
+ } |
+ if( nDirLen>nDir ){ |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); |
+ return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0); |
+ } |
+ sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory); |
+ } |
+ } |
+#if defined(__CYGWIN__) |
+ else{ |
+ static const char *azDirs[] = { |
+ 0, /* getenv("SQLITE_TMPDIR") */ |
+ 0, /* getenv("TMPDIR") */ |
+ 0, /* getenv("TMP") */ |
+ 0, /* getenv("TEMP") */ |
+ 0, /* getenv("USERPROFILE") */ |
+ "/var/tmp", |
+ "/usr/tmp", |
+ "/tmp", |
+ ".", |
+ 0 /* List terminator */ |
+ }; |
+ unsigned int i; |
+ const char *zDir = 0; |
+ |
+ if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); |
+ if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); |
+ if( !azDirs[2] ) azDirs[2] = getenv("TMP"); |
+ if( !azDirs[3] ) azDirs[3] = getenv("TEMP"); |
+ if( !azDirs[4] ) azDirs[4] = getenv("USERPROFILE"); |
+ for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){ |
+ void *zConverted; |
+ if( zDir==0 ) continue; |
+ /* If the path starts with a drive letter followed by the colon |
+ ** character, assume it is already a native Win32 path; otherwise, |
+ ** it must be converted to a native Win32 path via the Cygwin API |
+ ** prior to using it. |
+ */ |
+ if( winIsDriveLetterAndColon(zDir) ){ |
+ zConverted = winConvertFromUtf8Filename(zDir); |
+ if( !zConverted ){ |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ if( winIsDir(zConverted) ){ |
+ sqlite3_snprintf(nMax, zBuf, "%s", zDir); |
+ sqlite3_free(zConverted); |
+ break; |
+ } |
+ sqlite3_free(zConverted); |
+ }else{ |
+ zConverted = sqlite3MallocZero( nMax+1 ); |
+ if( !zConverted ){ |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ if( cygwin_conv_path( |
+ osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir, |
+ zConverted, nMax+1)<0 ){ |
+ sqlite3_free(zConverted); |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_CONVPATH\n")); |
+ return winLogError(SQLITE_IOERR_CONVPATH, (DWORD)errno, |
+ "winGetTempname2", zDir); |
+ } |
+ if( winIsDir(zConverted) ){ |
+ /* At this point, we know the candidate directory exists and should |
+ ** be used. However, we may need to convert the string containing |
+ ** its name into UTF-8 (i.e. if it is UTF-16 right now). |
+ */ |
+ char *zUtf8 = winConvertToUtf8Filename(zConverted); |
+ if( !zUtf8 ){ |
+ sqlite3_free(zConverted); |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ sqlite3_snprintf(nMax, zBuf, "%s", zUtf8); |
+ sqlite3_free(zUtf8); |
+ sqlite3_free(zConverted); |
+ break; |
+ } |
+ sqlite3_free(zConverted); |
+ } |
+ } |
+ } |
+#elif !SQLITE_OS_WINRT && !defined(__CYGWIN__) |
+ else if( osIsNT() ){ |
+ char *zMulti; |
+ LPWSTR zWidePath = sqlite3MallocZero( nMax*sizeof(WCHAR) ); |
+ if( !zWidePath ){ |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ if( osGetTempPathW(nMax, zWidePath)==0 ){ |
+ sqlite3_free(zWidePath); |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n")); |
+ return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(), |
+ "winGetTempname2", 0); |
+ } |
+ zMulti = winUnicodeToUtf8(zWidePath); |
+ if( zMulti ){ |
+ sqlite3_snprintf(nMax, zBuf, "%s", zMulti); |
+ sqlite3_free(zMulti); |
+ sqlite3_free(zWidePath); |
+ }else{ |
+ sqlite3_free(zWidePath); |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ char *zUtf8; |
+ char *zMbcsPath = sqlite3MallocZero( nMax ); |
+ if( !zMbcsPath ){ |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ if( osGetTempPathA(nMax, zMbcsPath)==0 ){ |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n")); |
+ return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(), |
+ "winGetTempname3", 0); |
+ } |
+ zUtf8 = winMbcsToUtf8(zMbcsPath, osAreFileApisANSI()); |
+ if( zUtf8 ){ |
+ sqlite3_snprintf(nMax, zBuf, "%s", zUtf8); |
+ sqlite3_free(zUtf8); |
+ }else{ |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n")); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ } |
+#endif /* SQLITE_WIN32_HAS_ANSI */ |
+#endif /* !SQLITE_OS_WINRT */ |
+ |
+ /* |
+ ** Check to make sure the temporary directory ends with an appropriate |
+ ** separator. If it does not and there is not enough space left to add |
+ ** one, fail. |
+ */ |
+ if( !winMakeEndInDirSep(nDir+1, zBuf) ){ |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); |
+ return winLogError(SQLITE_ERROR, 0, "winGetTempname4", 0); |
+ } |
+ |
+ /* |
+ ** Check that the output buffer is large enough for the temporary file |
+ ** name in the following format: |
+ ** |
+ ** "<temporary_directory>/etilqs_XXXXXXXXXXXXXXX\0\0" |
+ ** |
+ ** If not, return SQLITE_ERROR. The number 17 is used here in order to |
+ ** account for the space used by the 15 character random suffix and the |
+ ** two trailing NUL characters. The final directory separator character |
+ ** has already added if it was not already present. |
+ */ |
+ nLen = sqlite3Strlen30(zBuf); |
+ if( (nLen + nPre + 17) > nBuf ){ |
+ sqlite3_free(zBuf); |
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); |
+ return winLogError(SQLITE_ERROR, 0, "winGetTempname5", 0); |
+ } |
+ |
+ sqlite3_snprintf(nBuf-16-nLen, zBuf+nLen, SQLITE_TEMP_FILE_PREFIX); |
+ |
+ j = sqlite3Strlen30(zBuf); |
+ sqlite3_randomness(15, &zBuf[j]); |
+ for(i=0; i<15; i++, j++){ |
+ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
+ } |
+ zBuf[j] = 0; |
+ zBuf[j+1] = 0; |
+ *pzBuf = zBuf; |
+ |
+ OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf)); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Return TRUE if the named file is really a directory. Return false if |
+** it is something other than a directory, or if there is any kind of memory |
+** allocation failure. |
+*/ |
+static int winIsDir(const void *zConverted){ |
+ DWORD attr; |
+ int rc = 0; |
+ DWORD lastErrno; |
+ |
+ if( osIsNT() ){ |
+ int cnt = 0; |
+ WIN32_FILE_ATTRIBUTE_DATA sAttrData; |
+ memset(&sAttrData, 0, sizeof(sAttrData)); |
+ while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, |
+ GetFileExInfoStandard, |
+ &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} |
+ if( !rc ){ |
+ return 0; /* Invalid name? */ |
+ } |
+ attr = sAttrData.dwFileAttributes; |
+#if SQLITE_OS_WINCE==0 |
+ }else{ |
+ attr = osGetFileAttributesA((char*)zConverted); |
+#endif |
+ } |
+ return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); |
+} |
+ |
+/* |
+** Open a file. |
+*/ |
+static int winOpen( |
+ sqlite3_vfs *pVfs, /* Used to get maximum path length and AppData */ |
+ const char *zName, /* Name of the file (UTF-8) */ |
+ sqlite3_file *id, /* Write the SQLite file handle here */ |
+ int flags, /* Open mode flags */ |
+ int *pOutFlags /* Status return flags */ |
+){ |
+ HANDLE h; |
+ DWORD lastErrno = 0; |
+ DWORD dwDesiredAccess; |
+ DWORD dwShareMode; |
+ DWORD dwCreationDisposition; |
+ DWORD dwFlagsAndAttributes = 0; |
+#if SQLITE_OS_WINCE |
+ int isTemp = 0; |
+#endif |
+ winVfsAppData *pAppData; |
+ winFile *pFile = (winFile*)id; |
+ void *zConverted; /* Filename in OS encoding */ |
+ const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ |
+ int cnt = 0; |
+ |
+ /* If argument zPath is a NULL pointer, this function is required to open |
+ ** a temporary file. Use this buffer to store the file name in. |
+ */ |
+ char *zTmpname = 0; /* For temporary filename, if necessary. */ |
+ |
+ int rc = SQLITE_OK; /* Function Return Code */ |
+#if !defined(NDEBUG) || SQLITE_OS_WINCE |
+ int eType = flags&0xFFFFFF00; /* Type of file to open */ |
+#endif |
+ |
+ int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); |
+ int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); |
+ int isCreate = (flags & SQLITE_OPEN_CREATE); |
+ int isReadonly = (flags & SQLITE_OPEN_READONLY); |
+ int isReadWrite = (flags & SQLITE_OPEN_READWRITE); |
+ |
+#ifndef NDEBUG |
+ int isOpenJournal = (isCreate && ( |
+ eType==SQLITE_OPEN_MASTER_JOURNAL |
+ || eType==SQLITE_OPEN_MAIN_JOURNAL |
+ || eType==SQLITE_OPEN_WAL |
+ )); |
+#endif |
+ |
+ OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n", |
+ zUtf8Name, id, flags, pOutFlags)); |
+ |
+ /* Check the following statements are true: |
+ ** |
+ ** (a) Exactly one of the READWRITE and READONLY flags must be set, and |
+ ** (b) if CREATE is set, then READWRITE must also be set, and |
+ ** (c) if EXCLUSIVE is set, then CREATE must also be set. |
+ ** (d) if DELETEONCLOSE is set, then CREATE must also be set. |
+ */ |
+ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); |
+ assert(isCreate==0 || isReadWrite); |
+ assert(isExclusive==0 || isCreate); |
+ assert(isDelete==0 || isCreate); |
+ |
+ /* The main DB, main journal, WAL file and master journal are never |
+ ** automatically deleted. Nor are they ever temporary files. */ |
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); |
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); |
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL ); |
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); |
+ |
+ /* Assert that the upper layer has set one of the "file-type" flags. */ |
+ 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 |
+ ); |
+ |
+ assert( pFile!=0 ); |
+ memset(pFile, 0, sizeof(winFile)); |
+ pFile->h = INVALID_HANDLE_VALUE; |
+ |
+#if SQLITE_OS_WINRT |
+ if( !zUtf8Name && !sqlite3_temp_directory ){ |
+ sqlite3_log(SQLITE_ERROR, |
+ "sqlite3_temp_directory variable should be set for WinRT"); |
+ } |
+#endif |
+ |
+ /* If the second argument to this function is NULL, generate a |
+ ** temporary file name to use |
+ */ |
+ if( !zUtf8Name ){ |
+ assert( isDelete && !isOpenJournal ); |
+ rc = winGetTempname(pVfs, &zTmpname); |
+ if( rc!=SQLITE_OK ){ |
+ OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc))); |
+ return rc; |
+ } |
+ zUtf8Name = zTmpname; |
+ } |
+ |
+ /* Database filenames are double-zero terminated if they are not |
+ ** URIs with parameters. Hence, they can always be passed into |
+ ** sqlite3_uri_parameter(). |
+ */ |
+ assert( (eType!=SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || |
+ zUtf8Name[sqlite3Strlen30(zUtf8Name)+1]==0 ); |
+ |
+ /* Convert the filename to the system encoding. */ |
+ zConverted = winConvertFromUtf8Filename(zUtf8Name); |
+ if( zConverted==0 ){ |
+ sqlite3_free(zTmpname); |
+ OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name)); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ |
+ if( winIsDir(zConverted) ){ |
+ sqlite3_free(zConverted); |
+ sqlite3_free(zTmpname); |
+ OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name)); |
+ return SQLITE_CANTOPEN_ISDIR; |
+ } |
+ |
+ if( isReadWrite ){ |
+ dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; |
+ }else{ |
+ dwDesiredAccess = GENERIC_READ; |
+ } |
+ |
+ /* 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. */ |
+ /* If the file exists, it fails. */ |
+ dwCreationDisposition = CREATE_NEW; |
+ }else if( isCreate ){ |
+ /* Open existing file, or create if it doesn't exist */ |
+ dwCreationDisposition = OPEN_ALWAYS; |
+ }else{ |
+ /* Opens a file, only if it exists. */ |
+ dwCreationDisposition = OPEN_EXISTING; |
+ } |
+ |
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; |
+ |
+ if( isDelete ){ |
+#if SQLITE_OS_WINCE |
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN; |
+ isTemp = 1; |
+#else |
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY |
+ | FILE_ATTRIBUTE_HIDDEN |
+ | FILE_FLAG_DELETE_ON_CLOSE; |
+#endif |
+ }else{ |
+ dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; |
+ } |
+ /* Reports from the internet are that performance is always |
+ ** better if FILE_FLAG_RANDOM_ACCESS is used. Ticket #2699. */ |
+#if SQLITE_OS_WINCE |
+ dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS; |
+#endif |
+ |
+ if( osIsNT() ){ |
+#if SQLITE_OS_WINRT |
+ CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; |
+ extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); |
+ extendedParameters.dwFileAttributes = |
+ dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK; |
+ extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK; |
+ extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; |
+ extendedParameters.lpSecurityAttributes = NULL; |
+ extendedParameters.hTemplateFile = NULL; |
+ while( (h = osCreateFile2((LPCWSTR)zConverted, |
+ dwDesiredAccess, |
+ dwShareMode, |
+ dwCreationDisposition, |
+ &extendedParameters))==INVALID_HANDLE_VALUE && |
+ winRetryIoerr(&cnt, &lastErrno) ){ |
+ /* Noop */ |
+ } |
+#else |
+ while( (h = osCreateFileW((LPCWSTR)zConverted, |
+ dwDesiredAccess, |
+ dwShareMode, NULL, |
+ dwCreationDisposition, |
+ dwFlagsAndAttributes, |
+ NULL))==INVALID_HANDLE_VALUE && |
+ winRetryIoerr(&cnt, &lastErrno) ){ |
+ /* Noop */ |
+ } |
+#endif |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ while( (h = osCreateFileA((LPCSTR)zConverted, |
+ dwDesiredAccess, |
+ dwShareMode, NULL, |
+ dwCreationDisposition, |
+ dwFlagsAndAttributes, |
+ NULL))==INVALID_HANDLE_VALUE && |
+ winRetryIoerr(&cnt, &lastErrno) ){ |
+ /* Noop */ |
+ } |
+ } |
+#endif |
+ winLogIoerr(cnt, __LINE__); |
+ |
+ OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name, |
+ dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); |
+ |
+ if( h==INVALID_HANDLE_VALUE ){ |
+ pFile->lastErrno = lastErrno; |
+ winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); |
+ sqlite3_free(zConverted); |
+ sqlite3_free(zTmpname); |
+ if( isReadWrite && !isExclusive ){ |
+ return winOpen(pVfs, zName, id, |
+ ((flags|SQLITE_OPEN_READONLY) & |
+ ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), |
+ pOutFlags); |
+ }else{ |
+ return SQLITE_CANTOPEN_BKPT; |
+ } |
+ } |
+ |
+ if( pOutFlags ){ |
+ if( isReadWrite ){ |
+ *pOutFlags = SQLITE_OPEN_READWRITE; |
+ }else{ |
+ *pOutFlags = SQLITE_OPEN_READONLY; |
+ } |
+ } |
+ |
+ OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, " |
+ "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ? |
+ *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); |
+ |
+ pAppData = (winVfsAppData*)pVfs->pAppData; |
+ |
+#if SQLITE_OS_WINCE |
+ { |
+ if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB |
+ && ((pAppData==NULL) || !pAppData->bNoLock) |
+ && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK |
+ ){ |
+ osCloseHandle(h); |
+ sqlite3_free(zConverted); |
+ sqlite3_free(zTmpname); |
+ OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); |
+ return rc; |
+ } |
+ } |
+ if( isTemp ){ |
+ pFile->zDeleteOnClose = zConverted; |
+ }else |
+#endif |
+ { |
+ sqlite3_free(zConverted); |
+ } |
+ |
+ sqlite3_free(zTmpname); |
+ pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod; |
+ pFile->pVfs = pVfs; |
+ pFile->h = h; |
+ if( isReadonly ){ |
+ pFile->ctrlFlags |= WINFILE_RDONLY; |
+ } |
+ if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ |
+ pFile->ctrlFlags |= WINFILE_PSOW; |
+ } |
+ pFile->lastErrno = NO_ERROR; |
+ pFile->zPath = zName; |
+#if SQLITE_MAX_MMAP_SIZE>0 |
+ pFile->hMap = NULL; |
+ pFile->pMapRegion = 0; |
+ pFile->mmapSize = 0; |
+ pFile->mmapSizeActual = 0; |
+ pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap; |
+#endif |
+ |
+ OpenCounter(+1); |
+ return rc; |
+} |
+ |
+/* |
+** Delete the named file. |
+** |
+** Note that Windows does not allow a file to be deleted if some other |
+** process has it open. Sometimes a virus scanner or indexing program |
+** will open a journal file shortly after it is created in order to do |
+** whatever it does. While this other process is holding the |
+** file open, we will be unable to delete it. To work around this |
+** problem, we delay 100 milliseconds and try to delete again. Up |
+** to MX_DELETION_ATTEMPTs deletion attempts are run before giving |
+** up and returning an error. |
+*/ |
+static int winDelete( |
+ sqlite3_vfs *pVfs, /* Not used on win32 */ |
+ const char *zFilename, /* Name of file to delete */ |
+ int syncDir /* Not used on win32 */ |
+){ |
+ int cnt = 0; |
+ int rc; |
+ DWORD attr; |
+ DWORD lastErrno = 0; |
+ void *zConverted; |
+ UNUSED_PARAMETER(pVfs); |
+ UNUSED_PARAMETER(syncDir); |
+ |
+ SimulateIOError(return SQLITE_IOERR_DELETE); |
+ OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir)); |
+ |
+ zConverted = winConvertFromUtf8Filename(zFilename); |
+ if( zConverted==0 ){ |
+ OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ if( osIsNT() ){ |
+ do { |
+#if SQLITE_OS_WINRT |
+ WIN32_FILE_ATTRIBUTE_DATA sAttrData; |
+ memset(&sAttrData, 0, sizeof(sAttrData)); |
+ if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard, |
+ &sAttrData) ){ |
+ attr = sAttrData.dwFileAttributes; |
+ }else{ |
+ lastErrno = osGetLastError(); |
+ if( lastErrno==ERROR_FILE_NOT_FOUND |
+ || lastErrno==ERROR_PATH_NOT_FOUND ){ |
+ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ |
+ }else{ |
+ rc = SQLITE_ERROR; |
+ } |
+ break; |
+ } |
+#else |
+ attr = osGetFileAttributesW(zConverted); |
+#endif |
+ if ( attr==INVALID_FILE_ATTRIBUTES ){ |
+ lastErrno = osGetLastError(); |
+ if( lastErrno==ERROR_FILE_NOT_FOUND |
+ || lastErrno==ERROR_PATH_NOT_FOUND ){ |
+ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ |
+ }else{ |
+ rc = SQLITE_ERROR; |
+ } |
+ break; |
+ } |
+ if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ |
+ rc = SQLITE_ERROR; /* Files only. */ |
+ break; |
+ } |
+ if ( osDeleteFileW(zConverted) ){ |
+ rc = SQLITE_OK; /* Deleted OK. */ |
+ break; |
+ } |
+ if ( !winRetryIoerr(&cnt, &lastErrno) ){ |
+ rc = SQLITE_ERROR; /* No more retries. */ |
+ break; |
+ } |
+ } while(1); |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ do { |
+ attr = osGetFileAttributesA(zConverted); |
+ if ( attr==INVALID_FILE_ATTRIBUTES ){ |
+ lastErrno = osGetLastError(); |
+ if( lastErrno==ERROR_FILE_NOT_FOUND |
+ || lastErrno==ERROR_PATH_NOT_FOUND ){ |
+ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ |
+ }else{ |
+ rc = SQLITE_ERROR; |
+ } |
+ break; |
+ } |
+ if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ |
+ rc = SQLITE_ERROR; /* Files only. */ |
+ break; |
+ } |
+ if ( osDeleteFileA(zConverted) ){ |
+ rc = SQLITE_OK; /* Deleted OK. */ |
+ break; |
+ } |
+ if ( !winRetryIoerr(&cnt, &lastErrno) ){ |
+ rc = SQLITE_ERROR; /* No more retries. */ |
+ break; |
+ } |
+ } while(1); |
+ } |
+#endif |
+ if( rc && rc!=SQLITE_IOERR_DELETE_NOENT ){ |
+ rc = winLogError(SQLITE_IOERR_DELETE, lastErrno, "winDelete", zFilename); |
+ }else{ |
+ winLogIoerr(cnt, __LINE__); |
+ } |
+ sqlite3_free(zConverted); |
+ OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc))); |
+ return rc; |
+} |
+ |
+/* |
+** Check the existence and status of a file. |
+*/ |
+static int winAccess( |
+ sqlite3_vfs *pVfs, /* Not used on win32 */ |
+ const char *zFilename, /* Name of file to check */ |
+ int flags, /* Type of test to make on this file */ |
+ int *pResOut /* OUT: Result */ |
+){ |
+ DWORD attr; |
+ int rc = 0; |
+ DWORD lastErrno = 0; |
+ void *zConverted; |
+ UNUSED_PARAMETER(pVfs); |
+ |
+ SimulateIOError( return SQLITE_IOERR_ACCESS; ); |
+ OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n", |
+ zFilename, flags, pResOut)); |
+ |
+ zConverted = winConvertFromUtf8Filename(zFilename); |
+ if( zConverted==0 ){ |
+ OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename)); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ if( osIsNT() ){ |
+ int cnt = 0; |
+ WIN32_FILE_ATTRIBUTE_DATA sAttrData; |
+ memset(&sAttrData, 0, sizeof(sAttrData)); |
+ while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted, |
+ GetFileExInfoStandard, |
+ &sAttrData)) && winRetryIoerr(&cnt, &lastErrno) ){} |
+ if( rc ){ |
+ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file |
+ ** as if it does not exist. |
+ */ |
+ if( flags==SQLITE_ACCESS_EXISTS |
+ && sAttrData.nFileSizeHigh==0 |
+ && sAttrData.nFileSizeLow==0 ){ |
+ attr = INVALID_FILE_ATTRIBUTES; |
+ }else{ |
+ attr = sAttrData.dwFileAttributes; |
+ } |
+ }else{ |
+ winLogIoerr(cnt, __LINE__); |
+ if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){ |
+ sqlite3_free(zConverted); |
+ return winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", |
+ zFilename); |
+ }else{ |
+ attr = INVALID_FILE_ATTRIBUTES; |
+ } |
+ } |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ attr = osGetFileAttributesA((char*)zConverted); |
+ } |
+#endif |
+ sqlite3_free(zConverted); |
+ switch( flags ){ |
+ case SQLITE_ACCESS_READ: |
+ case SQLITE_ACCESS_EXISTS: |
+ rc = attr!=INVALID_FILE_ATTRIBUTES; |
+ break; |
+ case SQLITE_ACCESS_READWRITE: |
+ rc = attr!=INVALID_FILE_ATTRIBUTES && |
+ (attr & FILE_ATTRIBUTE_READONLY)==0; |
+ break; |
+ default: |
+ assert(!"Invalid flags argument"); |
+ } |
+ *pResOut = rc; |
+ OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", |
+ zFilename, pResOut, *pResOut)); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Returns non-zero if the specified path name starts with a drive letter |
+** followed by a colon character. |
+*/ |
+static BOOL winIsDriveLetterAndColon( |
+ const char *zPathname |
+){ |
+ return ( sqlite3Isalpha(zPathname[0]) && zPathname[1]==':' ); |
+} |
+ |
+/* |
+** Returns non-zero if the specified path name should be used verbatim. If |
+** non-zero is returned from this function, the calling function must simply |
+** use the provided path name verbatim -OR- resolve it into a full path name |
+** using the GetFullPathName Win32 API function (if available). |
+*/ |
+static BOOL winIsVerbatimPathname( |
+ const char *zPathname |
+){ |
+ /* |
+ ** If the path name starts with a forward slash or a backslash, it is either |
+ ** a legal UNC name, a volume relative path, or an absolute path name in the |
+ ** "Unix" format on Windows. There is no easy way to differentiate between |
+ ** the final two cases; therefore, we return the safer return value of TRUE |
+ ** so that callers of this function will simply use it verbatim. |
+ */ |
+ if ( winIsDirSep(zPathname[0]) ){ |
+ return TRUE; |
+ } |
+ |
+ /* |
+ ** If the path name starts with a letter and a colon it is either a volume |
+ ** relative path or an absolute path. Callers of this function must not |
+ ** attempt to treat it as a relative path name (i.e. they should simply use |
+ ** it verbatim). |
+ */ |
+ if ( winIsDriveLetterAndColon(zPathname) ){ |
+ return TRUE; |
+ } |
+ |
+ /* |
+ ** If we get to this point, the path name should almost certainly be a purely |
+ ** relative one (i.e. not a UNC name, not absolute, and not volume relative). |
+ */ |
+ return FALSE; |
+} |
+ |
+/* |
+** Turn a relative pathname into a full pathname. Write the full |
+** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname |
+** bytes in size. |
+*/ |
+static int winFullPathname( |
+ sqlite3_vfs *pVfs, /* Pointer to vfs object */ |
+ const char *zRelative, /* Possibly relative input path */ |
+ int nFull, /* Size of output buffer in bytes */ |
+ char *zFull /* Output buffer */ |
+){ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) |
+ DWORD nByte; |
+ void *zConverted; |
+ char *zOut; |
+#endif |
+ |
+ /* If this path name begins with "/X:", where "X" is any alphabetic |
+ ** character, discard the initial "/" from the pathname. |
+ */ |
+ if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ |
+ zRelative++; |
+ } |
+ |
+#if defined(__CYGWIN__) |
+ SimulateIOError( return SQLITE_ERROR ); |
+ UNUSED_PARAMETER(nFull); |
+ assert( nFull>=pVfs->mxPathname ); |
+ if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ |
+ /* |
+ ** NOTE: We are dealing with a relative path name and the data |
+ ** directory has been set. Therefore, use it as the basis |
+ ** for converting the relative path name to an absolute |
+ ** one by prepending the data directory and a slash. |
+ */ |
+ char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); |
+ if( !zOut ){ |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ if( cygwin_conv_path( |
+ (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) | |
+ CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){ |
+ sqlite3_free(zOut); |
+ return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, |
+ "winFullPathname1", zRelative); |
+ }else{ |
+ char *zUtf8 = winConvertToUtf8Filename(zOut); |
+ if( !zUtf8 ){ |
+ sqlite3_free(zOut); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", |
+ sqlite3_data_directory, winGetDirSep(), zUtf8); |
+ sqlite3_free(zUtf8); |
+ sqlite3_free(zOut); |
+ } |
+ }else{ |
+ char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 ); |
+ if( !zOut ){ |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ if( cygwin_conv_path( |
+ (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A), |
+ zRelative, zOut, pVfs->mxPathname+1)<0 ){ |
+ sqlite3_free(zOut); |
+ return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno, |
+ "winFullPathname2", zRelative); |
+ }else{ |
+ char *zUtf8 = winConvertToUtf8Filename(zOut); |
+ if( !zUtf8 ){ |
+ sqlite3_free(zOut); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8); |
+ sqlite3_free(zUtf8); |
+ sqlite3_free(zOut); |
+ } |
+ } |
+ return SQLITE_OK; |
+#endif |
+ |
+#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__) |
+ SimulateIOError( return SQLITE_ERROR ); |
+ /* WinCE has no concept of a relative pathname, or so I am told. */ |
+ /* WinRT has no way to convert a relative path to an absolute one. */ |
+ if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ |
+ /* |
+ ** NOTE: We are dealing with a relative path name and the data |
+ ** directory has been set. Therefore, use it as the basis |
+ ** for converting the relative path name to an absolute |
+ ** one by prepending the data directory and a backslash. |
+ */ |
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", |
+ sqlite3_data_directory, winGetDirSep(), zRelative); |
+ }else{ |
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); |
+ } |
+ return SQLITE_OK; |
+#endif |
+ |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) |
+ /* 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. This function could fail if, for example, the |
+ ** current working directory has been unlinked. |
+ */ |
+ SimulateIOError( return SQLITE_ERROR ); |
+ if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ |
+ /* |
+ ** NOTE: We are dealing with a relative path name and the data |
+ ** directory has been set. Therefore, use it as the basis |
+ ** for converting the relative path name to an absolute |
+ ** one by prepending the data directory and a backslash. |
+ */ |
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s", |
+ sqlite3_data_directory, winGetDirSep(), zRelative); |
+ return SQLITE_OK; |
+ } |
+ zConverted = winConvertFromUtf8Filename(zRelative); |
+ if( zConverted==0 ){ |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ if( osIsNT() ){ |
+ LPWSTR zTemp; |
+ nByte = osGetFullPathNameW((LPCWSTR)zConverted, 0, 0, 0); |
+ if( nByte==0 ){ |
+ sqlite3_free(zConverted); |
+ return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), |
+ "winFullPathname1", zRelative); |
+ } |
+ nByte += 3; |
+ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); |
+ if( zTemp==0 ){ |
+ sqlite3_free(zConverted); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0); |
+ if( nByte==0 ){ |
+ sqlite3_free(zConverted); |
+ sqlite3_free(zTemp); |
+ return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), |
+ "winFullPathname2", zRelative); |
+ } |
+ sqlite3_free(zConverted); |
+ zOut = winUnicodeToUtf8(zTemp); |
+ sqlite3_free(zTemp); |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ char *zTemp; |
+ nByte = osGetFullPathNameA((char*)zConverted, 0, 0, 0); |
+ if( nByte==0 ){ |
+ sqlite3_free(zConverted); |
+ return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), |
+ "winFullPathname3", zRelative); |
+ } |
+ nByte += 3; |
+ zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) ); |
+ if( zTemp==0 ){ |
+ sqlite3_free(zConverted); |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+ nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0); |
+ if( nByte==0 ){ |
+ sqlite3_free(zConverted); |
+ sqlite3_free(zTemp); |
+ return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(), |
+ "winFullPathname4", zRelative); |
+ } |
+ sqlite3_free(zConverted); |
+ zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI()); |
+ sqlite3_free(zTemp); |
+ } |
+#endif |
+ if( zOut ){ |
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut); |
+ sqlite3_free(zOut); |
+ return SQLITE_OK; |
+ }else{ |
+ return SQLITE_IOERR_NOMEM_BKPT; |
+ } |
+#endif |
+} |
+ |
+#ifndef SQLITE_OMIT_LOAD_EXTENSION |
+/* |
+** Interfaces for opening a shared library, finding entry points |
+** within the shared library, and closing the shared library. |
+*/ |
+static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ |
+ HANDLE h; |
+#if defined(__CYGWIN__) |
+ int nFull = pVfs->mxPathname+1; |
+ char *zFull = sqlite3MallocZero( nFull ); |
+ void *zConverted = 0; |
+ if( zFull==0 ){ |
+ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); |
+ return 0; |
+ } |
+ if( winFullPathname(pVfs, zFilename, nFull, zFull)!=SQLITE_OK ){ |
+ sqlite3_free(zFull); |
+ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); |
+ return 0; |
+ } |
+ zConverted = winConvertFromUtf8Filename(zFull); |
+ sqlite3_free(zFull); |
+#else |
+ void *zConverted = winConvertFromUtf8Filename(zFilename); |
+ UNUSED_PARAMETER(pVfs); |
+#endif |
+ if( zConverted==0 ){ |
+ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)0)); |
+ return 0; |
+ } |
+ if( osIsNT() ){ |
+#if SQLITE_OS_WINRT |
+ h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0); |
+#else |
+ h = osLoadLibraryW((LPCWSTR)zConverted); |
+#endif |
+ } |
+#ifdef SQLITE_WIN32_HAS_ANSI |
+ else{ |
+ h = osLoadLibraryA((char*)zConverted); |
+ } |
+#endif |
+ OSTRACE(("DLOPEN name=%s, handle=%p\n", zFilename, (void*)h)); |
+ sqlite3_free(zConverted); |
+ return (void*)h; |
+} |
+static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ |
+ UNUSED_PARAMETER(pVfs); |
+ winGetLastErrorMsg(osGetLastError(), nBuf, zBufOut); |
+} |
+static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){ |
+ FARPROC proc; |
+ UNUSED_PARAMETER(pVfs); |
+ proc = osGetProcAddressA((HANDLE)pH, zSym); |
+ OSTRACE(("DLSYM handle=%p, symbol=%s, address=%p\n", |
+ (void*)pH, zSym, (void*)proc)); |
+ return (void(*)(void))proc; |
+} |
+static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ |
+ UNUSED_PARAMETER(pVfs); |
+ osFreeLibrary((HANDLE)pHandle); |
+ OSTRACE(("DLCLOSE handle=%p\n", (void*)pHandle)); |
+} |
+#else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ |
+ #define winDlOpen 0 |
+ #define winDlError 0 |
+ #define winDlSym 0 |
+ #define winDlClose 0 |
+#endif |
+ |
+/* State information for the randomness gatherer. */ |
+typedef struct EntropyGatherer EntropyGatherer; |
+struct EntropyGatherer { |
+ unsigned char *a; /* Gather entropy into this buffer */ |
+ int na; /* Size of a[] in bytes */ |
+ int i; /* XOR next input into a[i] */ |
+ int nXor; /* Number of XOR operations done */ |
+}; |
+ |
+#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) |
+/* Mix sz bytes of entropy into p. */ |
+static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){ |
+ int j, k; |
+ for(j=0, k=p->i; j<sz; j++){ |
+ p->a[k++] ^= x[j]; |
+ if( k>=p->na ) k = 0; |
+ } |
+ p->i = k; |
+ p->nXor += sz; |
+} |
+#endif /* !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) */ |
+ |
+/* |
+** Write up to nBuf bytes of randomness into zBuf. |
+*/ |
+static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
+#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) |
+ UNUSED_PARAMETER(pVfs); |
+ memset(zBuf, 0, nBuf); |
+ return nBuf; |
+#else |
+ EntropyGatherer e; |
+ UNUSED_PARAMETER(pVfs); |
+ memset(zBuf, 0, nBuf); |
+#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE |
+ rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */ |
+#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */ |
+ e.a = (unsigned char*)zBuf; |
+ e.na = nBuf; |
+ e.nXor = 0; |
+ e.i = 0; |
+ { |
+ SYSTEMTIME x; |
+ osGetSystemTime(&x); |
+ xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME)); |
+ } |
+ { |
+ DWORD pid = osGetCurrentProcessId(); |
+ xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD)); |
+ } |
+#if SQLITE_OS_WINRT |
+ { |
+ ULONGLONG cnt = osGetTickCount64(); |
+ xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG)); |
+ } |
+#else |
+ { |
+ DWORD cnt = osGetTickCount(); |
+ xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD)); |
+ } |
+#endif /* SQLITE_OS_WINRT */ |
+ { |
+ LARGE_INTEGER i; |
+ osQueryPerformanceCounter(&i); |
+ xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER)); |
+ } |
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID |
+ { |
+ UUID id; |
+ memset(&id, 0, sizeof(UUID)); |
+ osUuidCreate(&id); |
+ xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); |
+ memset(&id, 0, sizeof(UUID)); |
+ osUuidCreateSequential(&id); |
+ xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); |
+ } |
+#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */ |
+ return e.nXor>nBuf ? nBuf : e.nXor; |
+#endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */ |
+} |
+ |
+ |
+/* |
+** Sleep for a little while. Return the amount of time slept. |
+*/ |
+static int winSleep(sqlite3_vfs *pVfs, int microsec){ |
+ sqlite3_win32_sleep((microsec+999)/1000); |
+ UNUSED_PARAMETER(pVfs); |
+ return ((microsec+999)/1000)*1000; |
+} |
+ |
+/* |
+** The following variable, if set to a non-zero value, is interpreted as |
+** the number of seconds since 1970 and is used to set the result of |
+** sqlite3OsCurrentTime() during testing. |
+*/ |
+#ifdef SQLITE_TEST |
+SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */ |
+#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 SQLITE_OK. Return SQLITE_ERROR if the time and date |
+** cannot be found. |
+*/ |
+static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ |
+ /* FILETIME structure is a 64-bit value representing the number of |
+ 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). |
+ */ |
+ FILETIME ft; |
+ static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000; |
+#ifdef SQLITE_TEST |
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; |
+#endif |
+ /* 2^32 - to avoid use of LL and warnings in gcc */ |
+ static const sqlite3_int64 max32BitValue = |
+ (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + |
+ (sqlite3_int64)294967296; |
+ |
+#if SQLITE_OS_WINCE |
+ SYSTEMTIME time; |
+ osGetSystemTime(&time); |
+ /* if SystemTimeToFileTime() fails, it returns zero. */ |
+ if (!osSystemTimeToFileTime(&time,&ft)){ |
+ return SQLITE_ERROR; |
+ } |
+#else |
+ osGetSystemTimeAsFileTime( &ft ); |
+#endif |
+ |
+ *piNow = winFiletimeEpoch + |
+ ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + |
+ (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000; |
+ |
+#ifdef SQLITE_TEST |
+ if( sqlite3_current_time ){ |
+ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; |
+ } |
+#endif |
+ UNUSED_PARAMETER(pVfs); |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** 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 winCurrentTime(sqlite3_vfs *pVfs, double *prNow){ |
+ int rc; |
+ sqlite3_int64 i; |
+ rc = winCurrentTimeInt64(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 winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
+ DWORD e = osGetLastError(); |
+ UNUSED_PARAMETER(pVfs); |
+ if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf); |
+ return e; |
+} |
+ |
+/* |
+** Initialize and deinitialize the operating system interface. |
+*/ |
+SQLITE_API int sqlite3_os_init(void){ |
+ static sqlite3_vfs winVfs = { |
+ 3, /* iVersion */ |
+ sizeof(winFile), /* szOsFile */ |
+ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ |
+ 0, /* pNext */ |
+ "win32", /* zName */ |
+ &winAppData, /* pAppData */ |
+ winOpen, /* xOpen */ |
+ winDelete, /* xDelete */ |
+ winAccess, /* xAccess */ |
+ winFullPathname, /* xFullPathname */ |
+ winDlOpen, /* xDlOpen */ |
+ winDlError, /* xDlError */ |
+ winDlSym, /* xDlSym */ |
+ winDlClose, /* xDlClose */ |
+ winRandomness, /* xRandomness */ |
+ winSleep, /* xSleep */ |
+ winCurrentTime, /* xCurrentTime */ |
+ winGetLastError, /* xGetLastError */ |
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */ |
+ winSetSystemCall, /* xSetSystemCall */ |
+ winGetSystemCall, /* xGetSystemCall */ |
+ winNextSystemCall, /* xNextSystemCall */ |
+ }; |
+#if defined(SQLITE_WIN32_HAS_WIDE) |
+ static sqlite3_vfs winLongPathVfs = { |
+ 3, /* iVersion */ |
+ sizeof(winFile), /* szOsFile */ |
+ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ |
+ 0, /* pNext */ |
+ "win32-longpath", /* zName */ |
+ &winAppData, /* pAppData */ |
+ winOpen, /* xOpen */ |
+ winDelete, /* xDelete */ |
+ winAccess, /* xAccess */ |
+ winFullPathname, /* xFullPathname */ |
+ winDlOpen, /* xDlOpen */ |
+ winDlError, /* xDlError */ |
+ winDlSym, /* xDlSym */ |
+ winDlClose, /* xDlClose */ |
+ winRandomness, /* xRandomness */ |
+ winSleep, /* xSleep */ |
+ winCurrentTime, /* xCurrentTime */ |
+ winGetLastError, /* xGetLastError */ |
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */ |
+ winSetSystemCall, /* xSetSystemCall */ |
+ winGetSystemCall, /* xGetSystemCall */ |
+ winNextSystemCall, /* xNextSystemCall */ |
+ }; |
+#endif |
+ static sqlite3_vfs winNolockVfs = { |
+ 3, /* iVersion */ |
+ sizeof(winFile), /* szOsFile */ |
+ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ |
+ 0, /* pNext */ |
+ "win32-none", /* zName */ |
+ &winNolockAppData, /* pAppData */ |
+ winOpen, /* xOpen */ |
+ winDelete, /* xDelete */ |
+ winAccess, /* xAccess */ |
+ winFullPathname, /* xFullPathname */ |
+ winDlOpen, /* xDlOpen */ |
+ winDlError, /* xDlError */ |
+ winDlSym, /* xDlSym */ |
+ winDlClose, /* xDlClose */ |
+ winRandomness, /* xRandomness */ |
+ winSleep, /* xSleep */ |
+ winCurrentTime, /* xCurrentTime */ |
+ winGetLastError, /* xGetLastError */ |
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */ |
+ winSetSystemCall, /* xSetSystemCall */ |
+ winGetSystemCall, /* xGetSystemCall */ |
+ winNextSystemCall, /* xNextSystemCall */ |
+ }; |
+#if defined(SQLITE_WIN32_HAS_WIDE) |
+ static sqlite3_vfs winLongPathNolockVfs = { |
+ 3, /* iVersion */ |
+ sizeof(winFile), /* szOsFile */ |
+ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ |
+ 0, /* pNext */ |
+ "win32-longpath-none", /* zName */ |
+ &winNolockAppData, /* pAppData */ |
+ winOpen, /* xOpen */ |
+ winDelete, /* xDelete */ |
+ winAccess, /* xAccess */ |
+ winFullPathname, /* xFullPathname */ |
+ winDlOpen, /* xDlOpen */ |
+ winDlError, /* xDlError */ |
+ winDlSym, /* xDlSym */ |
+ winDlClose, /* xDlClose */ |
+ winRandomness, /* xRandomness */ |
+ winSleep, /* xSleep */ |
+ winCurrentTime, /* xCurrentTime */ |
+ winGetLastError, /* xGetLastError */ |
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */ |
+ winSetSystemCall, /* xSetSystemCall */ |
+ winGetSystemCall, /* xGetSystemCall */ |
+ winNextSystemCall, /* xNextSystemCall */ |
+ }; |
+#endif |
+ |
+ /* Double-check that the aSyscall[] array has been constructed |
+ ** correctly. See ticket [bb3a86e890c8e96ab] */ |
+ assert( ArraySize(aSyscall)==80 ); |
+ |
+ /* get memory map allocation granularity */ |
+ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); |
+#if SQLITE_OS_WINRT |
+ osGetNativeSystemInfo(&winSysInfo); |
+#else |
+ osGetSystemInfo(&winSysInfo); |
+#endif |
+ assert( winSysInfo.dwAllocationGranularity>0 ); |
+ assert( winSysInfo.dwPageSize>0 ); |
+ |
+ sqlite3_vfs_register(&winVfs, 1); |
+ |
+#if defined(SQLITE_WIN32_HAS_WIDE) |
+ sqlite3_vfs_register(&winLongPathVfs, 0); |
+#endif |
+ |
+ sqlite3_vfs_register(&winNolockVfs, 0); |
+ |
+#if defined(SQLITE_WIN32_HAS_WIDE) |
+ sqlite3_vfs_register(&winLongPathNolockVfs, 0); |
+#endif |
+ |
+ return SQLITE_OK; |
+} |
+ |
+SQLITE_API int sqlite3_os_end(void){ |
+#if SQLITE_OS_WINRT |
+ if( sleepObj!=NULL ){ |
+ osCloseHandle(sleepObj); |
+ sleepObj = NULL; |
+ } |
+#endif |
+ return SQLITE_OK; |
+} |
+ |
+CHROMIUM_SQLITE_API |
+void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle) { |
+ winFile* winSQLite3File = (winFile*)file; |
+ memset(file, 0, sizeof(*file)); |
+ winSQLite3File->pMethod = &winIoMethod; |
+ winSQLite3File->h = handle; |
+} |
+ |
+#endif /* SQLITE_OS_WIN */ |
+ |
+/************** End of os_win.c **********************************************/ |
+/************** Begin file bitvec.c ******************************************/ |
+/* |
+** 2008 February 16 |
+** |
+** The author disclaims copyright to this source code. In place of |
+** a legal notice, here is a blessing: |
+** |
+** May you do good and not evil. |
+** May you find forgiveness for yourself and forgive others. |
+** May you share freely, never taking more than you give. |
+** |
+************************************************************************* |
+** This file implements an object that represents a fixed-length |
+** bitmap. Bits are numbered starting with 1. |
+** |
+** A bitmap is used to record which pages of a database file have been |
+** journalled during a transaction, or which pages have the "dont-write" |
+** property. Usually only a few pages are meet either condition. |
+** So the bitmap is usually sparse and has low cardinality. |
+** But sometimes (for example when during a DROP of a large table) most |
+** or all of the pages in a database can get journalled. In those cases, |
+** the bitmap becomes dense with high cardinality. The algorithm needs |
+** to handle both cases well. |
+** |
+** The size of the bitmap is fixed when the object is created. |
+** |
+** All bits are clear when the bitmap is created. Individual bits |
+** may be set or cleared one at a time. |
+** |
+** Test operations are about 100 times more common that set operations. |
+** Clear operations are exceedingly rare. There are usually between |
+** 5 and 500 set operations per Bitvec object, though the number of sets can |
+** sometimes grow into tens of thousands or larger. The size of the |
+** Bitvec object is the number of pages in the database file at the |
+** start of a transaction, and is thus usually less than a few thousand, |
+** but can be as large as 2 billion for a really big database. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* Size of the Bitvec structure in bytes. */ |
+#define BITVEC_SZ 512 |
+ |
+/* Round the union size down to the nearest pointer boundary, since that's how |
+** it will be aligned within the Bitvec struct. */ |
+#define BITVEC_USIZE \ |
+ (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*)) |
+ |
+/* Type of the array "element" for the bitmap representation. |
+** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE. |
+** Setting this to the "natural word" size of your CPU may improve |
+** performance. */ |
+#define BITVEC_TELEM u8 |
+/* Size, in bits, of the bitmap element. */ |
+#define BITVEC_SZELEM 8 |
+/* Number of elements in a bitmap array. */ |
+#define BITVEC_NELEM (BITVEC_USIZE/sizeof(BITVEC_TELEM)) |
+/* Number of bits in the bitmap array. */ |
+#define BITVEC_NBIT (BITVEC_NELEM*BITVEC_SZELEM) |
+ |
+/* Number of u32 values in hash table. */ |
+#define BITVEC_NINT (BITVEC_USIZE/sizeof(u32)) |
+/* Maximum number of entries in hash table before |
+** sub-dividing and re-hashing. */ |
+#define BITVEC_MXHASH (BITVEC_NINT/2) |
+/* Hashing function for the aHash representation. |
+** Empirical testing showed that the *37 multiplier |
+** (an arbitrary prime)in the hash function provided |
+** no fewer collisions than the no-op *1. */ |
+#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT) |
+ |
+#define BITVEC_NPTR (BITVEC_USIZE/sizeof(Bitvec *)) |
+ |
+ |
+/* |
+** A bitmap is an instance of the following structure. |
+** |
+** This bitmap records the existence of zero or more bits |
+** with values between 1 and iSize, inclusive. |
+** |
+** There are three possible representations of the bitmap. |
+** If iSize<=BITVEC_NBIT, then Bitvec.u.aBitmap[] is a straight |
+** bitmap. The least significant bit is bit 1. |
+** |
+** If iSize>BITVEC_NBIT and iDivisor==0 then Bitvec.u.aHash[] is |
+** a hash table that will hold up to BITVEC_MXHASH distinct values. |
+** |
+** Otherwise, the value i is redirected into one of BITVEC_NPTR |
+** sub-bitmaps pointed to by Bitvec.u.apSub[]. Each subbitmap |
+** handles up to iDivisor separate values of i. apSub[0] holds |
+** values between 1 and iDivisor. apSub[1] holds values between |
+** iDivisor+1 and 2*iDivisor. apSub[N] holds values between |
+** N*iDivisor+1 and (N+1)*iDivisor. Each subbitmap is normalized |
+** to hold deal with values between 1 and iDivisor. |
+*/ |
+struct Bitvec { |
+ u32 iSize; /* Maximum bit index. Max iSize is 4,294,967,296. */ |
+ u32 nSet; /* Number of bits that are set - only valid for aHash |
+ ** element. Max is BITVEC_NINT. For BITVEC_SZ of 512, |
+ ** this would be 125. */ |
+ u32 iDivisor; /* Number of bits handled by each apSub[] entry. */ |
+ /* Should >=0 for apSub element. */ |
+ /* Max iDivisor is max(u32) / BITVEC_NPTR + 1. */ |
+ /* For a BITVEC_SZ of 512, this would be 34,359,739. */ |
+ union { |
+ BITVEC_TELEM aBitmap[BITVEC_NELEM]; /* Bitmap representation */ |
+ u32 aHash[BITVEC_NINT]; /* Hash table representation */ |
+ Bitvec *apSub[BITVEC_NPTR]; /* Recursive representation */ |
+ } u; |
+}; |
+ |
+/* |
+** Create a new bitmap object able to handle bits between 0 and iSize, |
+** inclusive. Return a pointer to the new object. Return NULL if |
+** malloc fails. |
+*/ |
+SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){ |
+ Bitvec *p; |
+ assert( sizeof(*p)==BITVEC_SZ ); |
+ p = sqlite3MallocZero( sizeof(*p) ); |
+ if( p ){ |
+ p->iSize = iSize; |
+ } |
+ return p; |
+} |
+ |
+/* |
+** Check to see if the i-th bit is set. Return true or false. |
+** If p is NULL (if the bitmap has not been created) or if |
+** i is out of range, then return false. |
+*/ |
+SQLITE_PRIVATE int sqlite3BitvecTestNotNull(Bitvec *p, u32 i){ |
+ assert( p!=0 ); |
+ i--; |
+ if( i>=p->iSize ) return 0; |
+ while( p->iDivisor ){ |
+ u32 bin = i/p->iDivisor; |
+ i = i%p->iDivisor; |
+ p = p->u.apSub[bin]; |
+ if (!p) { |
+ return 0; |
+ } |
+ } |
+ if( p->iSize<=BITVEC_NBIT ){ |
+ return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0; |
+ } else{ |
+ u32 h = BITVEC_HASH(i++); |
+ while( p->u.aHash[h] ){ |
+ if( p->u.aHash[h]==i ) return 1; |
+ h = (h+1) % BITVEC_NINT; |
+ } |
+ return 0; |
+ } |
+} |
+SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){ |
+ return p!=0 && sqlite3BitvecTestNotNull(p,i); |
+} |
+ |
+/* |
+** Set the i-th bit. Return 0 on success and an error code if |
+** anything goes wrong. |
+** |
+** This routine might cause sub-bitmaps to be allocated. Failing |
+** to get the memory needed to hold the sub-bitmap is the only |
+** that can go wrong with an insert, assuming p and i are valid. |
+** |
+** The calling function must ensure that p is a valid Bitvec object |
+** and that the value for "i" is within range of the Bitvec object. |
+** Otherwise the behavior is undefined. |
+*/ |
+SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){ |
+ u32 h; |
+ if( p==0 ) return SQLITE_OK; |
+ assert( i>0 ); |
+ assert( i<=p->iSize ); |
+ i--; |
+ while((p->iSize > BITVEC_NBIT) && p->iDivisor) { |
+ u32 bin = i/p->iDivisor; |
+ i = i%p->iDivisor; |
+ if( p->u.apSub[bin]==0 ){ |
+ p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor ); |
+ if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT; |
+ } |
+ p = p->u.apSub[bin]; |
+ } |
+ if( p->iSize<=BITVEC_NBIT ){ |
+ p->u.aBitmap[i/BITVEC_SZELEM] |= 1 << (i&(BITVEC_SZELEM-1)); |
+ return SQLITE_OK; |
+ } |
+ h = BITVEC_HASH(i++); |
+ /* if there wasn't a hash collision, and this doesn't */ |
+ /* completely fill the hash, then just add it without */ |
+ /* worring about sub-dividing and re-hashing. */ |
+ if( !p->u.aHash[h] ){ |
+ if (p->nSet<(BITVEC_NINT-1)) { |
+ goto bitvec_set_end; |
+ } else { |
+ goto bitvec_set_rehash; |
+ } |
+ } |
+ /* there was a collision, check to see if it's already */ |
+ /* in hash, if not, try to find a spot for it */ |
+ do { |
+ if( p->u.aHash[h]==i ) return SQLITE_OK; |
+ h++; |
+ if( h>=BITVEC_NINT ) h = 0; |
+ } while( p->u.aHash[h] ); |
+ /* we didn't find it in the hash. h points to the first */ |
+ /* available free spot. check to see if this is going to */ |
+ /* make our hash too "full". */ |
+bitvec_set_rehash: |
+ if( p->nSet>=BITVEC_MXHASH ){ |
+ unsigned int j; |
+ int rc; |
+ u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash)); |
+ if( aiValues==0 ){ |
+ return SQLITE_NOMEM_BKPT; |
+ }else{ |
+ memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); |
+ memset(p->u.apSub, 0, sizeof(p->u.apSub)); |
+ p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR; |
+ rc = sqlite3BitvecSet(p, i); |
+ for(j=0; j<BITVEC_NINT; j++){ |
+ if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]); |
+ } |
+ sqlite3StackFree(0, aiValues); |
+ return rc; |
+ } |
+ } |
+bitvec_set_end: |
+ p->nSet++; |
+ p->u.aHash[h] = i; |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Clear the i-th bit. |
+** |
+** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage |
+** that BitvecClear can use to rebuilt its hash table. |
+*/ |
+SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){ |
+ if( p==0 ) return; |
+ assert( i>0 ); |
+ i--; |
+ while( p->iDivisor ){ |
+ u32 bin = i/p->iDivisor; |
+ i = i%p->iDivisor; |
+ p = p->u.apSub[bin]; |
+ if (!p) { |
+ return; |
+ } |
+ } |
+ if( p->iSize<=BITVEC_NBIT ){ |
+ p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1))); |
+ }else{ |
+ unsigned int j; |
+ u32 *aiValues = pBuf; |
+ memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); |
+ memset(p->u.aHash, 0, sizeof(p->u.aHash)); |
+ p->nSet = 0; |
+ for(j=0; j<BITVEC_NINT; j++){ |
+ if( aiValues[j] && aiValues[j]!=(i+1) ){ |
+ u32 h = BITVEC_HASH(aiValues[j]-1); |
+ p->nSet++; |
+ while( p->u.aHash[h] ){ |
+ h++; |
+ if( h>=BITVEC_NINT ) h = 0; |
+ } |
+ p->u.aHash[h] = aiValues[j]; |
+ } |
+ } |
+ } |
+} |
+ |
+/* |
+** Destroy a bitmap object. Reclaim all memory used. |
+*/ |
+SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec *p){ |
+ if( p==0 ) return; |
+ if( p->iDivisor ){ |
+ unsigned int i; |
+ for(i=0; i<BITVEC_NPTR; i++){ |
+ sqlite3BitvecDestroy(p->u.apSub[i]); |
+ } |
+ } |
+ sqlite3_free(p); |
+} |
+ |
+/* |
+** Return the value of the iSize parameter specified when Bitvec *p |
+** was created. |
+*/ |
+SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){ |
+ return p->iSize; |
+} |
+ |
+#ifndef SQLITE_UNTESTABLE |
+/* |
+** Let V[] be an array of unsigned characters sufficient to hold |
+** up to N bits. Let I be an integer between 0 and N. 0<=I<N. |
+** Then the following macros can be used to set, clear, or test |
+** individual bits within V. |
+*/ |
+#define SETBIT(V,I) V[I>>3] |= (1<<(I&7)) |
+#define CLEARBIT(V,I) V[I>>3] &= ~(1<<(I&7)) |
+#define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0 |
+ |
+/* |
+** This routine runs an extensive test of the Bitvec code. |
+** |
+** The input is an array of integers that acts as a program |
+** to test the Bitvec. The integers are opcodes followed |
+** by 0, 1, or 3 operands, depending on the opcode. Another |
+** opcode follows immediately after the last operand. |
+** |
+** There are 6 opcodes numbered from 0 through 5. 0 is the |
+** "halt" opcode and causes the test to end. |
+** |
+** 0 Halt and return the number of errors |
+** 1 N S X Set N bits beginning with S and incrementing by X |
+** 2 N S X Clear N bits beginning with S and incrementing by X |
+** 3 N Set N randomly chosen bits |
+** 4 N Clear N randomly chosen bits |
+** 5 N S X Set N bits from S increment X in array only, not in bitvec |
+** |
+** The opcodes 1 through 4 perform set and clear operations are performed |
+** on both a Bitvec object and on a linear array of bits obtained from malloc. |
+** Opcode 5 works on the linear array only, not on the Bitvec. |
+** Opcode 5 is used to deliberately induce a fault in order to |
+** confirm that error detection works. |
+** |
+** At the conclusion of the test the linear array is compared |
+** against the Bitvec object. If there are any differences, |
+** an error is returned. If they are the same, zero is returned. |
+** |
+** If a memory allocation error occurs, return -1. |
+*/ |
+SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){ |
+ Bitvec *pBitvec = 0; |
+ unsigned char *pV = 0; |
+ int rc = -1; |
+ int i, nx, pc, op; |
+ void *pTmpSpace; |
+ |
+ /* Allocate the Bitvec to be tested and a linear array of |
+ ** bits to act as the reference */ |
+ pBitvec = sqlite3BitvecCreate( sz ); |
+ pV = sqlite3MallocZero( (sz+7)/8 + 1 ); |
+ pTmpSpace = sqlite3_malloc64(BITVEC_SZ); |
+ if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; |
+ |
+ /* NULL pBitvec tests */ |
+ sqlite3BitvecSet(0, 1); |
+ sqlite3BitvecClear(0, 1, pTmpSpace); |
+ |
+ /* Run the program */ |
+ pc = 0; |
+ while( (op = aOp[pc])!=0 ){ |
+ switch( op ){ |
+ case 1: |
+ case 2: |
+ case 5: { |
+ nx = 4; |
+ i = aOp[pc+2] - 1; |
+ aOp[pc+2] += aOp[pc+3]; |
+ break; |
+ } |
+ case 3: |
+ case 4: |
+ default: { |
+ nx = 2; |
+ sqlite3_randomness(sizeof(i), &i); |
+ break; |
+ } |
+ } |
+ if( (--aOp[pc+1]) > 0 ) nx = 0; |
+ pc += nx; |
+ i = (i & 0x7fffffff)%sz; |
+ if( (op & 1)!=0 ){ |
+ SETBIT(pV, (i+1)); |
+ if( op!=5 ){ |
+ if( sqlite3BitvecSet(pBitvec, i+1) ) goto bitvec_end; |
+ } |
+ }else{ |
+ CLEARBIT(pV, (i+1)); |
+ sqlite3BitvecClear(pBitvec, i+1, pTmpSpace); |
+ } |
+ } |
+ |
+ /* Test to make sure the linear array exactly matches the |
+ ** Bitvec object. Start with the assumption that they do |
+ ** match (rc==0). Change rc to non-zero if a discrepancy |
+ ** is found. |
+ */ |
+ rc = sqlite3BitvecTest(0,0) + sqlite3BitvecTest(pBitvec, sz+1) |
+ + sqlite3BitvecTest(pBitvec, 0) |
+ + (sqlite3BitvecSize(pBitvec) - sz); |
+ for(i=1; i<=sz; i++){ |
+ if( (TESTBIT(pV,i))!=sqlite3BitvecTest(pBitvec,i) ){ |
+ rc = i; |
+ break; |
+ } |
+ } |
+ |
+ /* Free allocated structure */ |
+bitvec_end: |
+ sqlite3_free(pTmpSpace); |
+ sqlite3_free(pV); |
+ sqlite3BitvecDestroy(pBitvec); |
+ return rc; |
+} |
+#endif /* SQLITE_UNTESTABLE */ |
+ |
+/************** End of bitvec.c **********************************************/ |
+/************** Begin file pcache.c ******************************************/ |
+/* |
+** 2008 August 05 |
+** |
+** 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 that page cache. |
+*/ |
+/* #include "sqliteInt.h" */ |
+ |
+/* |
+** A complete page cache is an instance of this structure. Every |
+** entry in the cache holds a single page of the database file. The |
+** btree layer only operates on the cached copy of the database pages. |
+** |
+** A page cache entry is "clean" if it exactly matches what is currently |
+** on disk. A page is "dirty" if it has been modified and needs to be |
+** persisted to disk. |
+** |
+** pDirty, pDirtyTail, pSynced: |
+** All dirty pages are linked into the doubly linked list using |
+** PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order |
+** such that p was added to the list more recently than p->pDirtyNext. |
+** PCache.pDirty points to the first (newest) element in the list and |
+** pDirtyTail to the last (oldest). |
+** |
+** The PCache.pSynced variable is used to optimize searching for a dirty |
+** page to eject from the cache mid-transaction. It is better to eject |
+** a page that does not require a journal sync than one that does. |
+** Therefore, pSynced is maintained to that it *almost* always points |
+** to either the oldest page in the pDirty/pDirtyTail list that has a |
+** clear PGHDR_NEED_SYNC flag or to a page that is older than this one |
+** (so that the right page to eject can be found by following pDirtyPrev |
+** pointers). |
+*/ |
+struct PCache { |
+ PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ |
+ PgHdr *pSynced; /* Last synced page in dirty page list */ |
+ int nRefSum; /* Sum of ref counts over all pages */ |
+ int szCache; /* Configured cache size */ |
+ int szSpill; /* Size before spilling occurs */ |
+ int szPage; /* Size of every page in this cache */ |
+ int szExtra; /* Size of extra space for each page */ |
+ u8 bPurgeable; /* True if pages are on backing store */ |
+ u8 eCreate; /* eCreate value for for xFetch() */ |
+ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ |
+ void *pStress; /* Argument to xStress */ |
+ sqlite3_pcache *pCache; /* Pluggable cache module */ |
+}; |
+ |
+/********************************** Test and Debug Logic **********************/ |
+/* |
+** Debug tracing macros. Enable by by changing the "0" to "1" and |
+** recompiling. |
+** |
+** When sqlite3PcacheTrace is 1, single line trace messages are issued. |
+** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries |
+** is displayed for many operations, resulting in a lot of output. |
+*/ |
+#if defined(SQLITE_DEBUG) && 0 |
+ int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ |
+ int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ |
+# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;} |
+ void pcacheDump(PCache *pCache){ |
+ int N; |
+ int i, j; |
+ sqlite3_pcache_page *pLower; |
+ PgHdr *pPg; |
+ unsigned char *a; |
+ |
+ if( sqlite3PcacheTrace<2 ) return; |
+ if( pCache->pCache==0 ) return; |
+ N = sqlite3PcachePagecount(pCache); |
+ if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump; |
+ for(i=1; i<=N; i++){ |
+ pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0); |
+ if( pLower==0 ) continue; |
+ pPg = (PgHdr*)pLower->pExtra; |
+ printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags); |
+ a = (unsigned char *)pLower->pBuf; |
+ for(j=0; j<12; j++) printf("%02x", a[j]); |
+ printf("\n"); |
+ if( pPg->pPage==0 ){ |
+ sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0); |
+ } |
+ } |
+ } |
+ #else |
+# define pcacheTrace(X) |
+# define pcacheDump(X) |
+#endif |
+ |
+/* |
+** Check invariants on a PgHdr entry. Return true if everything is OK. |
+** Return false if any invariant is violated. |
+** |
+** This routine is for use inside of assert() statements only. For |
+** example: |
+** |
+** assert( sqlite3PcachePageSanity(pPg) ); |
+*/ |
+#if SQLITE_DEBUG |
+SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){ |
+ PCache *pCache; |
+ assert( pPg!=0 ); |
+ assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */ |
+ pCache = pPg->pCache; |
+ assert( pCache!=0 ); /* Every page has an associated PCache */ |
+ if( pPg->flags & PGHDR_CLEAN ){ |
+ assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */ |
+ assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */ |
+ assert( pCache->pDirtyTail!=pPg ); |
+ } |
+ /* WRITEABLE pages must also be DIRTY */ |
+ if( pPg->flags & PGHDR_WRITEABLE ){ |
+ assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */ |
+ } |
+ /* NEED_SYNC can be set independently of WRITEABLE. This can happen, |
+ ** for example, when using the sqlite3PagerDontWrite() optimization: |
+ ** (1) Page X is journalled, and gets WRITEABLE and NEED_SEEK. |
+ ** (2) Page X moved to freelist, WRITEABLE is cleared |
+ ** (3) Page X reused, WRITEABLE is set again |
+ ** If NEED_SYNC had been cleared in step 2, then it would not be reset |
+ ** in step 3, and page might be written into the database without first |
+ ** syncing the rollback journal, which might cause corruption on a power |
+ ** loss. |
+ ** |
+ ** Another example is when the database page size is smaller than the |
+ ** disk sector size. When any page of a sector is journalled, all pages |
+ ** in that sector are marked NEED_SYNC even if they are still CLEAN, just |
+ ** in case they are later modified, since all pages in the same sector |
+ ** must be journalled and synced before any of those pages can be safely |
+ ** written. |
+ */ |
+ return 1; |
+} |
+#endif /* SQLITE_DEBUG */ |
+ |
+ |
+/********************************** Linked List Management ********************/ |
+ |
+/* Allowed values for second argument to pcacheManageDirtyList() */ |
+#define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */ |
+#define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */ |
+#define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */ |
+ |
+/* |
+** Manage pPage's participation on the dirty list. Bits of the addRemove |
+** argument determines what operation to do. The 0x01 bit means first |
+** remove pPage from the dirty list. The 0x02 means add pPage back to |
+** the dirty list. Doing both moves pPage to the front of the dirty list. |
+*/ |
+static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ |
+ PCache *p = pPage->pCache; |
+ |
+ pcacheTrace(("%p.DIRTYLIST.%s %d\n", p, |
+ addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT", |
+ pPage->pgno)); |
+ if( addRemove & PCACHE_DIRTYLIST_REMOVE ){ |
+ assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); |
+ assert( pPage->pDirtyPrev || pPage==p->pDirty ); |
+ |
+ /* Update the PCache1.pSynced variable if necessary. */ |
+ if( p->pSynced==pPage ){ |
+ p->pSynced = pPage->pDirtyPrev; |
+ } |
+ |
+ if( pPage->pDirtyNext ){ |
+ pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; |
+ }else{ |
+ assert( pPage==p->pDirtyTail ); |
+ p->pDirtyTail = pPage->pDirtyPrev; |
+ } |
+ if( pPage->pDirtyPrev ){ |
+ pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; |
+ }else{ |
+ /* If there are now no dirty pages in the cache, set eCreate to 2. |
+ ** This is an optimization that allows sqlite3PcacheFetch() to skip |
+ ** searching for a dirty page to eject from the cache when it might |
+ ** otherwise have to. */ |
+ assert( pPage==p->pDirty ); |
+ p->pDirty = pPage->pDirtyNext; |
+ assert( p->bPurgeable || p->eCreate==2 ); |
+ if( p->pDirty==0 ){ /*OPTIMIZATION-IF-TRUE*/ |
+ assert( p->bPurgeable==0 || p->eCreate==1 ); |
+ p->eCreate = 2; |
+ } |
+ } |
+ pPage->pDirtyNext = 0; |
+ pPage->pDirtyPrev = 0; |
+ } |
+ if( addRemove & PCACHE_DIRTYLIST_ADD ){ |
+ assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage ); |
+ |
+ pPage->pDirtyNext = p->pDirty; |
+ if( pPage->pDirtyNext ){ |
+ assert( pPage->pDirtyNext->pDirtyPrev==0 ); |
+ pPage->pDirtyNext->pDirtyPrev = pPage; |
+ }else{ |
+ p->pDirtyTail = pPage; |
+ if( p->bPurgeable ){ |
+ assert( p->eCreate==2 ); |
+ p->eCreate = 1; |
+ } |
+ } |
+ p->pDirty = pPage; |
+ |
+ /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set |
+ ** pSynced to point to it. Checking the NEED_SYNC flag is an |
+ ** optimization, as if pSynced points to a page with the NEED_SYNC |
+ ** flag set sqlite3PcacheFetchStress() searches through all newer |
+ ** entries of the dirty-list for a page with NEED_SYNC clear anyway. */ |
+ if( !p->pSynced |
+ && 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/ |
+ ){ |
+ p->pSynced = pPage; |
+ } |
+ } |
+ pcacheDump(p); |
+} |
+ |
+/* |
+** Wrapper around the pluggable caches xUnpin method. If the cache is |
+** being used for an in-memory database, this function is a no-op. |
+*/ |
+static void pcacheUnpin(PgHdr *p){ |
+ if( p->pCache->bPurgeable ){ |
+ pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno)); |
+ sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); |
+ pcacheDump(p->pCache); |
+ } |
+} |
+ |
+/* |
+** Compute the number of pages of cache requested. p->szCache is the |
+** cache size requested by the "PRAGMA cache_size" statement. |
+*/ |
+static int numberOfCachePages(PCache *p){ |
+ if( p->szCache>=0 ){ |
+ /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the |
+ ** suggested cache size is set to N. */ |
+ return p->szCache; |
+ }else{ |
+ /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then |
+ ** the number of cache pages is adjusted to use approximately abs(N*1024) |
+ ** bytes of memory. */ |
+ return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); |
+ } |
+} |
+ |
+/*************************************************** General Interfaces ****** |
+** |
+** Initialize and shutdown the page cache subsystem. Neither of these |
+** functions are threadsafe. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcacheInitialize(void){ |
+ if( sqlite3GlobalConfig.pcache2.xInit==0 ){ |
+ /* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the |
+ ** built-in default page cache is used instead of the application defined |
+ ** page cache. */ |
+ sqlite3PCacheSetDefault(); |
+ } |
+ return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg); |
+} |
+SQLITE_PRIVATE void sqlite3PcacheShutdown(void){ |
+ if( sqlite3GlobalConfig.pcache2.xShutdown ){ |
+ /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */ |
+ sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg); |
+ } |
+} |
+ |
+/* |
+** Return the size in bytes of a PCache object. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); } |
+ |
+/* |
+** Create a new PCache object. Storage space to hold the object |
+** has already been allocated and is passed in as the p pointer. |
+** The caller discovers how much space needs to be allocated by |
+** calling sqlite3PcacheSize(). |
+** |
+** szExtra is some extra space allocated for each page. The first |
+** 8 bytes of the extra space will be zeroed as the page is allocated, |
+** but remaining content will be uninitialized. Though it is opaque |
+** to this module, the extra space really ends up being the MemPage |
+** structure in the pager. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcacheOpen( |
+ int szPage, /* Size of every page */ |
+ int szExtra, /* Extra space associated with each page */ |
+ int bPurgeable, /* True if pages are on backing store */ |
+ int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */ |
+ void *pStress, /* Argument to xStress */ |
+ PCache *p /* Preallocated space for the PCache */ |
+){ |
+ memset(p, 0, sizeof(PCache)); |
+ p->szPage = 1; |
+ p->szExtra = szExtra; |
+ assert( szExtra>=8 ); /* First 8 bytes will be zeroed */ |
+ p->bPurgeable = bPurgeable; |
+ p->eCreate = 2; |
+ p->xStress = xStress; |
+ p->pStress = pStress; |
+ p->szCache = 100; |
+ p->szSpill = 1; |
+ pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable)); |
+ return sqlite3PcacheSetPageSize(p, szPage); |
+} |
+ |
+/* |
+** Change the page size for PCache object. The caller must ensure that there |
+** are no outstanding page references when this function is called. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){ |
+ assert( pCache->nRefSum==0 && pCache->pDirty==0 ); |
+ if( pCache->szPage ){ |
+ sqlite3_pcache *pNew; |
+ pNew = sqlite3GlobalConfig.pcache2.xCreate( |
+ szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)), |
+ pCache->bPurgeable |
+ ); |
+ if( pNew==0 ) return SQLITE_NOMEM_BKPT; |
+ sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache)); |
+ if( pCache->pCache ){ |
+ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); |
+ } |
+ pCache->pCache = pNew; |
+ pCache->szPage = szPage; |
+ pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage)); |
+ } |
+ return SQLITE_OK; |
+} |
+ |
+/* |
+** Try to obtain a page from the cache. |
+** |
+** This routine returns a pointer to an sqlite3_pcache_page object if |
+** such an object is already in cache, or if a new one is created. |
+** This routine returns a NULL pointer if the object was not in cache |
+** and could not be created. |
+** |
+** The createFlags should be 0 to check for existing pages and should |
+** be 3 (not 1, but 3) to try to create a new page. |
+** |
+** If the createFlag is 0, then NULL is always returned if the page |
+** is not already in the cache. If createFlag is 1, then a new page |
+** is created only if that can be done without spilling dirty pages |
+** and without exceeding the cache size limit. |
+** |
+** The caller needs to invoke sqlite3PcacheFetchFinish() to properly |
+** initialize the sqlite3_pcache_page object and convert it into a |
+** PgHdr object. The sqlite3PcacheFetch() and sqlite3PcacheFetchFinish() |
+** routines are split this way for performance reasons. When separated |
+** they can both (usually) operate without having to push values to |
+** the stack on entry and pop them back off on exit, which saves a |
+** lot of pushing and popping. |
+*/ |
+SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch( |
+ PCache *pCache, /* Obtain the page from this cache */ |
+ Pgno pgno, /* Page number to obtain */ |
+ int createFlag /* If true, create page if it does not exist already */ |
+){ |
+ int eCreate; |
+ sqlite3_pcache_page *pRes; |
+ |
+ assert( pCache!=0 ); |
+ assert( pCache->pCache!=0 ); |
+ assert( createFlag==3 || createFlag==0 ); |
+ assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) ); |
+ |
+ /* eCreate defines what to do if the page does not exist. |
+ ** 0 Do not allocate a new page. (createFlag==0) |
+ ** 1 Allocate a new page if doing so is inexpensive. |
+ ** (createFlag==1 AND bPurgeable AND pDirty) |
+ ** 2 Allocate a new page even it doing so is difficult. |
+ ** (createFlag==1 AND !(bPurgeable AND pDirty) |
+ */ |
+ eCreate = createFlag & pCache->eCreate; |
+ assert( eCreate==0 || eCreate==1 || eCreate==2 ); |
+ assert( createFlag==0 || pCache->eCreate==eCreate ); |
+ assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); |
+ pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); |
+ pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno, |
+ createFlag?" create":"",pRes)); |
+ return pRes; |
+} |
+ |
+/* |
+** If the sqlite3PcacheFetch() routine is unable to allocate a new |
+** page because no clean pages are available for reuse and the cache |
+** size limit has been reached, then this routine can be invoked to |
+** try harder to allocate a page. This routine might invoke the stress |
+** callback to spill dirty pages to the journal. It will then try to |
+** allocate the new page and will only fail to allocate a new page on |
+** an OOM error. |
+** |
+** This routine should be invoked only after sqlite3PcacheFetch() fails. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcacheFetchStress( |
+ PCache *pCache, /* Obtain the page from this cache */ |
+ Pgno pgno, /* Page number to obtain */ |
+ sqlite3_pcache_page **ppPage /* Write result here */ |
+){ |
+ PgHdr *pPg; |
+ if( pCache->eCreate==2 ) return 0; |
+ |
+ if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){ |
+ /* Find a dirty page to write-out and recycle. First try to find a |
+ ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC |
+ ** cleared), but if that is not possible settle for any other |
+ ** unreferenced dirty page. |
+ ** |
+ ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC |
+ ** flag is currently referenced, then the following may leave pSynced |
+ ** set incorrectly (pointing to other than the LRU page with NEED_SYNC |
+ ** cleared). This is Ok, as pSynced is just an optimization. */ |
+ for(pPg=pCache->pSynced; |
+ pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); |
+ pPg=pPg->pDirtyPrev |
+ ); |
+ pCache->pSynced = pPg; |
+ if( !pPg ){ |
+ for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); |
+ } |
+ if( pPg ){ |
+ int rc; |
+#ifdef SQLITE_LOG_CACHE_SPILL |
+ sqlite3_log(SQLITE_FULL, |
+ "spill page %d making room for %d - cache used: %d/%d", |
+ pPg->pgno, pgno, |
+ sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), |
+ numberOfCachePages(pCache)); |
+#endif |
+ pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno)); |
+ rc = pCache->xStress(pCache->pStress, pPg); |
+ pcacheDump(pCache); |
+ if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ |
+ return rc; |
+ } |
+ } |
+ } |
+ *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); |
+ return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; |
+} |
+ |
+/* |
+** This is a helper routine for sqlite3PcacheFetchFinish() |
+** |
+** In the uncommon case where the page being fetched has not been |
+** initialized, this routine is invoked to do the initialization. |
+** This routine is broken out into a separate function since it |
+** requires extra stack manipulation that can be avoided in the common |
+** case. |
+*/ |
+static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit( |
+ PCache *pCache, /* Obtain the page from this cache */ |
+ Pgno pgno, /* Page number obtained */ |
+ sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ |
+){ |
+ PgHdr *pPgHdr; |
+ assert( pPage!=0 ); |
+ pPgHdr = (PgHdr*)pPage->pExtra; |
+ assert( pPgHdr->pPage==0 ); |
+ memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty)); |
+ pPgHdr->pPage = pPage; |
+ pPgHdr->pData = pPage->pBuf; |
+ pPgHdr->pExtra = (void *)&pPgHdr[1]; |
+ memset(pPgHdr->pExtra, 0, 8); |
+ pPgHdr->pCache = pCache; |
+ pPgHdr->pgno = pgno; |
+ pPgHdr->flags = PGHDR_CLEAN; |
+ return sqlite3PcacheFetchFinish(pCache,pgno,pPage); |
+} |
+ |
+/* |
+** This routine converts the sqlite3_pcache_page object returned by |
+** sqlite3PcacheFetch() into an initialized PgHdr object. This routine |
+** must be called after sqlite3PcacheFetch() in order to get a usable |
+** result. |
+*/ |
+SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish( |
+ PCache *pCache, /* Obtain the page from this cache */ |
+ Pgno pgno, /* Page number obtained */ |
+ sqlite3_pcache_page *pPage /* Page obtained by prior PcacheFetch() call */ |
+){ |
+ PgHdr *pPgHdr; |
+ |
+ assert( pPage!=0 ); |
+ pPgHdr = (PgHdr *)pPage->pExtra; |
+ |
+ if( !pPgHdr->pPage ){ |
+ return pcacheFetchFinishWithInit(pCache, pgno, pPage); |
+ } |
+ pCache->nRefSum++; |
+ pPgHdr->nRef++; |
+ assert( sqlite3PcachePageSanity(pPgHdr) ); |
+ return pPgHdr; |
+} |
+ |
+/* |
+** Decrement the reference count on a page. If the page is clean and the |
+** reference count drops to 0, then it is made eligible for recycling. |
+*/ |
+SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ |
+ assert( p->nRef>0 ); |
+ p->pCache->nRefSum--; |
+ if( (--p->nRef)==0 ){ |
+ if( p->flags&PGHDR_CLEAN ){ |
+ pcacheUnpin(p); |
+ }else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/ |
+ /* Move the page to the head of the dirty list. If p->pDirtyPrev==0, |
+ ** then page p is already at the head of the dirty list and the |
+ ** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE |
+ ** tag above. */ |
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); |
+ } |
+ } |
+} |
+ |
+/* |
+** Increase the reference count of a supplied page by 1. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){ |
+ assert(p->nRef>0); |
+ assert( sqlite3PcachePageSanity(p) ); |
+ p->nRef++; |
+ p->pCache->nRefSum++; |
+} |
+ |
+/* |
+** Drop a page from the cache. There must be exactly one reference to the |
+** page. This function deletes that reference, so after it returns the |
+** page pointed to by p is invalid. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){ |
+ assert( p->nRef==1 ); |
+ assert( sqlite3PcachePageSanity(p) ); |
+ if( p->flags&PGHDR_DIRTY ){ |
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); |
+ } |
+ p->pCache->nRefSum--; |
+ sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1); |
+} |
+ |
+/* |
+** Make sure the page is marked as dirty. If it isn't dirty already, |
+** make it so. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){ |
+ assert( p->nRef>0 ); |
+ assert( sqlite3PcachePageSanity(p) ); |
+ if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/ |
+ p->flags &= ~PGHDR_DONT_WRITE; |
+ if( p->flags & PGHDR_CLEAN ){ |
+ p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN); |
+ pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno)); |
+ assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY ); |
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); |
+ } |
+ assert( sqlite3PcachePageSanity(p) ); |
+ } |
+} |
+ |
+/* |
+** Make sure the page is marked as clean. If it isn't clean already, |
+** make it so. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){ |
+ assert( sqlite3PcachePageSanity(p) ); |
+ if( ALWAYS((p->flags & PGHDR_DIRTY)!=0) ){ |
+ assert( (p->flags & PGHDR_CLEAN)==0 ); |
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); |
+ p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE); |
+ p->flags |= PGHDR_CLEAN; |
+ pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno)); |
+ assert( sqlite3PcachePageSanity(p) ); |
+ if( p->nRef==0 ){ |
+ pcacheUnpin(p); |
+ } |
+ } |
+} |
+ |
+/* |
+** Make every page in the cache clean. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){ |
+ PgHdr *p; |
+ pcacheTrace(("%p.CLEAN-ALL\n",pCache)); |
+ while( (p = pCache->pDirty)!=0 ){ |
+ sqlite3PcacheMakeClean(p); |
+ } |
+} |
+ |
+/* |
+** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache *pCache){ |
+ PgHdr *p; |
+ pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache)); |
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){ |
+ p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE); |
+ } |
+ pCache->pSynced = pCache->pDirtyTail; |
+} |
+ |
+/* |
+** Clear the PGHDR_NEED_SYNC flag from all dirty pages. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){ |
+ PgHdr *p; |
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){ |
+ p->flags &= ~PGHDR_NEED_SYNC; |
+ } |
+ pCache->pSynced = pCache->pDirtyTail; |
+} |
+ |
+/* |
+** Change the page number of page p to newPgno. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ |
+ PCache *pCache = p->pCache; |
+ assert( p->nRef>0 ); |
+ assert( newPgno>0 ); |
+ assert( sqlite3PcachePageSanity(p) ); |
+ pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno)); |
+ sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); |
+ p->pgno = newPgno; |
+ if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ |
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); |
+ } |
+} |
+ |
+/* |
+** Drop every cache entry whose page number is greater than "pgno". The |
+** caller must ensure that there are no outstanding references to any pages |
+** other than page 1 with a page number greater than pgno. |
+** |
+** If there is a reference to page 1 and the pgno parameter passed to this |
+** function is 0, then the data area associated with page 1 is zeroed, but |
+** the page object is not dropped. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ |
+ if( pCache->pCache ){ |
+ PgHdr *p; |
+ PgHdr *pNext; |
+ pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno)); |
+ for(p=pCache->pDirty; p; p=pNext){ |
+ pNext = p->pDirtyNext; |
+ /* This routine never gets call with a positive pgno except right |
+ ** after sqlite3PcacheCleanAll(). So if there are dirty pages, |
+ ** it must be that pgno==0. |
+ */ |
+ assert( p->pgno>0 ); |
+ if( p->pgno>pgno ){ |
+ assert( p->flags&PGHDR_DIRTY ); |
+ sqlite3PcacheMakeClean(p); |
+ } |
+ } |
+ if( pgno==0 && pCache->nRefSum ){ |
+ sqlite3_pcache_page *pPage1; |
+ pPage1 = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache,1,0); |
+ if( ALWAYS(pPage1) ){ /* Page 1 is always available in cache, because |
+ ** pCache->nRefSum>0 */ |
+ memset(pPage1->pBuf, 0, pCache->szPage); |
+ pgno = 1; |
+ } |
+ } |
+ sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1); |
+ } |
+} |
+ |
+/* |
+** Close a cache. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){ |
+ assert( pCache->pCache!=0 ); |
+ pcacheTrace(("%p.CLOSE\n",pCache)); |
+ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); |
+} |
+ |
+/* |
+** Discard the contents of the cache. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){ |
+ sqlite3PcacheTruncate(pCache, 0); |
+} |
+ |
+/* |
+** Merge two lists of pages connected by pDirty and in pgno order. |
+** Do not bother fixing the pDirtyPrev pointers. |
+*/ |
+static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ |
+ PgHdr result, *pTail; |
+ pTail = &result; |
+ assert( pA!=0 && pB!=0 ); |
+ for(;;){ |
+ if( pA->pgno<pB->pgno ){ |
+ pTail->pDirty = pA; |
+ pTail = pA; |
+ pA = pA->pDirty; |
+ if( pA==0 ){ |
+ pTail->pDirty = pB; |
+ break; |
+ } |
+ }else{ |
+ pTail->pDirty = pB; |
+ pTail = pB; |
+ pB = pB->pDirty; |
+ if( pB==0 ){ |
+ pTail->pDirty = pA; |
+ break; |
+ } |
+ } |
+ } |
+ return result.pDirty; |
+} |
+ |
+/* |
+** Sort the list of pages in accending order by pgno. Pages are |
+** connected by pDirty pointers. The pDirtyPrev pointers are |
+** corrupted by this sort. |
+** |
+** Since there cannot be more than 2^31 distinct pages in a database, |
+** there cannot be more than 31 buckets required by the merge sorter. |
+** One extra bucket is added to catch overflow in case something |
+** ever changes to make the previous sentence incorrect. |
+*/ |
+#define N_SORT_BUCKET 32 |
+static PgHdr *pcacheSortDirtyList(PgHdr *pIn){ |
+ PgHdr *a[N_SORT_BUCKET], *p; |
+ int i; |
+ memset(a, 0, sizeof(a)); |
+ while( pIn ){ |
+ p = pIn; |
+ pIn = p->pDirty; |
+ p->pDirty = 0; |
+ for(i=0; ALWAYS(i<N_SORT_BUCKET-1); i++){ |
+ if( a[i]==0 ){ |
+ a[i] = p; |
+ break; |
+ }else{ |
+ p = pcacheMergeDirtyList(a[i], p); |
+ a[i] = 0; |
+ } |
+ } |
+ if( NEVER(i==N_SORT_BUCKET-1) ){ |
+ /* To get here, there need to be 2^(N_SORT_BUCKET) elements in |
+ ** the input list. But that is impossible. |
+ */ |
+ a[i] = pcacheMergeDirtyList(a[i], p); |
+ } |
+ } |
+ p = a[0]; |
+ for(i=1; i<N_SORT_BUCKET; i++){ |
+ if( a[i]==0 ) continue; |
+ p = p ? pcacheMergeDirtyList(p, a[i]) : a[i]; |
+ } |
+ return p; |
+} |
+ |
+/* |
+** Return a list of all dirty pages in the cache, sorted by page number. |
+*/ |
+SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){ |
+ PgHdr *p; |
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){ |
+ p->pDirty = p->pDirtyNext; |
+ } |
+ return pcacheSortDirtyList(pCache->pDirty); |
+} |
+ |
+/* |
+** Return the total number of references to all pages held by the cache. |
+** |
+** This is not the total number of pages referenced, but the sum of the |
+** reference count for all pages. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){ |
+ return pCache->nRefSum; |
+} |
+ |
+/* |
+** Return the number of references to the page supplied as an argument. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){ |
+ return p->nRef; |
+} |
+ |
+/* |
+** Return the total number of pages in the cache. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){ |
+ assert( pCache->pCache!=0 ); |
+ return sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache); |
+} |
+ |
+#ifdef SQLITE_TEST |
+/* |
+** Get the suggested cache-size value. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *pCache){ |
+ return numberOfCachePages(pCache); |
+} |
+#endif |
+ |
+/* |
+** Set the suggested cache-size value. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ |
+ assert( pCache->pCache!=0 ); |
+ pCache->szCache = mxPage; |
+ sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache, |
+ numberOfCachePages(pCache)); |
+} |
+ |
+/* |
+** Set the suggested cache-spill value. Make no changes if if the |
+** argument is zero. Return the effective cache-spill size, which will |
+** be the larger of the szSpill and szCache. |
+*/ |
+SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){ |
+ int res; |
+ assert( p->pCache!=0 ); |
+ if( mxPage ){ |
+ if( mxPage<0 ){ |
+ mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra)); |
+ } |
+ p->szSpill = mxPage; |
+ } |
+ res = numberOfCachePages(p); |
+ if( res<p->szSpill ) res = p->szSpill; |
+ return res; |
+} |
+ |
+/* |
+** Free up as much memory as possible from the page cache. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){ |
+ assert( pCache->pCache!=0 ); |
+ sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache); |
+} |
+ |
+/* |
+** Return the size of the header added by this middleware layer |
+** in the page-cache hierarchy. |
+*/ |
+SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); } |
+ |
+/* |
+** Return the number of dirty pages currently in the cache, as a percentage |
+** of the configured cache size. |
+*/ |
+SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){ |
+ PgHdr *pDirty; |
+ int nDirty = 0; |
+ int nCache = numberOfCachePages(pCache); |
+ for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++; |
+ return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0; |
+} |
+ |
+#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) |
+/* |
+** For all dirty pages currently in the cache, invoke the specified |
+** callback. This is only used if the SQLITE_CHECK_PAGES macro is |
+** defined. |
+*/ |
+SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){ |
+ PgHdr *pDirty; |
+ for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){ |
+ xIter(pDirty); |
+ } |
+} |
+#endif |
+ |
+/************** End of pcache.c **********************************************/ |
+ |
+/* Chain include. */ |
+#include "sqlite3.02.c" |