Fossil SCM

merge trunk

jan.nijtmans 2013-10-13 09:53 tkt-change-hook merge
Commit a4327ba0b63e4e0ebad79eae6853b2c712c5c917
82 files changed +186 -137 +1 -6 +3 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +251 -6 +152 -77 +152 -77 +1 -1 +25 +6 -1 +1 +1 +124 +1 +27 -11 +20 -6 +1 -1 +3 -3 +30 -3 +1 -1 +14 -1 +17 +71 -206 +1 -1 +20 -7 +20 -7 +1 -1 +1 -1 +1 -1 +1 -1 +3 -3 +2 -1 +64 -10 +5 -4 +4 -4 +4 -4 +1 +5 +1 -1 +13 -4 +1 -1 +2 -2 +1 -1 +1774 -1122 +1 -1 +1 -1 +8 -1 +6 +2 -2 +1 -1 +4 +6 +177 -87 +194 -24 +194 -24 +3 -3 +3 -3 +1 -1 +2 -20 +28 -1 +1 -8 +130 -10 +7 -7 +7 -7 +1 -1 +1 -1 +18 -11 +18 -11 +2 -2 +2 -1 +1 -1 +5 -5 +5 -5 +5 +1 -1 +4 +1 -1 +31 -4
+186 -137
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -185,11 +185,11 @@
185185
#endif
186186
187187
#define UCHAR(c) ((unsigned char)(c))
188188
189189
190
-#define JIM_VERSION 73
190
+#define JIM_VERSION 74
191191
192192
#define JIM_OK 0
193193
#define JIM_ERR 1
194194
#define JIM_RETURN 2
195195
#define JIM_BREAK 3
@@ -321,14 +321,14 @@
321321
#define Jim_GetHashTableSize(ht) ((ht)->size)
322322
#define Jim_GetHashTableUsed(ht) ((ht)->used)
323323
324324
325325
typedef struct Jim_Obj {
326
- int refCount;
327326
char *bytes;
328
- int length;
329327
const struct Jim_ObjType *typePtr;
328
+ int refCount;
329
+ int length;
330330
331331
union {
332332
333333
jim_wide wideValue;
334334
@@ -665,12 +665,10 @@
665665
666666
667667
JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
668668
JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
669669
JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
670
-JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes,
671
- int length);
672670
JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
673671
Jim_Obj *objPtr);
674672
JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
675673
int *lenPtr);
676674
JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr);
@@ -877,10 +875,12 @@
877875
JIM_EXPORT void Jim_HistoryShow(void);
878876
879877
880878
JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
881879
JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
880
+JIM_EXPORT int Jim_CheckSignal(Jim_Interp *interp);
881
+#define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
882882
883883
884884
JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
885885
JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
886886
@@ -5671,10 +5671,13 @@
56715671
#ifdef JIM_MAINTAINER
56725672
#define JIM_DEBUG_COMMAND
56735673
#define JIM_DEBUG_PANIC
56745674
#endif
56755675
5676
+
5677
+#define JIM_INTEGER_SPACE 24
5678
+
56765679
const char *jim_tt_name(int type);
56775680
56785681
#ifdef JIM_DEBUG_PANIC
56795682
static void JimPanicDump(int panic_condition, const char *fmt, ...);
56805683
#define JimPanic(X) JimPanicDump X
@@ -5690,10 +5693,11 @@
56905693
static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
56915694
int flags);
56925695
static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
56935696
static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
56945697
static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
5698
+static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len);
56955699
static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
56965700
const char *prefix, const char *const *tablePtr, const char *name);
56975701
static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
56985702
static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
56995703
static int JimSign(jim_wide w);
@@ -5934,15 +5938,42 @@
59345938
}
59355939
return n;
59365940
}
59375941
#endif
59385942
5939
-int Jim_WideToString(char *buf, jim_wide wideValue)
5943
+static int JimWideToString(char *buf, jim_wide wideValue)
59405944
{
5941
- const char *fmt = "%" JIM_WIDE_MODIFIER;
5945
+ int pos = 0;
59425946
5943
- return sprintf(buf, fmt, wideValue);
5947
+ if (wideValue == 0) {
5948
+ buf[pos++] = '0';
5949
+ }
5950
+ else {
5951
+ char tmp[JIM_INTEGER_SPACE];
5952
+ int num = 0;
5953
+ int i;
5954
+
5955
+ if (wideValue < 0) {
5956
+ buf[pos++] = '-';
5957
+
5958
+ i = wideValue % 10;
5959
+ tmp[num++] = (i > 0) ? (10 - i) : -i;
5960
+ wideValue /= -10;
5961
+ }
5962
+
5963
+ while (wideValue) {
5964
+ tmp[num++] = wideValue % 10;
5965
+ wideValue /= 10;
5966
+ }
5967
+
5968
+ for (i = 0; i < num; i++) {
5969
+ buf[pos++] = '0' + tmp[num - i - 1];
5970
+ }
5971
+ }
5972
+ buf[pos] = 0;
5973
+
5974
+ return pos;
59445975
}
59455976
59465977
static int JimCheckConversion(const char *str, const char *endptr)
59475978
{
59485979
if (str[0] == '\0' || str == endptr) {
@@ -6229,10 +6260,18 @@
62296260
ht->sizemask = 0;
62306261
ht->used = 0;
62316262
ht->collisions = 0;
62326263
}
62336264
6265
+static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter)
6266
+{
6267
+ iter->ht = ht;
6268
+ iter->index = -1;
6269
+ iter->entry = NULL;
6270
+ iter->nextEntry = NULL;
6271
+}
6272
+
62346273
62356274
int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
62366275
{
62376276
JimResetHashTable(ht);
62386277
ht->type = type;
@@ -6408,15 +6447,11 @@
64086447
}
64096448
64106449
Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
64116450
{
64126451
Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
6413
-
6414
- iter->ht = ht;
6415
- iter->index = -1;
6416
- iter->entry = NULL;
6417
- iter->nextEntry = NULL;
6452
+ JimInitHashTableIterator(ht, iter);
64186453
return iter;
64196454
}
64206455
64216456
Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
64226457
{
@@ -10500,12 +10535,10 @@
1050010535
int Jim_GetExitCode(Jim_Interp *interp)
1050110536
{
1050210537
return interp->exitCode;
1050310538
}
1050410539
10505
-#define JIM_INTEGER_SPACE 24
10506
-
1050710540
static void UpdateStringOfInt(struct Jim_Obj *objPtr);
1050810541
static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
1050910542
1051010543
static const Jim_ObjType intObjType = {
1051110544
"int",
@@ -10522,16 +10555,16 @@
1052210555
UpdateStringOfInt,
1052310556
JIM_TYPE_NONE,
1052410557
};
1052510558
1052610559
10527
-void UpdateStringOfInt(struct Jim_Obj *objPtr)
10560
+static void UpdateStringOfInt(struct Jim_Obj *objPtr)
1052810561
{
1052910562
int len;
1053010563
char buf[JIM_INTEGER_SPACE + 1];
1053110564
10532
- len = Jim_WideToString(buf, JimWideValue(objPtr));
10565
+ len = JimWideToString(buf, JimWideValue(objPtr));
1053310566
objPtr->bytes = Jim_Alloc(len + 1);
1053410567
memcpy(objPtr->bytes, buf, len + 1);
1053510568
objPtr->length = len;
1053610569
}
1053710570
@@ -10755,11 +10788,11 @@
1075510788
}
1075610789
1075710790
#define JIM_ELESTR_SIMPLE 0
1075810791
#define JIM_ELESTR_BRACE 1
1075910792
#define JIM_ELESTR_QUOTE 2
10760
-static int ListElementQuotingType(const char *s, int len)
10793
+static unsigned char ListElementQuotingType(const char *s, int len)
1076110794
{
1076210795
int i, level, blevel, trySimple = 1;
1076310796
1076410797
1076510798
if (len == 0)
@@ -10903,17 +10936,23 @@
1090310936
return p - q;
1090410937
}
1090510938
1090610939
static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
1090710940
{
10941
+ #define STATIC_QUOTING_LEN 32
1090810942
int i, bufLen, realLength;
1090910943
const char *strRep;
1091010944
char *p;
10911
- int *quotingType;
10945
+ unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
1091210946
1091310947
10914
- quotingType = Jim_Alloc(sizeof(int) * objc + 1);
10948
+ if (objc > STATIC_QUOTING_LEN) {
10949
+ quotingType = Jim_Alloc(objc);
10950
+ }
10951
+ else {
10952
+ quotingType = staticQuoting;
10953
+ }
1091510954
bufLen = 0;
1091610955
for (i = 0; i < objc; i++) {
1091710956
int len;
1091810957
1091910958
strRep = Jim_GetString(objv[i], &len);
@@ -10975,11 +11014,14 @@
1097511014
realLength++;
1097611015
}
1097711016
}
1097811017
*p = '\0';
1097911018
objPtr->length = realLength;
10980
- Jim_Free(quotingType);
11019
+
11020
+ if (quotingType != staticQuoting) {
11021
+ Jim_Free(quotingType);
11022
+ }
1098111023
}
1098211024
1098311025
static void UpdateStringOfList(struct Jim_Obj *objPtr)
1098411026
{
1098511027
JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
@@ -11000,11 +11042,11 @@
1100011042
if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) {
1100111043
Jim_Obj **listObjPtrPtr;
1100211044
int len;
1100311045
int i;
1100411046
11005
- Jim_DictPairs(interp, objPtr, &listObjPtrPtr, &len);
11047
+ listObjPtrPtr = JimDictPairs(objPtr, &len);
1100611048
for (i = 0; i < len; i++) {
1100711049
Jim_IncrRefCount(listObjPtrPtr[i]);
1100811050
}
1100911051
1101011052
@@ -11225,14 +11267,22 @@
1122511267
int requiredLen = currentLen + elemc;
1122611268
int i;
1122711269
Jim_Obj **point;
1122811270
1122911271
if (requiredLen > listPtr->internalRep.listValue.maxLen) {
11230
- listPtr->internalRep.listValue.maxLen = requiredLen * 2;
11272
+ if (requiredLen < 2) {
11273
+
11274
+ requiredLen = 4;
11275
+ }
11276
+ else {
11277
+ requiredLen *= 2;
11278
+ }
1123111279
1123211280
listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
11233
- sizeof(Jim_Obj *) * listPtr->internalRep.listValue.maxLen);
11281
+ sizeof(Jim_Obj *) * requiredLen);
11282
+
11283
+ listPtr->internalRep.listValue.maxLen = requiredLen;
1123411284
}
1123511285
if (idx < 0) {
1123611286
idx = currentLen;
1123711287
}
1123811288
point = listPtr->internalRep.listValue.ele + idx;
@@ -11523,55 +11573,53 @@
1152311573
}
1152411574
1152511575
void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
1152611576
{
1152711577
Jim_HashTable *ht, *dupHt;
11528
- Jim_HashTableIterator *htiter;
11578
+ Jim_HashTableIterator htiter;
1152911579
Jim_HashEntry *he;
1153011580
1153111581
1153211582
ht = srcPtr->internalRep.ptr;
1153311583
dupHt = Jim_Alloc(sizeof(*dupHt));
1153411584
Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
1153511585
if (ht->size != 0)
1153611586
Jim_ExpandHashTable(dupHt, ht->size);
1153711587
11538
- htiter = Jim_GetHashTableIterator(ht);
11539
- while ((he = Jim_NextHashEntry(htiter)) != NULL) {
11588
+ JimInitHashTableIterator(ht, &htiter);
11589
+ while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
1154011590
const Jim_Obj *keyObjPtr = he->key;
1154111591
Jim_Obj *valObjPtr = he->u.val;
1154211592
1154311593
Jim_IncrRefCount((Jim_Obj *)keyObjPtr);
1154411594
Jim_IncrRefCount(valObjPtr);
1154511595
Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
1154611596
}
11547
- Jim_FreeHashTableIterator(htiter);
1154811597
1154911598
dupPtr->internalRep.ptr = dupHt;
1155011599
dupPtr->typePtr = &dictObjType;
1155111600
}
1155211601
1155311602
static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len)
1155411603
{
1155511604
Jim_HashTable *ht;
11556
- Jim_HashTableIterator *htiter;
11605
+ Jim_HashTableIterator htiter;
1155711606
Jim_HashEntry *he;
1155811607
Jim_Obj **objv;
1155911608
int i;
1156011609
1156111610
ht = dictPtr->internalRep.ptr;
1156211611
1156311612
1156411613
objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
11565
- htiter = Jim_GetHashTableIterator(ht);
11614
+ JimInitHashTableIterator(ht, &htiter);
1156611615
i = 0;
11567
- while ((he = Jim_NextHashEntry(htiter)) != NULL) {
11616
+ while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
1156811617
objv[i++] = (Jim_Obj *)he->key;
1156911618
objv[i++] = he->u.val;
1157011619
}
1157111620
*len = i;
11572
- Jim_FreeHashTableIterator(htiter);
1157311621
return objv;
1157411622
}
1157511623
1157611624
static void UpdateStringOfDict(struct Jim_Obj *objPtr)
1157711625
{
@@ -12089,14 +12137,15 @@
1208912137
1209012138
1209112139
typedef struct Jim_ExprOperator
1209212140
{
1209312141
const char *name;
12094
- int precedence;
12095
- int arity;
1209612142
int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
12097
- int lazy;
12143
+ unsigned char precedence;
12144
+ unsigned char arity;
12145
+ unsigned char lazy;
12146
+ unsigned char namelen;
1209812147
} Jim_ExprOperator;
1209912148
1210012149
static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
1210112150
{
1210212151
Jim_IncrRefCount(obj);
@@ -12774,93 +12823,96 @@
1277412823
LAZY_OP,
1277512824
LAZY_LEFT,
1277612825
LAZY_RIGHT
1277712826
};
1277812827
12828
+#define OPRINIT(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1}
12829
+
1277912830
static const struct Jim_ExprOperator Jim_ExprOperators[] = {
12780
- {"*", 200, 2, JimExprOpBin, LAZY_NONE},
12781
- {"/", 200, 2, JimExprOpBin, LAZY_NONE},
12782
- {"%", 200, 2, JimExprOpIntBin, LAZY_NONE},
12783
-
12784
- {"-", 100, 2, JimExprOpBin, LAZY_NONE},
12785
- {"+", 100, 2, JimExprOpBin, LAZY_NONE},
12786
-
12787
- {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
12788
- {">>", 90, 2, JimExprOpIntBin, LAZY_NONE},
12789
-
12790
- {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
12791
- {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE},
12792
-
12793
- {"<", 80, 2, JimExprOpBin, LAZY_NONE},
12794
- {">", 80, 2, JimExprOpBin, LAZY_NONE},
12795
- {"<=", 80, 2, JimExprOpBin, LAZY_NONE},
12796
- {">=", 80, 2, JimExprOpBin, LAZY_NONE},
12797
-
12798
- {"==", 70, 2, JimExprOpBin, LAZY_NONE},
12799
- {"!=", 70, 2, JimExprOpBin, LAZY_NONE},
12800
-
12801
- {"&", 50, 2, JimExprOpIntBin, LAZY_NONE},
12802
- {"^", 49, 2, JimExprOpIntBin, LAZY_NONE},
12803
- {"|", 48, 2, JimExprOpIntBin, LAZY_NONE},
12804
-
12805
- {"&&", 10, 2, NULL, LAZY_OP},
12806
- {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT},
12807
- {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT},
12808
-
12809
- {"||", 9, 2, NULL, LAZY_OP},
12810
- {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT},
12811
- {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT},
12812
-
12813
- {"?", 5, 2, JimExprOpNull, LAZY_OP},
12814
- {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT},
12815
- {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
12816
-
12817
- {":", 5, 2, JimExprOpNull, LAZY_OP},
12818
- {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT},
12819
- {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
12820
-
12821
- {"**", 250, 2, JimExprOpBin, LAZY_NONE},
12822
-
12823
- {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE},
12824
- {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE},
12825
-
12826
- {"in", 55, 2, JimExprOpStrBin, LAZY_NONE},
12827
- {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE},
12828
-
12829
- {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE},
12830
- {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE},
12831
- {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
12832
- {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
12833
-
12834
-
12835
-
12836
- {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE},
12837
- {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE},
12838
- {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE},
12839
- {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE},
12840
- {"rand", 400, 0, JimExprOpNone, LAZY_NONE},
12841
- {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE},
12831
+ OPRINIT("*", 110, 2, JimExprOpBin, LAZY_NONE),
12832
+ OPRINIT("/", 110, 2, JimExprOpBin, LAZY_NONE),
12833
+ OPRINIT("%", 110, 2, JimExprOpIntBin, LAZY_NONE),
12834
+
12835
+ OPRINIT("-", 100, 2, JimExprOpBin, LAZY_NONE),
12836
+ OPRINIT("+", 100, 2, JimExprOpBin, LAZY_NONE),
12837
+
12838
+ OPRINIT("<<", 90, 2, JimExprOpIntBin, LAZY_NONE),
12839
+ OPRINIT(">>", 90, 2, JimExprOpIntBin, LAZY_NONE),
12840
+
12841
+ OPRINIT("<<<", 90, 2, JimExprOpIntBin, LAZY_NONE),
12842
+ OPRINIT(">>>", 90, 2, JimExprOpIntBin, LAZY_NONE),
12843
+
12844
+ OPRINIT("<", 80, 2, JimExprOpBin, LAZY_NONE),
12845
+ OPRINIT(">", 80, 2, JimExprOpBin, LAZY_NONE),
12846
+ OPRINIT("<=", 80, 2, JimExprOpBin, LAZY_NONE),
12847
+ OPRINIT(">=", 80, 2, JimExprOpBin, LAZY_NONE),
12848
+
12849
+ OPRINIT("==", 70, 2, JimExprOpBin, LAZY_NONE),
12850
+ OPRINIT("!=", 70, 2, JimExprOpBin, LAZY_NONE),
12851
+
12852
+ OPRINIT("&", 50, 2, JimExprOpIntBin, LAZY_NONE),
12853
+ OPRINIT("^", 49, 2, JimExprOpIntBin, LAZY_NONE),
12854
+ OPRINIT("|", 48, 2, JimExprOpIntBin, LAZY_NONE),
12855
+
12856
+ OPRINIT("&&", 10, 2, NULL, LAZY_OP),
12857
+ OPRINIT(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT),
12858
+ OPRINIT(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT),
12859
+
12860
+ OPRINIT("||", 9, 2, NULL, LAZY_OP),
12861
+ OPRINIT(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT),
12862
+ OPRINIT(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT),
12863
+
12864
+ OPRINIT("?", 5, 2, JimExprOpNull, LAZY_OP),
12865
+ OPRINIT(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT),
12866
+ OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
12867
+
12868
+ OPRINIT(":", 5, 2, JimExprOpNull, LAZY_OP),
12869
+ OPRINIT(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT),
12870
+ OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
12871
+
12872
+ OPRINIT("**", 250, 2, JimExprOpBin, LAZY_NONE),
12873
+
12874
+ OPRINIT("eq", 60, 2, JimExprOpStrBin, LAZY_NONE),
12875
+ OPRINIT("ne", 60, 2, JimExprOpStrBin, LAZY_NONE),
12876
+
12877
+ OPRINIT("in", 55, 2, JimExprOpStrBin, LAZY_NONE),
12878
+ OPRINIT("ni", 55, 2, JimExprOpStrBin, LAZY_NONE),
12879
+
12880
+ OPRINIT("!", 150, 1, JimExprOpNumUnary, LAZY_NONE),
12881
+ OPRINIT("~", 150, 1, JimExprOpIntUnary, LAZY_NONE),
12882
+ OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE),
12883
+ OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE),
12884
+
12885
+
12886
+
12887
+ OPRINIT("int", 200, 1, JimExprOpNumUnary, LAZY_NONE),
12888
+ OPRINIT("abs", 200, 1, JimExprOpNumUnary, LAZY_NONE),
12889
+ OPRINIT("double", 200, 1, JimExprOpNumUnary, LAZY_NONE),
12890
+ OPRINIT("round", 200, 1, JimExprOpNumUnary, LAZY_NONE),
12891
+ OPRINIT("rand", 200, 0, JimExprOpNone, LAZY_NONE),
12892
+ OPRINIT("srand", 200, 1, JimExprOpIntUnary, LAZY_NONE),
1284212893
1284312894
#ifdef JIM_MATH_FUNCTIONS
12844
- {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12845
- {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12846
- {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12847
- {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12848
- {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12849
- {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12850
- {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12851
- {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12852
- {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12853
- {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12854
- {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12855
- {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12856
- {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12857
- {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12858
- {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12859
- {"pow", 400, 2, JimExprOpBin, LAZY_NONE},
12895
+ OPRINIT("sin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12896
+ OPRINIT("cos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12897
+ OPRINIT("tan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12898
+ OPRINIT("asin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12899
+ OPRINIT("acos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12900
+ OPRINIT("atan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12901
+ OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12902
+ OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12903
+ OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12904
+ OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12905
+ OPRINIT("floor", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12906
+ OPRINIT("exp", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12907
+ OPRINIT("log", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12908
+ OPRINIT("log10", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12909
+ OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12910
+ OPRINIT("pow", 200, 2, JimExprOpBin, LAZY_NONE),
1286012911
#endif
1286112912
};
12913
+#undef OPRINIT
1286212914
1286312915
#define JIM_EXPR_OPERATORS_NUM \
1286412916
(sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
1286512917
1286612918
static int JimParseExpression(struct JimParserCtx *pc)
@@ -13026,20 +13078,18 @@
1302613078
int i;
1302713079
int bestIdx = -1, bestLen = 0;
1302813080
1302913081
1303013082
for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
13031
- const char *opname;
13032
- int oplen;
13083
+ const char * const opname = Jim_ExprOperators[i].name;
13084
+ const int oplen = Jim_ExprOperators[i].namelen;
1303313085
13034
- opname = Jim_ExprOperators[i].name;
13035
- if (opname == NULL) {
13086
+ if (opname == NULL || opname[0] != pc->p[0]) {
1303613087
continue;
1303713088
}
13038
- oplen = strlen(opname);
1303913089
13040
- if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) {
13090
+ if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) {
1304113091
bestIdx = i + JIM_TT_EXPR_OP;
1304213092
bestLen = oplen;
1304313093
}
1304413094
}
1304513095
if (bestIdx == -1) {
@@ -13111,12 +13161,12 @@
1311113161
};
1311213162
1311313163
1311413164
typedef struct ExprByteCode
1311513165
{
13116
- int len;
1311713166
ScriptToken *token;
13167
+ int len;
1311813168
int inUse;
1311913169
} ExprByteCode;
1312013170
1312113171
static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
1312213172
{
@@ -13855,16 +13905,16 @@
1385513905
1385613906
1385713907
1385813908
typedef struct ScanFmtPartDescr
1385913909
{
13860
- char type;
13861
- char modifier;
13910
+ char *arg;
13911
+ char *prefix;
1386213912
size_t width;
1386313913
int pos;
13864
- char *arg;
13865
- char *prefix;
13914
+ char type;
13915
+ char modifier;
1386613916
} ScanFmtPartDescr;
1386713917
1386813918
1386913919
typedef struct ScanFmtStringObj
1387013920
{
@@ -14871,12 +14921,12 @@
1487114921
}
1487214922
1487314923
if (retcode == JIM_OK && argc) {
1487414924
1487514925
retcode = JimInvokeCommand(interp, argc, argv);
14876
- if (interp->signal_level && interp->sigmask) {
14877
-
14926
+
14927
+ if (Jim_CheckSignal(interp)) {
1487814928
retcode = JIM_SIGNAL;
1487914929
}
1488014930
}
1488114931
1488214932
@@ -15446,17 +15496,17 @@
1544615496
if (he) {
1544715497
callback(interp, listObjPtr, he, type);
1544815498
}
1544915499
}
1545015500
else {
15451
- Jim_HashTableIterator *htiter = Jim_GetHashTableIterator(ht);
15452
- while ((he = Jim_NextHashEntry(htiter)) != NULL) {
15501
+ Jim_HashTableIterator htiter;
15502
+ JimInitHashTableIterator(ht, &htiter);
15503
+ while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
1545315504
if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), he->key, 0)) {
1545415505
callback(interp, listObjPtr, he, type);
1545515506
}
1545615507
}
15457
- Jim_FreeHashTableIterator(htiter);
1545815508
}
1545915509
return listObjPtr;
1546015510
}
1546115511
1546215512
@@ -17795,11 +17845,11 @@
1779517845
if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
1779617846
sig++;
1779717847
}
1779817848
1779917849
interp->signal_level += sig;
17800
- if (interp->signal_level && interp->sigmask) {
17850
+ if (Jim_CheckSignal(interp)) {
1780117851
1780217852
exitCode = JIM_SIGNAL;
1780317853
}
1780417854
else {
1780517855
exitCode = Jim_EvalObj(interp, argv[0]);
@@ -17951,25 +18001,24 @@
1795118001
1795218002
1795318003
static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1795418004
{
1795518005
Jim_Obj *listObjPtr;
17956
- Jim_HashTableIterator *htiter;
18006
+ Jim_HashTableIterator htiter;
1795718007
Jim_HashEntry *he;
1795818008
1795918009
listObjPtr = Jim_NewListObj(interp, NULL, 0);
1796018010
17961
- htiter = Jim_GetHashTableIterator(&interp->references);
17962
- while ((he = Jim_NextHashEntry(htiter)) != NULL) {
18011
+ JimInitHashTableIterator(&interp->references, &htiter);
18012
+ while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
1796318013
char buf[JIM_REFERENCE_SPACE + 1];
1796418014
Jim_Reference *refPtr = he->u.val;
1796518015
const unsigned long *refId = he->key;
1796618016
1796718017
JimFormatReference(buf, refPtr, *refId);
1796818018
Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1));
1796918019
}
17970
- Jim_FreeHashTableIterator(htiter);
1797118020
Jim_SetResult(interp, listObjPtr);
1797218021
return JIM_OK;
1797318022
}
1797418023
#endif
1797518024
@@ -18005,17 +18054,17 @@
1800518054
{
1800618055
Jim_HashEntry *he;
1800718056
Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
1800818057
1800918058
18010
- Jim_HashTableIterator *htiter = Jim_GetHashTableIterator(ht);
18011
- while ((he = Jim_NextHashEntry(htiter)) != NULL) {
18059
+ Jim_HashTableIterator htiter;
18060
+ JimInitHashTableIterator(ht, &htiter);
18061
+ while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
1801218062
if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) {
1801318063
callback(interp, listObjPtr, he, type);
1801418064
}
1801518065
}
18016
- Jim_FreeHashTableIterator(htiter);
1801718066
1801818067
return listObjPtr;
1801918068
}
1802018069
1802118070
1802218071
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -185,11 +185,11 @@
185 #endif
186
187 #define UCHAR(c) ((unsigned char)(c))
188
189
190 #define JIM_VERSION 73
191
192 #define JIM_OK 0
193 #define JIM_ERR 1
194 #define JIM_RETURN 2
195 #define JIM_BREAK 3
@@ -321,14 +321,14 @@
321 #define Jim_GetHashTableSize(ht) ((ht)->size)
322 #define Jim_GetHashTableUsed(ht) ((ht)->used)
323
324
325 typedef struct Jim_Obj {
326 int refCount;
327 char *bytes;
328 int length;
329 const struct Jim_ObjType *typePtr;
 
 
330
331 union {
332
333 jim_wide wideValue;
334
@@ -665,12 +665,10 @@
665
666
667 JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
668 JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
669 JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
670 JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes,
671 int length);
672 JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
673 Jim_Obj *objPtr);
674 JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
675 int *lenPtr);
676 JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr);
@@ -877,10 +875,12 @@
877 JIM_EXPORT void Jim_HistoryShow(void);
878
879
880 JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
881 JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
 
 
882
883
884 JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
885 JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
886
@@ -5671,10 +5671,13 @@
5671 #ifdef JIM_MAINTAINER
5672 #define JIM_DEBUG_COMMAND
5673 #define JIM_DEBUG_PANIC
5674 #endif
5675
 
 
 
5676 const char *jim_tt_name(int type);
5677
5678 #ifdef JIM_DEBUG_PANIC
5679 static void JimPanicDump(int panic_condition, const char *fmt, ...);
5680 #define JimPanic(X) JimPanicDump X
@@ -5690,10 +5693,11 @@
5690 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
5691 int flags);
5692 static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
5693 static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
5694 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
 
5695 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
5696 const char *prefix, const char *const *tablePtr, const char *name);
5697 static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
5698 static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
5699 static int JimSign(jim_wide w);
@@ -5934,15 +5938,42 @@
5934 }
5935 return n;
5936 }
5937 #endif
5938
5939 int Jim_WideToString(char *buf, jim_wide wideValue)
5940 {
5941 const char *fmt = "%" JIM_WIDE_MODIFIER;
5942
5943 return sprintf(buf, fmt, wideValue);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5944 }
5945
5946 static int JimCheckConversion(const char *str, const char *endptr)
5947 {
5948 if (str[0] == '\0' || str == endptr) {
@@ -6229,10 +6260,18 @@
6229 ht->sizemask = 0;
6230 ht->used = 0;
6231 ht->collisions = 0;
6232 }
6233
 
 
 
 
 
 
 
 
6234
6235 int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
6236 {
6237 JimResetHashTable(ht);
6238 ht->type = type;
@@ -6408,15 +6447,11 @@
6408 }
6409
6410 Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
6411 {
6412 Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
6413
6414 iter->ht = ht;
6415 iter->index = -1;
6416 iter->entry = NULL;
6417 iter->nextEntry = NULL;
6418 return iter;
6419 }
6420
6421 Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
6422 {
@@ -10500,12 +10535,10 @@
10500 int Jim_GetExitCode(Jim_Interp *interp)
10501 {
10502 return interp->exitCode;
10503 }
10504
10505 #define JIM_INTEGER_SPACE 24
10506
10507 static void UpdateStringOfInt(struct Jim_Obj *objPtr);
10508 static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
10509
10510 static const Jim_ObjType intObjType = {
10511 "int",
@@ -10522,16 +10555,16 @@
10522 UpdateStringOfInt,
10523 JIM_TYPE_NONE,
10524 };
10525
10526
10527 void UpdateStringOfInt(struct Jim_Obj *objPtr)
10528 {
10529 int len;
10530 char buf[JIM_INTEGER_SPACE + 1];
10531
10532 len = Jim_WideToString(buf, JimWideValue(objPtr));
10533 objPtr->bytes = Jim_Alloc(len + 1);
10534 memcpy(objPtr->bytes, buf, len + 1);
10535 objPtr->length = len;
10536 }
10537
@@ -10755,11 +10788,11 @@
10755 }
10756
10757 #define JIM_ELESTR_SIMPLE 0
10758 #define JIM_ELESTR_BRACE 1
10759 #define JIM_ELESTR_QUOTE 2
10760 static int ListElementQuotingType(const char *s, int len)
10761 {
10762 int i, level, blevel, trySimple = 1;
10763
10764
10765 if (len == 0)
@@ -10903,17 +10936,23 @@
10903 return p - q;
10904 }
10905
10906 static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
10907 {
 
10908 int i, bufLen, realLength;
10909 const char *strRep;
10910 char *p;
10911 int *quotingType;
10912
10913
10914 quotingType = Jim_Alloc(sizeof(int) * objc + 1);
 
 
 
 
 
10915 bufLen = 0;
10916 for (i = 0; i < objc; i++) {
10917 int len;
10918
10919 strRep = Jim_GetString(objv[i], &len);
@@ -10975,11 +11014,14 @@
10975 realLength++;
10976 }
10977 }
10978 *p = '\0';
10979 objPtr->length = realLength;
10980 Jim_Free(quotingType);
 
 
 
10981 }
10982
10983 static void UpdateStringOfList(struct Jim_Obj *objPtr)
10984 {
10985 JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
@@ -11000,11 +11042,11 @@
11000 if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) {
11001 Jim_Obj **listObjPtrPtr;
11002 int len;
11003 int i;
11004
11005 Jim_DictPairs(interp, objPtr, &listObjPtrPtr, &len);
11006 for (i = 0; i < len; i++) {
11007 Jim_IncrRefCount(listObjPtrPtr[i]);
11008 }
11009
11010
@@ -11225,14 +11267,22 @@
11225 int requiredLen = currentLen + elemc;
11226 int i;
11227 Jim_Obj **point;
11228
11229 if (requiredLen > listPtr->internalRep.listValue.maxLen) {
11230 listPtr->internalRep.listValue.maxLen = requiredLen * 2;
 
 
 
 
 
 
11231
11232 listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
11233 sizeof(Jim_Obj *) * listPtr->internalRep.listValue.maxLen);
 
 
11234 }
11235 if (idx < 0) {
11236 idx = currentLen;
11237 }
11238 point = listPtr->internalRep.listValue.ele + idx;
@@ -11523,55 +11573,53 @@
11523 }
11524
11525 void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
11526 {
11527 Jim_HashTable *ht, *dupHt;
11528 Jim_HashTableIterator *htiter;
11529 Jim_HashEntry *he;
11530
11531
11532 ht = srcPtr->internalRep.ptr;
11533 dupHt = Jim_Alloc(sizeof(*dupHt));
11534 Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
11535 if (ht->size != 0)
11536 Jim_ExpandHashTable(dupHt, ht->size);
11537
11538 htiter = Jim_GetHashTableIterator(ht);
11539 while ((he = Jim_NextHashEntry(htiter)) != NULL) {
11540 const Jim_Obj *keyObjPtr = he->key;
11541 Jim_Obj *valObjPtr = he->u.val;
11542
11543 Jim_IncrRefCount((Jim_Obj *)keyObjPtr);
11544 Jim_IncrRefCount(valObjPtr);
11545 Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
11546 }
11547 Jim_FreeHashTableIterator(htiter);
11548
11549 dupPtr->internalRep.ptr = dupHt;
11550 dupPtr->typePtr = &dictObjType;
11551 }
11552
11553 static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len)
11554 {
11555 Jim_HashTable *ht;
11556 Jim_HashTableIterator *htiter;
11557 Jim_HashEntry *he;
11558 Jim_Obj **objv;
11559 int i;
11560
11561 ht = dictPtr->internalRep.ptr;
11562
11563
11564 objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
11565 htiter = Jim_GetHashTableIterator(ht);
11566 i = 0;
11567 while ((he = Jim_NextHashEntry(htiter)) != NULL) {
11568 objv[i++] = (Jim_Obj *)he->key;
11569 objv[i++] = he->u.val;
11570 }
11571 *len = i;
11572 Jim_FreeHashTableIterator(htiter);
11573 return objv;
11574 }
11575
11576 static void UpdateStringOfDict(struct Jim_Obj *objPtr)
11577 {
@@ -12089,14 +12137,15 @@
12089
12090
12091 typedef struct Jim_ExprOperator
12092 {
12093 const char *name;
12094 int precedence;
12095 int arity;
12096 int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
12097 int lazy;
 
 
 
12098 } Jim_ExprOperator;
12099
12100 static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
12101 {
12102 Jim_IncrRefCount(obj);
@@ -12774,93 +12823,96 @@
12774 LAZY_OP,
12775 LAZY_LEFT,
12776 LAZY_RIGHT
12777 };
12778
 
 
12779 static const struct Jim_ExprOperator Jim_ExprOperators[] = {
12780 {"*", 200, 2, JimExprOpBin, LAZY_NONE},
12781 {"/", 200, 2, JimExprOpBin, LAZY_NONE},
12782 {"%", 200, 2, JimExprOpIntBin, LAZY_NONE},
12783
12784 {"-", 100, 2, JimExprOpBin, LAZY_NONE},
12785 {"+", 100, 2, JimExprOpBin, LAZY_NONE},
12786
12787 {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
12788 {">>", 90, 2, JimExprOpIntBin, LAZY_NONE},
12789
12790 {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
12791 {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE},
12792
12793 {"<", 80, 2, JimExprOpBin, LAZY_NONE},
12794 {">", 80, 2, JimExprOpBin, LAZY_NONE},
12795 {"<=", 80, 2, JimExprOpBin, LAZY_NONE},
12796 {">=", 80, 2, JimExprOpBin, LAZY_NONE},
12797
12798 {"==", 70, 2, JimExprOpBin, LAZY_NONE},
12799 {"!=", 70, 2, JimExprOpBin, LAZY_NONE},
12800
12801 {"&", 50, 2, JimExprOpIntBin, LAZY_NONE},
12802 {"^", 49, 2, JimExprOpIntBin, LAZY_NONE},
12803 {"|", 48, 2, JimExprOpIntBin, LAZY_NONE},
12804
12805 {"&&", 10, 2, NULL, LAZY_OP},
12806 {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT},
12807 {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT},
12808
12809 {"||", 9, 2, NULL, LAZY_OP},
12810 {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT},
12811 {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT},
12812
12813 {"?", 5, 2, JimExprOpNull, LAZY_OP},
12814 {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT},
12815 {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
12816
12817 {":", 5, 2, JimExprOpNull, LAZY_OP},
12818 {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT},
12819 {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
12820
12821 {"**", 250, 2, JimExprOpBin, LAZY_NONE},
12822
12823 {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE},
12824 {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE},
12825
12826 {"in", 55, 2, JimExprOpStrBin, LAZY_NONE},
12827 {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE},
12828
12829 {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE},
12830 {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE},
12831 {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
12832 {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
12833
12834
12835
12836 {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE},
12837 {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE},
12838 {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE},
12839 {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE},
12840 {"rand", 400, 0, JimExprOpNone, LAZY_NONE},
12841 {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE},
12842
12843 #ifdef JIM_MATH_FUNCTIONS
12844 {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12845 {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12846 {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12847 {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12848 {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12849 {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12850 {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12851 {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12852 {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12853 {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12854 {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12855 {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12856 {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12857 {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12858 {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
12859 {"pow", 400, 2, JimExprOpBin, LAZY_NONE},
12860 #endif
12861 };
 
12862
12863 #define JIM_EXPR_OPERATORS_NUM \
12864 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
12865
12866 static int JimParseExpression(struct JimParserCtx *pc)
@@ -13026,20 +13078,18 @@
13026 int i;
13027 int bestIdx = -1, bestLen = 0;
13028
13029
13030 for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
13031 const char *opname;
13032 int oplen;
13033
13034 opname = Jim_ExprOperators[i].name;
13035 if (opname == NULL) {
13036 continue;
13037 }
13038 oplen = strlen(opname);
13039
13040 if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) {
13041 bestIdx = i + JIM_TT_EXPR_OP;
13042 bestLen = oplen;
13043 }
13044 }
13045 if (bestIdx == -1) {
@@ -13111,12 +13161,12 @@
13111 };
13112
13113
13114 typedef struct ExprByteCode
13115 {
13116 int len;
13117 ScriptToken *token;
 
13118 int inUse;
13119 } ExprByteCode;
13120
13121 static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
13122 {
@@ -13855,16 +13905,16 @@
13855
13856
13857
13858 typedef struct ScanFmtPartDescr
13859 {
13860 char type;
13861 char modifier;
13862 size_t width;
13863 int pos;
13864 char *arg;
13865 char *prefix;
13866 } ScanFmtPartDescr;
13867
13868
13869 typedef struct ScanFmtStringObj
13870 {
@@ -14871,12 +14921,12 @@
14871 }
14872
14873 if (retcode == JIM_OK && argc) {
14874
14875 retcode = JimInvokeCommand(interp, argc, argv);
14876 if (interp->signal_level && interp->sigmask) {
14877
14878 retcode = JIM_SIGNAL;
14879 }
14880 }
14881
14882
@@ -15446,17 +15496,17 @@
15446 if (he) {
15447 callback(interp, listObjPtr, he, type);
15448 }
15449 }
15450 else {
15451 Jim_HashTableIterator *htiter = Jim_GetHashTableIterator(ht);
15452 while ((he = Jim_NextHashEntry(htiter)) != NULL) {
 
15453 if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), he->key, 0)) {
15454 callback(interp, listObjPtr, he, type);
15455 }
15456 }
15457 Jim_FreeHashTableIterator(htiter);
15458 }
15459 return listObjPtr;
15460 }
15461
15462
@@ -17795,11 +17845,11 @@
17795 if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
17796 sig++;
17797 }
17798
17799 interp->signal_level += sig;
17800 if (interp->signal_level && interp->sigmask) {
17801
17802 exitCode = JIM_SIGNAL;
17803 }
17804 else {
17805 exitCode = Jim_EvalObj(interp, argv[0]);
@@ -17951,25 +18001,24 @@
17951
17952
17953 static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17954 {
17955 Jim_Obj *listObjPtr;
17956 Jim_HashTableIterator *htiter;
17957 Jim_HashEntry *he;
17958
17959 listObjPtr = Jim_NewListObj(interp, NULL, 0);
17960
17961 htiter = Jim_GetHashTableIterator(&interp->references);
17962 while ((he = Jim_NextHashEntry(htiter)) != NULL) {
17963 char buf[JIM_REFERENCE_SPACE + 1];
17964 Jim_Reference *refPtr = he->u.val;
17965 const unsigned long *refId = he->key;
17966
17967 JimFormatReference(buf, refPtr, *refId);
17968 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1));
17969 }
17970 Jim_FreeHashTableIterator(htiter);
17971 Jim_SetResult(interp, listObjPtr);
17972 return JIM_OK;
17973 }
17974 #endif
17975
@@ -18005,17 +18054,17 @@
18005 {
18006 Jim_HashEntry *he;
18007 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
18008
18009
18010 Jim_HashTableIterator *htiter = Jim_GetHashTableIterator(ht);
18011 while ((he = Jim_NextHashEntry(htiter)) != NULL) {
 
18012 if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) {
18013 callback(interp, listObjPtr, he, type);
18014 }
18015 }
18016 Jim_FreeHashTableIterator(htiter);
18017
18018 return listObjPtr;
18019 }
18020
18021
18022
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -185,11 +185,11 @@
185 #endif
186
187 #define UCHAR(c) ((unsigned char)(c))
188
189
190 #define JIM_VERSION 74
191
192 #define JIM_OK 0
193 #define JIM_ERR 1
194 #define JIM_RETURN 2
195 #define JIM_BREAK 3
@@ -321,14 +321,14 @@
321 #define Jim_GetHashTableSize(ht) ((ht)->size)
322 #define Jim_GetHashTableUsed(ht) ((ht)->used)
323
324
325 typedef struct Jim_Obj {
 
326 char *bytes;
 
327 const struct Jim_ObjType *typePtr;
328 int refCount;
329 int length;
330
331 union {
332
333 jim_wide wideValue;
334
@@ -665,12 +665,10 @@
665
666
667 JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
668 JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
669 JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
 
 
670 JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
671 Jim_Obj *objPtr);
672 JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
673 int *lenPtr);
674 JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr);
@@ -877,10 +875,12 @@
875 JIM_EXPORT void Jim_HistoryShow(void);
876
877
878 JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
879 JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
880 JIM_EXPORT int Jim_CheckSignal(Jim_Interp *interp);
881 #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
882
883
884 JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
885 JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
886
@@ -5671,10 +5671,13 @@
5671 #ifdef JIM_MAINTAINER
5672 #define JIM_DEBUG_COMMAND
5673 #define JIM_DEBUG_PANIC
5674 #endif
5675
5676
5677 #define JIM_INTEGER_SPACE 24
5678
5679 const char *jim_tt_name(int type);
5680
5681 #ifdef JIM_DEBUG_PANIC
5682 static void JimPanicDump(int panic_condition, const char *fmt, ...);
5683 #define JimPanic(X) JimPanicDump X
@@ -5690,10 +5693,11 @@
5693 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
5694 int flags);
5695 static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
5696 static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
5697 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
5698 static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len);
5699 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
5700 const char *prefix, const char *const *tablePtr, const char *name);
5701 static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
5702 static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
5703 static int JimSign(jim_wide w);
@@ -5934,15 +5938,42 @@
5938 }
5939 return n;
5940 }
5941 #endif
5942
5943 static int JimWideToString(char *buf, jim_wide wideValue)
5944 {
5945 int pos = 0;
5946
5947 if (wideValue == 0) {
5948 buf[pos++] = '0';
5949 }
5950 else {
5951 char tmp[JIM_INTEGER_SPACE];
5952 int num = 0;
5953 int i;
5954
5955 if (wideValue < 0) {
5956 buf[pos++] = '-';
5957
5958 i = wideValue % 10;
5959 tmp[num++] = (i > 0) ? (10 - i) : -i;
5960 wideValue /= -10;
5961 }
5962
5963 while (wideValue) {
5964 tmp[num++] = wideValue % 10;
5965 wideValue /= 10;
5966 }
5967
5968 for (i = 0; i < num; i++) {
5969 buf[pos++] = '0' + tmp[num - i - 1];
5970 }
5971 }
5972 buf[pos] = 0;
5973
5974 return pos;
5975 }
5976
5977 static int JimCheckConversion(const char *str, const char *endptr)
5978 {
5979 if (str[0] == '\0' || str == endptr) {
@@ -6229,10 +6260,18 @@
6260 ht->sizemask = 0;
6261 ht->used = 0;
6262 ht->collisions = 0;
6263 }
6264
6265 static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter)
6266 {
6267 iter->ht = ht;
6268 iter->index = -1;
6269 iter->entry = NULL;
6270 iter->nextEntry = NULL;
6271 }
6272
6273
6274 int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
6275 {
6276 JimResetHashTable(ht);
6277 ht->type = type;
@@ -6408,15 +6447,11 @@
6447 }
6448
6449 Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
6450 {
6451 Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
6452 JimInitHashTableIterator(ht, iter);
 
 
 
 
6453 return iter;
6454 }
6455
6456 Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
6457 {
@@ -10500,12 +10535,10 @@
10535 int Jim_GetExitCode(Jim_Interp *interp)
10536 {
10537 return interp->exitCode;
10538 }
10539
 
 
10540 static void UpdateStringOfInt(struct Jim_Obj *objPtr);
10541 static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
10542
10543 static const Jim_ObjType intObjType = {
10544 "int",
@@ -10522,16 +10555,16 @@
10555 UpdateStringOfInt,
10556 JIM_TYPE_NONE,
10557 };
10558
10559
10560 static void UpdateStringOfInt(struct Jim_Obj *objPtr)
10561 {
10562 int len;
10563 char buf[JIM_INTEGER_SPACE + 1];
10564
10565 len = JimWideToString(buf, JimWideValue(objPtr));
10566 objPtr->bytes = Jim_Alloc(len + 1);
10567 memcpy(objPtr->bytes, buf, len + 1);
10568 objPtr->length = len;
10569 }
10570
@@ -10755,11 +10788,11 @@
10788 }
10789
10790 #define JIM_ELESTR_SIMPLE 0
10791 #define JIM_ELESTR_BRACE 1
10792 #define JIM_ELESTR_QUOTE 2
10793 static unsigned char ListElementQuotingType(const char *s, int len)
10794 {
10795 int i, level, blevel, trySimple = 1;
10796
10797
10798 if (len == 0)
@@ -10903,17 +10936,23 @@
10936 return p - q;
10937 }
10938
10939 static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
10940 {
10941 #define STATIC_QUOTING_LEN 32
10942 int i, bufLen, realLength;
10943 const char *strRep;
10944 char *p;
10945 unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
10946
10947
10948 if (objc > STATIC_QUOTING_LEN) {
10949 quotingType = Jim_Alloc(objc);
10950 }
10951 else {
10952 quotingType = staticQuoting;
10953 }
10954 bufLen = 0;
10955 for (i = 0; i < objc; i++) {
10956 int len;
10957
10958 strRep = Jim_GetString(objv[i], &len);
@@ -10975,11 +11014,14 @@
11014 realLength++;
11015 }
11016 }
11017 *p = '\0';
11018 objPtr->length = realLength;
11019
11020 if (quotingType != staticQuoting) {
11021 Jim_Free(quotingType);
11022 }
11023 }
11024
11025 static void UpdateStringOfList(struct Jim_Obj *objPtr)
11026 {
11027 JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
@@ -11000,11 +11042,11 @@
11042 if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) {
11043 Jim_Obj **listObjPtrPtr;
11044 int len;
11045 int i;
11046
11047 listObjPtrPtr = JimDictPairs(objPtr, &len);
11048 for (i = 0; i < len; i++) {
11049 Jim_IncrRefCount(listObjPtrPtr[i]);
11050 }
11051
11052
@@ -11225,14 +11267,22 @@
11267 int requiredLen = currentLen + elemc;
11268 int i;
11269 Jim_Obj **point;
11270
11271 if (requiredLen > listPtr->internalRep.listValue.maxLen) {
11272 if (requiredLen < 2) {
11273
11274 requiredLen = 4;
11275 }
11276 else {
11277 requiredLen *= 2;
11278 }
11279
11280 listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
11281 sizeof(Jim_Obj *) * requiredLen);
11282
11283 listPtr->internalRep.listValue.maxLen = requiredLen;
11284 }
11285 if (idx < 0) {
11286 idx = currentLen;
11287 }
11288 point = listPtr->internalRep.listValue.ele + idx;
@@ -11523,55 +11573,53 @@
11573 }
11574
11575 void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
11576 {
11577 Jim_HashTable *ht, *dupHt;
11578 Jim_HashTableIterator htiter;
11579 Jim_HashEntry *he;
11580
11581
11582 ht = srcPtr->internalRep.ptr;
11583 dupHt = Jim_Alloc(sizeof(*dupHt));
11584 Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
11585 if (ht->size != 0)
11586 Jim_ExpandHashTable(dupHt, ht->size);
11587
11588 JimInitHashTableIterator(ht, &htiter);
11589 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
11590 const Jim_Obj *keyObjPtr = he->key;
11591 Jim_Obj *valObjPtr = he->u.val;
11592
11593 Jim_IncrRefCount((Jim_Obj *)keyObjPtr);
11594 Jim_IncrRefCount(valObjPtr);
11595 Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
11596 }
 
11597
11598 dupPtr->internalRep.ptr = dupHt;
11599 dupPtr->typePtr = &dictObjType;
11600 }
11601
11602 static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len)
11603 {
11604 Jim_HashTable *ht;
11605 Jim_HashTableIterator htiter;
11606 Jim_HashEntry *he;
11607 Jim_Obj **objv;
11608 int i;
11609
11610 ht = dictPtr->internalRep.ptr;
11611
11612
11613 objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
11614 JimInitHashTableIterator(ht, &htiter);
11615 i = 0;
11616 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
11617 objv[i++] = (Jim_Obj *)he->key;
11618 objv[i++] = he->u.val;
11619 }
11620 *len = i;
 
11621 return objv;
11622 }
11623
11624 static void UpdateStringOfDict(struct Jim_Obj *objPtr)
11625 {
@@ -12089,14 +12137,15 @@
12137
12138
12139 typedef struct Jim_ExprOperator
12140 {
12141 const char *name;
 
 
12142 int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
12143 unsigned char precedence;
12144 unsigned char arity;
12145 unsigned char lazy;
12146 unsigned char namelen;
12147 } Jim_ExprOperator;
12148
12149 static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
12150 {
12151 Jim_IncrRefCount(obj);
@@ -12774,93 +12823,96 @@
12823 LAZY_OP,
12824 LAZY_LEFT,
12825 LAZY_RIGHT
12826 };
12827
12828 #define OPRINIT(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1}
12829
12830 static const struct Jim_ExprOperator Jim_ExprOperators[] = {
12831 OPRINIT("*", 110, 2, JimExprOpBin, LAZY_NONE),
12832 OPRINIT("/", 110, 2, JimExprOpBin, LAZY_NONE),
12833 OPRINIT("%", 110, 2, JimExprOpIntBin, LAZY_NONE),
12834
12835 OPRINIT("-", 100, 2, JimExprOpBin, LAZY_NONE),
12836 OPRINIT("+", 100, 2, JimExprOpBin, LAZY_NONE),
12837
12838 OPRINIT("<<", 90, 2, JimExprOpIntBin, LAZY_NONE),
12839 OPRINIT(">>", 90, 2, JimExprOpIntBin, LAZY_NONE),
12840
12841 OPRINIT("<<<", 90, 2, JimExprOpIntBin, LAZY_NONE),
12842 OPRINIT(">>>", 90, 2, JimExprOpIntBin, LAZY_NONE),
12843
12844 OPRINIT("<", 80, 2, JimExprOpBin, LAZY_NONE),
12845 OPRINIT(">", 80, 2, JimExprOpBin, LAZY_NONE),
12846 OPRINIT("<=", 80, 2, JimExprOpBin, LAZY_NONE),
12847 OPRINIT(">=", 80, 2, JimExprOpBin, LAZY_NONE),
12848
12849 OPRINIT("==", 70, 2, JimExprOpBin, LAZY_NONE),
12850 OPRINIT("!=", 70, 2, JimExprOpBin, LAZY_NONE),
12851
12852 OPRINIT("&", 50, 2, JimExprOpIntBin, LAZY_NONE),
12853 OPRINIT("^", 49, 2, JimExprOpIntBin, LAZY_NONE),
12854 OPRINIT("|", 48, 2, JimExprOpIntBin, LAZY_NONE),
12855
12856 OPRINIT("&&", 10, 2, NULL, LAZY_OP),
12857 OPRINIT(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT),
12858 OPRINIT(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT),
12859
12860 OPRINIT("||", 9, 2, NULL, LAZY_OP),
12861 OPRINIT(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT),
12862 OPRINIT(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT),
12863
12864 OPRINIT("?", 5, 2, JimExprOpNull, LAZY_OP),
12865 OPRINIT(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT),
12866 OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
12867
12868 OPRINIT(":", 5, 2, JimExprOpNull, LAZY_OP),
12869 OPRINIT(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT),
12870 OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
12871
12872 OPRINIT("**", 250, 2, JimExprOpBin, LAZY_NONE),
12873
12874 OPRINIT("eq", 60, 2, JimExprOpStrBin, LAZY_NONE),
12875 OPRINIT("ne", 60, 2, JimExprOpStrBin, LAZY_NONE),
12876
12877 OPRINIT("in", 55, 2, JimExprOpStrBin, LAZY_NONE),
12878 OPRINIT("ni", 55, 2, JimExprOpStrBin, LAZY_NONE),
12879
12880 OPRINIT("!", 150, 1, JimExprOpNumUnary, LAZY_NONE),
12881 OPRINIT("~", 150, 1, JimExprOpIntUnary, LAZY_NONE),
12882 OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE),
12883 OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE),
12884
12885
12886
12887 OPRINIT("int", 200, 1, JimExprOpNumUnary, LAZY_NONE),
12888 OPRINIT("abs", 200, 1, JimExprOpNumUnary, LAZY_NONE),
12889 OPRINIT("double", 200, 1, JimExprOpNumUnary, LAZY_NONE),
12890 OPRINIT("round", 200, 1, JimExprOpNumUnary, LAZY_NONE),
12891 OPRINIT("rand", 200, 0, JimExprOpNone, LAZY_NONE),
12892 OPRINIT("srand", 200, 1, JimExprOpIntUnary, LAZY_NONE),
12893
12894 #ifdef JIM_MATH_FUNCTIONS
12895 OPRINIT("sin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12896 OPRINIT("cos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12897 OPRINIT("tan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12898 OPRINIT("asin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12899 OPRINIT("acos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12900 OPRINIT("atan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12901 OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12902 OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12903 OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12904 OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12905 OPRINIT("floor", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12906 OPRINIT("exp", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12907 OPRINIT("log", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12908 OPRINIT("log10", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12909 OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
12910 OPRINIT("pow", 200, 2, JimExprOpBin, LAZY_NONE),
12911 #endif
12912 };
12913 #undef OPRINIT
12914
12915 #define JIM_EXPR_OPERATORS_NUM \
12916 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
12917
12918 static int JimParseExpression(struct JimParserCtx *pc)
@@ -13026,20 +13078,18 @@
13078 int i;
13079 int bestIdx = -1, bestLen = 0;
13080
13081
13082 for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
13083 const char * const opname = Jim_ExprOperators[i].name;
13084 const int oplen = Jim_ExprOperators[i].namelen;
13085
13086 if (opname == NULL || opname[0] != pc->p[0]) {
 
13087 continue;
13088 }
 
13089
13090 if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) {
13091 bestIdx = i + JIM_TT_EXPR_OP;
13092 bestLen = oplen;
13093 }
13094 }
13095 if (bestIdx == -1) {
@@ -13111,12 +13161,12 @@
13161 };
13162
13163
13164 typedef struct ExprByteCode
13165 {
 
13166 ScriptToken *token;
13167 int len;
13168 int inUse;
13169 } ExprByteCode;
13170
13171 static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
13172 {
@@ -13855,16 +13905,16 @@
13905
13906
13907
13908 typedef struct ScanFmtPartDescr
13909 {
13910 char *arg;
13911 char *prefix;
13912 size_t width;
13913 int pos;
13914 char type;
13915 char modifier;
13916 } ScanFmtPartDescr;
13917
13918
13919 typedef struct ScanFmtStringObj
13920 {
@@ -14871,12 +14921,12 @@
14921 }
14922
14923 if (retcode == JIM_OK && argc) {
14924
14925 retcode = JimInvokeCommand(interp, argc, argv);
14926
14927 if (Jim_CheckSignal(interp)) {
14928 retcode = JIM_SIGNAL;
14929 }
14930 }
14931
14932
@@ -15446,17 +15496,17 @@
15496 if (he) {
15497 callback(interp, listObjPtr, he, type);
15498 }
15499 }
15500 else {
15501 Jim_HashTableIterator htiter;
15502 JimInitHashTableIterator(ht, &htiter);
15503 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
15504 if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), he->key, 0)) {
15505 callback(interp, listObjPtr, he, type);
15506 }
15507 }
 
15508 }
15509 return listObjPtr;
15510 }
15511
15512
@@ -17795,11 +17845,11 @@
17845 if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
17846 sig++;
17847 }
17848
17849 interp->signal_level += sig;
17850 if (Jim_CheckSignal(interp)) {
17851
17852 exitCode = JIM_SIGNAL;
17853 }
17854 else {
17855 exitCode = Jim_EvalObj(interp, argv[0]);
@@ -17951,25 +18001,24 @@
18001
18002
18003 static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18004 {
18005 Jim_Obj *listObjPtr;
18006 Jim_HashTableIterator htiter;
18007 Jim_HashEntry *he;
18008
18009 listObjPtr = Jim_NewListObj(interp, NULL, 0);
18010
18011 JimInitHashTableIterator(&interp->references, &htiter);
18012 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18013 char buf[JIM_REFERENCE_SPACE + 1];
18014 Jim_Reference *refPtr = he->u.val;
18015 const unsigned long *refId = he->key;
18016
18017 JimFormatReference(buf, refPtr, *refId);
18018 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1));
18019 }
 
18020 Jim_SetResult(interp, listObjPtr);
18021 return JIM_OK;
18022 }
18023 #endif
18024
@@ -18005,17 +18054,17 @@
18054 {
18055 Jim_HashEntry *he;
18056 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
18057
18058
18059 Jim_HashTableIterator htiter;
18060 JimInitHashTableIterator(ht, &htiter);
18061 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18062 if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) {
18063 callback(interp, listObjPtr, he, type);
18064 }
18065 }
 
18066
18067 return listObjPtr;
18068 }
18069
18070
18071
+1 -6
--- src/add.c
+++ src/add.c
@@ -20,16 +20,11 @@
2020
*/
2121
#include "config.h"
2222
#include "add.h"
2323
#include <assert.h>
2424
#include <dirent.h>
25
-#ifdef __CYGWIN__
26
- __declspec(dllimport) extern __stdcall int RegOpenKeyExW(void *, void *,
27
- int, int, void *);
28
- __declspec(dllimport) extern __stdcall int RegQueryValueExW(void *, void *,
29
- int, void *, void *, void *);
30
-#endif
25
+#include "cygsup.h"
3126
3227
/*
3328
** This routine returns the names of files in a working checkout that
3429
** are created by Fossil itself, and hence should not be added, deleted,
3530
** or merge, and should be omitted from "clean" and "extra" lists.
3631
--- src/add.c
+++ src/add.c
@@ -20,16 +20,11 @@
20 */
21 #include "config.h"
22 #include "add.h"
23 #include <assert.h>
24 #include <dirent.h>
25 #ifdef __CYGWIN__
26 __declspec(dllimport) extern __stdcall int RegOpenKeyExW(void *, void *,
27 int, int, void *);
28 __declspec(dllimport) extern __stdcall int RegQueryValueExW(void *, void *,
29 int, void *, void *, void *);
30 #endif
31
32 /*
33 ** This routine returns the names of files in a working checkout that
34 ** are created by Fossil itself, and hence should not be added, deleted,
35 ** or merge, and should be omitted from "clean" and "extra" lists.
36
--- src/add.c
+++ src/add.c
@@ -20,16 +20,11 @@
20 */
21 #include "config.h"
22 #include "add.h"
23 #include <assert.h>
24 #include <dirent.h>
25 #include "cygsup.h"
 
 
 
 
 
26
27 /*
28 ** This routine returns the names of files in a working checkout that
29 ** are created by Fossil itself, and hence should not be added, deleted,
30 ** or merge, and should be omitted from "clean" and "extra" lists.
31
--- src/allrepo.c
+++ src/allrepo.c
@@ -100,10 +100,13 @@
100100
**
101101
** Repositories are automatically added to the set of known repositories
102102
** when one of the following commands are run against the repository: clone,
103103
** info, pull, push, or sync. Even previously ignored repositories are
104104
** added back to the list of repositories by these commands.
105
+**
106
+** Options:
107
+** --dontstop Continue with other repositories even after an error
105108
*/
106109
void all_cmd(void){
107110
int n;
108111
Stmt q;
109112
const char *zCmd;
110113
--- src/allrepo.c
+++ src/allrepo.c
@@ -100,10 +100,13 @@
100 **
101 ** Repositories are automatically added to the set of known repositories
102 ** when one of the following commands are run against the repository: clone,
103 ** info, pull, push, or sync. Even previously ignored repositories are
104 ** added back to the list of repositories by these commands.
 
 
 
105 */
106 void all_cmd(void){
107 int n;
108 Stmt q;
109 const char *zCmd;
110
--- src/allrepo.c
+++ src/allrepo.c
@@ -100,10 +100,13 @@
100 **
101 ** Repositories are automatically added to the set of known repositories
102 ** when one of the following commands are run against the repository: clone,
103 ** info, pull, push, or sync. Even previously ignored repositories are
104 ** added back to the list of repositories by these commands.
105 **
106 ** Options:
107 ** --dontstop Continue with other repositories even after an error
108 */
109 void all_cmd(void){
110 int n;
111 Stmt q;
112 const char *zCmd;
113
+1 -1
--- src/attach.c
+++ src/attach.c
@@ -384,11 +384,11 @@
384384
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
385385
g.zTop, zUuid);
386386
}
387387
}
388388
#endif
389
- pAttach = manifest_get(rid, CFTYPE_ATTACHMENT);
389
+ pAttach = manifest_get(rid, CFTYPE_ATTACHMENT, 0);
390390
if( pAttach==0 ) fossil_redirect_home();
391391
zTarget = pAttach->zAttachTarget;
392392
zSrc = pAttach->zAttachSrc;
393393
ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%s'", zSrc);
394394
zName = pAttach->zAttachName;
395395
--- src/attach.c
+++ src/attach.c
@@ -384,11 +384,11 @@
384 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
385 g.zTop, zUuid);
386 }
387 }
388 #endif
389 pAttach = manifest_get(rid, CFTYPE_ATTACHMENT);
390 if( pAttach==0 ) fossil_redirect_home();
391 zTarget = pAttach->zAttachTarget;
392 zSrc = pAttach->zAttachSrc;
393 ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%s'", zSrc);
394 zName = pAttach->zAttachName;
395
--- src/attach.c
+++ src/attach.c
@@ -384,11 +384,11 @@
384 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
385 g.zTop, zUuid);
386 }
387 }
388 #endif
389 pAttach = manifest_get(rid, CFTYPE_ATTACHMENT, 0);
390 if( pAttach==0 ) fossil_redirect_home();
391 zTarget = pAttach->zAttachTarget;
392 zSrc = pAttach->zAttachSrc;
393 ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%s'", zSrc);
394 zName = pAttach->zAttachName;
395
+1 -1
--- src/branch.c
+++ src/branch.c
@@ -73,11 +73,11 @@
7373
rootid = name_to_typed_rid(g.argv[4], "ci");
7474
if( rootid==0 ){
7575
fossil_fatal("unable to locate check-in off of which to branch");
7676
}
7777
78
- pParent = manifest_get(rootid, CFTYPE_MANIFEST);
78
+ pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
7979
if( pParent==0 ){
8080
fossil_fatal("%s is not a valid check-in", g.argv[4]);
8181
}
8282
8383
/* Create a manifest for the new branch */
8484
--- src/branch.c
+++ src/branch.c
@@ -73,11 +73,11 @@
73 rootid = name_to_typed_rid(g.argv[4], "ci");
74 if( rootid==0 ){
75 fossil_fatal("unable to locate check-in off of which to branch");
76 }
77
78 pParent = manifest_get(rootid, CFTYPE_MANIFEST);
79 if( pParent==0 ){
80 fossil_fatal("%s is not a valid check-in", g.argv[4]);
81 }
82
83 /* Create a manifest for the new branch */
84
--- src/branch.c
+++ src/branch.c
@@ -73,11 +73,11 @@
73 rootid = name_to_typed_rid(g.argv[4], "ci");
74 if( rootid==0 ){
75 fossil_fatal("unable to locate check-in off of which to branch");
76 }
77
78 pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
79 if( pParent==0 ){
80 fossil_fatal("%s is not a valid check-in", g.argv[4]);
81 }
82
83 /* Create a manifest for the new branch */
84
+1 -1
--- src/branch.c
+++ src/branch.c
@@ -73,11 +73,11 @@
7373
rootid = name_to_typed_rid(g.argv[4], "ci");
7474
if( rootid==0 ){
7575
fossil_fatal("unable to locate check-in off of which to branch");
7676
}
7777
78
- pParent = manifest_get(rootid, CFTYPE_MANIFEST);
78
+ pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
7979
if( pParent==0 ){
8080
fossil_fatal("%s is not a valid check-in", g.argv[4]);
8181
}
8282
8383
/* Create a manifest for the new branch */
8484
--- src/branch.c
+++ src/branch.c
@@ -73,11 +73,11 @@
73 rootid = name_to_typed_rid(g.argv[4], "ci");
74 if( rootid==0 ){
75 fossil_fatal("unable to locate check-in off of which to branch");
76 }
77
78 pParent = manifest_get(rootid, CFTYPE_MANIFEST);
79 if( pParent==0 ){
80 fossil_fatal("%s is not a valid check-in", g.argv[4]);
81 }
82
83 /* Create a manifest for the new branch */
84
--- src/branch.c
+++ src/branch.c
@@ -73,11 +73,11 @@
73 rootid = name_to_typed_rid(g.argv[4], "ci");
74 if( rootid==0 ){
75 fossil_fatal("unable to locate check-in off of which to branch");
76 }
77
78 pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
79 if( pParent==0 ){
80 fossil_fatal("%s is not a valid check-in", g.argv[4]);
81 }
82
83 /* Create a manifest for the new branch */
84
+1 -1
--- src/browse.c
+++ src/browse.c
@@ -331,11 +331,11 @@
331331
" mtime DATETIME,"
332332
" pathname TEXT"
333333
");"
334334
"CREATE INDEX fileage_fid ON fileage(fid);"
335335
);
336
- pManifest = manifest_get(vid, CFTYPE_MANIFEST);
336
+ pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0);
337337
if( pManifest==0 ) return 1;
338338
manifest_file_rewind(pManifest);
339339
db_prepare(&ins,
340340
"INSERT INTO temp.fileage(fid, pathname)"
341341
" SELECT rid, :path FROM blob WHERE uuid=:uuid"
342342
--- src/browse.c
+++ src/browse.c
@@ -331,11 +331,11 @@
331 " mtime DATETIME,"
332 " pathname TEXT"
333 ");"
334 "CREATE INDEX fileage_fid ON fileage(fid);"
335 );
336 pManifest = manifest_get(vid, CFTYPE_MANIFEST);
337 if( pManifest==0 ) return 1;
338 manifest_file_rewind(pManifest);
339 db_prepare(&ins,
340 "INSERT INTO temp.fileage(fid, pathname)"
341 " SELECT rid, :path FROM blob WHERE uuid=:uuid"
342
--- src/browse.c
+++ src/browse.c
@@ -331,11 +331,11 @@
331 " mtime DATETIME,"
332 " pathname TEXT"
333 ");"
334 "CREATE INDEX fileage_fid ON fileage(fid);"
335 );
336 pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0);
337 if( pManifest==0 ) return 1;
338 manifest_file_rewind(pManifest);
339 db_prepare(&ins,
340 "INSERT INTO temp.fileage(fid, pathname)"
341 " SELECT rid, :path FROM blob WHERE uuid=:uuid"
342
+1 -1
--- src/captcha.c
+++ src/captcha.c
@@ -17,12 +17,12 @@
1717
**
1818
** This file contains code to a simple text-based CAPTCHA. Though easily
1919
** defeated by a sophisticated attacker, this CAPTCHA does at least make
2020
** scripting attacks more difficult.
2121
*/
22
-#include <assert.h>
2322
#include "config.h"
23
+#include <assert.h>
2424
#include "captcha.h"
2525
2626
#if INTERFACE
2727
#define CAPTCHA 3 /* Which captcha rendering to use */
2828
#endif
2929
--- src/captcha.c
+++ src/captcha.c
@@ -17,12 +17,12 @@
17 **
18 ** This file contains code to a simple text-based CAPTCHA. Though easily
19 ** defeated by a sophisticated attacker, this CAPTCHA does at least make
20 ** scripting attacks more difficult.
21 */
22 #include <assert.h>
23 #include "config.h"
 
24 #include "captcha.h"
25
26 #if INTERFACE
27 #define CAPTCHA 3 /* Which captcha rendering to use */
28 #endif
29
--- src/captcha.c
+++ src/captcha.c
@@ -17,12 +17,12 @@
17 **
18 ** This file contains code to a simple text-based CAPTCHA. Though easily
19 ** defeated by a sophisticated attacker, this CAPTCHA does at least make
20 ** scripting attacks more difficult.
21 */
 
22 #include "config.h"
23 #include <assert.h>
24 #include "captcha.h"
25
26 #if INTERFACE
27 #define CAPTCHA 3 /* Which captcha rendering to use */
28 #endif
29
+251 -6
--- src/cgi.c
+++ src/cgi.c
@@ -40,15 +40,11 @@
4040
#include <time.h>
4141
#include <stdio.h>
4242
#include <stdlib.h>
4343
#include <unistd.h>
4444
#include "cgi.h"
45
-#ifdef __CYGWIN__
46
- __declspec(dllimport) extern __stdcall int ShellExecuteW(void *, void *,
47
- void *, void *, void *, int);
48
- __declspec(dllimport) extern __stdcall size_t wcslen(const wchar_t *);
49
-#endif
45
+#include "cygsup.h"
5046
5147
#if INTERFACE
5248
/*
5349
** Shortcuts for cgi_parameter. P("x") returns the value of query parameter
5450
** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y")
@@ -64,10 +60,17 @@
6460
** Destinations for output text.
6561
*/
6662
#define CGI_HEADER 0
6763
#define CGI_BODY 1
6864
65
+/*
66
+** Flags for SSH HTTP clients
67
+*/
68
+#define CGI_SSH_CLIENT 0x0001 /* Client is SSH */
69
+#define CGI_SSH_COMPAT 0x0002 /* Compat for old SSH transport */
70
+#define CGI_SSH_FOSSIL 0x0004 /* Use new Fossil SSH transport */
71
+
6972
#endif /* INTERFACE */
7073
7174
/*
7275
** The HTTP reply is generated in two pieces: the header and the body.
7376
** These pieces are generated separately because they are not necessary
@@ -1306,10 +1309,234 @@
13061309
}
13071310
}
13081311
cgi_init();
13091312
cgi_trace(0);
13101313
}
1314
+
1315
+/*
1316
+** This routine handles a single HTTP request from an SSH client which is
1317
+** coming in on g.httpIn and which replies on g.httpOut
1318
+**
1319
+** Once all the setup is finished, this procedure returns
1320
+** and subsequent code handles the actual generation of the webpage.
1321
+**
1322
+** It is called in a loop so some variables will need to be replaced
1323
+*/
1324
+void cgi_handle_ssh_http_request(const char *zIpAddr){
1325
+ static int nCycles = 0;
1326
+ static char *zCmd = 0;
1327
+ char *z, *zToken;
1328
+ const char *zType;
1329
+ int i, content_length;
1330
+ char zLine[2000]; /* A single line of input. */
1331
+
1332
+ if( zIpAddr ){
1333
+ if( nCycles==0 ){
1334
+ cgi_setenv("REMOTE_ADDR", zIpAddr);
1335
+ g.zIpAddr = mprintf("%s", zIpAddr);
1336
+ }
1337
+ }else{
1338
+ fossil_panic("missing SSH IP address");
1339
+ }
1340
+ if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1341
+ malformed_request("missing HTTP header");
1342
+ }
1343
+ cgi_trace(zLine);
1344
+ zToken = extract_token(zLine, &z);
1345
+ if( zToken==0 ){
1346
+ malformed_request("malformed HTTP header");
1347
+ }
1348
+
1349
+ if( fossil_strcmp(zToken, "echo")==0 ){
1350
+ /* start looking for probes to complete transport_open */
1351
+ zCmd = cgi_handle_ssh_probes(zLine, sizeof(zLine), z, zToken);
1352
+ if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1353
+ malformed_request("missing HTTP header");
1354
+ }
1355
+ cgi_trace(zLine);
1356
+ zToken = extract_token(zLine, &z);
1357
+ if( zToken==0 ){
1358
+ malformed_request("malformed HTTP header");
1359
+ }
1360
+ }else if( zToken && strlen(zToken)==0 && zCmd ){
1361
+ /* transport_flip request and continued transport_open */
1362
+ cgi_handle_ssh_transport(zCmd);
1363
+ if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1364
+ malformed_request("missing HTTP header");
1365
+ }
1366
+ cgi_trace(zLine);
1367
+ zToken = extract_token(zLine, &z);
1368
+ if( zToken==0 ){
1369
+ malformed_request("malformed HTTP header");
1370
+ }
1371
+ }
1372
+
1373
+ if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
1374
+ && fossil_strcmp(zToken,"HEAD")!=0 ){
1375
+ malformed_request("unsupported HTTP method");
1376
+ }
1377
+
1378
+ if( nCycles==0 ){
1379
+ cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
1380
+ cgi_setenv("REQUEST_METHOD",zToken);
1381
+ }
1382
+
1383
+ zToken = extract_token(z, &z);
1384
+ if( zToken==0 ){
1385
+ malformed_request("malformed URL in HTTP header");
1386
+ }
1387
+ if( nCycles==0 ){
1388
+ cgi_setenv("REQUEST_URI", zToken);
1389
+ cgi_setenv("SCRIPT_NAME", "");
1390
+ }
1391
+
1392
+ for(i=0; zToken[i] && zToken[i]!='?'; i++){}
1393
+ if( zToken[i] ) zToken[i++] = 0;
1394
+ if( nCycles==0 ){
1395
+ cgi_setenv("PATH_INFO", zToken);
1396
+ }else{
1397
+ cgi_replace_parameter("PATH_INFO", mprintf("%s",zToken));
1398
+ }
1399
+
1400
+ /* Get all the optional fields that follow the first line.
1401
+ */
1402
+ while( fgets(zLine,sizeof(zLine),g.httpIn) ){
1403
+ char *zFieldName;
1404
+ char *zVal;
1405
+
1406
+ cgi_trace(zLine);
1407
+ zFieldName = extract_token(zLine,&zVal);
1408
+ if( zFieldName==0 || *zFieldName==0 ) break;
1409
+ while( fossil_isspace(*zVal) ){ zVal++; }
1410
+ i = strlen(zVal);
1411
+ while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
1412
+ zVal[i] = 0;
1413
+ for(i=0; zFieldName[i]; i++){
1414
+ zFieldName[i] = fossil_tolower(zFieldName[i]);
1415
+ }
1416
+ if( fossil_strcmp(zFieldName,"content-length:")==0 ){
1417
+ content_length = atoi(zVal);
1418
+ }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){
1419
+ g.zContentType = zType = mprintf("%s", zVal);
1420
+ }else if( fossil_strcmp(zFieldName,"host:")==0 ){
1421
+ if( nCycles==0 ){
1422
+ cgi_setenv("HTTP_HOST", zVal);
1423
+ }
1424
+ }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){
1425
+ if( nCycles==0 ){
1426
+ cgi_setenv("HTTP_USER_AGENT", zVal);
1427
+ }
1428
+ }else if( fossil_strcmp(zFieldName,"x-fossil-transport:")==0 ){
1429
+ if( fossil_strnicmp(zVal, "ssh", 3)==0 ){
1430
+ if( nCycles==0 ){
1431
+ g.fSshClient |= CGI_SSH_FOSSIL;
1432
+ g.fullHttpReply = 0;
1433
+ }
1434
+ }
1435
+ }
1436
+ }
1437
+
1438
+ if( nCycles==0 ){
1439
+ if( ! ( g.fSshClient & CGI_SSH_FOSSIL ) ){
1440
+ /* did not find new fossil ssh transport */
1441
+ g.fSshClient &= ~CGI_SSH_CLIENT;
1442
+ g.fullHttpReply = 1;
1443
+ cgi_replace_parameter("REMOTE_ADDR", "127.0.0.1");
1444
+ }
1445
+ }
1446
+
1447
+ cgi_reset_content();
1448
+ cgi_destination(CGI_BODY);
1449
+
1450
+ if( content_length>0 && zType ){
1451
+ blob_zero(&g.cgiIn);
1452
+ if( fossil_strcmp(zType, "application/x-fossil")==0 ){
1453
+ blob_read_from_channel(&g.cgiIn, g.httpIn, content_length);
1454
+ blob_uncompress(&g.cgiIn, &g.cgiIn);
1455
+ }else if( fossil_strcmp(zType, "application/x-fossil-debug")==0 ){
1456
+ blob_read_from_channel(&g.cgiIn, g.httpIn, content_length);
1457
+ }else if( fossil_strcmp(zType, "application/x-fossil-uncompressed")==0 ){
1458
+ blob_read_from_channel(&g.cgiIn, g.httpIn, content_length);
1459
+ }
1460
+ }
1461
+ cgi_trace(0);
1462
+ nCycles++;
1463
+}
1464
+
1465
+/*
1466
+** This routine handles the old fossil SSH probes
1467
+*/
1468
+char *cgi_handle_ssh_probes(char *zLine, int zSize, char *z, char *zToken){
1469
+ /* Start looking for probes */
1470
+ while( fossil_strcmp(zToken, "echo")==0 ){
1471
+ zToken = extract_token(z, &z);
1472
+ if( zToken==0 ){
1473
+ malformed_request("malformed probe");
1474
+ }
1475
+ if( fossil_strncmp(zToken, "test", 4)==0 ||
1476
+ fossil_strncmp(zToken, "probe-", 6)==0 ){
1477
+ fprintf(g.httpOut, "%s\n", zToken);
1478
+ fflush(g.httpOut);
1479
+ }else{
1480
+ malformed_request("malformed probe");
1481
+ }
1482
+ if( fgets(zLine, zSize, g.httpIn)==0 ){
1483
+ malformed_request("malformed probe");
1484
+ }
1485
+ cgi_trace(zLine);
1486
+ zToken = extract_token(zLine, &z);
1487
+ if( zToken==0 ){
1488
+ malformed_request("malformed probe");
1489
+ }
1490
+ }
1491
+
1492
+ /* Got all probes now first transport_open is completed
1493
+ ** so return the command that was requested
1494
+ */
1495
+ g.fSshClient |= CGI_SSH_COMPAT;
1496
+ return mprintf("%s", zToken);
1497
+}
1498
+
1499
+/*
1500
+** This routine handles the old fossil SSH transport_flip
1501
+** and transport_open communications if detected.
1502
+*/
1503
+void cgi_handle_ssh_transport(const char *zCmd){
1504
+ char *z, *zToken;
1505
+ char zLine[2000]; /* A single line of input. */
1506
+
1507
+ /* look for second newline of transport_flip */
1508
+ if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1509
+ malformed_request("incorrect transport_flip");
1510
+ }
1511
+ cgi_trace(zLine);
1512
+ zToken = extract_token(zLine, &z);
1513
+ if( zToken && strlen(zToken)==0 ){
1514
+ /* look for path to fossil */
1515
+ if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1516
+ if ( zCmd==0 ){
1517
+ malformed_request("missing fossil command");
1518
+ }else{
1519
+ /* no new command so exit */
1520
+ fossil_exit(0);
1521
+ }
1522
+ }
1523
+ cgi_trace(zLine);
1524
+ zToken = extract_token(zLine, &z);
1525
+ if( zToken==0 ){
1526
+ malformed_request("malformed fossil command");
1527
+ }
1528
+ /* see if we've seen the command */
1529
+ if( zCmd && zCmd[0] && fossil_strcmp(zToken, zCmd)==0 ){
1530
+ return;
1531
+ }else{
1532
+ malformed_request("transport_open failed");
1533
+ }
1534
+ }else{
1535
+ malformed_request("transport_flip failed");
1536
+ }
1537
+}
13111538
13121539
/*
13131540
** This routine handles a single SCGI request which is coming in on
13141541
** g.httpIn and which replies on g.httpOut
13151542
**
@@ -1445,11 +1672,11 @@
14451672
#if defined(__CYGWIN__)
14461673
/* On Cygwin, we can do better than "echo" */
14471674
if( memcmp(zBrowser, "echo ", 5)==0 ){
14481675
wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5);
14491676
wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */
1450
- if( ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){
1677
+ if( (size_t)ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){
14511678
fossil_warning("cannot start browser\n");
14521679
}
14531680
}else
14541681
#endif
14551682
if( system(zBrowser)<0 ){
@@ -1604,5 +1831,23 @@
16041831
cgi_set_status(304,"Not Modified");
16051832
cgi_reset_content();
16061833
cgi_reply();
16071834
fossil_exit(0);
16081835
}
1836
+
1837
+/*
1838
+** Check to see if the remote client is SSH and return
1839
+** its IP or return default
1840
+*/
1841
+const char *cgi_ssh_remote_addr(const char *zDefault){
1842
+ char *zIndex;
1843
+ const char *zSshConn = fossil_getenv("SSH_CONNECTION");
1844
+
1845
+ if( zSshConn && zSshConn[0] ){
1846
+ char *zSshClient = mprintf("%s",zSshConn);
1847
+ if( (zIndex = strchr(zSshClient,' '))!=0 ){
1848
+ zSshClient[zIndex-zSshClient] = '\0';
1849
+ return zSshClient;
1850
+ }
1851
+ }
1852
+ return zDefault;
1853
+}
16091854
--- src/cgi.c
+++ src/cgi.c
@@ -40,15 +40,11 @@
40 #include <time.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include "cgi.h"
45 #ifdef __CYGWIN__
46 __declspec(dllimport) extern __stdcall int ShellExecuteW(void *, void *,
47 void *, void *, void *, int);
48 __declspec(dllimport) extern __stdcall size_t wcslen(const wchar_t *);
49 #endif
50
51 #if INTERFACE
52 /*
53 ** Shortcuts for cgi_parameter. P("x") returns the value of query parameter
54 ** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y")
@@ -64,10 +60,17 @@
64 ** Destinations for output text.
65 */
66 #define CGI_HEADER 0
67 #define CGI_BODY 1
68
 
 
 
 
 
 
 
69 #endif /* INTERFACE */
70
71 /*
72 ** The HTTP reply is generated in two pieces: the header and the body.
73 ** These pieces are generated separately because they are not necessary
@@ -1306,10 +1309,234 @@
1306 }
1307 }
1308 cgi_init();
1309 cgi_trace(0);
1310 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1311
1312 /*
1313 ** This routine handles a single SCGI request which is coming in on
1314 ** g.httpIn and which replies on g.httpOut
1315 **
@@ -1445,11 +1672,11 @@
1445 #if defined(__CYGWIN__)
1446 /* On Cygwin, we can do better than "echo" */
1447 if( memcmp(zBrowser, "echo ", 5)==0 ){
1448 wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5);
1449 wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */
1450 if( ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){
1451 fossil_warning("cannot start browser\n");
1452 }
1453 }else
1454 #endif
1455 if( system(zBrowser)<0 ){
@@ -1604,5 +1831,23 @@
1604 cgi_set_status(304,"Not Modified");
1605 cgi_reset_content();
1606 cgi_reply();
1607 fossil_exit(0);
1608 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1609
--- src/cgi.c
+++ src/cgi.c
@@ -40,15 +40,11 @@
40 #include <time.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include "cgi.h"
45 #include "cygsup.h"
 
 
 
 
46
47 #if INTERFACE
48 /*
49 ** Shortcuts for cgi_parameter. P("x") returns the value of query parameter
50 ** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y")
@@ -64,10 +60,17 @@
60 ** Destinations for output text.
61 */
62 #define CGI_HEADER 0
63 #define CGI_BODY 1
64
65 /*
66 ** Flags for SSH HTTP clients
67 */
68 #define CGI_SSH_CLIENT 0x0001 /* Client is SSH */
69 #define CGI_SSH_COMPAT 0x0002 /* Compat for old SSH transport */
70 #define CGI_SSH_FOSSIL 0x0004 /* Use new Fossil SSH transport */
71
72 #endif /* INTERFACE */
73
74 /*
75 ** The HTTP reply is generated in two pieces: the header and the body.
76 ** These pieces are generated separately because they are not necessary
@@ -1306,10 +1309,234 @@
1309 }
1310 }
1311 cgi_init();
1312 cgi_trace(0);
1313 }
1314
1315 /*
1316 ** This routine handles a single HTTP request from an SSH client which is
1317 ** coming in on g.httpIn and which replies on g.httpOut
1318 **
1319 ** Once all the setup is finished, this procedure returns
1320 ** and subsequent code handles the actual generation of the webpage.
1321 **
1322 ** It is called in a loop so some variables will need to be replaced
1323 */
1324 void cgi_handle_ssh_http_request(const char *zIpAddr){
1325 static int nCycles = 0;
1326 static char *zCmd = 0;
1327 char *z, *zToken;
1328 const char *zType;
1329 int i, content_length;
1330 char zLine[2000]; /* A single line of input. */
1331
1332 if( zIpAddr ){
1333 if( nCycles==0 ){
1334 cgi_setenv("REMOTE_ADDR", zIpAddr);
1335 g.zIpAddr = mprintf("%s", zIpAddr);
1336 }
1337 }else{
1338 fossil_panic("missing SSH IP address");
1339 }
1340 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1341 malformed_request("missing HTTP header");
1342 }
1343 cgi_trace(zLine);
1344 zToken = extract_token(zLine, &z);
1345 if( zToken==0 ){
1346 malformed_request("malformed HTTP header");
1347 }
1348
1349 if( fossil_strcmp(zToken, "echo")==0 ){
1350 /* start looking for probes to complete transport_open */
1351 zCmd = cgi_handle_ssh_probes(zLine, sizeof(zLine), z, zToken);
1352 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1353 malformed_request("missing HTTP header");
1354 }
1355 cgi_trace(zLine);
1356 zToken = extract_token(zLine, &z);
1357 if( zToken==0 ){
1358 malformed_request("malformed HTTP header");
1359 }
1360 }else if( zToken && strlen(zToken)==0 && zCmd ){
1361 /* transport_flip request and continued transport_open */
1362 cgi_handle_ssh_transport(zCmd);
1363 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1364 malformed_request("missing HTTP header");
1365 }
1366 cgi_trace(zLine);
1367 zToken = extract_token(zLine, &z);
1368 if( zToken==0 ){
1369 malformed_request("malformed HTTP header");
1370 }
1371 }
1372
1373 if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
1374 && fossil_strcmp(zToken,"HEAD")!=0 ){
1375 malformed_request("unsupported HTTP method");
1376 }
1377
1378 if( nCycles==0 ){
1379 cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
1380 cgi_setenv("REQUEST_METHOD",zToken);
1381 }
1382
1383 zToken = extract_token(z, &z);
1384 if( zToken==0 ){
1385 malformed_request("malformed URL in HTTP header");
1386 }
1387 if( nCycles==0 ){
1388 cgi_setenv("REQUEST_URI", zToken);
1389 cgi_setenv("SCRIPT_NAME", "");
1390 }
1391
1392 for(i=0; zToken[i] && zToken[i]!='?'; i++){}
1393 if( zToken[i] ) zToken[i++] = 0;
1394 if( nCycles==0 ){
1395 cgi_setenv("PATH_INFO", zToken);
1396 }else{
1397 cgi_replace_parameter("PATH_INFO", mprintf("%s",zToken));
1398 }
1399
1400 /* Get all the optional fields that follow the first line.
1401 */
1402 while( fgets(zLine,sizeof(zLine),g.httpIn) ){
1403 char *zFieldName;
1404 char *zVal;
1405
1406 cgi_trace(zLine);
1407 zFieldName = extract_token(zLine,&zVal);
1408 if( zFieldName==0 || *zFieldName==0 ) break;
1409 while( fossil_isspace(*zVal) ){ zVal++; }
1410 i = strlen(zVal);
1411 while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
1412 zVal[i] = 0;
1413 for(i=0; zFieldName[i]; i++){
1414 zFieldName[i] = fossil_tolower(zFieldName[i]);
1415 }
1416 if( fossil_strcmp(zFieldName,"content-length:")==0 ){
1417 content_length = atoi(zVal);
1418 }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){
1419 g.zContentType = zType = mprintf("%s", zVal);
1420 }else if( fossil_strcmp(zFieldName,"host:")==0 ){
1421 if( nCycles==0 ){
1422 cgi_setenv("HTTP_HOST", zVal);
1423 }
1424 }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){
1425 if( nCycles==0 ){
1426 cgi_setenv("HTTP_USER_AGENT", zVal);
1427 }
1428 }else if( fossil_strcmp(zFieldName,"x-fossil-transport:")==0 ){
1429 if( fossil_strnicmp(zVal, "ssh", 3)==0 ){
1430 if( nCycles==0 ){
1431 g.fSshClient |= CGI_SSH_FOSSIL;
1432 g.fullHttpReply = 0;
1433 }
1434 }
1435 }
1436 }
1437
1438 if( nCycles==0 ){
1439 if( ! ( g.fSshClient & CGI_SSH_FOSSIL ) ){
1440 /* did not find new fossil ssh transport */
1441 g.fSshClient &= ~CGI_SSH_CLIENT;
1442 g.fullHttpReply = 1;
1443 cgi_replace_parameter("REMOTE_ADDR", "127.0.0.1");
1444 }
1445 }
1446
1447 cgi_reset_content();
1448 cgi_destination(CGI_BODY);
1449
1450 if( content_length>0 && zType ){
1451 blob_zero(&g.cgiIn);
1452 if( fossil_strcmp(zType, "application/x-fossil")==0 ){
1453 blob_read_from_channel(&g.cgiIn, g.httpIn, content_length);
1454 blob_uncompress(&g.cgiIn, &g.cgiIn);
1455 }else if( fossil_strcmp(zType, "application/x-fossil-debug")==0 ){
1456 blob_read_from_channel(&g.cgiIn, g.httpIn, content_length);
1457 }else if( fossil_strcmp(zType, "application/x-fossil-uncompressed")==0 ){
1458 blob_read_from_channel(&g.cgiIn, g.httpIn, content_length);
1459 }
1460 }
1461 cgi_trace(0);
1462 nCycles++;
1463 }
1464
1465 /*
1466 ** This routine handles the old fossil SSH probes
1467 */
1468 char *cgi_handle_ssh_probes(char *zLine, int zSize, char *z, char *zToken){
1469 /* Start looking for probes */
1470 while( fossil_strcmp(zToken, "echo")==0 ){
1471 zToken = extract_token(z, &z);
1472 if( zToken==0 ){
1473 malformed_request("malformed probe");
1474 }
1475 if( fossil_strncmp(zToken, "test", 4)==0 ||
1476 fossil_strncmp(zToken, "probe-", 6)==0 ){
1477 fprintf(g.httpOut, "%s\n", zToken);
1478 fflush(g.httpOut);
1479 }else{
1480 malformed_request("malformed probe");
1481 }
1482 if( fgets(zLine, zSize, g.httpIn)==0 ){
1483 malformed_request("malformed probe");
1484 }
1485 cgi_trace(zLine);
1486 zToken = extract_token(zLine, &z);
1487 if( zToken==0 ){
1488 malformed_request("malformed probe");
1489 }
1490 }
1491
1492 /* Got all probes now first transport_open is completed
1493 ** so return the command that was requested
1494 */
1495 g.fSshClient |= CGI_SSH_COMPAT;
1496 return mprintf("%s", zToken);
1497 }
1498
1499 /*
1500 ** This routine handles the old fossil SSH transport_flip
1501 ** and transport_open communications if detected.
1502 */
1503 void cgi_handle_ssh_transport(const char *zCmd){
1504 char *z, *zToken;
1505 char zLine[2000]; /* A single line of input. */
1506
1507 /* look for second newline of transport_flip */
1508 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1509 malformed_request("incorrect transport_flip");
1510 }
1511 cgi_trace(zLine);
1512 zToken = extract_token(zLine, &z);
1513 if( zToken && strlen(zToken)==0 ){
1514 /* look for path to fossil */
1515 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1516 if ( zCmd==0 ){
1517 malformed_request("missing fossil command");
1518 }else{
1519 /* no new command so exit */
1520 fossil_exit(0);
1521 }
1522 }
1523 cgi_trace(zLine);
1524 zToken = extract_token(zLine, &z);
1525 if( zToken==0 ){
1526 malformed_request("malformed fossil command");
1527 }
1528 /* see if we've seen the command */
1529 if( zCmd && zCmd[0] && fossil_strcmp(zToken, zCmd)==0 ){
1530 return;
1531 }else{
1532 malformed_request("transport_open failed");
1533 }
1534 }else{
1535 malformed_request("transport_flip failed");
1536 }
1537 }
1538
1539 /*
1540 ** This routine handles a single SCGI request which is coming in on
1541 ** g.httpIn and which replies on g.httpOut
1542 **
@@ -1445,11 +1672,11 @@
1672 #if defined(__CYGWIN__)
1673 /* On Cygwin, we can do better than "echo" */
1674 if( memcmp(zBrowser, "echo ", 5)==0 ){
1675 wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5);
1676 wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */
1677 if( (size_t)ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){
1678 fossil_warning("cannot start browser\n");
1679 }
1680 }else
1681 #endif
1682 if( system(zBrowser)<0 ){
@@ -1604,5 +1831,23 @@
1831 cgi_set_status(304,"Not Modified");
1832 cgi_reset_content();
1833 cgi_reply();
1834 fossil_exit(0);
1835 }
1836
1837 /*
1838 ** Check to see if the remote client is SSH and return
1839 ** its IP or return default
1840 */
1841 const char *cgi_ssh_remote_addr(const char *zDefault){
1842 char *zIndex;
1843 const char *zSshConn = fossil_getenv("SSH_CONNECTION");
1844
1845 if( zSshConn && zSshConn[0] ){
1846 char *zSshClient = mprintf("%s",zSshConn);
1847 if( (zIndex = strchr(zSshClient,' '))!=0 ){
1848 zSshClient[zIndex-zSshClient] = '\0';
1849 return zSshClient;
1850 }
1851 }
1852 return zDefault;
1853 }
1854
+152 -77
--- src/checkin.c
+++ src/checkin.c
@@ -248,11 +248,11 @@
248248
** COMMAND: ls
249249
**
250250
** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
251251
**
252252
** Show the names of all files in the current checkout. The -v provides
253
-** extra information about each file. If FILENAMES are included, the only
253
+** extra information about each file. If FILENAMES are included, only
254254
** the files listed (or their children if they are directories) are shown.
255255
**
256256
** Options:
257257
** --age Show when each file was committed
258258
** -v|--verbose Provide extra information about each file.
@@ -363,27 +363,28 @@
363363
}
364364
db_finalize(&q);
365365
}
366366
367367
/*
368
-** Create a TEMP table named SFILE and add all unmanaged files named on the command-line
369
-** to that table. If directories are named, then add all unmanaged files contained
370
-** underneath those directories. If there are no files or directories named on the
371
-** command-line, then add all unmanaged files anywhere in the checkout.
368
+** Create a TEMP table named SFILE and add all unmanaged files named on
369
+** the command-line to that table. If directories are named, then add
370
+** all unmanaged files contained underneath those directories. If there
371
+** are no files or directories named on the command-line, then add all
372
+** unmanaged files anywhere in the checkout.
372373
*/
373374
static void locate_unmanaged_files(
374
- int argc, /* Number of command-line arguments to examine */
375
- char **argv, /* values of command-line arguments */
376
- unsigned scanFlags, /* Zero or more SCAN_xxx flags */
377
- Glob *pIgnore1, /* Do not add files that match this GLOB */
378
- Glob *pIgnore2 /* Omit files matching this GLOB too */
375
+ int argc, /* Number of command-line arguments to examine */
376
+ char **argv, /* values of command-line arguments */
377
+ unsigned scanFlags, /* Zero or more SCAN_xxx flags */
378
+ Glob *pIgnore1, /* Do not add files that match this GLOB */
379
+ Glob *pIgnore2 /* Omit files matching this GLOB too */
379380
){
380
- Blob name; /* Name of a candidate file or directory */
381
- char *zName; /* Name of a candidate file or directory */
382
- int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
383
- int i; /* Loop counter */
384
- int nRoot; /* length of g.zLocalRoot */
381
+ Blob name; /* Name of a candidate file or directory */
382
+ char *zName; /* Name of a candidate file or directory */
383
+ int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
384
+ int i; /* Loop counter */
385
+ int nRoot; /* length of g.zLocalRoot */
385386
386387
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
387388
filename_collation());
388389
nRoot = (int)strlen(g.zLocalRoot);
389390
if( argc==0 ){
@@ -506,12 +507,28 @@
506507
** Files and subdirectories whose names begin with "." are
507508
** normally kept. They are handled if the "--dotfiles" option
508509
** is used.
509510
**
510511
** Options:
512
+** --allckouts Check for empty directories within any checkouts
513
+** that may be nested within the current one. This
514
+** option should be used with great care because the
515
+** empty-dirs setting (and other applicable settings)
516
+** belonging to the other repositories, if any, will
517
+** not be checked.
511518
** --case-sensitive <BOOL> override case-sensitive setting
519
+** --dirsonly Only remove empty directories. No files will
520
+** be removed. Using this option will automatically
521
+** enable the --emptydirs option as well.
512522
** --dotfiles Include files beginning with a dot (".").
523
+** --emptydirs Remove any empty directories that are not
524
+** explicitly exempted via the empty-dirs setting
525
+** or another applicable setting or command line
526
+** argument. Matching files, if any, are removed
527
+** prior to checking for any empty directories;
528
+** therefore, directories that contain only files
529
+** that were removed will be removed as well.
513530
** -f|--force Remove files without prompting.
514531
** --clean <CSG> Never prompt for files matching this
515532
** comma separated list of glob patterns.
516533
** --ignore <CSG> Ignore files matching patterns from the
517534
** comma separated list of glob patterns.
@@ -522,25 +539,27 @@
522539
** -v|--verbose Show all files as they are removed.
523540
**
524541
** See also: addremove, extra, status
525542
*/
526543
void clean_cmd(void){
527
- int allFlag, dryRunFlag, verboseFlag;
544
+ int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
545
+ int emptyDirsFlag, dirsOnlyFlag;
528546
unsigned scanFlags = 0;
529547
const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
530
- Blob repo;
531
- Stmt q;
532548
Glob *pIgnore, *pKeep, *pClean;
533549
int nRoot;
534550
535551
dryRunFlag = find_option("dry-run","n",0)!=0;
536552
if( !dryRunFlag ){
537553
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
538554
}
539
- allFlag = find_option("force","f",0)!=0;
555
+ allFileFlag = allDirFlag = find_option("force","f",0)!=0;
556
+ dirsOnlyFlag = find_option("dirsonly",0,0)!=0;
557
+ emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag;
540558
if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
541559
if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
560
+ if( find_option("allckouts",0,0)!=0 ) scanFlags |= SCAN_NESTED;
542561
zIgnoreFlag = find_option("ignore",0,1);
543562
verboseFlag = find_option("verbose","v",0)!=0;
544563
zKeepFlag = find_option("keep",0,1);
545564
zCleanFlag = find_option("clean",0,1);
546565
capture_case_sensitive_option();
@@ -556,51 +575,99 @@
556575
}
557576
verify_all_options();
558577
pIgnore = glob_create(zIgnoreFlag);
559578
pKeep = glob_create(zKeepFlag);
560579
pClean = glob_create(zCleanFlag);
561
- locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep);
562
- glob_free(pKeep);
563
- glob_free(pIgnore);
564
- db_prepare(&q,
565
- "SELECT %Q || x FROM sfile"
566
- " WHERE x NOT IN (%s)"
567
- " ORDER BY 1",
568
- g.zLocalRoot, fossil_all_reserved_names(0)
569
- );
570
- if( file_tree_name(g.zRepositoryName, &repo, 0) ){
571
- db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
572
- }
573
- db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
574580
nRoot = (int)strlen(g.zLocalRoot);
575
- while( db_step(&q)==SQLITE_ROW ){
576
- const char *zName = db_column_text(&q, 0);
577
- if( !allFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
578
- Blob ans;
579
- char cReply;
580
- char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
581
- zName+nRoot);
582
- blob_zero(&ans);
583
- prompt_user(prompt, &ans);
584
- cReply = blob_str(&ans)[0];
585
- if( cReply=='a' || cReply=='A' ){
586
- allFlag = 1;
587
- }else if( cReply!='y' && cReply!='Y' ){
588
- blob_reset(&ans);
589
- continue;
590
- }
591
- blob_reset(&ans);
592
- }
593
- if( verboseFlag || dryRunFlag ){
594
- fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
595
- }
596
- if( !dryRunFlag ){
597
- file_delete(zName);
598
- }
581
+ if( !dirsOnlyFlag ){
582
+ Stmt q;
583
+ Blob repo;
584
+ locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep);
585
+ db_prepare(&q,
586
+ "SELECT %Q || x FROM sfile"
587
+ " WHERE x NOT IN (%s)"
588
+ " ORDER BY 1",
589
+ g.zLocalRoot, fossil_all_reserved_names(0)
590
+ );
591
+ if( file_tree_name(g.zRepositoryName, &repo, 0) ){
592
+ db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
593
+ }
594
+ db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
595
+ while( db_step(&q)==SQLITE_ROW ){
596
+ const char *zName = db_column_text(&q, 0);
597
+ if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
598
+ Blob ans;
599
+ char cReply;
600
+ char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
601
+ zName+nRoot);
602
+ blob_zero(&ans);
603
+ prompt_user(prompt, &ans);
604
+ cReply = blob_str(&ans)[0];
605
+ if( cReply=='a' || cReply=='A' ){
606
+ allFileFlag = 1;
607
+ }else if( cReply!='y' && cReply!='Y' ){
608
+ blob_reset(&ans);
609
+ continue;
610
+ }
611
+ blob_reset(&ans);
612
+ }
613
+ if ( dryRunFlag || file_delete(zName)==0 ){
614
+ if( verboseFlag || dryRunFlag ){
615
+ fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
616
+ }
617
+ }else if( verboseFlag ){
618
+ fossil_print("Could not remove file: %s\n", zName+nRoot);
619
+ }
620
+ }
621
+ db_finalize(&q);
622
+ }
623
+ if( emptyDirsFlag ){
624
+ Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
625
+ Stmt q;
626
+ Blob root;
627
+ blob_init(&root, g.zLocalRoot, nRoot - 1);
628
+ vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore, pKeep,
629
+ pEmptyDirs);
630
+ blob_reset(&root);
631
+ db_prepare(&q,
632
+ "SELECT %Q || x FROM dscan_temp"
633
+ " WHERE x NOT IN (%s) AND y = 0"
634
+ " ORDER BY 1 DESC",
635
+ g.zLocalRoot, fossil_all_reserved_names(0)
636
+ );
637
+ while( db_step(&q)==SQLITE_ROW ){
638
+ const char *zName = db_column_text(&q, 0);
639
+ if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
640
+ Blob ans;
641
+ char cReply;
642
+ char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
643
+ zName+nRoot);
644
+ blob_zero(&ans);
645
+ prompt_user(prompt, &ans);
646
+ cReply = blob_str(&ans)[0];
647
+ if( cReply=='a' || cReply=='A' ){
648
+ allDirFlag = 1;
649
+ }else if( cReply!='y' && cReply!='Y' ){
650
+ blob_reset(&ans);
651
+ continue;
652
+ }
653
+ blob_reset(&ans);
654
+ }
655
+ if ( dryRunFlag || file_rmdir(zName)==0 ){
656
+ if( verboseFlag || dryRunFlag ){
657
+ fossil_print("Removed unmanaged directory: %s\n", zName+nRoot);
658
+ }
659
+ }else if( verboseFlag ){
660
+ fossil_print("Could not remove directory: %s\n", zName+nRoot);
661
+ }
662
+ }
663
+ db_finalize(&q);
664
+ glob_free(pEmptyDirs);
599665
}
600666
glob_free(pClean);
601
- db_finalize(&q);
667
+ glob_free(pKeep);
668
+ glob_free(pIgnore);
602669
}
603670
604671
/*
605672
** Prompt the user for a check-in or stash comment (given in pPrompt),
606673
** gather the response, then return the response in pComment.
@@ -920,11 +987,17 @@
920987
const char *zColor; /* Modified value of p->zColor */
921988
922989
assert( pBaseline==0 || pBaseline->zBaseline==0 );
923990
assert( pBaseline==0 || zBaselineUuid!=0 );
924991
blob_zero(pOut);
925
- zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
992
+ zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d AND "
993
+ "EXISTS(SELECT 1 FROM event WHERE event.type='ci' and event.objid=%d)",
994
+ vid, vid);
995
+ if( !zParentUuid ){
996
+ fossil_fatal("Could not find a valid check-in for RID %d. "
997
+ "Possible checkout/repo mismatch.", vid);
998
+ }
926999
if( pBaseline ){
9271000
blob_appendf(pOut, "B %s\n", zBaselineUuid);
9281001
manifest_file_rewind(pBaseline);
9291002
pFile = manifest_file_next(pBaseline, 0);
9301003
nFBcard++;
@@ -1015,28 +1088,30 @@
10151088
nFBcard++;
10161089
}
10171090
if( p->zMimetype && p->zMimetype[0] ){
10181091
blob_appendf(pOut, "N %F\n", p->zMimetype);
10191092
}
1020
- blob_appendf(pOut, "P %s", zParentUuid);
1021
- if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate);
1022
- free(zParentUuid);
1023
- db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1024
- while( db_step(&q)==SQLITE_ROW ){
1025
- char *zMergeUuid;
1026
- int mid = db_column_int(&q, 0);
1027
- if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
1028
- zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1029
- if( zMergeUuid ){
1030
- blob_appendf(pOut, " %s", zMergeUuid);
1031
- if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1032
- free(zMergeUuid);
1033
- }
1034
- }
1035
- db_finalize(&q);
1036
- free(zDate);
1037
- blob_appendf(pOut, "\n");
1093
+ if( zParentUuid ){
1094
+ blob_appendf(pOut, "P %s", zParentUuid);
1095
+ if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate);
1096
+ free(zParentUuid);
1097
+ db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1098
+ while( db_step(&q)==SQLITE_ROW ){
1099
+ char *zMergeUuid;
1100
+ int mid = db_column_int(&q, 0);
1101
+ if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
1102
+ zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1103
+ if( zMergeUuid ){
1104
+ blob_appendf(pOut, " %s", zMergeUuid);
1105
+ if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1106
+ free(zMergeUuid);
1107
+ }
1108
+ }
1109
+ db_finalize(&q);
1110
+ blob_appendf(pOut, "\n");
1111
+ }
1112
+ free(zDate);
10381113
10391114
db_prepare(&q,
10401115
"SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge"
10411116
" FROM vmerge, blob"
10421117
" WHERE (vmerge.id=-1 OR vmerge.id=-2)"
@@ -1663,11 +1738,11 @@
16631738
/* See if a delta-manifest would be more appropriate */
16641739
if( !forceBaseline ){
16651740
const char *zBaselineUuid;
16661741
Manifest *pParent;
16671742
Manifest *pBaseline;
1668
- pParent = manifest_get(vid, CFTYPE_MANIFEST);
1743
+ pParent = manifest_get(vid, CFTYPE_MANIFEST, 0);
16691744
if( pParent && pParent->zBaseline ){
16701745
zBaselineUuid = pParent->zBaseline;
16711746
pBaseline = manifest_get_by_name(zBaselineUuid, 0);
16721747
}else{
16731748
zBaselineUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
16741749
--- src/checkin.c
+++ src/checkin.c
@@ -248,11 +248,11 @@
248 ** COMMAND: ls
249 **
250 ** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
251 **
252 ** Show the names of all files in the current checkout. The -v provides
253 ** extra information about each file. If FILENAMES are included, the only
254 ** the files listed (or their children if they are directories) are shown.
255 **
256 ** Options:
257 ** --age Show when each file was committed
258 ** -v|--verbose Provide extra information about each file.
@@ -363,27 +363,28 @@
363 }
364 db_finalize(&q);
365 }
366
367 /*
368 ** Create a TEMP table named SFILE and add all unmanaged files named on the command-line
369 ** to that table. If directories are named, then add all unmanaged files contained
370 ** underneath those directories. If there are no files or directories named on the
371 ** command-line, then add all unmanaged files anywhere in the checkout.
 
372 */
373 static void locate_unmanaged_files(
374 int argc, /* Number of command-line arguments to examine */
375 char **argv, /* values of command-line arguments */
376 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
377 Glob *pIgnore1, /* Do not add files that match this GLOB */
378 Glob *pIgnore2 /* Omit files matching this GLOB too */
379 ){
380 Blob name; /* Name of a candidate file or directory */
381 char *zName; /* Name of a candidate file or directory */
382 int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
383 int i; /* Loop counter */
384 int nRoot; /* length of g.zLocalRoot */
385
386 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
387 filename_collation());
388 nRoot = (int)strlen(g.zLocalRoot);
389 if( argc==0 ){
@@ -506,12 +507,28 @@
506 ** Files and subdirectories whose names begin with "." are
507 ** normally kept. They are handled if the "--dotfiles" option
508 ** is used.
509 **
510 ** Options:
 
 
 
 
 
 
511 ** --case-sensitive <BOOL> override case-sensitive setting
 
 
 
512 ** --dotfiles Include files beginning with a dot (".").
 
 
 
 
 
 
 
513 ** -f|--force Remove files without prompting.
514 ** --clean <CSG> Never prompt for files matching this
515 ** comma separated list of glob patterns.
516 ** --ignore <CSG> Ignore files matching patterns from the
517 ** comma separated list of glob patterns.
@@ -522,25 +539,27 @@
522 ** -v|--verbose Show all files as they are removed.
523 **
524 ** See also: addremove, extra, status
525 */
526 void clean_cmd(void){
527 int allFlag, dryRunFlag, verboseFlag;
 
528 unsigned scanFlags = 0;
529 const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
530 Blob repo;
531 Stmt q;
532 Glob *pIgnore, *pKeep, *pClean;
533 int nRoot;
534
535 dryRunFlag = find_option("dry-run","n",0)!=0;
536 if( !dryRunFlag ){
537 dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
538 }
539 allFlag = find_option("force","f",0)!=0;
 
 
540 if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
541 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
 
542 zIgnoreFlag = find_option("ignore",0,1);
543 verboseFlag = find_option("verbose","v",0)!=0;
544 zKeepFlag = find_option("keep",0,1);
545 zCleanFlag = find_option("clean",0,1);
546 capture_case_sensitive_option();
@@ -556,51 +575,99 @@
556 }
557 verify_all_options();
558 pIgnore = glob_create(zIgnoreFlag);
559 pKeep = glob_create(zKeepFlag);
560 pClean = glob_create(zCleanFlag);
561 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep);
562 glob_free(pKeep);
563 glob_free(pIgnore);
564 db_prepare(&q,
565 "SELECT %Q || x FROM sfile"
566 " WHERE x NOT IN (%s)"
567 " ORDER BY 1",
568 g.zLocalRoot, fossil_all_reserved_names(0)
569 );
570 if( file_tree_name(g.zRepositoryName, &repo, 0) ){
571 db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
572 }
573 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
574 nRoot = (int)strlen(g.zLocalRoot);
575 while( db_step(&q)==SQLITE_ROW ){
576 const char *zName = db_column_text(&q, 0);
577 if( !allFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
578 Blob ans;
579 char cReply;
580 char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
581 zName+nRoot);
582 blob_zero(&ans);
583 prompt_user(prompt, &ans);
584 cReply = blob_str(&ans)[0];
585 if( cReply=='a' || cReply=='A' ){
586 allFlag = 1;
587 }else if( cReply!='y' && cReply!='Y' ){
588 blob_reset(&ans);
589 continue;
590 }
591 blob_reset(&ans);
592 }
593 if( verboseFlag || dryRunFlag ){
594 fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
595 }
596 if( !dryRunFlag ){
597 file_delete(zName);
598 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599 }
600 glob_free(pClean);
601 db_finalize(&q);
 
602 }
603
604 /*
605 ** Prompt the user for a check-in or stash comment (given in pPrompt),
606 ** gather the response, then return the response in pComment.
@@ -920,11 +987,17 @@
920 const char *zColor; /* Modified value of p->zColor */
921
922 assert( pBaseline==0 || pBaseline->zBaseline==0 );
923 assert( pBaseline==0 || zBaselineUuid!=0 );
924 blob_zero(pOut);
925 zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
 
 
 
 
 
 
926 if( pBaseline ){
927 blob_appendf(pOut, "B %s\n", zBaselineUuid);
928 manifest_file_rewind(pBaseline);
929 pFile = manifest_file_next(pBaseline, 0);
930 nFBcard++;
@@ -1015,28 +1088,30 @@
1015 nFBcard++;
1016 }
1017 if( p->zMimetype && p->zMimetype[0] ){
1018 blob_appendf(pOut, "N %F\n", p->zMimetype);
1019 }
1020 blob_appendf(pOut, "P %s", zParentUuid);
1021 if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate);
1022 free(zParentUuid);
1023 db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1024 while( db_step(&q)==SQLITE_ROW ){
1025 char *zMergeUuid;
1026 int mid = db_column_int(&q, 0);
1027 if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
1028 zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1029 if( zMergeUuid ){
1030 blob_appendf(pOut, " %s", zMergeUuid);
1031 if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1032 free(zMergeUuid);
1033 }
1034 }
1035 db_finalize(&q);
1036 free(zDate);
1037 blob_appendf(pOut, "\n");
 
 
1038
1039 db_prepare(&q,
1040 "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge"
1041 " FROM vmerge, blob"
1042 " WHERE (vmerge.id=-1 OR vmerge.id=-2)"
@@ -1663,11 +1738,11 @@
1663 /* See if a delta-manifest would be more appropriate */
1664 if( !forceBaseline ){
1665 const char *zBaselineUuid;
1666 Manifest *pParent;
1667 Manifest *pBaseline;
1668 pParent = manifest_get(vid, CFTYPE_MANIFEST);
1669 if( pParent && pParent->zBaseline ){
1670 zBaselineUuid = pParent->zBaseline;
1671 pBaseline = manifest_get_by_name(zBaselineUuid, 0);
1672 }else{
1673 zBaselineUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
1674
--- src/checkin.c
+++ src/checkin.c
@@ -248,11 +248,11 @@
248 ** COMMAND: ls
249 **
250 ** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
251 **
252 ** Show the names of all files in the current checkout. The -v provides
253 ** extra information about each file. If FILENAMES are included, only
254 ** the files listed (or their children if they are directories) are shown.
255 **
256 ** Options:
257 ** --age Show when each file was committed
258 ** -v|--verbose Provide extra information about each file.
@@ -363,27 +363,28 @@
363 }
364 db_finalize(&q);
365 }
366
367 /*
368 ** Create a TEMP table named SFILE and add all unmanaged files named on
369 ** the command-line to that table. If directories are named, then add
370 ** all unmanaged files contained underneath those directories. If there
371 ** are no files or directories named on the command-line, then add all
372 ** unmanaged files anywhere in the checkout.
373 */
374 static void locate_unmanaged_files(
375 int argc, /* Number of command-line arguments to examine */
376 char **argv, /* values of command-line arguments */
377 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
378 Glob *pIgnore1, /* Do not add files that match this GLOB */
379 Glob *pIgnore2 /* Omit files matching this GLOB too */
380 ){
381 Blob name; /* Name of a candidate file or directory */
382 char *zName; /* Name of a candidate file or directory */
383 int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
384 int i; /* Loop counter */
385 int nRoot; /* length of g.zLocalRoot */
386
387 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
388 filename_collation());
389 nRoot = (int)strlen(g.zLocalRoot);
390 if( argc==0 ){
@@ -506,12 +507,28 @@
507 ** Files and subdirectories whose names begin with "." are
508 ** normally kept. They are handled if the "--dotfiles" option
509 ** is used.
510 **
511 ** Options:
512 ** --allckouts Check for empty directories within any checkouts
513 ** that may be nested within the current one. This
514 ** option should be used with great care because the
515 ** empty-dirs setting (and other applicable settings)
516 ** belonging to the other repositories, if any, will
517 ** not be checked.
518 ** --case-sensitive <BOOL> override case-sensitive setting
519 ** --dirsonly Only remove empty directories. No files will
520 ** be removed. Using this option will automatically
521 ** enable the --emptydirs option as well.
522 ** --dotfiles Include files beginning with a dot (".").
523 ** --emptydirs Remove any empty directories that are not
524 ** explicitly exempted via the empty-dirs setting
525 ** or another applicable setting or command line
526 ** argument. Matching files, if any, are removed
527 ** prior to checking for any empty directories;
528 ** therefore, directories that contain only files
529 ** that were removed will be removed as well.
530 ** -f|--force Remove files without prompting.
531 ** --clean <CSG> Never prompt for files matching this
532 ** comma separated list of glob patterns.
533 ** --ignore <CSG> Ignore files matching patterns from the
534 ** comma separated list of glob patterns.
@@ -522,25 +539,27 @@
539 ** -v|--verbose Show all files as they are removed.
540 **
541 ** See also: addremove, extra, status
542 */
543 void clean_cmd(void){
544 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
545 int emptyDirsFlag, dirsOnlyFlag;
546 unsigned scanFlags = 0;
547 const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
 
 
548 Glob *pIgnore, *pKeep, *pClean;
549 int nRoot;
550
551 dryRunFlag = find_option("dry-run","n",0)!=0;
552 if( !dryRunFlag ){
553 dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
554 }
555 allFileFlag = allDirFlag = find_option("force","f",0)!=0;
556 dirsOnlyFlag = find_option("dirsonly",0,0)!=0;
557 emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag;
558 if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
559 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
560 if( find_option("allckouts",0,0)!=0 ) scanFlags |= SCAN_NESTED;
561 zIgnoreFlag = find_option("ignore",0,1);
562 verboseFlag = find_option("verbose","v",0)!=0;
563 zKeepFlag = find_option("keep",0,1);
564 zCleanFlag = find_option("clean",0,1);
565 capture_case_sensitive_option();
@@ -556,51 +575,99 @@
575 }
576 verify_all_options();
577 pIgnore = glob_create(zIgnoreFlag);
578 pKeep = glob_create(zKeepFlag);
579 pClean = glob_create(zCleanFlag);
 
 
 
 
 
 
 
 
 
 
 
 
 
580 nRoot = (int)strlen(g.zLocalRoot);
581 if( !dirsOnlyFlag ){
582 Stmt q;
583 Blob repo;
584 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep);
585 db_prepare(&q,
586 "SELECT %Q || x FROM sfile"
587 " WHERE x NOT IN (%s)"
588 " ORDER BY 1",
589 g.zLocalRoot, fossil_all_reserved_names(0)
590 );
591 if( file_tree_name(g.zRepositoryName, &repo, 0) ){
592 db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
593 }
594 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
595 while( db_step(&q)==SQLITE_ROW ){
596 const char *zName = db_column_text(&q, 0);
597 if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
598 Blob ans;
599 char cReply;
600 char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
601 zName+nRoot);
602 blob_zero(&ans);
603 prompt_user(prompt, &ans);
604 cReply = blob_str(&ans)[0];
605 if( cReply=='a' || cReply=='A' ){
606 allFileFlag = 1;
607 }else if( cReply!='y' && cReply!='Y' ){
608 blob_reset(&ans);
609 continue;
610 }
611 blob_reset(&ans);
612 }
613 if ( dryRunFlag || file_delete(zName)==0 ){
614 if( verboseFlag || dryRunFlag ){
615 fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
616 }
617 }else if( verboseFlag ){
618 fossil_print("Could not remove file: %s\n", zName+nRoot);
619 }
620 }
621 db_finalize(&q);
622 }
623 if( emptyDirsFlag ){
624 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
625 Stmt q;
626 Blob root;
627 blob_init(&root, g.zLocalRoot, nRoot - 1);
628 vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore, pKeep,
629 pEmptyDirs);
630 blob_reset(&root);
631 db_prepare(&q,
632 "SELECT %Q || x FROM dscan_temp"
633 " WHERE x NOT IN (%s) AND y = 0"
634 " ORDER BY 1 DESC",
635 g.zLocalRoot, fossil_all_reserved_names(0)
636 );
637 while( db_step(&q)==SQLITE_ROW ){
638 const char *zName = db_column_text(&q, 0);
639 if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
640 Blob ans;
641 char cReply;
642 char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
643 zName+nRoot);
644 blob_zero(&ans);
645 prompt_user(prompt, &ans);
646 cReply = blob_str(&ans)[0];
647 if( cReply=='a' || cReply=='A' ){
648 allDirFlag = 1;
649 }else if( cReply!='y' && cReply!='Y' ){
650 blob_reset(&ans);
651 continue;
652 }
653 blob_reset(&ans);
654 }
655 if ( dryRunFlag || file_rmdir(zName)==0 ){
656 if( verboseFlag || dryRunFlag ){
657 fossil_print("Removed unmanaged directory: %s\n", zName+nRoot);
658 }
659 }else if( verboseFlag ){
660 fossil_print("Could not remove directory: %s\n", zName+nRoot);
661 }
662 }
663 db_finalize(&q);
664 glob_free(pEmptyDirs);
665 }
666 glob_free(pClean);
667 glob_free(pKeep);
668 glob_free(pIgnore);
669 }
670
671 /*
672 ** Prompt the user for a check-in or stash comment (given in pPrompt),
673 ** gather the response, then return the response in pComment.
@@ -920,11 +987,17 @@
987 const char *zColor; /* Modified value of p->zColor */
988
989 assert( pBaseline==0 || pBaseline->zBaseline==0 );
990 assert( pBaseline==0 || zBaselineUuid!=0 );
991 blob_zero(pOut);
992 zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d AND "
993 "EXISTS(SELECT 1 FROM event WHERE event.type='ci' and event.objid=%d)",
994 vid, vid);
995 if( !zParentUuid ){
996 fossil_fatal("Could not find a valid check-in for RID %d. "
997 "Possible checkout/repo mismatch.", vid);
998 }
999 if( pBaseline ){
1000 blob_appendf(pOut, "B %s\n", zBaselineUuid);
1001 manifest_file_rewind(pBaseline);
1002 pFile = manifest_file_next(pBaseline, 0);
1003 nFBcard++;
@@ -1015,28 +1088,30 @@
1088 nFBcard++;
1089 }
1090 if( p->zMimetype && p->zMimetype[0] ){
1091 blob_appendf(pOut, "N %F\n", p->zMimetype);
1092 }
1093 if( zParentUuid ){
1094 blob_appendf(pOut, "P %s", zParentUuid);
1095 if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate);
1096 free(zParentUuid);
1097 db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1098 while( db_step(&q)==SQLITE_ROW ){
1099 char *zMergeUuid;
1100 int mid = db_column_int(&q, 0);
1101 if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
1102 zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1103 if( zMergeUuid ){
1104 blob_appendf(pOut, " %s", zMergeUuid);
1105 if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1106 free(zMergeUuid);
1107 }
1108 }
1109 db_finalize(&q);
1110 blob_appendf(pOut, "\n");
1111 }
1112 free(zDate);
1113
1114 db_prepare(&q,
1115 "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge"
1116 " FROM vmerge, blob"
1117 " WHERE (vmerge.id=-1 OR vmerge.id=-2)"
@@ -1663,11 +1738,11 @@
1738 /* See if a delta-manifest would be more appropriate */
1739 if( !forceBaseline ){
1740 const char *zBaselineUuid;
1741 Manifest *pParent;
1742 Manifest *pBaseline;
1743 pParent = manifest_get(vid, CFTYPE_MANIFEST, 0);
1744 if( pParent && pParent->zBaseline ){
1745 zBaselineUuid = pParent->zBaseline;
1746 pBaseline = manifest_get_by_name(zBaselineUuid, 0);
1747 }else{
1748 zBaselineUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
1749
+152 -77
--- src/checkin.c
+++ src/checkin.c
@@ -248,11 +248,11 @@
248248
** COMMAND: ls
249249
**
250250
** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
251251
**
252252
** Show the names of all files in the current checkout. The -v provides
253
-** extra information about each file. If FILENAMES are included, the only
253
+** extra information about each file. If FILENAMES are included, only
254254
** the files listed (or their children if they are directories) are shown.
255255
**
256256
** Options:
257257
** --age Show when each file was committed
258258
** -v|--verbose Provide extra information about each file.
@@ -363,27 +363,28 @@
363363
}
364364
db_finalize(&q);
365365
}
366366
367367
/*
368
-** Create a TEMP table named SFILE and add all unmanaged files named on the command-line
369
-** to that table. If directories are named, then add all unmanaged files contained
370
-** underneath those directories. If there are no files or directories named on the
371
-** command-line, then add all unmanaged files anywhere in the checkout.
368
+** Create a TEMP table named SFILE and add all unmanaged files named on
369
+** the command-line to that table. If directories are named, then add
370
+** all unmanaged files contained underneath those directories. If there
371
+** are no files or directories named on the command-line, then add all
372
+** unmanaged files anywhere in the checkout.
372373
*/
373374
static void locate_unmanaged_files(
374
- int argc, /* Number of command-line arguments to examine */
375
- char **argv, /* values of command-line arguments */
376
- unsigned scanFlags, /* Zero or more SCAN_xxx flags */
377
- Glob *pIgnore1, /* Do not add files that match this GLOB */
378
- Glob *pIgnore2 /* Omit files matching this GLOB too */
375
+ int argc, /* Number of command-line arguments to examine */
376
+ char **argv, /* values of command-line arguments */
377
+ unsigned scanFlags, /* Zero or more SCAN_xxx flags */
378
+ Glob *pIgnore1, /* Do not add files that match this GLOB */
379
+ Glob *pIgnore2 /* Omit files matching this GLOB too */
379380
){
380
- Blob name; /* Name of a candidate file or directory */
381
- char *zName; /* Name of a candidate file or directory */
382
- int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
383
- int i; /* Loop counter */
384
- int nRoot; /* length of g.zLocalRoot */
381
+ Blob name; /* Name of a candidate file or directory */
382
+ char *zName; /* Name of a candidate file or directory */
383
+ int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
384
+ int i; /* Loop counter */
385
+ int nRoot; /* length of g.zLocalRoot */
385386
386387
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
387388
filename_collation());
388389
nRoot = (int)strlen(g.zLocalRoot);
389390
if( argc==0 ){
@@ -506,12 +507,28 @@
506507
** Files and subdirectories whose names begin with "." are
507508
** normally kept. They are handled if the "--dotfiles" option
508509
** is used.
509510
**
510511
** Options:
512
+** --allckouts Check for empty directories within any checkouts
513
+** that may be nested within the current one. This
514
+** option should be used with great care because the
515
+** empty-dirs setting (and other applicable settings)
516
+** belonging to the other repositories, if any, will
517
+** not be checked.
511518
** --case-sensitive <BOOL> override case-sensitive setting
519
+** --dirsonly Only remove empty directories. No files will
520
+** be removed. Using this option will automatically
521
+** enable the --emptydirs option as well.
512522
** --dotfiles Include files beginning with a dot (".").
523
+** --emptydirs Remove any empty directories that are not
524
+** explicitly exempted via the empty-dirs setting
525
+** or another applicable setting or command line
526
+** argument. Matching files, if any, are removed
527
+** prior to checking for any empty directories;
528
+** therefore, directories that contain only files
529
+** that were removed will be removed as well.
513530
** -f|--force Remove files without prompting.
514531
** --clean <CSG> Never prompt for files matching this
515532
** comma separated list of glob patterns.
516533
** --ignore <CSG> Ignore files matching patterns from the
517534
** comma separated list of glob patterns.
@@ -522,25 +539,27 @@
522539
** -v|--verbose Show all files as they are removed.
523540
**
524541
** See also: addremove, extra, status
525542
*/
526543
void clean_cmd(void){
527
- int allFlag, dryRunFlag, verboseFlag;
544
+ int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
545
+ int emptyDirsFlag, dirsOnlyFlag;
528546
unsigned scanFlags = 0;
529547
const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
530
- Blob repo;
531
- Stmt q;
532548
Glob *pIgnore, *pKeep, *pClean;
533549
int nRoot;
534550
535551
dryRunFlag = find_option("dry-run","n",0)!=0;
536552
if( !dryRunFlag ){
537553
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
538554
}
539
- allFlag = find_option("force","f",0)!=0;
555
+ allFileFlag = allDirFlag = find_option("force","f",0)!=0;
556
+ dirsOnlyFlag = find_option("dirsonly",0,0)!=0;
557
+ emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag;
540558
if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
541559
if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
560
+ if( find_option("allckouts",0,0)!=0 ) scanFlags |= SCAN_NESTED;
542561
zIgnoreFlag = find_option("ignore",0,1);
543562
verboseFlag = find_option("verbose","v",0)!=0;
544563
zKeepFlag = find_option("keep",0,1);
545564
zCleanFlag = find_option("clean",0,1);
546565
capture_case_sensitive_option();
@@ -556,51 +575,99 @@
556575
}
557576
verify_all_options();
558577
pIgnore = glob_create(zIgnoreFlag);
559578
pKeep = glob_create(zKeepFlag);
560579
pClean = glob_create(zCleanFlag);
561
- locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep);
562
- glob_free(pKeep);
563
- glob_free(pIgnore);
564
- db_prepare(&q,
565
- "SELECT %Q || x FROM sfile"
566
- " WHERE x NOT IN (%s)"
567
- " ORDER BY 1",
568
- g.zLocalRoot, fossil_all_reserved_names(0)
569
- );
570
- if( file_tree_name(g.zRepositoryName, &repo, 0) ){
571
- db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
572
- }
573
- db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
574580
nRoot = (int)strlen(g.zLocalRoot);
575
- while( db_step(&q)==SQLITE_ROW ){
576
- const char *zName = db_column_text(&q, 0);
577
- if( !allFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
578
- Blob ans;
579
- char cReply;
580
- char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
581
- zName+nRoot);
582
- blob_zero(&ans);
583
- prompt_user(prompt, &ans);
584
- cReply = blob_str(&ans)[0];
585
- if( cReply=='a' || cReply=='A' ){
586
- allFlag = 1;
587
- }else if( cReply!='y' && cReply!='Y' ){
588
- blob_reset(&ans);
589
- continue;
590
- }
591
- blob_reset(&ans);
592
- }
593
- if( verboseFlag || dryRunFlag ){
594
- fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
595
- }
596
- if( !dryRunFlag ){
597
- file_delete(zName);
598
- }
581
+ if( !dirsOnlyFlag ){
582
+ Stmt q;
583
+ Blob repo;
584
+ locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep);
585
+ db_prepare(&q,
586
+ "SELECT %Q || x FROM sfile"
587
+ " WHERE x NOT IN (%s)"
588
+ " ORDER BY 1",
589
+ g.zLocalRoot, fossil_all_reserved_names(0)
590
+ );
591
+ if( file_tree_name(g.zRepositoryName, &repo, 0) ){
592
+ db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
593
+ }
594
+ db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
595
+ while( db_step(&q)==SQLITE_ROW ){
596
+ const char *zName = db_column_text(&q, 0);
597
+ if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
598
+ Blob ans;
599
+ char cReply;
600
+ char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
601
+ zName+nRoot);
602
+ blob_zero(&ans);
603
+ prompt_user(prompt, &ans);
604
+ cReply = blob_str(&ans)[0];
605
+ if( cReply=='a' || cReply=='A' ){
606
+ allFileFlag = 1;
607
+ }else if( cReply!='y' && cReply!='Y' ){
608
+ blob_reset(&ans);
609
+ continue;
610
+ }
611
+ blob_reset(&ans);
612
+ }
613
+ if ( dryRunFlag || file_delete(zName)==0 ){
614
+ if( verboseFlag || dryRunFlag ){
615
+ fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
616
+ }
617
+ }else if( verboseFlag ){
618
+ fossil_print("Could not remove file: %s\n", zName+nRoot);
619
+ }
620
+ }
621
+ db_finalize(&q);
622
+ }
623
+ if( emptyDirsFlag ){
624
+ Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
625
+ Stmt q;
626
+ Blob root;
627
+ blob_init(&root, g.zLocalRoot, nRoot - 1);
628
+ vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore, pKeep,
629
+ pEmptyDirs);
630
+ blob_reset(&root);
631
+ db_prepare(&q,
632
+ "SELECT %Q || x FROM dscan_temp"
633
+ " WHERE x NOT IN (%s) AND y = 0"
634
+ " ORDER BY 1 DESC",
635
+ g.zLocalRoot, fossil_all_reserved_names(0)
636
+ );
637
+ while( db_step(&q)==SQLITE_ROW ){
638
+ const char *zName = db_column_text(&q, 0);
639
+ if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
640
+ Blob ans;
641
+ char cReply;
642
+ char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
643
+ zName+nRoot);
644
+ blob_zero(&ans);
645
+ prompt_user(prompt, &ans);
646
+ cReply = blob_str(&ans)[0];
647
+ if( cReply=='a' || cReply=='A' ){
648
+ allDirFlag = 1;
649
+ }else if( cReply!='y' && cReply!='Y' ){
650
+ blob_reset(&ans);
651
+ continue;
652
+ }
653
+ blob_reset(&ans);
654
+ }
655
+ if ( dryRunFlag || file_rmdir(zName)==0 ){
656
+ if( verboseFlag || dryRunFlag ){
657
+ fossil_print("Removed unmanaged directory: %s\n", zName+nRoot);
658
+ }
659
+ }else if( verboseFlag ){
660
+ fossil_print("Could not remove directory: %s\n", zName+nRoot);
661
+ }
662
+ }
663
+ db_finalize(&q);
664
+ glob_free(pEmptyDirs);
599665
}
600666
glob_free(pClean);
601
- db_finalize(&q);
667
+ glob_free(pKeep);
668
+ glob_free(pIgnore);
602669
}
603670
604671
/*
605672
** Prompt the user for a check-in or stash comment (given in pPrompt),
606673
** gather the response, then return the response in pComment.
@@ -920,11 +987,17 @@
920987
const char *zColor; /* Modified value of p->zColor */
921988
922989
assert( pBaseline==0 || pBaseline->zBaseline==0 );
923990
assert( pBaseline==0 || zBaselineUuid!=0 );
924991
blob_zero(pOut);
925
- zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
992
+ zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d AND "
993
+ "EXISTS(SELECT 1 FROM event WHERE event.type='ci' and event.objid=%d)",
994
+ vid, vid);
995
+ if( !zParentUuid ){
996
+ fossil_fatal("Could not find a valid check-in for RID %d. "
997
+ "Possible checkout/repo mismatch.", vid);
998
+ }
926999
if( pBaseline ){
9271000
blob_appendf(pOut, "B %s\n", zBaselineUuid);
9281001
manifest_file_rewind(pBaseline);
9291002
pFile = manifest_file_next(pBaseline, 0);
9301003
nFBcard++;
@@ -1015,28 +1088,30 @@
10151088
nFBcard++;
10161089
}
10171090
if( p->zMimetype && p->zMimetype[0] ){
10181091
blob_appendf(pOut, "N %F\n", p->zMimetype);
10191092
}
1020
- blob_appendf(pOut, "P %s", zParentUuid);
1021
- if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate);
1022
- free(zParentUuid);
1023
- db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1024
- while( db_step(&q)==SQLITE_ROW ){
1025
- char *zMergeUuid;
1026
- int mid = db_column_int(&q, 0);
1027
- if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
1028
- zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1029
- if( zMergeUuid ){
1030
- blob_appendf(pOut, " %s", zMergeUuid);
1031
- if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1032
- free(zMergeUuid);
1033
- }
1034
- }
1035
- db_finalize(&q);
1036
- free(zDate);
1037
- blob_appendf(pOut, "\n");
1093
+ if( zParentUuid ){
1094
+ blob_appendf(pOut, "P %s", zParentUuid);
1095
+ if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate);
1096
+ free(zParentUuid);
1097
+ db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1098
+ while( db_step(&q)==SQLITE_ROW ){
1099
+ char *zMergeUuid;
1100
+ int mid = db_column_int(&q, 0);
1101
+ if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
1102
+ zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1103
+ if( zMergeUuid ){
1104
+ blob_appendf(pOut, " %s", zMergeUuid);
1105
+ if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1106
+ free(zMergeUuid);
1107
+ }
1108
+ }
1109
+ db_finalize(&q);
1110
+ blob_appendf(pOut, "\n");
1111
+ }
1112
+ free(zDate);
10381113
10391114
db_prepare(&q,
10401115
"SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge"
10411116
" FROM vmerge, blob"
10421117
" WHERE (vmerge.id=-1 OR vmerge.id=-2)"
@@ -1663,11 +1738,11 @@
16631738
/* See if a delta-manifest would be more appropriate */
16641739
if( !forceBaseline ){
16651740
const char *zBaselineUuid;
16661741
Manifest *pParent;
16671742
Manifest *pBaseline;
1668
- pParent = manifest_get(vid, CFTYPE_MANIFEST);
1743
+ pParent = manifest_get(vid, CFTYPE_MANIFEST, 0);
16691744
if( pParent && pParent->zBaseline ){
16701745
zBaselineUuid = pParent->zBaseline;
16711746
pBaseline = manifest_get_by_name(zBaselineUuid, 0);
16721747
}else{
16731748
zBaselineUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
16741749
--- src/checkin.c
+++ src/checkin.c
@@ -248,11 +248,11 @@
248 ** COMMAND: ls
249 **
250 ** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
251 **
252 ** Show the names of all files in the current checkout. The -v provides
253 ** extra information about each file. If FILENAMES are included, the only
254 ** the files listed (or their children if they are directories) are shown.
255 **
256 ** Options:
257 ** --age Show when each file was committed
258 ** -v|--verbose Provide extra information about each file.
@@ -363,27 +363,28 @@
363 }
364 db_finalize(&q);
365 }
366
367 /*
368 ** Create a TEMP table named SFILE and add all unmanaged files named on the command-line
369 ** to that table. If directories are named, then add all unmanaged files contained
370 ** underneath those directories. If there are no files or directories named on the
371 ** command-line, then add all unmanaged files anywhere in the checkout.
 
372 */
373 static void locate_unmanaged_files(
374 int argc, /* Number of command-line arguments to examine */
375 char **argv, /* values of command-line arguments */
376 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
377 Glob *pIgnore1, /* Do not add files that match this GLOB */
378 Glob *pIgnore2 /* Omit files matching this GLOB too */
379 ){
380 Blob name; /* Name of a candidate file or directory */
381 char *zName; /* Name of a candidate file or directory */
382 int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
383 int i; /* Loop counter */
384 int nRoot; /* length of g.zLocalRoot */
385
386 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
387 filename_collation());
388 nRoot = (int)strlen(g.zLocalRoot);
389 if( argc==0 ){
@@ -506,12 +507,28 @@
506 ** Files and subdirectories whose names begin with "." are
507 ** normally kept. They are handled if the "--dotfiles" option
508 ** is used.
509 **
510 ** Options:
 
 
 
 
 
 
511 ** --case-sensitive <BOOL> override case-sensitive setting
 
 
 
512 ** --dotfiles Include files beginning with a dot (".").
 
 
 
 
 
 
 
513 ** -f|--force Remove files without prompting.
514 ** --clean <CSG> Never prompt for files matching this
515 ** comma separated list of glob patterns.
516 ** --ignore <CSG> Ignore files matching patterns from the
517 ** comma separated list of glob patterns.
@@ -522,25 +539,27 @@
522 ** -v|--verbose Show all files as they are removed.
523 **
524 ** See also: addremove, extra, status
525 */
526 void clean_cmd(void){
527 int allFlag, dryRunFlag, verboseFlag;
 
528 unsigned scanFlags = 0;
529 const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
530 Blob repo;
531 Stmt q;
532 Glob *pIgnore, *pKeep, *pClean;
533 int nRoot;
534
535 dryRunFlag = find_option("dry-run","n",0)!=0;
536 if( !dryRunFlag ){
537 dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
538 }
539 allFlag = find_option("force","f",0)!=0;
 
 
540 if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
541 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
 
542 zIgnoreFlag = find_option("ignore",0,1);
543 verboseFlag = find_option("verbose","v",0)!=0;
544 zKeepFlag = find_option("keep",0,1);
545 zCleanFlag = find_option("clean",0,1);
546 capture_case_sensitive_option();
@@ -556,51 +575,99 @@
556 }
557 verify_all_options();
558 pIgnore = glob_create(zIgnoreFlag);
559 pKeep = glob_create(zKeepFlag);
560 pClean = glob_create(zCleanFlag);
561 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep);
562 glob_free(pKeep);
563 glob_free(pIgnore);
564 db_prepare(&q,
565 "SELECT %Q || x FROM sfile"
566 " WHERE x NOT IN (%s)"
567 " ORDER BY 1",
568 g.zLocalRoot, fossil_all_reserved_names(0)
569 );
570 if( file_tree_name(g.zRepositoryName, &repo, 0) ){
571 db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
572 }
573 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
574 nRoot = (int)strlen(g.zLocalRoot);
575 while( db_step(&q)==SQLITE_ROW ){
576 const char *zName = db_column_text(&q, 0);
577 if( !allFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
578 Blob ans;
579 char cReply;
580 char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
581 zName+nRoot);
582 blob_zero(&ans);
583 prompt_user(prompt, &ans);
584 cReply = blob_str(&ans)[0];
585 if( cReply=='a' || cReply=='A' ){
586 allFlag = 1;
587 }else if( cReply!='y' && cReply!='Y' ){
588 blob_reset(&ans);
589 continue;
590 }
591 blob_reset(&ans);
592 }
593 if( verboseFlag || dryRunFlag ){
594 fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
595 }
596 if( !dryRunFlag ){
597 file_delete(zName);
598 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599 }
600 glob_free(pClean);
601 db_finalize(&q);
 
602 }
603
604 /*
605 ** Prompt the user for a check-in or stash comment (given in pPrompt),
606 ** gather the response, then return the response in pComment.
@@ -920,11 +987,17 @@
920 const char *zColor; /* Modified value of p->zColor */
921
922 assert( pBaseline==0 || pBaseline->zBaseline==0 );
923 assert( pBaseline==0 || zBaselineUuid!=0 );
924 blob_zero(pOut);
925 zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
 
 
 
 
 
 
926 if( pBaseline ){
927 blob_appendf(pOut, "B %s\n", zBaselineUuid);
928 manifest_file_rewind(pBaseline);
929 pFile = manifest_file_next(pBaseline, 0);
930 nFBcard++;
@@ -1015,28 +1088,30 @@
1015 nFBcard++;
1016 }
1017 if( p->zMimetype && p->zMimetype[0] ){
1018 blob_appendf(pOut, "N %F\n", p->zMimetype);
1019 }
1020 blob_appendf(pOut, "P %s", zParentUuid);
1021 if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate);
1022 free(zParentUuid);
1023 db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1024 while( db_step(&q)==SQLITE_ROW ){
1025 char *zMergeUuid;
1026 int mid = db_column_int(&q, 0);
1027 if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
1028 zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1029 if( zMergeUuid ){
1030 blob_appendf(pOut, " %s", zMergeUuid);
1031 if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1032 free(zMergeUuid);
1033 }
1034 }
1035 db_finalize(&q);
1036 free(zDate);
1037 blob_appendf(pOut, "\n");
 
 
1038
1039 db_prepare(&q,
1040 "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge"
1041 " FROM vmerge, blob"
1042 " WHERE (vmerge.id=-1 OR vmerge.id=-2)"
@@ -1663,11 +1738,11 @@
1663 /* See if a delta-manifest would be more appropriate */
1664 if( !forceBaseline ){
1665 const char *zBaselineUuid;
1666 Manifest *pParent;
1667 Manifest *pBaseline;
1668 pParent = manifest_get(vid, CFTYPE_MANIFEST);
1669 if( pParent && pParent->zBaseline ){
1670 zBaselineUuid = pParent->zBaseline;
1671 pBaseline = manifest_get_by_name(zBaselineUuid, 0);
1672 }else{
1673 zBaselineUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
1674
--- src/checkin.c
+++ src/checkin.c
@@ -248,11 +248,11 @@
248 ** COMMAND: ls
249 **
250 ** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
251 **
252 ** Show the names of all files in the current checkout. The -v provides
253 ** extra information about each file. If FILENAMES are included, only
254 ** the files listed (or their children if they are directories) are shown.
255 **
256 ** Options:
257 ** --age Show when each file was committed
258 ** -v|--verbose Provide extra information about each file.
@@ -363,27 +363,28 @@
363 }
364 db_finalize(&q);
365 }
366
367 /*
368 ** Create a TEMP table named SFILE and add all unmanaged files named on
369 ** the command-line to that table. If directories are named, then add
370 ** all unmanaged files contained underneath those directories. If there
371 ** are no files or directories named on the command-line, then add all
372 ** unmanaged files anywhere in the checkout.
373 */
374 static void locate_unmanaged_files(
375 int argc, /* Number of command-line arguments to examine */
376 char **argv, /* values of command-line arguments */
377 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
378 Glob *pIgnore1, /* Do not add files that match this GLOB */
379 Glob *pIgnore2 /* Omit files matching this GLOB too */
380 ){
381 Blob name; /* Name of a candidate file or directory */
382 char *zName; /* Name of a candidate file or directory */
383 int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
384 int i; /* Loop counter */
385 int nRoot; /* length of g.zLocalRoot */
386
387 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
388 filename_collation());
389 nRoot = (int)strlen(g.zLocalRoot);
390 if( argc==0 ){
@@ -506,12 +507,28 @@
507 ** Files and subdirectories whose names begin with "." are
508 ** normally kept. They are handled if the "--dotfiles" option
509 ** is used.
510 **
511 ** Options:
512 ** --allckouts Check for empty directories within any checkouts
513 ** that may be nested within the current one. This
514 ** option should be used with great care because the
515 ** empty-dirs setting (and other applicable settings)
516 ** belonging to the other repositories, if any, will
517 ** not be checked.
518 ** --case-sensitive <BOOL> override case-sensitive setting
519 ** --dirsonly Only remove empty directories. No files will
520 ** be removed. Using this option will automatically
521 ** enable the --emptydirs option as well.
522 ** --dotfiles Include files beginning with a dot (".").
523 ** --emptydirs Remove any empty directories that are not
524 ** explicitly exempted via the empty-dirs setting
525 ** or another applicable setting or command line
526 ** argument. Matching files, if any, are removed
527 ** prior to checking for any empty directories;
528 ** therefore, directories that contain only files
529 ** that were removed will be removed as well.
530 ** -f|--force Remove files without prompting.
531 ** --clean <CSG> Never prompt for files matching this
532 ** comma separated list of glob patterns.
533 ** --ignore <CSG> Ignore files matching patterns from the
534 ** comma separated list of glob patterns.
@@ -522,25 +539,27 @@
539 ** -v|--verbose Show all files as they are removed.
540 **
541 ** See also: addremove, extra, status
542 */
543 void clean_cmd(void){
544 int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
545 int emptyDirsFlag, dirsOnlyFlag;
546 unsigned scanFlags = 0;
547 const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
 
 
548 Glob *pIgnore, *pKeep, *pClean;
549 int nRoot;
550
551 dryRunFlag = find_option("dry-run","n",0)!=0;
552 if( !dryRunFlag ){
553 dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
554 }
555 allFileFlag = allDirFlag = find_option("force","f",0)!=0;
556 dirsOnlyFlag = find_option("dirsonly",0,0)!=0;
557 emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag;
558 if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
559 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
560 if( find_option("allckouts",0,0)!=0 ) scanFlags |= SCAN_NESTED;
561 zIgnoreFlag = find_option("ignore",0,1);
562 verboseFlag = find_option("verbose","v",0)!=0;
563 zKeepFlag = find_option("keep",0,1);
564 zCleanFlag = find_option("clean",0,1);
565 capture_case_sensitive_option();
@@ -556,51 +575,99 @@
575 }
576 verify_all_options();
577 pIgnore = glob_create(zIgnoreFlag);
578 pKeep = glob_create(zKeepFlag);
579 pClean = glob_create(zCleanFlag);
 
 
 
 
 
 
 
 
 
 
 
 
 
580 nRoot = (int)strlen(g.zLocalRoot);
581 if( !dirsOnlyFlag ){
582 Stmt q;
583 Blob repo;
584 locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep);
585 db_prepare(&q,
586 "SELECT %Q || x FROM sfile"
587 " WHERE x NOT IN (%s)"
588 " ORDER BY 1",
589 g.zLocalRoot, fossil_all_reserved_names(0)
590 );
591 if( file_tree_name(g.zRepositoryName, &repo, 0) ){
592 db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
593 }
594 db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
595 while( db_step(&q)==SQLITE_ROW ){
596 const char *zName = db_column_text(&q, 0);
597 if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
598 Blob ans;
599 char cReply;
600 char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
601 zName+nRoot);
602 blob_zero(&ans);
603 prompt_user(prompt, &ans);
604 cReply = blob_str(&ans)[0];
605 if( cReply=='a' || cReply=='A' ){
606 allFileFlag = 1;
607 }else if( cReply!='y' && cReply!='Y' ){
608 blob_reset(&ans);
609 continue;
610 }
611 blob_reset(&ans);
612 }
613 if ( dryRunFlag || file_delete(zName)==0 ){
614 if( verboseFlag || dryRunFlag ){
615 fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
616 }
617 }else if( verboseFlag ){
618 fossil_print("Could not remove file: %s\n", zName+nRoot);
619 }
620 }
621 db_finalize(&q);
622 }
623 if( emptyDirsFlag ){
624 Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
625 Stmt q;
626 Blob root;
627 blob_init(&root, g.zLocalRoot, nRoot - 1);
628 vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore, pKeep,
629 pEmptyDirs);
630 blob_reset(&root);
631 db_prepare(&q,
632 "SELECT %Q || x FROM dscan_temp"
633 " WHERE x NOT IN (%s) AND y = 0"
634 " ORDER BY 1 DESC",
635 g.zLocalRoot, fossil_all_reserved_names(0)
636 );
637 while( db_step(&q)==SQLITE_ROW ){
638 const char *zName = db_column_text(&q, 0);
639 if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
640 Blob ans;
641 char cReply;
642 char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
643 zName+nRoot);
644 blob_zero(&ans);
645 prompt_user(prompt, &ans);
646 cReply = blob_str(&ans)[0];
647 if( cReply=='a' || cReply=='A' ){
648 allDirFlag = 1;
649 }else if( cReply!='y' && cReply!='Y' ){
650 blob_reset(&ans);
651 continue;
652 }
653 blob_reset(&ans);
654 }
655 if ( dryRunFlag || file_rmdir(zName)==0 ){
656 if( verboseFlag || dryRunFlag ){
657 fossil_print("Removed unmanaged directory: %s\n", zName+nRoot);
658 }
659 }else if( verboseFlag ){
660 fossil_print("Could not remove directory: %s\n", zName+nRoot);
661 }
662 }
663 db_finalize(&q);
664 glob_free(pEmptyDirs);
665 }
666 glob_free(pClean);
667 glob_free(pKeep);
668 glob_free(pIgnore);
669 }
670
671 /*
672 ** Prompt the user for a check-in or stash comment (given in pPrompt),
673 ** gather the response, then return the response in pComment.
@@ -920,11 +987,17 @@
987 const char *zColor; /* Modified value of p->zColor */
988
989 assert( pBaseline==0 || pBaseline->zBaseline==0 );
990 assert( pBaseline==0 || zBaselineUuid!=0 );
991 blob_zero(pOut);
992 zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d AND "
993 "EXISTS(SELECT 1 FROM event WHERE event.type='ci' and event.objid=%d)",
994 vid, vid);
995 if( !zParentUuid ){
996 fossil_fatal("Could not find a valid check-in for RID %d. "
997 "Possible checkout/repo mismatch.", vid);
998 }
999 if( pBaseline ){
1000 blob_appendf(pOut, "B %s\n", zBaselineUuid);
1001 manifest_file_rewind(pBaseline);
1002 pFile = manifest_file_next(pBaseline, 0);
1003 nFBcard++;
@@ -1015,28 +1088,30 @@
1088 nFBcard++;
1089 }
1090 if( p->zMimetype && p->zMimetype[0] ){
1091 blob_appendf(pOut, "N %F\n", p->zMimetype);
1092 }
1093 if( zParentUuid ){
1094 blob_appendf(pOut, "P %s", zParentUuid);
1095 if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate);
1096 free(zParentUuid);
1097 db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
1098 while( db_step(&q)==SQLITE_ROW ){
1099 char *zMergeUuid;
1100 int mid = db_column_int(&q, 0);
1101 if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
1102 zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
1103 if( zMergeUuid ){
1104 blob_appendf(pOut, " %s", zMergeUuid);
1105 if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
1106 free(zMergeUuid);
1107 }
1108 }
1109 db_finalize(&q);
1110 blob_appendf(pOut, "\n");
1111 }
1112 free(zDate);
1113
1114 db_prepare(&q,
1115 "SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge"
1116 " FROM vmerge, blob"
1117 " WHERE (vmerge.id=-1 OR vmerge.id=-2)"
@@ -1663,11 +1738,11 @@
1738 /* See if a delta-manifest would be more appropriate */
1739 if( !forceBaseline ){
1740 const char *zBaselineUuid;
1741 Manifest *pParent;
1742 Manifest *pBaseline;
1743 pParent = manifest_get(vid, CFTYPE_MANIFEST, 0);
1744 if( pParent && pParent->zBaseline ){
1745 zBaselineUuid = pParent->zBaseline;
1746 pBaseline = manifest_get_by_name(zBaselineUuid, 0);
1747 }else{
1748 zBaselineUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
1749
+1 -1
--- src/checkout.c
+++ src/checkout.c
@@ -103,11 +103,11 @@
103103
Manifest *pManifest;
104104
ManifestFile *pFile;
105105
106106
/* Check the EXE permission status of all files
107107
*/
108
- pManifest = manifest_get(vid, CFTYPE_MANIFEST);
108
+ pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0);
109109
if( pManifest==0 ) return;
110110
blob_zero(&filename);
111111
blob_appendf(&filename, "%s", g.zLocalRoot);
112112
baseLen = blob_size(&filename);
113113
manifest_file_rewind(pManifest);
114114
--- src/checkout.c
+++ src/checkout.c
@@ -103,11 +103,11 @@
103 Manifest *pManifest;
104 ManifestFile *pFile;
105
106 /* Check the EXE permission status of all files
107 */
108 pManifest = manifest_get(vid, CFTYPE_MANIFEST);
109 if( pManifest==0 ) return;
110 blob_zero(&filename);
111 blob_appendf(&filename, "%s", g.zLocalRoot);
112 baseLen = blob_size(&filename);
113 manifest_file_rewind(pManifest);
114
--- src/checkout.c
+++ src/checkout.c
@@ -103,11 +103,11 @@
103 Manifest *pManifest;
104 ManifestFile *pFile;
105
106 /* Check the EXE permission status of all files
107 */
108 pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0);
109 if( pManifest==0 ) return;
110 blob_zero(&filename);
111 blob_appendf(&filename, "%s", g.zLocalRoot);
112 baseLen = blob_size(&filename);
113 manifest_file_rewind(pManifest);
114
+25
--- src/clone.c
+++ src/clone.c
@@ -107,10 +107,11 @@
107107
**
108108
** Options:
109109
** --admin-user|-A USERNAME Make USERNAME the administrator
110110
** --private Also clone private branches
111111
** --ssl-identity=filename Use the SSL identity if requested by the server
112
+** --ssh-command|-c 'command' Use this SSH command
112113
**
113114
** See also: init
114115
*/
115116
void clone_cmd(void){
116117
char *zPassword;
@@ -117,10 +118,11 @@
117118
const char *zDefaultUser; /* Optional name of the default user */
118119
int nErr = 0;
119120
int bPrivate = 0; /* Also clone private branches */
120121
121122
if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
123
+ clone_ssh_find_options();
122124
url_proxy_options();
123125
if( g.argc < 4 ){
124126
usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
125127
}
126128
db_open_config(0);
@@ -167,10 +169,11 @@
167169
db_multi_exec(
168170
"REPLACE INTO config(name,value,mtime)"
169171
" VALUES('server-code', lower(hex(randomblob(20))), now());"
170172
);
171173
url_enable_proxy(0);
174
+ clone_ssh_db_set_options();
172175
url_get_password_if_needed();
173176
g.xlinkClusterOnly = 1;
174177
nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
175178
g.xlinkClusterOnly = 0;
176179
verify_cancel();
@@ -188,5 +191,27 @@
188191
fossil_print("project-id: %s\n", db_get("project-code", 0));
189192
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
190193
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
191194
db_end_transaction(0);
192195
}
196
+
197
+/*
198
+** Look for SSH clone command line options and setup in globals.
199
+*/
200
+void clone_ssh_find_options(void){
201
+ const char *zSshCmd; /* SSH command string */
202
+
203
+ zSshCmd = find_option("ssh-command","c",1);
204
+ if( zSshCmd && zSshCmd[0] ){
205
+ g.zSshCmd = mprintf("%s", zSshCmd);
206
+ }
207
+}
208
+
209
+/*
210
+** Set SSH options discovered in global variables (set from command line
211
+** options).
212
+*/
213
+void clone_ssh_db_set_options(void){
214
+ if( g.zSshCmd && g.zSshCmd[0] ){
215
+ db_set("ssh-command", g.zSshCmd, 0);
216
+ }
217
+}
193218
--- src/clone.c
+++ src/clone.c
@@ -107,10 +107,11 @@
107 **
108 ** Options:
109 ** --admin-user|-A USERNAME Make USERNAME the administrator
110 ** --private Also clone private branches
111 ** --ssl-identity=filename Use the SSL identity if requested by the server
 
112 **
113 ** See also: init
114 */
115 void clone_cmd(void){
116 char *zPassword;
@@ -117,10 +118,11 @@
117 const char *zDefaultUser; /* Optional name of the default user */
118 int nErr = 0;
119 int bPrivate = 0; /* Also clone private branches */
120
121 if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
 
122 url_proxy_options();
123 if( g.argc < 4 ){
124 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
125 }
126 db_open_config(0);
@@ -167,10 +169,11 @@
167 db_multi_exec(
168 "REPLACE INTO config(name,value,mtime)"
169 " VALUES('server-code', lower(hex(randomblob(20))), now());"
170 );
171 url_enable_proxy(0);
 
172 url_get_password_if_needed();
173 g.xlinkClusterOnly = 1;
174 nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
175 g.xlinkClusterOnly = 0;
176 verify_cancel();
@@ -188,5 +191,27 @@
188 fossil_print("project-id: %s\n", db_get("project-code", 0));
189 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
190 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
191 db_end_transaction(0);
192 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
--- src/clone.c
+++ src/clone.c
@@ -107,10 +107,11 @@
107 **
108 ** Options:
109 ** --admin-user|-A USERNAME Make USERNAME the administrator
110 ** --private Also clone private branches
111 ** --ssl-identity=filename Use the SSL identity if requested by the server
112 ** --ssh-command|-c 'command' Use this SSH command
113 **
114 ** See also: init
115 */
116 void clone_cmd(void){
117 char *zPassword;
@@ -117,10 +118,11 @@
118 const char *zDefaultUser; /* Optional name of the default user */
119 int nErr = 0;
120 int bPrivate = 0; /* Also clone private branches */
121
122 if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
123 clone_ssh_find_options();
124 url_proxy_options();
125 if( g.argc < 4 ){
126 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
127 }
128 db_open_config(0);
@@ -167,10 +169,11 @@
169 db_multi_exec(
170 "REPLACE INTO config(name,value,mtime)"
171 " VALUES('server-code', lower(hex(randomblob(20))), now());"
172 );
173 url_enable_proxy(0);
174 clone_ssh_db_set_options();
175 url_get_password_if_needed();
176 g.xlinkClusterOnly = 1;
177 nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
178 g.xlinkClusterOnly = 0;
179 verify_cancel();
@@ -188,5 +191,27 @@
191 fossil_print("project-id: %s\n", db_get("project-code", 0));
192 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
193 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
194 db_end_transaction(0);
195 }
196
197 /*
198 ** Look for SSH clone command line options and setup in globals.
199 */
200 void clone_ssh_find_options(void){
201 const char *zSshCmd; /* SSH command string */
202
203 zSshCmd = find_option("ssh-command","c",1);
204 if( zSshCmd && zSshCmd[0] ){
205 g.zSshCmd = mprintf("%s", zSshCmd);
206 }
207 }
208
209 /*
210 ** Set SSH options discovered in global variables (set from command line
211 ** options).
212 */
213 void clone_ssh_db_set_options(void){
214 if( g.zSshCmd && g.zSshCmd[0] ){
215 db_set("ssh-command", g.zSshCmd, 0);
216 }
217 }
218
+6 -1
--- src/config.h
+++ src/config.h
@@ -24,10 +24,15 @@
2424
#define _LARGE_FILE 1
2525
#ifndef _FILE_OFFSET_BITS
2626
# define _FILE_OFFSET_BITS 64
2727
#endif
2828
#define _LARGEFILE_SOURCE 1
29
+
30
+/* Make sure that in Win32 builds, _USE_32BIT_TIME_T is always defined. */
31
+#if defined(_WIN32) && !defined(_WIN64)
32
+# define _USE_32BIT_TIME_T
33
+#endif
2934
3035
#ifdef HAVE_AUTOCONFIG_H
3136
#include "autoconfig.h"
3237
#endif
3338
@@ -82,11 +87,11 @@
8287
# else
8388
# define COMPILER_NAME "unknown"
8489
# endif
8590
#endif
8691
87
-#ifndef _RC_COMPILE_
92
+#if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION)
8893
8994
#include "sqlite3.h"
9095
9196
/*
9297
** On Solaris, getpass() will only return up to 8 characters. getpassphrase() returns up to 257.
9398
--- src/config.h
+++ src/config.h
@@ -24,10 +24,15 @@
24 #define _LARGE_FILE 1
25 #ifndef _FILE_OFFSET_BITS
26 # define _FILE_OFFSET_BITS 64
27 #endif
28 #define _LARGEFILE_SOURCE 1
 
 
 
 
 
29
30 #ifdef HAVE_AUTOCONFIG_H
31 #include "autoconfig.h"
32 #endif
33
@@ -82,11 +87,11 @@
82 # else
83 # define COMPILER_NAME "unknown"
84 # endif
85 #endif
86
87 #ifndef _RC_COMPILE_
88
89 #include "sqlite3.h"
90
91 /*
92 ** On Solaris, getpass() will only return up to 8 characters. getpassphrase() returns up to 257.
93
--- src/config.h
+++ src/config.h
@@ -24,10 +24,15 @@
24 #define _LARGE_FILE 1
25 #ifndef _FILE_OFFSET_BITS
26 # define _FILE_OFFSET_BITS 64
27 #endif
28 #define _LARGEFILE_SOURCE 1
29
30 /* Make sure that in Win32 builds, _USE_32BIT_TIME_T is always defined. */
31 #if defined(_WIN32) && !defined(_WIN64)
32 # define _USE_32BIT_TIME_T
33 #endif
34
35 #ifdef HAVE_AUTOCONFIG_H
36 #include "autoconfig.h"
37 #endif
38
@@ -82,11 +87,11 @@
87 # else
88 # define COMPILER_NAME "unknown"
89 # endif
90 #endif
91
92 #if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION)
93
94 #include "sqlite3.h"
95
96 /*
97 ** On Solaris, getpass() will only return up to 8 characters. getpassphrase() returns up to 257.
98
--- src/configure.c
+++ src/configure.c
@@ -98,10 +98,11 @@
9898
{ "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
9999
{ "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
100100
#endif
101101
102102
{ "project-name", CONFIGSET_PROJ },
103
+ { "short-project-name", CONFIGSET_PROJ },
103104
{ "project-description", CONFIGSET_PROJ },
104105
{ "manifest", CONFIGSET_PROJ },
105106
{ "binary-glob", CONFIGSET_PROJ },
106107
{ "clean-glob", CONFIGSET_PROJ },
107108
{ "ignore-glob", CONFIGSET_PROJ },
108109
109110
ADDED src/cygsup.h
--- src/configure.c
+++ src/configure.c
@@ -98,10 +98,11 @@
98 { "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
99 { "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
100 #endif
101
102 { "project-name", CONFIGSET_PROJ },
 
103 { "project-description", CONFIGSET_PROJ },
104 { "manifest", CONFIGSET_PROJ },
105 { "binary-glob", CONFIGSET_PROJ },
106 { "clean-glob", CONFIGSET_PROJ },
107 { "ignore-glob", CONFIGSET_PROJ },
108
109 DDED src/cygsup.h
--- src/configure.c
+++ src/configure.c
@@ -98,10 +98,11 @@
98 { "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
99 { "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
100 #endif
101
102 { "project-name", CONFIGSET_PROJ },
103 { "short-project-name", CONFIGSET_PROJ },
104 { "project-description", CONFIGSET_PROJ },
105 { "manifest", CONFIGSET_PROJ },
106 { "binary-glob", CONFIGSET_PROJ },
107 { "clean-glob", CONFIGSET_PROJ },
108 { "ignore-glob", CONFIGSET_PROJ },
109
110 DDED src/cygsup.h
--- src/configure.c
+++ src/configure.c
@@ -98,10 +98,11 @@
9898
{ "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
9999
{ "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
100100
#endif
101101
102102
{ "project-name", CONFIGSET_PROJ },
103
+ { "short-project-name", CONFIGSET_PROJ },
103104
{ "project-description", CONFIGSET_PROJ },
104105
{ "manifest", CONFIGSET_PROJ },
105106
{ "binary-glob", CONFIGSET_PROJ },
106107
{ "clean-glob", CONFIGSET_PROJ },
107108
{ "ignore-glob", CONFIGSET_PROJ },
108109
109110
ADDED src/cygsup.h
--- src/configure.c
+++ src/configure.c
@@ -98,10 +98,11 @@
98 { "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
99 { "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
100 #endif
101
102 { "project-name", CONFIGSET_PROJ },
 
103 { "project-description", CONFIGSET_PROJ },
104 { "manifest", CONFIGSET_PROJ },
105 { "binary-glob", CONFIGSET_PROJ },
106 { "clean-glob", CONFIGSET_PROJ },
107 { "ignore-glob", CONFIGSET_PROJ },
108
109 DDED src/cygsup.h
--- src/configure.c
+++ src/configure.c
@@ -98,10 +98,11 @@
98 { "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
99 { "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
100 #endif
101
102 { "project-name", CONFIGSET_PROJ },
103 { "short-project-name", CONFIGSET_PROJ },
104 { "project-description", CONFIGSET_PROJ },
105 { "manifest", CONFIGSET_PROJ },
106 { "binary-glob", CONFIGSET_PROJ },
107 { "clean-glob", CONFIGSET_PROJ },
108 { "ignore-glob", CONFIGSET_PROJ },
109
110 DDED src/cygsup.h
+124
--- a/src/cygsup.h
+++ b/src/cygsup.h
@@ -0,0 +1,124 @@
1
+/*
2
+** Copyright (c) 2007 D. Richard Hipp
3
+**
4
+** This program is free software; you can redistribute it and/or
5
+** modify it under the terms of the Simplified BSD License (also
6
+** known as the "2-Clause License" or "FreeBSD License".)
7
+
8
+** This program is distributed in the hope that it will be useful,
9
+** but without any warranty; without even the implied warranty of
10
+** merchantability or fitness for a particular purpose.
11
+**
12
+** Author contact information:
13
+** [email protected]
14
+** http://www.hwaci.com/drh/
15
+**
16
+*******************************************************************************
17
+**
18
+** This file contains preprocessor directives used to help integrate with the
19
+** Cygwin runtime and build environment. The intent of this file is to keep
20
+** the Cygwin-specific preprocessor directives together.
21
+*/
22
+
23
+#if defined(__CYGWIN__) && !defined(CYGSUP_H)
24
+#define CYGSUP_H
25
+
26
+/*
27
+*******************************************************************************
28
+** Include any Cygwin-specific headers here. **
29
+*******************************************************************************
30
+*/
31
+
32
+#include <wchar.h>
33
+#include <sys/cygwin.h>
34
+
35
+/*
36
+*******************************************************************************
37
+** Define any Cygwin-specific preprocessor macros here. All macros defined in
38
+** this section should be wrapped with #ifndef, in order to allow them to be
39
+** externally overridden.
40
+*******************************************************************************
41
+*/
42
+
43
+#ifndef CP_UTF8
44
+# define CP_UTF8 65001
45
+#endif
46
+
47
+#ifndef WINBASEAPI
48
+# define WINBASEAPI __declspec(dllimport)
49
+#endif
50
+
51
+#ifndef WINADVAPI
52
+# define WINADVAPI __declspec(dllimport)
53
+#endif
54
+
55
+#ifndef SHSTDAPI
56
+# define SHSTDAPI __declspec(dllimport)
57
+#endif
58
+
59
+#ifndef STDAPI
60
+# define STDAPI __stdcall
61
+#endif
62
+
63
+#ifndef WINAPI
64
+# define WINAPI __stdcall
65
+#endif
66
+
67
+/*
68
+*******************************************************************************
69
+** Declare any Cygwin-specific Win32 or other APIs here. Functions declared in
70
+** this section should use the built-in ANSI C types in order to make sure this
71
+** header file continues to work as a self-contained unit.
72
+**
73
+** On Cygwin64, "long" is 64-bit but in Win64 it's 32-bit. That's why in the
74
+** signatures below "long" should not be used. They now use "int" instead.
75
+*******************************************************************************
76
+*/
77
+
78
+WINADVAPI extern WINAPI int RegOpenKeyExW(
79
+ void *, /* HKEY */
80
+ const wchar_t *, /* LPCWSTR */
81
+ unsigned int, /* DWORD */
82
+ unsigned int, /* REGSAM */
83
+ void * /* PHKEY */
84
+ );
85
+
86
+WINADVAPI extern WINAPI int RegQueryValueExW(
87
+ void *, /* HKEY */
88
+ const wchar_t *, /* LPCWSTR */
89
+ unsigned int *, /* LPDWORD */
90
+ unsigned int *, /* LPDWORD */
91
+ unsigned char *, /* LPBYTE */
92
+ unsigned int * /* LPDWORD */
93
+ );
94
+
95
+SHSTDAPI extern STDAPI void *ShellExecuteW(
96
+ void *, /* HWND */
97
+ const wchar_t *, /* LPCWSTR */
98
+ const wchar_t *, /* LPCWSTR */
99
+ const wchar_t *, /* LPCWSTR */
100
+ const wchar_t *, /* LPCWSTR */
101
+ int /* INT */
102
+ );
103
+
104
+WINBASEAPI extern WINAPI int WideCharToMultiByte(
105
+ unsigned int, /* UINT */
106
+ unsigned int, /* DWORD */
107
+ const wchar_t *, /* LPCWSTR */
108
+ int, /* int */
109
+ char *, /* LPSTR */
110
+ int, /* int */
111
+ const char *, /* LPCSTR */
112
+ int * /* LPBOOL */
113
+ );
114
+
115
+WINBASEAPI extern WINAPI int MultiByteToWideChar(
116
+ unsigned int, /* UINT */
117
+ unsigned int, /* DWORD */
118
+ const char *, /* LPCSTR */
119
+ int, /* int */
120
+ wchar_t *, /* LPWSTR */
121
+ int /* int */
122
+ );
123
+
124
+#endif /* defined(__CYGWIN__) && !defined(CYGSUP_H) */
--- a/src/cygsup.h
+++ b/src/cygsup.h
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/cygsup.h
+++ b/src/cygsup.h
@@ -0,0 +1,124 @@
1 /*
2 ** Copyright (c) 2007 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
13 ** [email protected]
14 ** http://www.hwaci.com/drh/
15 **
16 *******************************************************************************
17 **
18 ** This file contains preprocessor directives used to help integrate with the
19 ** Cygwin runtime and build environment. The intent of this file is to keep
20 ** the Cygwin-specific preprocessor directives together.
21 */
22
23 #if defined(__CYGWIN__) && !defined(CYGSUP_H)
24 #define CYGSUP_H
25
26 /*
27 *******************************************************************************
28 ** Include any Cygwin-specific headers here. **
29 *******************************************************************************
30 */
31
32 #include <wchar.h>
33 #include <sys/cygwin.h>
34
35 /*
36 *******************************************************************************
37 ** Define any Cygwin-specific preprocessor macros here. All macros defined in
38 ** this section should be wrapped with #ifndef, in order to allow them to be
39 ** externally overridden.
40 *******************************************************************************
41 */
42
43 #ifndef CP_UTF8
44 # define CP_UTF8 65001
45 #endif
46
47 #ifndef WINBASEAPI
48 # define WINBASEAPI __declspec(dllimport)
49 #endif
50
51 #ifndef WINADVAPI
52 # define WINADVAPI __declspec(dllimport)
53 #endif
54
55 #ifndef SHSTDAPI
56 # define SHSTDAPI __declspec(dllimport)
57 #endif
58
59 #ifndef STDAPI
60 # define STDAPI __stdcall
61 #endif
62
63 #ifndef WINAPI
64 # define WINAPI __stdcall
65 #endif
66
67 /*
68 *******************************************************************************
69 ** Declare any Cygwin-specific Win32 or other APIs here. Functions declared in
70 ** this section should use the built-in ANSI C types in order to make sure this
71 ** header file continues to work as a self-contained unit.
72 **
73 ** On Cygwin64, "long" is 64-bit but in Win64 it's 32-bit. That's why in the
74 ** signatures below "long" should not be used. They now use "int" instead.
75 *******************************************************************************
76 */
77
78 WINADVAPI extern WINAPI int RegOpenKeyExW(
79 void *, /* HKEY */
80 const wchar_t *, /* LPCWSTR */
81 unsigned int, /* DWORD */
82 unsigned int, /* REGSAM */
83 void * /* PHKEY */
84 );
85
86 WINADVAPI extern WINAPI int RegQueryValueExW(
87 void *, /* HKEY */
88 const wchar_t *, /* LPCWSTR */
89 unsigned int *, /* LPDWORD */
90 unsigned int *, /* LPDWORD */
91 unsigned char *, /* LPBYTE */
92 unsigned int * /* LPDWORD */
93 );
94
95 SHSTDAPI extern STDAPI void *ShellExecuteW(
96 void *, /* HWND */
97 const wchar_t *, /* LPCWSTR */
98 const wchar_t *, /* LPCWSTR */
99 const wchar_t *, /* LPCWSTR */
100 const wchar_t *, /* LPCWSTR */
101 int /* INT */
102 );
103
104 WINBASEAPI extern WINAPI int WideCharToMultiByte(
105 unsigned int, /* UINT */
106 unsigned int, /* DWORD */
107 const wchar_t *, /* LPCWSTR */
108 int, /* int */
109 char *, /* LPSTR */
110 int, /* int */
111 const char *, /* LPCSTR */
112 int * /* LPBOOL */
113 );
114
115 WINBASEAPI extern WINAPI int MultiByteToWideChar(
116 unsigned int, /* UINT */
117 unsigned int, /* DWORD */
118 const char *, /* LPCSTR */
119 int, /* int */
120 wchar_t *, /* LPWSTR */
121 int /* int */
122 );
123
124 #endif /* defined(__CYGWIN__) && !defined(CYGSUP_H) */
--- src/delta.c
+++ src/delta.c
@@ -20,10 +20,11 @@
2020
** Though developed specifically for fossil, the code in this file
2121
** is generally applicable and is thus easily separated from the
2222
** fossil source code base. Nothing in this file depends on anything
2323
** else in fossil.
2424
*/
25
+#include "config.h"
2526
#include <stdio.h>
2627
#include <assert.h>
2728
#include <stdlib.h>
2829
#include <string.h>
2930
#include "delta.h"
3031
--- src/delta.c
+++ src/delta.c
@@ -20,10 +20,11 @@
20 ** Though developed specifically for fossil, the code in this file
21 ** is generally applicable and is thus easily separated from the
22 ** fossil source code base. Nothing in this file depends on anything
23 ** else in fossil.
24 */
 
25 #include <stdio.h>
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include "delta.h"
30
--- src/delta.c
+++ src/delta.c
@@ -20,10 +20,11 @@
20 ** Though developed specifically for fossil, the code in this file
21 ** is generally applicable and is thus easily separated from the
22 ** fossil source code base. Nothing in this file depends on anything
23 ** else in fossil.
24 */
25 #include "config.h"
26 #include <stdio.h>
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include "delta.h"
31
+27 -11
--- src/diff.c
+++ src/diff.c
@@ -1939,10 +1939,11 @@
19391939
struct AnnVers {
19401940
const char *zFUuid; /* File being analyzed */
19411941
const char *zMUuid; /* Check-in containing the file */
19421942
const char *zDate; /* Date of the check-in */
19431943
const char *zBgColor; /* Suggested background color */
1944
+ const char *zUser; /* Name of user who did the check-in */
19441945
unsigned cnt; /* Number of lines contributed by this check-in */
19451946
} *aVers; /* For each check-in analyzed */
19461947
char **azVers; /* Names of versions analyzed */
19471948
};
19481949
@@ -2061,10 +2062,11 @@
20612062
db_prepare(&ins, "INSERT OR IGNORE INTO vseen(rid) VALUES(:rid)");
20622063
db_prepare(&q,
20632064
"SELECT (SELECT uuid FROM blob WHERE rid=mlink.fid),"
20642065
" (SELECT uuid FROM blob WHERE rid=mlink.mid),"
20652066
" date(event.mtime),"
2067
+ " coalesce(event.euser,event.user),"
20662068
" mlink.pid"
20672069
" FROM mlink, event"
20682070
" WHERE mlink.fid=:rid"
20692071
" AND event.objid=mlink.mid"
20702072
" AND mlink.pid NOT IN vseen"
@@ -2074,15 +2076,16 @@
20742076
);
20752077
20762078
db_bind_int(&q, ":rid", rid);
20772079
if( iLimit==0 ) iLimit = 1000000000;
20782080
while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2079
- int prevId = db_column_int(&q, 3);
2081
+ int prevId = db_column_int(&q, 4);
20802082
p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0]));
20812083
p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0));
20822084
p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1));
20832085
p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2));
2086
+ p->aVers[p->nVers].zUser = fossil_strdup(db_column_text(&q, 3));
20842087
if( p->nVers ){
20852088
content_get(rid, &step);
20862089
annotation_step(p, &step, p->nVers-1);
20872090
blob_reset(&step);
20882091
}
@@ -2268,15 +2271,18 @@
22682271
style_footer();
22692272
}
22702273
22712274
/*
22722275
** COMMAND: annotate
2276
+** COMMAND: blame
22732277
**
2274
-** %fossil annotate ?OPTIONS? FILENAME
2278
+** %fossil (annotate|blame) ?OPTIONS? FILENAME
22752279
**
22762280
** Output the text of a file with markings to show when each line of
2277
-** the file was last modified.
2281
+** the file was last modified. The "annotate" command shows line numbers
2282
+** and omits the username. The "blame" command shows the user who made each
2283
+** checkin and omits the line number.
22782284
**
22792285
** Options:
22802286
** --filevers Show file version numbers rather than check-in versions
22812287
** -l|--log List all versions analyzed
22822288
** -n|--limit N Only look backwards in time by N versions
@@ -2295,11 +2301,13 @@
22952301
const char *zLimit; /* The value to the -n|--limit option */
22962302
int iLimit; /* How far back in time to look */
22972303
int showLog; /* True to show the log */
22982304
int fileVers; /* Show file version instead of check-in versions */
22992305
int annFlags = 0; /* Flags to control annotation properties */
2306
+ int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
23002307
2308
+ bBlame = g.argv[1][0]=='b';
23012309
zLimit = find_option("limit","n",1);
23022310
if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
23032311
iLimit = atoi(zLimit);
23042312
showLog = find_option("log","l",0)!=0;
23052313
fileVers = find_option("filevers",0,0)!=0;
@@ -2342,18 +2350,26 @@
23422350
}
23432351
for(i=0; i<ann.nOrig; i++){
23442352
int iVers = ann.aOrig[i].iVers;
23452353
char *z = (char*)ann.aOrig[i].z;
23462354
int n = ann.aOrig[i].n;
2347
- char zPrefix[200];
2348
- z[n] = 0;
2355
+ struct AnnVers *p;
23492356
if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2350
- if( iVers>=0 ){
2351
- struct AnnVers *p = ann.aVers+iVers;
2352
- sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%.10s %s",
2353
- fileVers ? p->zFUuid : p->zMUuid, p->zDate);
2357
+ p = ann.aVers + iVers;
2358
+ if( bBlame ){
2359
+ if( iVers>=0 ){
2360
+ fossil_print("%.10s %s %13.13s: %.*s\n",
2361
+ fileVers ? p->zFUuid : p->zMUuid, p->zDate, p->zUser, n, z);
2362
+ }else{
2363
+ fossil_print("%35s %.*s\n", "", n, z);
2364
+ }
23542365
}else{
2355
- zPrefix[0] = 0;
2366
+ if( iVers>=0 ){
2367
+ fossil_print("%.10s %s %5d: %.*s\n",
2368
+ fileVers ? p->zFUuid : p->zMUuid, p->zDate, i+1, n, z);
2369
+ }else{
2370
+ fossil_print("%21s %5d: %.*s\n",
2371
+ "", i+1, n, z);
2372
+ }
23562373
}
2357
- fossil_print("%21s %4d: %.*s\n", zPrefix, i+1, n, z);
23582374
}
23592375
}
23602376
--- src/diff.c
+++ src/diff.c
@@ -1939,10 +1939,11 @@
1939 struct AnnVers {
1940 const char *zFUuid; /* File being analyzed */
1941 const char *zMUuid; /* Check-in containing the file */
1942 const char *zDate; /* Date of the check-in */
1943 const char *zBgColor; /* Suggested background color */
 
1944 unsigned cnt; /* Number of lines contributed by this check-in */
1945 } *aVers; /* For each check-in analyzed */
1946 char **azVers; /* Names of versions analyzed */
1947 };
1948
@@ -2061,10 +2062,11 @@
2061 db_prepare(&ins, "INSERT OR IGNORE INTO vseen(rid) VALUES(:rid)");
2062 db_prepare(&q,
2063 "SELECT (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2064 " (SELECT uuid FROM blob WHERE rid=mlink.mid),"
2065 " date(event.mtime),"
 
2066 " mlink.pid"
2067 " FROM mlink, event"
2068 " WHERE mlink.fid=:rid"
2069 " AND event.objid=mlink.mid"
2070 " AND mlink.pid NOT IN vseen"
@@ -2074,15 +2076,16 @@
2074 );
2075
2076 db_bind_int(&q, ":rid", rid);
2077 if( iLimit==0 ) iLimit = 1000000000;
2078 while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2079 int prevId = db_column_int(&q, 3);
2080 p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0]));
2081 p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0));
2082 p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1));
2083 p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2));
 
2084 if( p->nVers ){
2085 content_get(rid, &step);
2086 annotation_step(p, &step, p->nVers-1);
2087 blob_reset(&step);
2088 }
@@ -2268,15 +2271,18 @@
2268 style_footer();
2269 }
2270
2271 /*
2272 ** COMMAND: annotate
 
2273 **
2274 ** %fossil annotate ?OPTIONS? FILENAME
2275 **
2276 ** Output the text of a file with markings to show when each line of
2277 ** the file was last modified.
 
 
2278 **
2279 ** Options:
2280 ** --filevers Show file version numbers rather than check-in versions
2281 ** -l|--log List all versions analyzed
2282 ** -n|--limit N Only look backwards in time by N versions
@@ -2295,11 +2301,13 @@
2295 const char *zLimit; /* The value to the -n|--limit option */
2296 int iLimit; /* How far back in time to look */
2297 int showLog; /* True to show the log */
2298 int fileVers; /* Show file version instead of check-in versions */
2299 int annFlags = 0; /* Flags to control annotation properties */
 
2300
 
2301 zLimit = find_option("limit","n",1);
2302 if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2303 iLimit = atoi(zLimit);
2304 showLog = find_option("log","l",0)!=0;
2305 fileVers = find_option("filevers",0,0)!=0;
@@ -2342,18 +2350,26 @@
2342 }
2343 for(i=0; i<ann.nOrig; i++){
2344 int iVers = ann.aOrig[i].iVers;
2345 char *z = (char*)ann.aOrig[i].z;
2346 int n = ann.aOrig[i].n;
2347 char zPrefix[200];
2348 z[n] = 0;
2349 if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2350 if( iVers>=0 ){
2351 struct AnnVers *p = ann.aVers+iVers;
2352 sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%.10s %s",
2353 fileVers ? p->zFUuid : p->zMUuid, p->zDate);
 
 
 
 
2354 }else{
2355 zPrefix[0] = 0;
 
 
 
 
 
 
2356 }
2357 fossil_print("%21s %4d: %.*s\n", zPrefix, i+1, n, z);
2358 }
2359 }
2360
--- src/diff.c
+++ src/diff.c
@@ -1939,10 +1939,11 @@
1939 struct AnnVers {
1940 const char *zFUuid; /* File being analyzed */
1941 const char *zMUuid; /* Check-in containing the file */
1942 const char *zDate; /* Date of the check-in */
1943 const char *zBgColor; /* Suggested background color */
1944 const char *zUser; /* Name of user who did the check-in */
1945 unsigned cnt; /* Number of lines contributed by this check-in */
1946 } *aVers; /* For each check-in analyzed */
1947 char **azVers; /* Names of versions analyzed */
1948 };
1949
@@ -2061,10 +2062,11 @@
2062 db_prepare(&ins, "INSERT OR IGNORE INTO vseen(rid) VALUES(:rid)");
2063 db_prepare(&q,
2064 "SELECT (SELECT uuid FROM blob WHERE rid=mlink.fid),"
2065 " (SELECT uuid FROM blob WHERE rid=mlink.mid),"
2066 " date(event.mtime),"
2067 " coalesce(event.euser,event.user),"
2068 " mlink.pid"
2069 " FROM mlink, event"
2070 " WHERE mlink.fid=:rid"
2071 " AND event.objid=mlink.mid"
2072 " AND mlink.pid NOT IN vseen"
@@ -2074,15 +2076,16 @@
2076 );
2077
2078 db_bind_int(&q, ":rid", rid);
2079 if( iLimit==0 ) iLimit = 1000000000;
2080 while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
2081 int prevId = db_column_int(&q, 4);
2082 p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0]));
2083 p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0));
2084 p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1));
2085 p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2));
2086 p->aVers[p->nVers].zUser = fossil_strdup(db_column_text(&q, 3));
2087 if( p->nVers ){
2088 content_get(rid, &step);
2089 annotation_step(p, &step, p->nVers-1);
2090 blob_reset(&step);
2091 }
@@ -2268,15 +2271,18 @@
2271 style_footer();
2272 }
2273
2274 /*
2275 ** COMMAND: annotate
2276 ** COMMAND: blame
2277 **
2278 ** %fossil (annotate|blame) ?OPTIONS? FILENAME
2279 **
2280 ** Output the text of a file with markings to show when each line of
2281 ** the file was last modified. The "annotate" command shows line numbers
2282 ** and omits the username. The "blame" command shows the user who made each
2283 ** checkin and omits the line number.
2284 **
2285 ** Options:
2286 ** --filevers Show file version numbers rather than check-in versions
2287 ** -l|--log List all versions analyzed
2288 ** -n|--limit N Only look backwards in time by N versions
@@ -2295,11 +2301,13 @@
2301 const char *zLimit; /* The value to the -n|--limit option */
2302 int iLimit; /* How far back in time to look */
2303 int showLog; /* True to show the log */
2304 int fileVers; /* Show file version instead of check-in versions */
2305 int annFlags = 0; /* Flags to control annotation properties */
2306 int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
2307
2308 bBlame = g.argv[1][0]=='b';
2309 zLimit = find_option("limit","n",1);
2310 if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
2311 iLimit = atoi(zLimit);
2312 showLog = find_option("log","l",0)!=0;
2313 fileVers = find_option("filevers",0,0)!=0;
@@ -2342,18 +2350,26 @@
2350 }
2351 for(i=0; i<ann.nOrig; i++){
2352 int iVers = ann.aOrig[i].iVers;
2353 char *z = (char*)ann.aOrig[i].z;
2354 int n = ann.aOrig[i].n;
2355 struct AnnVers *p;
 
2356 if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
2357 p = ann.aVers + iVers;
2358 if( bBlame ){
2359 if( iVers>=0 ){
2360 fossil_print("%.10s %s %13.13s: %.*s\n",
2361 fileVers ? p->zFUuid : p->zMUuid, p->zDate, p->zUser, n, z);
2362 }else{
2363 fossil_print("%35s %.*s\n", "", n, z);
2364 }
2365 }else{
2366 if( iVers>=0 ){
2367 fossil_print("%.10s %s %5d: %.*s\n",
2368 fileVers ? p->zFUuid : p->zMUuid, p->zDate, i+1, n, z);
2369 }else{
2370 fossil_print("%21s %5d: %.*s\n",
2371 "", i+1, n, z);
2372 }
2373 }
 
2374 }
2375 }
2376
+20 -6
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -915,11 +915,11 @@
915915
** (3) Delete the temp file.
916916
*/
917917
void diff_tk(const char *zSubCmd, int firstArg){
918918
int i;
919919
Blob script;
920
- char *zTempFile;
920
+ char *zTempFile = 0;
921921
char *zCmd;
922922
blob_zero(&script);
923923
blob_appendf(&script, "set fossilcmd {| \"%/\" %s --html -y -i -v",
924924
g.nameOfExe, zSubCmd);
925925
for(i=firstArg; i<g.argc; i++){
@@ -926,20 +926,34 @@
926926
const char *z = g.argv[i];
927927
if( z[0]=='-' ){
928928
if( strglob("*-html",z) ) continue;
929929
if( strglob("*-y",z) ) continue;
930930
if( strglob("*-i",z) ) continue;
931
+ /* The undocumented --script FILENAME option causes the Tk script to
932
+ ** be written into the FILENAME instead of being run. This is used
933
+ ** for testing and debugging. */
934
+ if( strglob("*-script",z) && i<g.argc-1 ){
935
+ i++;
936
+ zTempFile = g.argv[i];
937
+ continue;
938
+ }
931939
}
932940
blob_append(&script, " ", 1);
933941
shell_escape(&script, z);
934942
}
935943
blob_appendf(&script, "}\n%s", zDiffScript);
936
- zTempFile = write_blob_to_temp_file(&script);
937
- zCmd = mprintf("tclsh \"%s\"", zTempFile);
938
- fossil_system(zCmd);
939
- file_delete(zTempFile);
940
- fossil_free(zCmd);
944
+ if( zTempFile ){
945
+ blob_write_to_file(&script, zTempFile);
946
+ fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile);
947
+ }else{
948
+ zTempFile = write_blob_to_temp_file(&script);
949
+ zCmd = mprintf("tclsh \"%s\"", zTempFile);
950
+ fossil_system(zCmd);
951
+ file_delete(zTempFile);
952
+ fossil_free(zCmd);
953
+ }
954
+ blob_reset(&script);
941955
}
942956
943957
/*
944958
** Returns non-zero if files that may be binary should be used with external
945959
** diff programs.
946960
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -915,11 +915,11 @@
915 ** (3) Delete the temp file.
916 */
917 void diff_tk(const char *zSubCmd, int firstArg){
918 int i;
919 Blob script;
920 char *zTempFile;
921 char *zCmd;
922 blob_zero(&script);
923 blob_appendf(&script, "set fossilcmd {| \"%/\" %s --html -y -i -v",
924 g.nameOfExe, zSubCmd);
925 for(i=firstArg; i<g.argc; i++){
@@ -926,20 +926,34 @@
926 const char *z = g.argv[i];
927 if( z[0]=='-' ){
928 if( strglob("*-html",z) ) continue;
929 if( strglob("*-y",z) ) continue;
930 if( strglob("*-i",z) ) continue;
 
 
 
 
 
 
 
 
931 }
932 blob_append(&script, " ", 1);
933 shell_escape(&script, z);
934 }
935 blob_appendf(&script, "}\n%s", zDiffScript);
936 zTempFile = write_blob_to_temp_file(&script);
937 zCmd = mprintf("tclsh \"%s\"", zTempFile);
938 fossil_system(zCmd);
939 file_delete(zTempFile);
940 fossil_free(zCmd);
 
 
 
 
 
 
941 }
942
943 /*
944 ** Returns non-zero if files that may be binary should be used with external
945 ** diff programs.
946
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -915,11 +915,11 @@
915 ** (3) Delete the temp file.
916 */
917 void diff_tk(const char *zSubCmd, int firstArg){
918 int i;
919 Blob script;
920 char *zTempFile = 0;
921 char *zCmd;
922 blob_zero(&script);
923 blob_appendf(&script, "set fossilcmd {| \"%/\" %s --html -y -i -v",
924 g.nameOfExe, zSubCmd);
925 for(i=firstArg; i<g.argc; i++){
@@ -926,20 +926,34 @@
926 const char *z = g.argv[i];
927 if( z[0]=='-' ){
928 if( strglob("*-html",z) ) continue;
929 if( strglob("*-y",z) ) continue;
930 if( strglob("*-i",z) ) continue;
931 /* The undocumented --script FILENAME option causes the Tk script to
932 ** be written into the FILENAME instead of being run. This is used
933 ** for testing and debugging. */
934 if( strglob("*-script",z) && i<g.argc-1 ){
935 i++;
936 zTempFile = g.argv[i];
937 continue;
938 }
939 }
940 blob_append(&script, " ", 1);
941 shell_escape(&script, z);
942 }
943 blob_appendf(&script, "}\n%s", zDiffScript);
944 if( zTempFile ){
945 blob_write_to_file(&script, zTempFile);
946 fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile);
947 }else{
948 zTempFile = write_blob_to_temp_file(&script);
949 zCmd = mprintf("tclsh \"%s\"", zTempFile);
950 fossil_system(zCmd);
951 file_delete(zTempFile);
952 fossil_free(zCmd);
953 }
954 blob_reset(&script);
955 }
956
957 /*
958 ** Returns non-zero if files that may be binary should be used with external
959 ** diff programs.
960
+1 -1
--- src/doc.c
+++ src/doc.c
@@ -449,11 +449,11 @@
449449
450450
/* Add the vid baseline to the cache */
451451
if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){
452452
db_multi_exec("DELETE FROM vcache");
453453
}
454
- pM = manifest_get(vid, CFTYPE_MANIFEST);
454
+ pM = manifest_get(vid, CFTYPE_MANIFEST, 0);
455455
if( pM==0 ){
456456
goto doc_not_found;
457457
}
458458
db_prepare(&s,
459459
"INSERT INTO vcache(vid,fname,rid)"
460460
--- src/doc.c
+++ src/doc.c
@@ -449,11 +449,11 @@
449
450 /* Add the vid baseline to the cache */
451 if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){
452 db_multi_exec("DELETE FROM vcache");
453 }
454 pM = manifest_get(vid, CFTYPE_MANIFEST);
455 if( pM==0 ){
456 goto doc_not_found;
457 }
458 db_prepare(&s,
459 "INSERT INTO vcache(vid,fname,rid)"
460
--- src/doc.c
+++ src/doc.c
@@ -449,11 +449,11 @@
449
450 /* Add the vid baseline to the cache */
451 if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){
452 db_multi_exec("DELETE FROM vcache");
453 }
454 pM = manifest_get(vid, CFTYPE_MANIFEST, 0);
455 if( pM==0 ){
456 goto doc_not_found;
457 }
458 db_prepare(&s,
459 "INSERT INTO vcache(vid,fname,rid)"
460
+3 -3
--- src/event.c
+++ src/event.c
@@ -21,13 +21,13 @@
2121
** Blog posts
2222
** New articles
2323
** Process checkpoints
2424
** Announcements
2525
*/
26
+#include "config.h"
2627
#include <assert.h>
2728
#include <ctype.h>
28
-#include "config.h"
2929
#include "event.h"
3030
3131
/*
3232
** Output a hyperlink to an event given its tagid.
3333
*/
@@ -113,11 +113,11 @@
113113
}
114114
verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
115115
116116
/* Extract the event content.
117117
*/
118
- pEvent = manifest_get(rid, CFTYPE_EVENT);
118
+ pEvent = manifest_get(rid, CFTYPE_EVENT, 0);
119119
if( pEvent==0 ){
120120
fossil_fatal("Object #%d is not an event", rid);
121121
}
122122
blob_init(&fullbody, pEvent->zWiki, -1);
123123
if( wiki_find_title(&fullbody, &title, &tail) ){
@@ -257,11 +257,11 @@
257257
/* If editing an existing event, extract the key fields to use as
258258
** a starting point for the edit.
259259
*/
260260
if( rid && (zBody==0 || zETime==0 || zComment==0 || zTags==0) ){
261261
Manifest *pEvent;
262
- pEvent = manifest_get(rid, CFTYPE_EVENT);
262
+ pEvent = manifest_get(rid, CFTYPE_EVENT, 0);
263263
if( pEvent && pEvent->type==CFTYPE_EVENT ){
264264
if( zBody==0 ) zBody = pEvent->zWiki;
265265
if( zETime==0 ){
266266
zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate);
267267
}
268268
--- src/event.c
+++ src/event.c
@@ -21,13 +21,13 @@
21 ** Blog posts
22 ** New articles
23 ** Process checkpoints
24 ** Announcements
25 */
 
26 #include <assert.h>
27 #include <ctype.h>
28 #include "config.h"
29 #include "event.h"
30
31 /*
32 ** Output a hyperlink to an event given its tagid.
33 */
@@ -113,11 +113,11 @@
113 }
114 verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
115
116 /* Extract the event content.
117 */
118 pEvent = manifest_get(rid, CFTYPE_EVENT);
119 if( pEvent==0 ){
120 fossil_fatal("Object #%d is not an event", rid);
121 }
122 blob_init(&fullbody, pEvent->zWiki, -1);
123 if( wiki_find_title(&fullbody, &title, &tail) ){
@@ -257,11 +257,11 @@
257 /* If editing an existing event, extract the key fields to use as
258 ** a starting point for the edit.
259 */
260 if( rid && (zBody==0 || zETime==0 || zComment==0 || zTags==0) ){
261 Manifest *pEvent;
262 pEvent = manifest_get(rid, CFTYPE_EVENT);
263 if( pEvent && pEvent->type==CFTYPE_EVENT ){
264 if( zBody==0 ) zBody = pEvent->zWiki;
265 if( zETime==0 ){
266 zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate);
267 }
268
--- src/event.c
+++ src/event.c
@@ -21,13 +21,13 @@
21 ** Blog posts
22 ** New articles
23 ** Process checkpoints
24 ** Announcements
25 */
26 #include "config.h"
27 #include <assert.h>
28 #include <ctype.h>
 
29 #include "event.h"
30
31 /*
32 ** Output a hyperlink to an event given its tagid.
33 */
@@ -113,11 +113,11 @@
113 }
114 verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
115
116 /* Extract the event content.
117 */
118 pEvent = manifest_get(rid, CFTYPE_EVENT, 0);
119 if( pEvent==0 ){
120 fossil_fatal("Object #%d is not an event", rid);
121 }
122 blob_init(&fullbody, pEvent->zWiki, -1);
123 if( wiki_find_title(&fullbody, &title, &tail) ){
@@ -257,11 +257,11 @@
257 /* If editing an existing event, extract the key fields to use as
258 ** a starting point for the edit.
259 */
260 if( rid && (zBody==0 || zETime==0 || zComment==0 || zTags==0) ){
261 Manifest *pEvent;
262 pEvent = manifest_get(rid, CFTYPE_EVENT, 0);
263 if( pEvent && pEvent->type==CFTYPE_EVENT ){
264 if( zBody==0 ) zBody = pEvent->zWiki;
265 if( zETime==0 ){
266 zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate);
267 }
268
+30 -3
--- src/file.c
+++ src/file.c
@@ -461,20 +461,24 @@
461461
fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
462462
}
463463
464464
/*
465465
** Delete a file.
466
+**
467
+** Returns zero upon success.
466468
*/
467
-void file_delete(const char *zFilename){
469
+int file_delete(const char *zFilename){
470
+ int rc;
468471
#ifdef _WIN32
469472
wchar_t *z = fossil_utf8_to_filename(zFilename);
470
- _wunlink(z);
473
+ rc = _wunlink(z);
471474
#else
472475
char *z = fossil_utf8_to_filename(zFilename);
473
- unlink(zFilename);
476
+ rc = unlink(zFilename);
474477
#endif
475478
fossil_filename_free(z);
479
+ return rc;
476480
}
477481
478482
/*
479483
** Create the directory named in the argument, if it does not already
480484
** exist. If forceFlag is 1, delete any prior non-directory object
@@ -493,10 +497,33 @@
493497
wchar_t *zMbcs = fossil_utf8_to_filename(zName);
494498
rc = _wmkdir(zMbcs);
495499
#else
496500
char *zMbcs = fossil_utf8_to_filename(zName);
497501
rc = mkdir(zName, 0755);
502
+#endif
503
+ fossil_filename_free(zMbcs);
504
+ return rc;
505
+ }
506
+ return 0;
507
+}
508
+
509
+/*
510
+** Removes the directory named in the argument, if it exists. The directory
511
+** must be empty and cannot be the current directory or the root directory.
512
+**
513
+** Returns zero upon success.
514
+*/
515
+int file_rmdir(const char *zName){
516
+ int rc = file_wd_isdir(zName);
517
+ if( rc==2 ) return 1; /* cannot remove normal file */
518
+ if( rc==1 ){
519
+#if defined(_WIN32)
520
+ wchar_t *zMbcs = fossil_utf8_to_filename(zName);
521
+ rc = _wrmdir(zMbcs);
522
+#else
523
+ char *zMbcs = fossil_utf8_to_filename(zName);
524
+ rc = rmdir(zName);
498525
#endif
499526
fossil_filename_free(zMbcs);
500527
return rc;
501528
}
502529
return 0;
503530
--- src/file.c
+++ src/file.c
@@ -461,20 +461,24 @@
461 fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
462 }
463
464 /*
465 ** Delete a file.
 
 
466 */
467 void file_delete(const char *zFilename){
 
468 #ifdef _WIN32
469 wchar_t *z = fossil_utf8_to_filename(zFilename);
470 _wunlink(z);
471 #else
472 char *z = fossil_utf8_to_filename(zFilename);
473 unlink(zFilename);
474 #endif
475 fossil_filename_free(z);
 
476 }
477
478 /*
479 ** Create the directory named in the argument, if it does not already
480 ** exist. If forceFlag is 1, delete any prior non-directory object
@@ -493,10 +497,33 @@
493 wchar_t *zMbcs = fossil_utf8_to_filename(zName);
494 rc = _wmkdir(zMbcs);
495 #else
496 char *zMbcs = fossil_utf8_to_filename(zName);
497 rc = mkdir(zName, 0755);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
498 #endif
499 fossil_filename_free(zMbcs);
500 return rc;
501 }
502 return 0;
503
--- src/file.c
+++ src/file.c
@@ -461,20 +461,24 @@
461 fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
462 }
463
464 /*
465 ** Delete a file.
466 **
467 ** Returns zero upon success.
468 */
469 int file_delete(const char *zFilename){
470 int rc;
471 #ifdef _WIN32
472 wchar_t *z = fossil_utf8_to_filename(zFilename);
473 rc = _wunlink(z);
474 #else
475 char *z = fossil_utf8_to_filename(zFilename);
476 rc = unlink(zFilename);
477 #endif
478 fossil_filename_free(z);
479 return rc;
480 }
481
482 /*
483 ** Create the directory named in the argument, if it does not already
484 ** exist. If forceFlag is 1, delete any prior non-directory object
@@ -493,10 +497,33 @@
497 wchar_t *zMbcs = fossil_utf8_to_filename(zName);
498 rc = _wmkdir(zMbcs);
499 #else
500 char *zMbcs = fossil_utf8_to_filename(zName);
501 rc = mkdir(zName, 0755);
502 #endif
503 fossil_filename_free(zMbcs);
504 return rc;
505 }
506 return 0;
507 }
508
509 /*
510 ** Removes the directory named in the argument, if it exists. The directory
511 ** must be empty and cannot be the current directory or the root directory.
512 **
513 ** Returns zero upon success.
514 */
515 int file_rmdir(const char *zName){
516 int rc = file_wd_isdir(zName);
517 if( rc==2 ) return 1; /* cannot remove normal file */
518 if( rc==1 ){
519 #if defined(_WIN32)
520 wchar_t *zMbcs = fossil_utf8_to_filename(zName);
521 rc = _wrmdir(zMbcs);
522 #else
523 char *zMbcs = fossil_utf8_to_filename(zName);
524 rc = rmdir(zName);
525 #endif
526 fossil_filename_free(zMbcs);
527 return rc;
528 }
529 return 0;
530
+1 -1
--- src/gzip.c
+++ src/gzip.c
@@ -19,13 +19,13 @@
1919
** file. The GZIP format is described in RFC-1952.
2020
**
2121
** State information is stored in static variables, so this implementation
2222
** can only be building up a single GZIP file at a time.
2323
*/
24
+#include "config.h"
2425
#include <assert.h>
2526
#include <zlib.h>
26
-#include "config.h"
2727
#include "gzip.h"
2828
2929
/*
3030
** State information for the GZIP file under construction.
3131
*/
3232
--- src/gzip.c
+++ src/gzip.c
@@ -19,13 +19,13 @@
19 ** file. The GZIP format is described in RFC-1952.
20 **
21 ** State information is stored in static variables, so this implementation
22 ** can only be building up a single GZIP file at a time.
23 */
 
24 #include <assert.h>
25 #include <zlib.h>
26 #include "config.h"
27 #include "gzip.h"
28
29 /*
30 ** State information for the GZIP file under construction.
31 */
32
--- src/gzip.c
+++ src/gzip.c
@@ -19,13 +19,13 @@
19 ** file. The GZIP format is described in RFC-1952.
20 **
21 ** State information is stored in static variables, so this implementation
22 ** can only be building up a single GZIP file at a time.
23 */
24 #include "config.h"
25 #include <assert.h>
26 #include <zlib.h>
 
27 #include "gzip.h"
28
29 /*
30 ** State information for the GZIP file under construction.
31 */
32
+14 -1
--- src/http.c
+++ src/http.c
@@ -112,10 +112,11 @@
112112
fossil_free(zCredentials);
113113
}
114114
blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
115115
blob_appendf(pHdr, "User-Agent: Fossil/" RELEASE_VERSION
116116
" (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n");
117
+ if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
117118
if( g.fHttpTrace ){
118119
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
119120
}else{
120121
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
121122
}
@@ -217,10 +218,20 @@
217218
if( iHttpVersion==0 ){
218219
closeConnection = 1;
219220
}else{
220221
closeConnection = 0;
221222
}
223
+ }else if( g.urlIsSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){
224
+ if( sscanf(zLine, "Status: %d", &rc)!=1 ) goto write_err;
225
+ if( rc!=200 && rc!=302 ){
226
+ int ii;
227
+ for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
228
+ while( zLine[ii]==' ' ) ii++;
229
+ fossil_warning("server says: %s", &zLine[ii]);
230
+ goto write_err;
231
+ }
232
+ closeConnection = 0;
222233
}else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){
223234
for(i=15; fossil_isspace(zLine[i]); i++){}
224235
iLength = atoi(&zLine[i]);
225236
}else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){
226237
char c;
@@ -295,12 +306,14 @@
295306
** Close the connection to the server if appropriate.
296307
**
297308
** FIXME: There is some bug in the lower layers that prevents the
298309
** connection from remaining open. The easiest fix for now is to
299310
** simply close and restart the connection for each round-trip.
311
+ **
312
+ ** For SSH we will leave the connection open.
300313
*/
301
- closeConnection = 1; /* FIX ME */
314
+ if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
302315
if( closeConnection ){
303316
transport_close();
304317
}else{
305318
transport_rewind();
306319
}
307320
--- src/http.c
+++ src/http.c
@@ -112,10 +112,11 @@
112 fossil_free(zCredentials);
113 }
114 blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
115 blob_appendf(pHdr, "User-Agent: Fossil/" RELEASE_VERSION
116 " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n");
 
117 if( g.fHttpTrace ){
118 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
119 }else{
120 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
121 }
@@ -217,10 +218,20 @@
217 if( iHttpVersion==0 ){
218 closeConnection = 1;
219 }else{
220 closeConnection = 0;
221 }
 
 
 
 
 
 
 
 
 
 
222 }else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){
223 for(i=15; fossil_isspace(zLine[i]); i++){}
224 iLength = atoi(&zLine[i]);
225 }else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){
226 char c;
@@ -295,12 +306,14 @@
295 ** Close the connection to the server if appropriate.
296 **
297 ** FIXME: There is some bug in the lower layers that prevents the
298 ** connection from remaining open. The easiest fix for now is to
299 ** simply close and restart the connection for each round-trip.
 
 
300 */
301 closeConnection = 1; /* FIX ME */
302 if( closeConnection ){
303 transport_close();
304 }else{
305 transport_rewind();
306 }
307
--- src/http.c
+++ src/http.c
@@ -112,10 +112,11 @@
112 fossil_free(zCredentials);
113 }
114 blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
115 blob_appendf(pHdr, "User-Agent: Fossil/" RELEASE_VERSION
116 " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n");
117 if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
118 if( g.fHttpTrace ){
119 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
120 }else{
121 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
122 }
@@ -217,10 +218,20 @@
218 if( iHttpVersion==0 ){
219 closeConnection = 1;
220 }else{
221 closeConnection = 0;
222 }
223 }else if( g.urlIsSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){
224 if( sscanf(zLine, "Status: %d", &rc)!=1 ) goto write_err;
225 if( rc!=200 && rc!=302 ){
226 int ii;
227 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
228 while( zLine[ii]==' ' ) ii++;
229 fossil_warning("server says: %s", &zLine[ii]);
230 goto write_err;
231 }
232 closeConnection = 0;
233 }else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){
234 for(i=15; fossil_isspace(zLine[i]); i++){}
235 iLength = atoi(&zLine[i]);
236 }else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){
237 char c;
@@ -295,12 +306,14 @@
306 ** Close the connection to the server if appropriate.
307 **
308 ** FIXME: There is some bug in the lower layers that prevents the
309 ** connection from remaining open. The easiest fix for now is to
310 ** simply close and restart the connection for each round-trip.
311 **
312 ** For SSH we will leave the connection open.
313 */
314 if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
315 if( closeConnection ){
316 transport_close();
317 }else{
318 transport_rewind();
319 }
320
--- src/http_socket.c
+++ src/http_socket.c
@@ -209,5 +209,22 @@
209209
N -= (size_t)got;
210210
pContent = (void*)&((char*)pContent)[got];
211211
}
212212
return total;
213213
}
214
+
215
+/*
216
+** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
217
+** populated. For hostnames with more than one IP (or if overridden in
218
+** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
219
+*/
220
+void socket_ssh_resolve_addr(void){
221
+ struct hostent *pHost; /* Used to make best effort for rcvfrom */
222
+ struct sockaddr_in addr;
223
+
224
+ memset(&addr, 0, sizeof(addr));
225
+ pHost = gethostbyname(g.urlName);
226
+ if( pHost!=0 ){
227
+ memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
228
+ g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
229
+ }
230
+}
214231
--- src/http_socket.c
+++ src/http_socket.c
@@ -209,5 +209,22 @@
209 N -= (size_t)got;
210 pContent = (void*)&((char*)pContent)[got];
211 }
212 return total;
213 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
--- src/http_socket.c
+++ src/http_socket.c
@@ -209,5 +209,22 @@
209 N -= (size_t)got;
210 pContent = (void*)&((char*)pContent)[got];
211 }
212 return total;
213 }
214
215 /*
216 ** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
217 ** populated. For hostnames with more than one IP (or if overridden in
218 ** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
219 */
220 void socket_ssh_resolve_addr(void){
221 struct hostent *pHost; /* Used to make best effort for rcvfrom */
222 struct sockaddr_in addr;
223
224 memset(&addr, 0, sizeof(addr));
225 pHost = gethostbyname(g.urlName);
226 if( pHost!=0 ){
227 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
228 g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
229 }
230 }
231
--- src/http_transport.c
+++ src/http_transport.c
@@ -74,25 +74,10 @@
7474
transport.nSent = 0;
7575
transport.nRcvd = 0;
7676
}
7777
}
7878
79
-/*
80
-** Read text from sshIn. Zero-terminate and remove trailing
81
-** whitespace.
82
-*/
83
-static void sshin_read(char *zBuf, int szBuf){
84
- int got;
85
- zBuf[0] = 0;
86
- got = read(sshIn, zBuf, szBuf-1);
87
- while( got>=0 ){
88
- zBuf[got] = 0;
89
- if( got==0 || !fossil_isspace(zBuf[got-1]) ) break;
90
- got--;
91
- }
92
-}
93
-
9479
/*
9580
** Default SSH command
9681
*/
9782
#ifdef __MINGW32__
9883
static char zDefaultSshCmd[] = "ssh -T";
@@ -99,183 +84,60 @@
9984
#else
10085
static char zDefaultSshCmd[] = "ssh -e none -T";
10186
#endif
10287
10388
/*
104
-** Generate a random SSH link problem keyword
105
-*/
106
-static int random_probe(char *zProbe, int nProbe){
107
- unsigned r[4];
108
- sqlite3_randomness(sizeof(r), r);
109
- sqlite3_snprintf(nProbe, zProbe, "probe-%08x%08x%08x%08x",
110
- r[0], r[1], r[2], r[3]);
111
- return (int)strlen(zProbe);
112
-}
113
-
114
-/*
115
-** Bring up an SSH link. This involves sending some "echo" commands and
116
-** get back appropriate responses. The point is to move past the MOTD and
117
-** verify that the link is working.
118
-*/
119
-static void transport_ssh_startup(void){
120
- char *zIn; /* An input line received back from remote */
121
- int nWait; /* Number of times waiting for the MOTD */
122
- char zProbe[40]; /* Text of the random probe */
123
- int nProbe; /* Size of probe message */
124
- int nIn; /* Size of input */
125
- static const int nBuf = 10000; /* Size of input buffer */
126
-
127
- zIn = fossil_malloc(nBuf);
128
- nProbe = random_probe(zProbe, sizeof(zProbe));
129
- fprintf(sshOut, "echo %s\n", zProbe);
130
- fflush(sshOut);
131
- if( g.fSshTrace ){
132
- printf("Sent: [echo %s]\n", zProbe);
133
- fflush(stdout);
134
- }
135
- memset(zIn, '*', nProbe);
136
- for(nWait=1; nWait<=10; nWait++){
137
- sshin_read(zIn+nProbe, nBuf-nProbe);
138
- if( g.fSshTrace ){
139
- printf("Got back-----------------------------------------------\n"
140
- "%s\n"
141
- "-------------------------------------------------------\n",
142
- zIn+nProbe);
143
- }
144
- if( strstr(zIn, zProbe) ) break;
145
- sqlite3_sleep(100*nWait);
146
- nIn = (int)strlen(zIn);
147
- memcpy(zIn, zIn+(nIn-nProbe), nProbe);
148
- if( g.fSshTrace ){
149
- printf("Fetching more text. Looking for [%s]...\n", zProbe);
150
- fflush(stdout);
151
- }
152
- }
153
- nProbe = random_probe(zProbe, sizeof(zProbe));
154
- fprintf(sshOut, "echo %s\n", zProbe);
155
- fflush(sshOut);
156
- if( g.fSshTrace ){
157
- printf("Sent: [echo %s]\n", zProbe);
158
- fflush(stdout);
159
- }
160
- sshin_read(zIn, nBuf);
161
- if( zIn[0]==0 ){
162
- sqlite3_sleep(250);
163
- sshin_read(zIn, nBuf);
164
- }
165
- if( g.fSshTrace ){
166
- printf("Got back-----------------------------------------------\n"
167
- "%s\n"
168
- "-------------------------------------------------------\n", zIn);
169
- }
170
- if( memcmp(zIn, zProbe, nProbe)!=0 ){
171
- pclose2(sshIn, sshOut, sshPid);
172
- fossil_fatal("ssh connection failed: [%s]", zIn);
173
- }
174
- fossil_free(zIn);
175
-}
176
-
177
-/*
178
-** Global initialization of the transport layer
179
-*/
180
-void transport_global_startup(void){
181
- if( g.urlIsSsh ){
182
- /* Only SSH requires a global initialization. For SSH we need to create
183
- ** and run an SSH command to talk to the remote machine.
184
- */
185
- const char *zSsh; /* The base SSH command */
186
- Blob zCmd; /* The SSH command */
187
- char *zHost; /* The host name to contact */
188
- int n; /* Size of prefix string */
189
-
190
- zSsh = db_get("ssh-command", zDefaultSshCmd);
191
- blob_init(&zCmd, zSsh, -1);
192
- if( g.urlPort!=g.urlDfltPort ){
193
-#ifdef __MINGW32__
194
- blob_appendf(&zCmd, " -P %d", g.urlPort);
195
-#else
196
- blob_appendf(&zCmd, " -p %d", g.urlPort);
197
-#endif
198
- }
199
- fossil_force_newline();
200
- fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
201
- if( g.urlUser && g.urlUser[0] ){
202
- zHost = mprintf("%s@%s", g.urlUser, g.urlName);
203
-#ifdef __MINGW32__
204
- /* Only win32 (and specifically PLINK.EXE) support the -pw option */
205
- if( g.urlPasswd && g.urlPasswd[0] ){
206
- Blob pw;
207
- blob_zero(&pw);
208
- if( g.urlPasswd[0]=='*' ){
209
- char *zPrompt;
210
- zPrompt = mprintf("Password for [%s]: ", zHost);
211
- prompt_for_password(zPrompt, &pw, 0);
212
- free(zPrompt);
213
- }else{
214
- blob_init(&pw, g.urlPasswd, -1);
215
- }
216
- blob_append(&zCmd, " -pw ", -1);
217
- shell_escape(&zCmd, blob_str(&pw));
218
- blob_reset(&pw);
219
- fossil_print(" -pw ********"); /* Do not show the password text */
220
- }
221
-#endif
222
- }else{
223
- zHost = mprintf("%s", g.urlName);
224
- }
225
- n = blob_size(&zCmd);
226
- blob_append(&zCmd, " ", 1);
227
- shell_escape(&zCmd, zHost);
228
- if( g.urlShell ){
229
- blob_appendf(&zCmd, " %s", g.urlShell);
230
- }else{
231
-#if defined(FOSSIL_ENABLE_SSH_FAR_SIDE)
232
- /* The following works. But only if the fossil on the remote side
233
- ** is recent enough to support the test-ssh-far-side command. That
234
- ** command was added on 2013-02-06. We will leave this turned off
235
- ** until most fossil servers have upgraded to that version or a later
236
- ** version. The sync will still work as long as the shell on the far
237
- ** side is bash and not tcsh. And if the default far side shell is
238
- ** tcsh, then the shell=/bin/bash query parameter can be used as a
239
- ** work-around. Enable this code after about a year...
240
- */
241
- blob_appendf(&zCmd, " exec %s test-ssh-far-side", g.urlFossil);
242
-#endif
243
- }
244
- fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
245
- free(zHost);
246
- popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
247
- if( sshPid==0 ){
248
- fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
249
- }
250
- blob_reset(&zCmd);
251
- transport_ssh_startup();
252
- }
253
-}
254
-
255
-/*
256
-** COMMAND: test-ssh-far-side
257
-**
258
-** Read lines of input text, one by one, and evaluate each line using
259
-** system(). The ssh: sync protocol uses this on the far side of the
260
-** SSH link.
261
-*/
262
-void test_ssh_far_side_cmd(void){
263
- int i = 0;
264
- int got;
265
- char zLine[5000];
266
- while( i<sizeof(zLine) ){
267
- got = read(0, zLine+i, 1);
268
- if( got==0 ) return;
269
- if( zLine[i]=='\n' ){
270
- zLine[i] = 0;
271
- system(zLine);
272
- i = 0;
273
- }else{
274
- i++;
275
- }
276
- }
89
+** SSH initialization of the transport layer
90
+*/
91
+int transport_ssh_open(void){
92
+ /* For SSH we need to create and run SSH fossil http
93
+ ** to talk to the remote machine.
94
+ */
95
+ const char *zSsh; /* The base SSH command */
96
+ Blob zCmd; /* The SSH command */
97
+ char *zHost; /* The host name to contact */
98
+ int n; /* Size of prefix string */
99
+
100
+ socket_ssh_resolve_addr();
101
+ zSsh = db_get("ssh-command", zDefaultSshCmd);
102
+ blob_init(&zCmd, zSsh, -1);
103
+ if( g.urlPort!=g.urlDfltPort && g.urlPort ){
104
+#ifdef __MINGW32__
105
+ blob_appendf(&zCmd, " -P %d", g.urlPort);
106
+#else
107
+ blob_appendf(&zCmd, " -p %d", g.urlPort);
108
+#endif
109
+ }
110
+ if( g.fSshTrace ){
111
+ fossil_force_newline();
112
+ fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
113
+ }
114
+ if( g.urlUser && g.urlUser[0] ){
115
+ zHost = mprintf("%s@%s", g.urlUser, g.urlName);
116
+ }else{
117
+ zHost = mprintf("%s", g.urlName);
118
+ }
119
+ n = blob_size(&zCmd);
120
+ blob_append(&zCmd, " ", 1);
121
+ shell_escape(&zCmd, zHost);
122
+ blob_append(&zCmd, " ", 1);
123
+ shell_escape(&zCmd, mprintf("%s", g.urlFossil));
124
+ blob_append(&zCmd, " test-http", 10);
125
+ if( g.urlPath && g.urlPath[0] ){
126
+ blob_append(&zCmd, " ", 1);
127
+ shell_escape(&zCmd, mprintf("%s", g.urlPath));
128
+ }
129
+ if( g.fSshTrace ){
130
+ fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
131
+ }
132
+ free(zHost);
133
+ popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
134
+ if( sshPid==0 ){
135
+ socket_set_errmsg("cannot start ssh tunnel using [%b]", &zCmd);
136
+ }
137
+ blob_reset(&zCmd);
138
+ return sshPid==0;
277139
}
278140
279141
/*
280142
** Open a connection to the server. The server is defined by the following
281143
** global variables:
@@ -288,19 +150,12 @@
288150
*/
289151
int transport_open(void){
290152
int rc = 0;
291153
if( transport.isOpen==0 ){
292154
if( g.urlIsSsh ){
293
- Blob cmd;
294
- blob_zero(&cmd);
295
- shell_escape(&cmd, g.urlFossil);
296
- blob_append(&cmd, " test-http ", -1);
297
- shell_escape(&cmd, g.urlPath);
298
- fprintf(sshOut, "%s || true\n", blob_str(&cmd));
299
- fflush(sshOut);
300
- if( g.fSshTrace ) printf("Sent: [%s]\n", blob_str(&cmd));
301
- blob_reset(&cmd);
155
+ rc = transport_ssh_open();
156
+ if( rc==0 ) transport.isOpen = 1;
302157
}else if( g.urlIsHttps ){
303158
#ifdef FOSSIL_ENABLE_SSL
304159
rc = ssl_open();
305160
if( rc==0 ) transport.isOpen = 1;
306161
#else
@@ -340,11 +195,11 @@
340195
if( transport.pLog ){
341196
fclose(transport.pLog);
342197
transport.pLog = 0;
343198
}
344199
if( g.urlIsSsh ){
345
- /* No-op */
200
+ transport_ssh_close();
346201
}else if( g.urlIsHttps ){
347202
#ifdef FOSSIL_ENABLE_SSL
348203
ssl_close();
349204
#endif
350205
}else if( g.urlIsFile ){
@@ -399,13 +254,11 @@
399254
/*
400255
** This routine is called when the outbound message is complete and
401256
** it is time to being receiving a reply.
402257
*/
403258
void transport_flip(void){
404
- if( g.urlIsSsh ){
405
- fprintf(sshOut, "\n\n");
406
- }else if( g.urlIsFile ){
259
+ if( g.urlIsFile ){
407260
char *zCmd;
408261
fclose(transport.pFile);
409262
zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
410263
g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
411264
);
@@ -581,20 +434,32 @@
581434
}
582435
if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
583436
return &transport.pBuf[iStart];
584437
}
585438
439
+/*
440
+** Global transport shutdown
441
+*/
586442
void transport_global_shutdown(void){
587
- if( g.urlIsSsh && sshPid ){
588
- /*printf("Closing SSH tunnel: ");*/
589
- fflush(stdout);
590
- pclose2(sshIn, sshOut, sshPid);
591
- sshPid = 0;
443
+ if( g.urlIsSsh ){
444
+ transport_ssh_close();
592445
}
593446
if( g.urlIsHttps ){
594447
#ifdef FOSSIL_ENABLE_SSL
595448
ssl_global_shutdown();
596449
#endif
597450
}else{
598451
socket_global_shutdown();
599452
}
600453
}
454
+
455
+/*
456
+** Close SSH transport.
457
+*/
458
+void transport_ssh_close(void){
459
+ if( sshPid ){
460
+ /*printf("Closing SSH tunnel: ");*/
461
+ fflush(stdout);
462
+ pclose2(sshIn, sshOut, sshPid);
463
+ sshPid = 0;
464
+ }
465
+}
601466
--- src/http_transport.c
+++ src/http_transport.c
@@ -74,25 +74,10 @@
74 transport.nSent = 0;
75 transport.nRcvd = 0;
76 }
77 }
78
79 /*
80 ** Read text from sshIn. Zero-terminate and remove trailing
81 ** whitespace.
82 */
83 static void sshin_read(char *zBuf, int szBuf){
84 int got;
85 zBuf[0] = 0;
86 got = read(sshIn, zBuf, szBuf-1);
87 while( got>=0 ){
88 zBuf[got] = 0;
89 if( got==0 || !fossil_isspace(zBuf[got-1]) ) break;
90 got--;
91 }
92 }
93
94 /*
95 ** Default SSH command
96 */
97 #ifdef __MINGW32__
98 static char zDefaultSshCmd[] = "ssh -T";
@@ -99,183 +84,60 @@
99 #else
100 static char zDefaultSshCmd[] = "ssh -e none -T";
101 #endif
102
103 /*
104 ** Generate a random SSH link problem keyword
105 */
106 static int random_probe(char *zProbe, int nProbe){
107 unsigned r[4];
108 sqlite3_randomness(sizeof(r), r);
109 sqlite3_snprintf(nProbe, zProbe, "probe-%08x%08x%08x%08x",
110 r[0], r[1], r[2], r[3]);
111 return (int)strlen(zProbe);
112 }
113
114 /*
115 ** Bring up an SSH link. This involves sending some "echo" commands and
116 ** get back appropriate responses. The point is to move past the MOTD and
117 ** verify that the link is working.
118 */
119 static void transport_ssh_startup(void){
120 char *zIn; /* An input line received back from remote */
121 int nWait; /* Number of times waiting for the MOTD */
122 char zProbe[40]; /* Text of the random probe */
123 int nProbe; /* Size of probe message */
124 int nIn; /* Size of input */
125 static const int nBuf = 10000; /* Size of input buffer */
126
127 zIn = fossil_malloc(nBuf);
128 nProbe = random_probe(zProbe, sizeof(zProbe));
129 fprintf(sshOut, "echo %s\n", zProbe);
130 fflush(sshOut);
131 if( g.fSshTrace ){
132 printf("Sent: [echo %s]\n", zProbe);
133 fflush(stdout);
134 }
135 memset(zIn, '*', nProbe);
136 for(nWait=1; nWait<=10; nWait++){
137 sshin_read(zIn+nProbe, nBuf-nProbe);
138 if( g.fSshTrace ){
139 printf("Got back-----------------------------------------------\n"
140 "%s\n"
141 "-------------------------------------------------------\n",
142 zIn+nProbe);
143 }
144 if( strstr(zIn, zProbe) ) break;
145 sqlite3_sleep(100*nWait);
146 nIn = (int)strlen(zIn);
147 memcpy(zIn, zIn+(nIn-nProbe), nProbe);
148 if( g.fSshTrace ){
149 printf("Fetching more text. Looking for [%s]...\n", zProbe);
150 fflush(stdout);
151 }
152 }
153 nProbe = random_probe(zProbe, sizeof(zProbe));
154 fprintf(sshOut, "echo %s\n", zProbe);
155 fflush(sshOut);
156 if( g.fSshTrace ){
157 printf("Sent: [echo %s]\n", zProbe);
158 fflush(stdout);
159 }
160 sshin_read(zIn, nBuf);
161 if( zIn[0]==0 ){
162 sqlite3_sleep(250);
163 sshin_read(zIn, nBuf);
164 }
165 if( g.fSshTrace ){
166 printf("Got back-----------------------------------------------\n"
167 "%s\n"
168 "-------------------------------------------------------\n", zIn);
169 }
170 if( memcmp(zIn, zProbe, nProbe)!=0 ){
171 pclose2(sshIn, sshOut, sshPid);
172 fossil_fatal("ssh connection failed: [%s]", zIn);
173 }
174 fossil_free(zIn);
175 }
176
177 /*
178 ** Global initialization of the transport layer
179 */
180 void transport_global_startup(void){
181 if( g.urlIsSsh ){
182 /* Only SSH requires a global initialization. For SSH we need to create
183 ** and run an SSH command to talk to the remote machine.
184 */
185 const char *zSsh; /* The base SSH command */
186 Blob zCmd; /* The SSH command */
187 char *zHost; /* The host name to contact */
188 int n; /* Size of prefix string */
189
190 zSsh = db_get("ssh-command", zDefaultSshCmd);
191 blob_init(&zCmd, zSsh, -1);
192 if( g.urlPort!=g.urlDfltPort ){
193 #ifdef __MINGW32__
194 blob_appendf(&zCmd, " -P %d", g.urlPort);
195 #else
196 blob_appendf(&zCmd, " -p %d", g.urlPort);
197 #endif
198 }
199 fossil_force_newline();
200 fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
201 if( g.urlUser && g.urlUser[0] ){
202 zHost = mprintf("%s@%s", g.urlUser, g.urlName);
203 #ifdef __MINGW32__
204 /* Only win32 (and specifically PLINK.EXE) support the -pw option */
205 if( g.urlPasswd && g.urlPasswd[0] ){
206 Blob pw;
207 blob_zero(&pw);
208 if( g.urlPasswd[0]=='*' ){
209 char *zPrompt;
210 zPrompt = mprintf("Password for [%s]: ", zHost);
211 prompt_for_password(zPrompt, &pw, 0);
212 free(zPrompt);
213 }else{
214 blob_init(&pw, g.urlPasswd, -1);
215 }
216 blob_append(&zCmd, " -pw ", -1);
217 shell_escape(&zCmd, blob_str(&pw));
218 blob_reset(&pw);
219 fossil_print(" -pw ********"); /* Do not show the password text */
220 }
221 #endif
222 }else{
223 zHost = mprintf("%s", g.urlName);
224 }
225 n = blob_size(&zCmd);
226 blob_append(&zCmd, " ", 1);
227 shell_escape(&zCmd, zHost);
228 if( g.urlShell ){
229 blob_appendf(&zCmd, " %s", g.urlShell);
230 }else{
231 #if defined(FOSSIL_ENABLE_SSH_FAR_SIDE)
232 /* The following works. But only if the fossil on the remote side
233 ** is recent enough to support the test-ssh-far-side command. That
234 ** command was added on 2013-02-06. We will leave this turned off
235 ** until most fossil servers have upgraded to that version or a later
236 ** version. The sync will still work as long as the shell on the far
237 ** side is bash and not tcsh. And if the default far side shell is
238 ** tcsh, then the shell=/bin/bash query parameter can be used as a
239 ** work-around. Enable this code after about a year...
240 */
241 blob_appendf(&zCmd, " exec %s test-ssh-far-side", g.urlFossil);
242 #endif
243 }
244 fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
245 free(zHost);
246 popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
247 if( sshPid==0 ){
248 fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
249 }
250 blob_reset(&zCmd);
251 transport_ssh_startup();
252 }
253 }
254
255 /*
256 ** COMMAND: test-ssh-far-side
257 **
258 ** Read lines of input text, one by one, and evaluate each line using
259 ** system(). The ssh: sync protocol uses this on the far side of the
260 ** SSH link.
261 */
262 void test_ssh_far_side_cmd(void){
263 int i = 0;
264 int got;
265 char zLine[5000];
266 while( i<sizeof(zLine) ){
267 got = read(0, zLine+i, 1);
268 if( got==0 ) return;
269 if( zLine[i]=='\n' ){
270 zLine[i] = 0;
271 system(zLine);
272 i = 0;
273 }else{
274 i++;
275 }
276 }
277 }
278
279 /*
280 ** Open a connection to the server. The server is defined by the following
281 ** global variables:
@@ -288,19 +150,12 @@
288 */
289 int transport_open(void){
290 int rc = 0;
291 if( transport.isOpen==0 ){
292 if( g.urlIsSsh ){
293 Blob cmd;
294 blob_zero(&cmd);
295 shell_escape(&cmd, g.urlFossil);
296 blob_append(&cmd, " test-http ", -1);
297 shell_escape(&cmd, g.urlPath);
298 fprintf(sshOut, "%s || true\n", blob_str(&cmd));
299 fflush(sshOut);
300 if( g.fSshTrace ) printf("Sent: [%s]\n", blob_str(&cmd));
301 blob_reset(&cmd);
302 }else if( g.urlIsHttps ){
303 #ifdef FOSSIL_ENABLE_SSL
304 rc = ssl_open();
305 if( rc==0 ) transport.isOpen = 1;
306 #else
@@ -340,11 +195,11 @@
340 if( transport.pLog ){
341 fclose(transport.pLog);
342 transport.pLog = 0;
343 }
344 if( g.urlIsSsh ){
345 /* No-op */
346 }else if( g.urlIsHttps ){
347 #ifdef FOSSIL_ENABLE_SSL
348 ssl_close();
349 #endif
350 }else if( g.urlIsFile ){
@@ -399,13 +254,11 @@
399 /*
400 ** This routine is called when the outbound message is complete and
401 ** it is time to being receiving a reply.
402 */
403 void transport_flip(void){
404 if( g.urlIsSsh ){
405 fprintf(sshOut, "\n\n");
406 }else if( g.urlIsFile ){
407 char *zCmd;
408 fclose(transport.pFile);
409 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
410 g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
411 );
@@ -581,20 +434,32 @@
581 }
582 if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
583 return &transport.pBuf[iStart];
584 }
585
 
 
 
586 void transport_global_shutdown(void){
587 if( g.urlIsSsh && sshPid ){
588 /*printf("Closing SSH tunnel: ");*/
589 fflush(stdout);
590 pclose2(sshIn, sshOut, sshPid);
591 sshPid = 0;
592 }
593 if( g.urlIsHttps ){
594 #ifdef FOSSIL_ENABLE_SSL
595 ssl_global_shutdown();
596 #endif
597 }else{
598 socket_global_shutdown();
599 }
600 }
 
 
 
 
 
 
 
 
 
 
 
 
601
--- src/http_transport.c
+++ src/http_transport.c
@@ -74,25 +74,10 @@
74 transport.nSent = 0;
75 transport.nRcvd = 0;
76 }
77 }
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79 /*
80 ** Default SSH command
81 */
82 #ifdef __MINGW32__
83 static char zDefaultSshCmd[] = "ssh -T";
@@ -99,183 +84,60 @@
84 #else
85 static char zDefaultSshCmd[] = "ssh -e none -T";
86 #endif
87
88 /*
89 ** SSH initialization of the transport layer
90 */
91 int transport_ssh_open(void){
92 /* For SSH we need to create and run SSH fossil http
93 ** to talk to the remote machine.
94 */
95 const char *zSsh; /* The base SSH command */
96 Blob zCmd; /* The SSH command */
97 char *zHost; /* The host name to contact */
98 int n; /* Size of prefix string */
99
100 socket_ssh_resolve_addr();
101 zSsh = db_get("ssh-command", zDefaultSshCmd);
102 blob_init(&zCmd, zSsh, -1);
103 if( g.urlPort!=g.urlDfltPort && g.urlPort ){
104 #ifdef __MINGW32__
105 blob_appendf(&zCmd, " -P %d", g.urlPort);
106 #else
107 blob_appendf(&zCmd, " -p %d", g.urlPort);
108 #endif
109 }
110 if( g.fSshTrace ){
111 fossil_force_newline();
112 fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
113 }
114 if( g.urlUser && g.urlUser[0] ){
115 zHost = mprintf("%s@%s", g.urlUser, g.urlName);
116 }else{
117 zHost = mprintf("%s", g.urlName);
118 }
119 n = blob_size(&zCmd);
120 blob_append(&zCmd, " ", 1);
121 shell_escape(&zCmd, zHost);
122 blob_append(&zCmd, " ", 1);
123 shell_escape(&zCmd, mprintf("%s", g.urlFossil));
124 blob_append(&zCmd, " test-http", 10);
125 if( g.urlPath && g.urlPath[0] ){
126 blob_append(&zCmd, " ", 1);
127 shell_escape(&zCmd, mprintf("%s", g.urlPath));
128 }
129 if( g.fSshTrace ){
130 fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
131 }
132 free(zHost);
133 popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
134 if( sshPid==0 ){
135 socket_set_errmsg("cannot start ssh tunnel using [%b]", &zCmd);
136 }
137 blob_reset(&zCmd);
138 return sshPid==0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139 }
140
141 /*
142 ** Open a connection to the server. The server is defined by the following
143 ** global variables:
@@ -288,19 +150,12 @@
150 */
151 int transport_open(void){
152 int rc = 0;
153 if( transport.isOpen==0 ){
154 if( g.urlIsSsh ){
155 rc = transport_ssh_open();
156 if( rc==0 ) transport.isOpen = 1;
 
 
 
 
 
 
 
157 }else if( g.urlIsHttps ){
158 #ifdef FOSSIL_ENABLE_SSL
159 rc = ssl_open();
160 if( rc==0 ) transport.isOpen = 1;
161 #else
@@ -340,11 +195,11 @@
195 if( transport.pLog ){
196 fclose(transport.pLog);
197 transport.pLog = 0;
198 }
199 if( g.urlIsSsh ){
200 transport_ssh_close();
201 }else if( g.urlIsHttps ){
202 #ifdef FOSSIL_ENABLE_SSL
203 ssl_close();
204 #endif
205 }else if( g.urlIsFile ){
@@ -399,13 +254,11 @@
254 /*
255 ** This routine is called when the outbound message is complete and
256 ** it is time to being receiving a reply.
257 */
258 void transport_flip(void){
259 if( g.urlIsFile ){
 
 
260 char *zCmd;
261 fclose(transport.pFile);
262 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
263 g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
264 );
@@ -581,20 +434,32 @@
434 }
435 if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
436 return &transport.pBuf[iStart];
437 }
438
439 /*
440 ** Global transport shutdown
441 */
442 void transport_global_shutdown(void){
443 if( g.urlIsSsh ){
444 transport_ssh_close();
 
 
 
445 }
446 if( g.urlIsHttps ){
447 #ifdef FOSSIL_ENABLE_SSL
448 ssl_global_shutdown();
449 #endif
450 }else{
451 socket_global_shutdown();
452 }
453 }
454
455 /*
456 ** Close SSH transport.
457 */
458 void transport_ssh_close(void){
459 if( sshPid ){
460 /*printf("Closing SSH tunnel: ");*/
461 fflush(stdout);
462 pclose2(sshIn, sshOut, sshPid);
463 sshPid = 0;
464 }
465 }
466
+1 -1
--- src/import.c
+++ src/import.c
@@ -419,11 +419,11 @@
419419
gg.zPrevCheckin = 0;
420420
}
421421
if( gg.zFrom==0 ) return;
422422
rid = fast_uuid_to_rid(gg.zFrom);
423423
if( rid==0 ) return;
424
- p = manifest_get(rid, CFTYPE_MANIFEST);
424
+ p = manifest_get(rid, CFTYPE_MANIFEST, 0);
425425
if( p==0 ) return;
426426
manifest_file_rewind(p);
427427
while( (pOld = manifest_file_next(p, 0))!=0 ){
428428
pNew = import_add_file();
429429
pNew->zName = fossil_strdup(pOld->zName);
430430
--- src/import.c
+++ src/import.c
@@ -419,11 +419,11 @@
419 gg.zPrevCheckin = 0;
420 }
421 if( gg.zFrom==0 ) return;
422 rid = fast_uuid_to_rid(gg.zFrom);
423 if( rid==0 ) return;
424 p = manifest_get(rid, CFTYPE_MANIFEST);
425 if( p==0 ) return;
426 manifest_file_rewind(p);
427 while( (pOld = manifest_file_next(p, 0))!=0 ){
428 pNew = import_add_file();
429 pNew->zName = fossil_strdup(pOld->zName);
430
--- src/import.c
+++ src/import.c
@@ -419,11 +419,11 @@
419 gg.zPrevCheckin = 0;
420 }
421 if( gg.zFrom==0 ) return;
422 rid = fast_uuid_to_rid(gg.zFrom);
423 if( rid==0 ) return;
424 p = manifest_get(rid, CFTYPE_MANIFEST, 0);
425 if( p==0 ) return;
426 manifest_file_rewind(p);
427 while( (pOld = manifest_file_next(p, 0))!=0 ){
428 pNew = import_add_file();
429 pNew->zName = fossil_strdup(pOld->zName);
430
+20 -7
--- src/info.c
+++ src/info.c
@@ -579,11 +579,23 @@
579579
@ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
580580
}
581581
db_finalize(&q2);
582582
}
583583
if( g.perm.Hyperlink ){
584
- const char *zProjName = db_get("project-name", "unnamed");
584
+ char *zPJ = db_get("short-project-name", 0);
585
+ Blob projName;
586
+ int jj;
587
+ if( zPJ==0 ) zPJ = db_get("project-name", "unnamed");
588
+ blob_zero(&projName);
589
+ blob_append(&projName, zPJ, -1);
590
+ blob_trim(&projName);
591
+ zPJ = blob_str(&projName);
592
+ for(jj=0; zPJ[jj]; jj++){
593
+ if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
594
+ zPJ[jj] = '_';
595
+ }
596
+ }
585597
@ <tr><th>Timelines:</th><td>
586598
@ %z(href("%R/timeline?f=%S",zUuid))family</a>
587599
if( zParent ){
588600
@ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
589601
}
@@ -605,15 +617,15 @@
605617
606618
607619
/* The Download: line */
608620
if( g.perm.Zip ){
609621
char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
610
- zProjName, zUuid, zUuid);
622
+ zPJ, zUuid, zUuid);
611623
@ </td></tr>
612624
@ <tr><th>Downloads:</th><td>
613625
@ %z(href("%s",zUrl))Tarball</a>
614
- @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zProjName,zUuid,zUuid))
626
+ @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zPJ,zUuid,zUuid))
615627
@ ZIP archive</a>
616628
fossil_free(zUrl);
617629
}
618630
@ </td></tr>
619631
@ <tr><th>Other&nbsp;Links:</th>
@@ -624,10 +636,11 @@
624636
if( g.perm.Write ){
625637
@ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
626638
}
627639
@ </td>
628640
@ </tr>
641
+ blob_reset(&projName);
629642
}
630643
@ </table>
631644
}else{
632645
style_header("Check-in Information");
633646
login_anonymous_available();
@@ -723,11 +736,11 @@
723736
const char *zModAction;
724737
725738
login_check_credentials();
726739
if( !g.perm.RdWiki ){ login_needed(); return; }
727740
rid = name_to_rid_www("name");
728
- if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI))==0 ){
741
+ if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))==0 ){
729742
style_header("Wiki Page Information Error");
730743
@ No such object: %h(P("name"))
731744
style_footer();
732745
return;
733746
}
@@ -834,11 +847,11 @@
834847
}
835848
if( !is_a_version(rid) ){
836849
webpage_error("Artifact %s is not a checkin.", P(zParam));
837850
return 0;
838851
}
839
- return manifest_get(rid, CFTYPE_MANIFEST);
852
+ return manifest_get(rid, CFTYPE_MANIFEST, 0);
840853
}
841854
842855
/*
843856
** Output a description of a check-in
844857
*/
@@ -1485,11 +1498,11 @@
14851498
zCI = P("ci");
14861499
if( zCI==0 ) return 0;
14871500
zFilename = P("filename");
14881501
if( zFilename==0 ) return 0;
14891502
cirid = name_to_rid_www("ci");
1490
- pManifest = manifest_get(cirid, CFTYPE_MANIFEST);
1503
+ pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
14911504
if( pManifest==0 ) return 0;
14921505
manifest_file_rewind(pManifest);
14931506
while( (pFile = manifest_file_next(pManifest,0))!=0 ){
14941507
if( fossil_strcmp(zFilename, pFile->zName)==0 ){
14951508
int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
@@ -1708,11 +1721,11 @@
17081721
}else{
17091722
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
17101723
g.zTop, zUuid);
17111724
}
17121725
}
1713
- pTktChng = manifest_get(rid, CFTYPE_TICKET);
1726
+ pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
17141727
if( pTktChng==0 ) fossil_redirect_home();
17151728
zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
17161729
memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
17171730
if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
17181731
if( strcmp(zModAction,"delete")==0 ){
17191732
--- src/info.c
+++ src/info.c
@@ -579,11 +579,23 @@
579 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
580 }
581 db_finalize(&q2);
582 }
583 if( g.perm.Hyperlink ){
584 const char *zProjName = db_get("project-name", "unnamed");
 
 
 
 
 
 
 
 
 
 
 
 
585 @ <tr><th>Timelines:</th><td>
586 @ %z(href("%R/timeline?f=%S",zUuid))family</a>
587 if( zParent ){
588 @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
589 }
@@ -605,15 +617,15 @@
605
606
607 /* The Download: line */
608 if( g.perm.Zip ){
609 char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
610 zProjName, zUuid, zUuid);
611 @ </td></tr>
612 @ <tr><th>Downloads:</th><td>
613 @ %z(href("%s",zUrl))Tarball</a>
614 @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zProjName,zUuid,zUuid))
615 @ ZIP archive</a>
616 fossil_free(zUrl);
617 }
618 @ </td></tr>
619 @ <tr><th>Other&nbsp;Links:</th>
@@ -624,10 +636,11 @@
624 if( g.perm.Write ){
625 @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
626 }
627 @ </td>
628 @ </tr>
 
629 }
630 @ </table>
631 }else{
632 style_header("Check-in Information");
633 login_anonymous_available();
@@ -723,11 +736,11 @@
723 const char *zModAction;
724
725 login_check_credentials();
726 if( !g.perm.RdWiki ){ login_needed(); return; }
727 rid = name_to_rid_www("name");
728 if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI))==0 ){
729 style_header("Wiki Page Information Error");
730 @ No such object: %h(P("name"))
731 style_footer();
732 return;
733 }
@@ -834,11 +847,11 @@
834 }
835 if( !is_a_version(rid) ){
836 webpage_error("Artifact %s is not a checkin.", P(zParam));
837 return 0;
838 }
839 return manifest_get(rid, CFTYPE_MANIFEST);
840 }
841
842 /*
843 ** Output a description of a check-in
844 */
@@ -1485,11 +1498,11 @@
1485 zCI = P("ci");
1486 if( zCI==0 ) return 0;
1487 zFilename = P("filename");
1488 if( zFilename==0 ) return 0;
1489 cirid = name_to_rid_www("ci");
1490 pManifest = manifest_get(cirid, CFTYPE_MANIFEST);
1491 if( pManifest==0 ) return 0;
1492 manifest_file_rewind(pManifest);
1493 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
1494 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1495 int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
@@ -1708,11 +1721,11 @@
1708 }else{
1709 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1710 g.zTop, zUuid);
1711 }
1712 }
1713 pTktChng = manifest_get(rid, CFTYPE_TICKET);
1714 if( pTktChng==0 ) fossil_redirect_home();
1715 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1716 memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
1717 if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
1718 if( strcmp(zModAction,"delete")==0 ){
1719
--- src/info.c
+++ src/info.c
@@ -579,11 +579,23 @@
579 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
580 }
581 db_finalize(&q2);
582 }
583 if( g.perm.Hyperlink ){
584 char *zPJ = db_get("short-project-name", 0);
585 Blob projName;
586 int jj;
587 if( zPJ==0 ) zPJ = db_get("project-name", "unnamed");
588 blob_zero(&projName);
589 blob_append(&projName, zPJ, -1);
590 blob_trim(&projName);
591 zPJ = blob_str(&projName);
592 for(jj=0; zPJ[jj]; jj++){
593 if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
594 zPJ[jj] = '_';
595 }
596 }
597 @ <tr><th>Timelines:</th><td>
598 @ %z(href("%R/timeline?f=%S",zUuid))family</a>
599 if( zParent ){
600 @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
601 }
@@ -605,15 +617,15 @@
617
618
619 /* The Download: line */
620 if( g.perm.Zip ){
621 char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
622 zPJ, zUuid, zUuid);
623 @ </td></tr>
624 @ <tr><th>Downloads:</th><td>
625 @ %z(href("%s",zUrl))Tarball</a>
626 @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zPJ,zUuid,zUuid))
627 @ ZIP archive</a>
628 fossil_free(zUrl);
629 }
630 @ </td></tr>
631 @ <tr><th>Other&nbsp;Links:</th>
@@ -624,10 +636,11 @@
636 if( g.perm.Write ){
637 @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
638 }
639 @ </td>
640 @ </tr>
641 blob_reset(&projName);
642 }
643 @ </table>
644 }else{
645 style_header("Check-in Information");
646 login_anonymous_available();
@@ -723,11 +736,11 @@
736 const char *zModAction;
737
738 login_check_credentials();
739 if( !g.perm.RdWiki ){ login_needed(); return; }
740 rid = name_to_rid_www("name");
741 if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))==0 ){
742 style_header("Wiki Page Information Error");
743 @ No such object: %h(P("name"))
744 style_footer();
745 return;
746 }
@@ -834,11 +847,11 @@
847 }
848 if( !is_a_version(rid) ){
849 webpage_error("Artifact %s is not a checkin.", P(zParam));
850 return 0;
851 }
852 return manifest_get(rid, CFTYPE_MANIFEST, 0);
853 }
854
855 /*
856 ** Output a description of a check-in
857 */
@@ -1485,11 +1498,11 @@
1498 zCI = P("ci");
1499 if( zCI==0 ) return 0;
1500 zFilename = P("filename");
1501 if( zFilename==0 ) return 0;
1502 cirid = name_to_rid_www("ci");
1503 pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
1504 if( pManifest==0 ) return 0;
1505 manifest_file_rewind(pManifest);
1506 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
1507 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1508 int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
@@ -1708,11 +1721,11 @@
1721 }else{
1722 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1723 g.zTop, zUuid);
1724 }
1725 }
1726 pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
1727 if( pTktChng==0 ) fossil_redirect_home();
1728 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1729 memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
1730 if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
1731 if( strcmp(zModAction,"delete")==0 ){
1732
+20 -7
--- src/info.c
+++ src/info.c
@@ -579,11 +579,23 @@
579579
@ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
580580
}
581581
db_finalize(&q2);
582582
}
583583
if( g.perm.Hyperlink ){
584
- const char *zProjName = db_get("project-name", "unnamed");
584
+ char *zPJ = db_get("short-project-name", 0);
585
+ Blob projName;
586
+ int jj;
587
+ if( zPJ==0 ) zPJ = db_get("project-name", "unnamed");
588
+ blob_zero(&projName);
589
+ blob_append(&projName, zPJ, -1);
590
+ blob_trim(&projName);
591
+ zPJ = blob_str(&projName);
592
+ for(jj=0; zPJ[jj]; jj++){
593
+ if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
594
+ zPJ[jj] = '_';
595
+ }
596
+ }
585597
@ <tr><th>Timelines:</th><td>
586598
@ %z(href("%R/timeline?f=%S",zUuid))family</a>
587599
if( zParent ){
588600
@ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
589601
}
@@ -605,15 +617,15 @@
605617
606618
607619
/* The Download: line */
608620
if( g.perm.Zip ){
609621
char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
610
- zProjName, zUuid, zUuid);
622
+ zPJ, zUuid, zUuid);
611623
@ </td></tr>
612624
@ <tr><th>Downloads:</th><td>
613625
@ %z(href("%s",zUrl))Tarball</a>
614
- @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zProjName,zUuid,zUuid))
626
+ @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zPJ,zUuid,zUuid))
615627
@ ZIP archive</a>
616628
fossil_free(zUrl);
617629
}
618630
@ </td></tr>
619631
@ <tr><th>Other&nbsp;Links:</th>
@@ -624,10 +636,11 @@
624636
if( g.perm.Write ){
625637
@ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
626638
}
627639
@ </td>
628640
@ </tr>
641
+ blob_reset(&projName);
629642
}
630643
@ </table>
631644
}else{
632645
style_header("Check-in Information");
633646
login_anonymous_available();
@@ -723,11 +736,11 @@
723736
const char *zModAction;
724737
725738
login_check_credentials();
726739
if( !g.perm.RdWiki ){ login_needed(); return; }
727740
rid = name_to_rid_www("name");
728
- if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI))==0 ){
741
+ if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))==0 ){
729742
style_header("Wiki Page Information Error");
730743
@ No such object: %h(P("name"))
731744
style_footer();
732745
return;
733746
}
@@ -834,11 +847,11 @@
834847
}
835848
if( !is_a_version(rid) ){
836849
webpage_error("Artifact %s is not a checkin.", P(zParam));
837850
return 0;
838851
}
839
- return manifest_get(rid, CFTYPE_MANIFEST);
852
+ return manifest_get(rid, CFTYPE_MANIFEST, 0);
840853
}
841854
842855
/*
843856
** Output a description of a check-in
844857
*/
@@ -1485,11 +1498,11 @@
14851498
zCI = P("ci");
14861499
if( zCI==0 ) return 0;
14871500
zFilename = P("filename");
14881501
if( zFilename==0 ) return 0;
14891502
cirid = name_to_rid_www("ci");
1490
- pManifest = manifest_get(cirid, CFTYPE_MANIFEST);
1503
+ pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
14911504
if( pManifest==0 ) return 0;
14921505
manifest_file_rewind(pManifest);
14931506
while( (pFile = manifest_file_next(pManifest,0))!=0 ){
14941507
if( fossil_strcmp(zFilename, pFile->zName)==0 ){
14951508
int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
@@ -1708,11 +1721,11 @@
17081721
}else{
17091722
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
17101723
g.zTop, zUuid);
17111724
}
17121725
}
1713
- pTktChng = manifest_get(rid, CFTYPE_TICKET);
1726
+ pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
17141727
if( pTktChng==0 ) fossil_redirect_home();
17151728
zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
17161729
memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
17171730
if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
17181731
if( strcmp(zModAction,"delete")==0 ){
17191732
--- src/info.c
+++ src/info.c
@@ -579,11 +579,23 @@
579 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
580 }
581 db_finalize(&q2);
582 }
583 if( g.perm.Hyperlink ){
584 const char *zProjName = db_get("project-name", "unnamed");
 
 
 
 
 
 
 
 
 
 
 
 
585 @ <tr><th>Timelines:</th><td>
586 @ %z(href("%R/timeline?f=%S",zUuid))family</a>
587 if( zParent ){
588 @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
589 }
@@ -605,15 +617,15 @@
605
606
607 /* The Download: line */
608 if( g.perm.Zip ){
609 char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
610 zProjName, zUuid, zUuid);
611 @ </td></tr>
612 @ <tr><th>Downloads:</th><td>
613 @ %z(href("%s",zUrl))Tarball</a>
614 @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zProjName,zUuid,zUuid))
615 @ ZIP archive</a>
616 fossil_free(zUrl);
617 }
618 @ </td></tr>
619 @ <tr><th>Other&nbsp;Links:</th>
@@ -624,10 +636,11 @@
624 if( g.perm.Write ){
625 @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
626 }
627 @ </td>
628 @ </tr>
 
629 }
630 @ </table>
631 }else{
632 style_header("Check-in Information");
633 login_anonymous_available();
@@ -723,11 +736,11 @@
723 const char *zModAction;
724
725 login_check_credentials();
726 if( !g.perm.RdWiki ){ login_needed(); return; }
727 rid = name_to_rid_www("name");
728 if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI))==0 ){
729 style_header("Wiki Page Information Error");
730 @ No such object: %h(P("name"))
731 style_footer();
732 return;
733 }
@@ -834,11 +847,11 @@
834 }
835 if( !is_a_version(rid) ){
836 webpage_error("Artifact %s is not a checkin.", P(zParam));
837 return 0;
838 }
839 return manifest_get(rid, CFTYPE_MANIFEST);
840 }
841
842 /*
843 ** Output a description of a check-in
844 */
@@ -1485,11 +1498,11 @@
1485 zCI = P("ci");
1486 if( zCI==0 ) return 0;
1487 zFilename = P("filename");
1488 if( zFilename==0 ) return 0;
1489 cirid = name_to_rid_www("ci");
1490 pManifest = manifest_get(cirid, CFTYPE_MANIFEST);
1491 if( pManifest==0 ) return 0;
1492 manifest_file_rewind(pManifest);
1493 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
1494 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1495 int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
@@ -1708,11 +1721,11 @@
1708 }else{
1709 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1710 g.zTop, zUuid);
1711 }
1712 }
1713 pTktChng = manifest_get(rid, CFTYPE_TICKET);
1714 if( pTktChng==0 ) fossil_redirect_home();
1715 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1716 memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
1717 if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
1718 if( strcmp(zModAction,"delete")==0 ){
1719
--- src/info.c
+++ src/info.c
@@ -579,11 +579,23 @@
579 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
580 }
581 db_finalize(&q2);
582 }
583 if( g.perm.Hyperlink ){
584 char *zPJ = db_get("short-project-name", 0);
585 Blob projName;
586 int jj;
587 if( zPJ==0 ) zPJ = db_get("project-name", "unnamed");
588 blob_zero(&projName);
589 blob_append(&projName, zPJ, -1);
590 blob_trim(&projName);
591 zPJ = blob_str(&projName);
592 for(jj=0; zPJ[jj]; jj++){
593 if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
594 zPJ[jj] = '_';
595 }
596 }
597 @ <tr><th>Timelines:</th><td>
598 @ %z(href("%R/timeline?f=%S",zUuid))family</a>
599 if( zParent ){
600 @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
601 }
@@ -605,15 +617,15 @@
617
618
619 /* The Download: line */
620 if( g.perm.Zip ){
621 char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
622 zPJ, zUuid, zUuid);
623 @ </td></tr>
624 @ <tr><th>Downloads:</th><td>
625 @ %z(href("%s",zUrl))Tarball</a>
626 @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zPJ,zUuid,zUuid))
627 @ ZIP archive</a>
628 fossil_free(zUrl);
629 }
630 @ </td></tr>
631 @ <tr><th>Other&nbsp;Links:</th>
@@ -624,10 +636,11 @@
636 if( g.perm.Write ){
637 @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
638 }
639 @ </td>
640 @ </tr>
641 blob_reset(&projName);
642 }
643 @ </table>
644 }else{
645 style_header("Check-in Information");
646 login_anonymous_available();
@@ -723,11 +736,11 @@
736 const char *zModAction;
737
738 login_check_credentials();
739 if( !g.perm.RdWiki ){ login_needed(); return; }
740 rid = name_to_rid_www("name");
741 if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))==0 ){
742 style_header("Wiki Page Information Error");
743 @ No such object: %h(P("name"))
744 style_footer();
745 return;
746 }
@@ -834,11 +847,11 @@
847 }
848 if( !is_a_version(rid) ){
849 webpage_error("Artifact %s is not a checkin.", P(zParam));
850 return 0;
851 }
852 return manifest_get(rid, CFTYPE_MANIFEST, 0);
853 }
854
855 /*
856 ** Output a description of a check-in
857 */
@@ -1485,11 +1498,11 @@
1498 zCI = P("ci");
1499 if( zCI==0 ) return 0;
1500 zFilename = P("filename");
1501 if( zFilename==0 ) return 0;
1502 cirid = name_to_rid_www("ci");
1503 pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
1504 if( pManifest==0 ) return 0;
1505 manifest_file_rewind(pManifest);
1506 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
1507 if( fossil_strcmp(zFilename, pFile->zName)==0 ){
1508 int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
@@ -1708,11 +1721,11 @@
1721 }else{
1722 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1723 g.zTop, zUuid);
1724 }
1725 }
1726 pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
1727 if( pTktChng==0 ) fossil_redirect_home();
1728 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1729 memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
1730 if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
1731 if( strcmp(zModAction,"delete")==0 ){
1732
--- src/json_artifact.c
+++ src/json_artifact.c
@@ -192,11 +192,11 @@
192192
if(!eventTypeLabel){
193193
eventTypeLabel = json_new_string("ticket");
194194
json_gc_add("$EVENT_TYPE_LABEL(ticket)", eventTypeLabel);
195195
}
196196
197
- pTktChng = manifest_get(rid, CFTYPE_TICKET);
197
+ pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
198198
if( pTktChng==0 ){
199199
g.json.resultCode = FSL_JSON_E_MANIFEST_READ_FAILED;
200200
return NULL;
201201
}
202202
pay = cson_new_object();
203203
--- src/json_artifact.c
+++ src/json_artifact.c
@@ -192,11 +192,11 @@
192 if(!eventTypeLabel){
193 eventTypeLabel = json_new_string("ticket");
194 json_gc_add("$EVENT_TYPE_LABEL(ticket)", eventTypeLabel);
195 }
196
197 pTktChng = manifest_get(rid, CFTYPE_TICKET);
198 if( pTktChng==0 ){
199 g.json.resultCode = FSL_JSON_E_MANIFEST_READ_FAILED;
200 return NULL;
201 }
202 pay = cson_new_object();
203
--- src/json_artifact.c
+++ src/json_artifact.c
@@ -192,11 +192,11 @@
192 if(!eventTypeLabel){
193 eventTypeLabel = json_new_string("ticket");
194 json_gc_add("$EVENT_TYPE_LABEL(ticket)", eventTypeLabel);
195 }
196
197 pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
198 if( pTktChng==0 ){
199 g.json.resultCode = FSL_JSON_E_MANIFEST_READ_FAILED;
200 return NULL;
201 }
202 pay = cson_new_object();
203
--- src/json_branch.c
+++ src/json_branch.c
@@ -218,11 +218,11 @@
218218
if( rootid==0 ){
219219
zOpt->rcErrMsg = "Basis branch not found.";
220220
return FSL_JSON_E_RESOURCE_NOT_FOUND;
221221
}
222222
223
- pParent = manifest_get(rootid, CFTYPE_MANIFEST);
223
+ pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
224224
if( pParent==0 ){
225225
zOpt->rcErrMsg = "Could not read parent manifest.";
226226
return FSL_JSON_E_UNKNOWN;
227227
}
228228
229229
--- src/json_branch.c
+++ src/json_branch.c
@@ -218,11 +218,11 @@
218 if( rootid==0 ){
219 zOpt->rcErrMsg = "Basis branch not found.";
220 return FSL_JSON_E_RESOURCE_NOT_FOUND;
221 }
222
223 pParent = manifest_get(rootid, CFTYPE_MANIFEST);
224 if( pParent==0 ){
225 zOpt->rcErrMsg = "Could not read parent manifest.";
226 return FSL_JSON_E_UNKNOWN;
227 }
228
229
--- src/json_branch.c
+++ src/json_branch.c
@@ -218,11 +218,11 @@
218 if( rootid==0 ){
219 zOpt->rcErrMsg = "Basis branch not found.";
220 return FSL_JSON_E_RESOURCE_NOT_FOUND;
221 }
222
223 pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
224 if( pParent==0 ){
225 zOpt->rcErrMsg = "Could not read parent manifest.";
226 return FSL_JSON_E_UNKNOWN;
227 }
228
229
--- src/json_branch.c
+++ src/json_branch.c
@@ -218,11 +218,11 @@
218218
if( rootid==0 ){
219219
zOpt->rcErrMsg = "Basis branch not found.";
220220
return FSL_JSON_E_RESOURCE_NOT_FOUND;
221221
}
222222
223
- pParent = manifest_get(rootid, CFTYPE_MANIFEST);
223
+ pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
224224
if( pParent==0 ){
225225
zOpt->rcErrMsg = "Could not read parent manifest.";
226226
return FSL_JSON_E_UNKNOWN;
227227
}
228228
229229
--- src/json_branch.c
+++ src/json_branch.c
@@ -218,11 +218,11 @@
218 if( rootid==0 ){
219 zOpt->rcErrMsg = "Basis branch not found.";
220 return FSL_JSON_E_RESOURCE_NOT_FOUND;
221 }
222
223 pParent = manifest_get(rootid, CFTYPE_MANIFEST);
224 if( pParent==0 ){
225 zOpt->rcErrMsg = "Could not read parent manifest.";
226 return FSL_JSON_E_UNKNOWN;
227 }
228
229
--- src/json_branch.c
+++ src/json_branch.c
@@ -218,11 +218,11 @@
218 if( rootid==0 ){
219 zOpt->rcErrMsg = "Basis branch not found.";
220 return FSL_JSON_E_RESOURCE_NOT_FOUND;
221 }
222
223 pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
224 if( pParent==0 ){
225 zOpt->rcErrMsg = "Could not read parent manifest.";
226 return FSL_JSON_E_UNKNOWN;
227 }
228
229
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -632,11 +632,11 @@
632632
int const rid = db_column_int(&q,0);
633633
Manifest * pMan = NULL;
634634
cson_value * rowV;
635635
cson_object * row;
636636
/*printf("rid=%d\n",rid);*/
637
- pMan = manifest_get(rid, CFTYPE_TICKET);
637
+ pMan = manifest_get(rid, CFTYPE_TICKET, 0);
638638
if(!pMan){
639639
/* this might be an attachment? I'm seeing this with
640640
rid 15380, uuid [1292fef05f2472108].
641641
642642
/json/artifact/1292fef05f2472108 returns not-found,
643643
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -632,11 +632,11 @@
632 int const rid = db_column_int(&q,0);
633 Manifest * pMan = NULL;
634 cson_value * rowV;
635 cson_object * row;
636 /*printf("rid=%d\n",rid);*/
637 pMan = manifest_get(rid, CFTYPE_TICKET);
638 if(!pMan){
639 /* this might be an attachment? I'm seeing this with
640 rid 15380, uuid [1292fef05f2472108].
641
642 /json/artifact/1292fef05f2472108 returns not-found,
643
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -632,11 +632,11 @@
632 int const rid = db_column_int(&q,0);
633 Manifest * pMan = NULL;
634 cson_value * rowV;
635 cson_object * row;
636 /*printf("rid=%d\n",rid);*/
637 pMan = manifest_get(rid, CFTYPE_TICKET, 0);
638 if(!pMan){
639 /* this might be an attachment? I'm seeing this with
640 rid 15380, uuid [1292fef05f2472108].
641
642 /json/artifact/1292fef05f2472108 returns not-found,
643
+3 -3
--- src/json_wiki.c
+++ src/json_wiki.c
@@ -82,11 +82,11 @@
8282
** The returned value, if not NULL, is-a JSON Object owned by the
8383
** caller. If it returns NULL then it may set g.json's error state.
8484
*/
8585
cson_value * json_get_wiki_page_by_rid(int rid, char contentFormat){
8686
Manifest * pWiki = NULL;
87
- if( NULL == (pWiki = manifest_get(rid, CFTYPE_WIKI)) ){
87
+ if( NULL == (pWiki = manifest_get(rid, CFTYPE_WIKI, 0)) ){
8888
json_set_err( FSL_JSON_E_UNKNOWN,
8989
"Error reading wiki page from manifest (rid=%d).",
9090
rid );
9191
return NULL;
9292
}else{
@@ -528,16 +528,16 @@
528528
}else if(0==r2){
529529
goto invalid;
530530
}
531531
532532
zErrTag = zV1;
533
- pW1 = manifest_get(r1, CFTYPE_WIKI);
533
+ pW1 = manifest_get(r1, CFTYPE_WIKI, 0);
534534
if( pW1==0 ) {
535535
goto manifest;
536536
}
537537
zErrTag = zV2;
538
- pW2 = manifest_get(r2, CFTYPE_WIKI);
538
+ pW2 = manifest_get(r2, CFTYPE_WIKI, 0);
539539
if( pW2==0 ) {
540540
goto manifest;
541541
}
542542
543543
blob_init(&w1, pW1->zWiki, -1);
544544
--- src/json_wiki.c
+++ src/json_wiki.c
@@ -82,11 +82,11 @@
82 ** The returned value, if not NULL, is-a JSON Object owned by the
83 ** caller. If it returns NULL then it may set g.json's error state.
84 */
85 cson_value * json_get_wiki_page_by_rid(int rid, char contentFormat){
86 Manifest * pWiki = NULL;
87 if( NULL == (pWiki = manifest_get(rid, CFTYPE_WIKI)) ){
88 json_set_err( FSL_JSON_E_UNKNOWN,
89 "Error reading wiki page from manifest (rid=%d).",
90 rid );
91 return NULL;
92 }else{
@@ -528,16 +528,16 @@
528 }else if(0==r2){
529 goto invalid;
530 }
531
532 zErrTag = zV1;
533 pW1 = manifest_get(r1, CFTYPE_WIKI);
534 if( pW1==0 ) {
535 goto manifest;
536 }
537 zErrTag = zV2;
538 pW2 = manifest_get(r2, CFTYPE_WIKI);
539 if( pW2==0 ) {
540 goto manifest;
541 }
542
543 blob_init(&w1, pW1->zWiki, -1);
544
--- src/json_wiki.c
+++ src/json_wiki.c
@@ -82,11 +82,11 @@
82 ** The returned value, if not NULL, is-a JSON Object owned by the
83 ** caller. If it returns NULL then it may set g.json's error state.
84 */
85 cson_value * json_get_wiki_page_by_rid(int rid, char contentFormat){
86 Manifest * pWiki = NULL;
87 if( NULL == (pWiki = manifest_get(rid, CFTYPE_WIKI, 0)) ){
88 json_set_err( FSL_JSON_E_UNKNOWN,
89 "Error reading wiki page from manifest (rid=%d).",
90 rid );
91 return NULL;
92 }else{
@@ -528,16 +528,16 @@
528 }else if(0==r2){
529 goto invalid;
530 }
531
532 zErrTag = zV1;
533 pW1 = manifest_get(r1, CFTYPE_WIKI, 0);
534 if( pW1==0 ) {
535 goto manifest;
536 }
537 zErrTag = zV2;
538 pW2 = manifest_get(r2, CFTYPE_WIKI, 0);
539 if( pW2==0 ) {
540 goto manifest;
541 }
542
543 blob_init(&w1, pW1->zWiki, -1);
544
+2 -1
--- src/login.c
+++ src/login.c
@@ -793,11 +793,12 @@
793793
**
794794
** This feature allows the "fossil ui" command to give the user
795795
** full access rights without having to log in.
796796
*/
797797
zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil"));
798
- if( fossil_strcmp(zIpAddr, "127.0.0.1")==0
798
+ if( ( fossil_strcmp(zIpAddr, "127.0.0.1")==0 ||
799
+ g.fSshClient & CGI_SSH_CLIENT )
799800
&& g.useLocalauth
800801
&& db_get_int("localauth",0)==0
801802
&& P("HTTPS")==0
802803
){
803804
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
804805
--- src/login.c
+++ src/login.c
@@ -793,11 +793,12 @@
793 **
794 ** This feature allows the "fossil ui" command to give the user
795 ** full access rights without having to log in.
796 */
797 zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil"));
798 if( fossil_strcmp(zIpAddr, "127.0.0.1")==0
 
799 && g.useLocalauth
800 && db_get_int("localauth",0)==0
801 && P("HTTPS")==0
802 ){
803 uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
804
--- src/login.c
+++ src/login.c
@@ -793,11 +793,12 @@
793 **
794 ** This feature allows the "fossil ui" command to give the user
795 ** full access rights without having to log in.
796 */
797 zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil"));
798 if( ( fossil_strcmp(zIpAddr, "127.0.0.1")==0 ||
799 g.fSshClient & CGI_SSH_CLIENT )
800 && g.useLocalauth
801 && db_get_int("localauth",0)==0
802 && P("HTTPS")==0
803 ){
804 uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
805
+64 -10
--- src/main.c
+++ src/main.c
@@ -100,11 +100,13 @@
100100
char **argv; /* Full copy of the original (expanded) arguments. */
101101
void *library; /* The Tcl library module handle. */
102102
void *xFindExecutable; /* See tcl_FindExecutableProc in th_tcl.c. */
103103
void *xCreateInterp; /* See tcl_CreateInterpProc in th_tcl.c. */
104104
void *xDeleteInterp; /* See tcl_DeleteInterpProc in th_tcl.c. */
105
+ void *xFinalize; /* See tcl_FinalizeProc in th_tcl.c. */
105106
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
107
+ int useObjProc; /* Non-zero if an objProc can be called directly. */
106108
char *setup; /* The optional Tcl setup script. */
107109
void *xPreEval; /* Optional, called before Tcl_Eval*(). */
108110
void *pPreContext; /* Optional, provided to xPreEval(). */
109111
void *xPostEval; /* Optional, called after Tcl_Eval*(). */
110112
void *pPostContext; /* Optional, provided to xPostEval(). */
@@ -136,10 +138,12 @@
136138
int fSqlPrint; /* True if -sqlprint flag is present */
137139
int fQuiet; /* True if -quiet flag is present */
138140
int fHttpTrace; /* Trace outbound HTTP requests */
139141
int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
140142
int fSshTrace; /* Trace the SSH setup traffic */
143
+ int fSshClient; /* HTTP client flags for SSH client */
144
+ char *zSshCmd; /* SSH command string */
141145
int fNoSync; /* Do not do an autosync ever. --nosync */
142146
char *zPath; /* Name of webpage being served */
143147
char *zExtra; /* Extra path information past the webpage name */
144148
char *zBaseURL; /* Full text of the URL being served */
145149
char *zTop; /* Parent directory of zPath */
@@ -177,11 +181,10 @@
177181
char *urlUser; /* User id for http: */
178182
char *urlPasswd; /* Password for http: */
179183
char *urlCanonical; /* Canonical representation of the URL */
180184
char *urlProxyAuth; /* Proxy-Authorizer: string */
181185
char *urlFossil; /* The fossil query parameter on ssh: */
182
- char *urlShell; /* The shell query parameter on ssh: */
183186
unsigned urlFlags; /* Boolean flags controlling URL processing */
184187
185188
const char *zLogin; /* Login name. "" if not logged in. */
186189
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
187190
** SSL client identity */
@@ -344,10 +347,24 @@
344347
/*
345348
** atexit() handler which frees up "some" of the resources
346349
** used by fossil.
347350
*/
348351
static void fossil_atexit(void) {
352
+#if defined(_WIN32) && !defined(_WIN64) && defined(FOSSIL_ENABLE_TCL) && \
353
+ defined(USE_TCL_STUBS)
354
+ /*
355
+ ** If Tcl is compiled on Windows using the latest MinGW, Fossil can crash
356
+ ** when exiting while a stubs-enabled Tcl is still loaded. This is due to
357
+ ** a bug in MinGW, see:
358
+ **
359
+ ** http://comments.gmane.org/gmane.comp.gnu.mingw.user/41724
360
+ **
361
+ ** The workaround is to manually unload the loaded Tcl library prior to
362
+ ** exiting the process. This issue does not impact 64-bit Windows.
363
+ */
364
+ unloadTcl(g.interp, &g.tcl);
365
+#endif
349366
#ifdef FOSSIL_ENABLE_JSON
350367
cson_value_free(g.json.gc.v);
351368
memset(&g.json, 0, sizeof(g.json));
352369
#endif
353370
free(g.zErrMsg);
@@ -525,10 +542,13 @@
525542
*/
526543
#if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE)
527544
int _dowildcard = -1; /* This turns on command-line globbing in MinGW-w64 */
528545
int wmain(int argc, wchar_t **argv)
529546
#else
547
+#if defined(_WIN32)
548
+int _CRT_glob = 0x0001; /* See MinGW bug #2062 */
549
+#endif
530550
int main(int argc, char **argv)
531551
#endif
532552
{
533553
const char *zCmdName = "unknown";
534554
int idx;
@@ -584,10 +604,12 @@
584604
g.fQuiet = find_option("quiet", 0, 0)!=0;
585605
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
586606
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
587607
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
588608
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
609
+ g.fSshClient = 0;
610
+ g.zSshCmd = 0;
589611
if( g.fSqlTrace ) g.fSqlStats = 1;
590612
g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
591613
g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
592614
g.zLogin = find_option("user", "U", 1);
593615
g.zSSLIdentity = find_option("ssl-identity", 0, 1);
@@ -813,16 +835,19 @@
813835
#if defined(FOSSIL_ENABLE_SSL)
814836
fossil_print("SSL (%s)\n", OPENSSL_VERSION_TEXT);
815837
#endif
816838
#if defined(FOSSIL_ENABLE_TCL)
817839
Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL);
818
- rc = Th_Eval(g.interp, 0, "tclEval {info patchlevel}", -1);
840
+ rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1);
819841
zRc = Th_ReturnCodeName(rc, 0);
820842
fossil_print("TCL (Tcl %s, loaded %s: %s)\n",
821843
TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0)
822844
);
823845
#endif
846
+#if defined(USE_TCL_STUBS)
847
+ fossil_print("USE_TCL_STUBS\n");
848
+#endif
824849
#if defined(FOSSIL_ENABLE_TCL_STUBS)
825850
fossil_print("TCL_STUBS\n");
826851
#endif
827852
#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
828853
fossil_print("TCL_PRIVATE_STUBS\n");
@@ -1127,10 +1152,13 @@
11271152
if( getuid()==0 ){
11281153
int i;
11291154
struct stat sStat;
11301155
Blob dir;
11311156
char *zDir;
1157
+ if( g.db!=0 ){
1158
+ db_close(1);
1159
+ }
11321160
11331161
file_canonical_name(zRepo, &dir, 0);
11341162
zDir = blob_str(&dir);
11351163
if( file_isdir(zDir)==1 ){
11361164
if( file_chdir(zDir, 1) ){
@@ -1155,14 +1183,10 @@
11551183
i = setgid(sStat.st_gid);
11561184
i = i || setuid(sStat.st_uid);
11571185
if(i){
11581186
fossil_fatal("setgid/uid() failed with errno %d", errno);
11591187
}
1160
- if( g.db!=0 ){
1161
- db_close(1);
1162
- db_open_repository(zRepo);
1163
- }
11641188
}
11651189
#endif
11661190
return zRepo;
11671191
}
11681192
@@ -1293,11 +1317,12 @@
12931317
}
12941318
12951319
/* Find the page that the user has requested, construct and deliver that
12961320
** page.
12971321
*/
1298
- if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){
1322
+ if( g.zContentType &&
1323
+ strncmp(g.zContentType, "application/x-fossil", 20)==0 ){
12991324
zPathInfo = "/xfer";
13001325
}
13011326
set_base_url(0);
13021327
if( zPathInfo==0 || zPathInfo[0]==0
13031328
|| (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
@@ -1710,39 +1735,68 @@
17101735
zIpAddr = g.argv[5];
17111736
}else{
17121737
g.httpIn = stdin;
17131738
g.httpOut = stdout;
17141739
zIpAddr = 0;
1740
+ }
1741
+ if( zIpAddr==0 ){
1742
+ zIpAddr = cgi_ssh_remote_addr(0);
1743
+ if( zIpAddr && zIpAddr[0] ){
1744
+ g.fSshClient |= CGI_SSH_CLIENT;
1745
+ }
17151746
}
17161747
find_server_repository(0);
17171748
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
17181749
if( useSCGI ){
17191750
cgi_handle_scgi_request();
1751
+ }else if( g.fSshClient & CGI_SSH_CLIENT ){
1752
+ ssh_request_loop(zIpAddr, glob_create(zFileGlob));
17201753
}else{
17211754
cgi_handle_http_request(zIpAddr);
17221755
}
17231756
process_one_web_page(zNotFound, glob_create(zFileGlob));
17241757
}
1758
+
1759
+/*
1760
+** Process all requests in a single SSH connection if possible.
1761
+*/
1762
+void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){
1763
+ do{
1764
+ cgi_handle_ssh_http_request(zIpAddr);
1765
+ process_one_web_page(0, FileGlob);
1766
+ blob_reset(&g.cgiIn);
1767
+ } while ( g.fSshClient & CGI_SSH_FOSSIL ||
1768
+ g.fSshClient & CGI_SSH_COMPAT );
1769
+}
17251770
17261771
/*
17271772
** Note that the following command is used by ssh:// processing.
17281773
**
17291774
** COMMAND: test-http
17301775
** Works like the http command but gives setup permission to all users.
1776
+**
17311777
*/
17321778
void cmd_test_http(void){
1779
+ const char *zIpAddr; /* IP address of remote client */
1780
+
17331781
Th_InitTraceLog();
17341782
login_set_capabilities("sx", 0);
17351783
g.useLocalauth = 1;
1736
- cgi_set_parameter("REMOTE_ADDR", "127.0.0.1");
17371784
g.httpIn = stdin;
17381785
g.httpOut = stdout;
17391786
find_server_repository(0);
17401787
g.cgiOutput = 1;
17411788
g.fullHttpReply = 1;
1742
- cgi_handle_http_request(0);
1743
- process_one_web_page(0, 0);
1789
+ zIpAddr = cgi_ssh_remote_addr(0);
1790
+ if( zIpAddr && zIpAddr[0] ){
1791
+ g.fSshClient |= CGI_SSH_CLIENT;
1792
+ ssh_request_loop(zIpAddr, 0);
1793
+ }else{
1794
+ cgi_set_parameter("REMOTE_ADDR", "127.0.0.1");
1795
+ cgi_handle_http_request(0);
1796
+ process_one_web_page(0, 0);
1797
+ }
17441798
}
17451799
17461800
#if !defined(_WIN32)
17471801
#if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
17481802
/*
17491803
--- src/main.c
+++ src/main.c
@@ -100,11 +100,13 @@
100 char **argv; /* Full copy of the original (expanded) arguments. */
101 void *library; /* The Tcl library module handle. */
102 void *xFindExecutable; /* See tcl_FindExecutableProc in th_tcl.c. */
103 void *xCreateInterp; /* See tcl_CreateInterpProc in th_tcl.c. */
104 void *xDeleteInterp; /* See tcl_DeleteInterpProc in th_tcl.c. */
 
105 Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
 
106 char *setup; /* The optional Tcl setup script. */
107 void *xPreEval; /* Optional, called before Tcl_Eval*(). */
108 void *pPreContext; /* Optional, provided to xPreEval(). */
109 void *xPostEval; /* Optional, called after Tcl_Eval*(). */
110 void *pPostContext; /* Optional, provided to xPostEval(). */
@@ -136,10 +138,12 @@
136 int fSqlPrint; /* True if -sqlprint flag is present */
137 int fQuiet; /* True if -quiet flag is present */
138 int fHttpTrace; /* Trace outbound HTTP requests */
139 int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
140 int fSshTrace; /* Trace the SSH setup traffic */
 
 
141 int fNoSync; /* Do not do an autosync ever. --nosync */
142 char *zPath; /* Name of webpage being served */
143 char *zExtra; /* Extra path information past the webpage name */
144 char *zBaseURL; /* Full text of the URL being served */
145 char *zTop; /* Parent directory of zPath */
@@ -177,11 +181,10 @@
177 char *urlUser; /* User id for http: */
178 char *urlPasswd; /* Password for http: */
179 char *urlCanonical; /* Canonical representation of the URL */
180 char *urlProxyAuth; /* Proxy-Authorizer: string */
181 char *urlFossil; /* The fossil query parameter on ssh: */
182 char *urlShell; /* The shell query parameter on ssh: */
183 unsigned urlFlags; /* Boolean flags controlling URL processing */
184
185 const char *zLogin; /* Login name. "" if not logged in. */
186 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
187 ** SSL client identity */
@@ -344,10 +347,24 @@
344 /*
345 ** atexit() handler which frees up "some" of the resources
346 ** used by fossil.
347 */
348 static void fossil_atexit(void) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349 #ifdef FOSSIL_ENABLE_JSON
350 cson_value_free(g.json.gc.v);
351 memset(&g.json, 0, sizeof(g.json));
352 #endif
353 free(g.zErrMsg);
@@ -525,10 +542,13 @@
525 */
526 #if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE)
527 int _dowildcard = -1; /* This turns on command-line globbing in MinGW-w64 */
528 int wmain(int argc, wchar_t **argv)
529 #else
 
 
 
530 int main(int argc, char **argv)
531 #endif
532 {
533 const char *zCmdName = "unknown";
534 int idx;
@@ -584,10 +604,12 @@
584 g.fQuiet = find_option("quiet", 0, 0)!=0;
585 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
586 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
587 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
588 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
 
 
589 if( g.fSqlTrace ) g.fSqlStats = 1;
590 g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
591 g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
592 g.zLogin = find_option("user", "U", 1);
593 g.zSSLIdentity = find_option("ssl-identity", 0, 1);
@@ -813,16 +835,19 @@
813 #if defined(FOSSIL_ENABLE_SSL)
814 fossil_print("SSL (%s)\n", OPENSSL_VERSION_TEXT);
815 #endif
816 #if defined(FOSSIL_ENABLE_TCL)
817 Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL);
818 rc = Th_Eval(g.interp, 0, "tclEval {info patchlevel}", -1);
819 zRc = Th_ReturnCodeName(rc, 0);
820 fossil_print("TCL (Tcl %s, loaded %s: %s)\n",
821 TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0)
822 );
823 #endif
 
 
 
824 #if defined(FOSSIL_ENABLE_TCL_STUBS)
825 fossil_print("TCL_STUBS\n");
826 #endif
827 #if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
828 fossil_print("TCL_PRIVATE_STUBS\n");
@@ -1127,10 +1152,13 @@
1127 if( getuid()==0 ){
1128 int i;
1129 struct stat sStat;
1130 Blob dir;
1131 char *zDir;
 
 
 
1132
1133 file_canonical_name(zRepo, &dir, 0);
1134 zDir = blob_str(&dir);
1135 if( file_isdir(zDir)==1 ){
1136 if( file_chdir(zDir, 1) ){
@@ -1155,14 +1183,10 @@
1155 i = setgid(sStat.st_gid);
1156 i = i || setuid(sStat.st_uid);
1157 if(i){
1158 fossil_fatal("setgid/uid() failed with errno %d", errno);
1159 }
1160 if( g.db!=0 ){
1161 db_close(1);
1162 db_open_repository(zRepo);
1163 }
1164 }
1165 #endif
1166 return zRepo;
1167 }
1168
@@ -1293,11 +1317,12 @@
1293 }
1294
1295 /* Find the page that the user has requested, construct and deliver that
1296 ** page.
1297 */
1298 if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){
 
1299 zPathInfo = "/xfer";
1300 }
1301 set_base_url(0);
1302 if( zPathInfo==0 || zPathInfo[0]==0
1303 || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
@@ -1710,39 +1735,68 @@
1710 zIpAddr = g.argv[5];
1711 }else{
1712 g.httpIn = stdin;
1713 g.httpOut = stdout;
1714 zIpAddr = 0;
 
 
 
 
 
 
1715 }
1716 find_server_repository(0);
1717 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1718 if( useSCGI ){
1719 cgi_handle_scgi_request();
 
 
1720 }else{
1721 cgi_handle_http_request(zIpAddr);
1722 }
1723 process_one_web_page(zNotFound, glob_create(zFileGlob));
1724 }
 
 
 
 
 
 
 
 
 
 
 
 
1725
1726 /*
1727 ** Note that the following command is used by ssh:// processing.
1728 **
1729 ** COMMAND: test-http
1730 ** Works like the http command but gives setup permission to all users.
 
1731 */
1732 void cmd_test_http(void){
 
 
1733 Th_InitTraceLog();
1734 login_set_capabilities("sx", 0);
1735 g.useLocalauth = 1;
1736 cgi_set_parameter("REMOTE_ADDR", "127.0.0.1");
1737 g.httpIn = stdin;
1738 g.httpOut = stdout;
1739 find_server_repository(0);
1740 g.cgiOutput = 1;
1741 g.fullHttpReply = 1;
1742 cgi_handle_http_request(0);
1743 process_one_web_page(0, 0);
 
 
 
 
 
 
 
1744 }
1745
1746 #if !defined(_WIN32)
1747 #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
1748 /*
1749
--- src/main.c
+++ src/main.c
@@ -100,11 +100,13 @@
100 char **argv; /* Full copy of the original (expanded) arguments. */
101 void *library; /* The Tcl library module handle. */
102 void *xFindExecutable; /* See tcl_FindExecutableProc in th_tcl.c. */
103 void *xCreateInterp; /* See tcl_CreateInterpProc in th_tcl.c. */
104 void *xDeleteInterp; /* See tcl_DeleteInterpProc in th_tcl.c. */
105 void *xFinalize; /* See tcl_FinalizeProc in th_tcl.c. */
106 Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
107 int useObjProc; /* Non-zero if an objProc can be called directly. */
108 char *setup; /* The optional Tcl setup script. */
109 void *xPreEval; /* Optional, called before Tcl_Eval*(). */
110 void *pPreContext; /* Optional, provided to xPreEval(). */
111 void *xPostEval; /* Optional, called after Tcl_Eval*(). */
112 void *pPostContext; /* Optional, provided to xPostEval(). */
@@ -136,10 +138,12 @@
138 int fSqlPrint; /* True if -sqlprint flag is present */
139 int fQuiet; /* True if -quiet flag is present */
140 int fHttpTrace; /* Trace outbound HTTP requests */
141 int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
142 int fSshTrace; /* Trace the SSH setup traffic */
143 int fSshClient; /* HTTP client flags for SSH client */
144 char *zSshCmd; /* SSH command string */
145 int fNoSync; /* Do not do an autosync ever. --nosync */
146 char *zPath; /* Name of webpage being served */
147 char *zExtra; /* Extra path information past the webpage name */
148 char *zBaseURL; /* Full text of the URL being served */
149 char *zTop; /* Parent directory of zPath */
@@ -177,11 +181,10 @@
181 char *urlUser; /* User id for http: */
182 char *urlPasswd; /* Password for http: */
183 char *urlCanonical; /* Canonical representation of the URL */
184 char *urlProxyAuth; /* Proxy-Authorizer: string */
185 char *urlFossil; /* The fossil query parameter on ssh: */
 
186 unsigned urlFlags; /* Boolean flags controlling URL processing */
187
188 const char *zLogin; /* Login name. "" if not logged in. */
189 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
190 ** SSL client identity */
@@ -344,10 +347,24 @@
347 /*
348 ** atexit() handler which frees up "some" of the resources
349 ** used by fossil.
350 */
351 static void fossil_atexit(void) {
352 #if defined(_WIN32) && !defined(_WIN64) && defined(FOSSIL_ENABLE_TCL) && \
353 defined(USE_TCL_STUBS)
354 /*
355 ** If Tcl is compiled on Windows using the latest MinGW, Fossil can crash
356 ** when exiting while a stubs-enabled Tcl is still loaded. This is due to
357 ** a bug in MinGW, see:
358 **
359 ** http://comments.gmane.org/gmane.comp.gnu.mingw.user/41724
360 **
361 ** The workaround is to manually unload the loaded Tcl library prior to
362 ** exiting the process. This issue does not impact 64-bit Windows.
363 */
364 unloadTcl(g.interp, &g.tcl);
365 #endif
366 #ifdef FOSSIL_ENABLE_JSON
367 cson_value_free(g.json.gc.v);
368 memset(&g.json, 0, sizeof(g.json));
369 #endif
370 free(g.zErrMsg);
@@ -525,10 +542,13 @@
542 */
543 #if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE)
544 int _dowildcard = -1; /* This turns on command-line globbing in MinGW-w64 */
545 int wmain(int argc, wchar_t **argv)
546 #else
547 #if defined(_WIN32)
548 int _CRT_glob = 0x0001; /* See MinGW bug #2062 */
549 #endif
550 int main(int argc, char **argv)
551 #endif
552 {
553 const char *zCmdName = "unknown";
554 int idx;
@@ -584,10 +604,12 @@
604 g.fQuiet = find_option("quiet", 0, 0)!=0;
605 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
606 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
607 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
608 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
609 g.fSshClient = 0;
610 g.zSshCmd = 0;
611 if( g.fSqlTrace ) g.fSqlStats = 1;
612 g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
613 g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
614 g.zLogin = find_option("user", "U", 1);
615 g.zSSLIdentity = find_option("ssl-identity", 0, 1);
@@ -813,16 +835,19 @@
835 #if defined(FOSSIL_ENABLE_SSL)
836 fossil_print("SSL (%s)\n", OPENSSL_VERSION_TEXT);
837 #endif
838 #if defined(FOSSIL_ENABLE_TCL)
839 Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL);
840 rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1);
841 zRc = Th_ReturnCodeName(rc, 0);
842 fossil_print("TCL (Tcl %s, loaded %s: %s)\n",
843 TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0)
844 );
845 #endif
846 #if defined(USE_TCL_STUBS)
847 fossil_print("USE_TCL_STUBS\n");
848 #endif
849 #if defined(FOSSIL_ENABLE_TCL_STUBS)
850 fossil_print("TCL_STUBS\n");
851 #endif
852 #if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
853 fossil_print("TCL_PRIVATE_STUBS\n");
@@ -1127,10 +1152,13 @@
1152 if( getuid()==0 ){
1153 int i;
1154 struct stat sStat;
1155 Blob dir;
1156 char *zDir;
1157 if( g.db!=0 ){
1158 db_close(1);
1159 }
1160
1161 file_canonical_name(zRepo, &dir, 0);
1162 zDir = blob_str(&dir);
1163 if( file_isdir(zDir)==1 ){
1164 if( file_chdir(zDir, 1) ){
@@ -1155,14 +1183,10 @@
1183 i = setgid(sStat.st_gid);
1184 i = i || setuid(sStat.st_uid);
1185 if(i){
1186 fossil_fatal("setgid/uid() failed with errno %d", errno);
1187 }
 
 
 
 
1188 }
1189 #endif
1190 return zRepo;
1191 }
1192
@@ -1293,11 +1317,12 @@
1317 }
1318
1319 /* Find the page that the user has requested, construct and deliver that
1320 ** page.
1321 */
1322 if( g.zContentType &&
1323 strncmp(g.zContentType, "application/x-fossil", 20)==0 ){
1324 zPathInfo = "/xfer";
1325 }
1326 set_base_url(0);
1327 if( zPathInfo==0 || zPathInfo[0]==0
1328 || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
@@ -1710,39 +1735,68 @@
1735 zIpAddr = g.argv[5];
1736 }else{
1737 g.httpIn = stdin;
1738 g.httpOut = stdout;
1739 zIpAddr = 0;
1740 }
1741 if( zIpAddr==0 ){
1742 zIpAddr = cgi_ssh_remote_addr(0);
1743 if( zIpAddr && zIpAddr[0] ){
1744 g.fSshClient |= CGI_SSH_CLIENT;
1745 }
1746 }
1747 find_server_repository(0);
1748 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1749 if( useSCGI ){
1750 cgi_handle_scgi_request();
1751 }else if( g.fSshClient & CGI_SSH_CLIENT ){
1752 ssh_request_loop(zIpAddr, glob_create(zFileGlob));
1753 }else{
1754 cgi_handle_http_request(zIpAddr);
1755 }
1756 process_one_web_page(zNotFound, glob_create(zFileGlob));
1757 }
1758
1759 /*
1760 ** Process all requests in a single SSH connection if possible.
1761 */
1762 void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){
1763 do{
1764 cgi_handle_ssh_http_request(zIpAddr);
1765 process_one_web_page(0, FileGlob);
1766 blob_reset(&g.cgiIn);
1767 } while ( g.fSshClient & CGI_SSH_FOSSIL ||
1768 g.fSshClient & CGI_SSH_COMPAT );
1769 }
1770
1771 /*
1772 ** Note that the following command is used by ssh:// processing.
1773 **
1774 ** COMMAND: test-http
1775 ** Works like the http command but gives setup permission to all users.
1776 **
1777 */
1778 void cmd_test_http(void){
1779 const char *zIpAddr; /* IP address of remote client */
1780
1781 Th_InitTraceLog();
1782 login_set_capabilities("sx", 0);
1783 g.useLocalauth = 1;
 
1784 g.httpIn = stdin;
1785 g.httpOut = stdout;
1786 find_server_repository(0);
1787 g.cgiOutput = 1;
1788 g.fullHttpReply = 1;
1789 zIpAddr = cgi_ssh_remote_addr(0);
1790 if( zIpAddr && zIpAddr[0] ){
1791 g.fSshClient |= CGI_SSH_CLIENT;
1792 ssh_request_loop(zIpAddr, 0);
1793 }else{
1794 cgi_set_parameter("REMOTE_ADDR", "127.0.0.1");
1795 cgi_handle_http_request(0);
1796 process_one_web_page(0, 0);
1797 }
1798 }
1799
1800 #if !defined(_WIN32)
1801 #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
1802 /*
1803
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -407,13 +407,13 @@
407407
FOSSIL_TCL_SOURCE = 1
408408
409409
#### Check if the workaround for the MinGW command line handling needs to
410410
# be enabled by default.
411411
#
412
-ifndef BROKEN_MINGW_CMDLINE
412
+ifndef MINGW_IS_32BIT_ONLY
413413
ifeq (,$(findstring w64-mingw32,$(PREFIX)))
414
-BROKEN_MINGW_CMDLINE = 1
414
+MINGW_IS_32BIT_ONLY = 1
415415
endif
416416
endif
417417
418418
#### The directories where the zlib include and library files are located.
419419
#
@@ -501,11 +501,11 @@
501501
RCC += -I$(TCLINCDIR)
502502
endif
503503
endif
504504
505505
# With MinGW command line handling workaround
506
-ifdef BROKEN_MINGW_CMDLINE
506
+ifdef MINGW_IS_32BIT_ONLY
507507
TCC += -DBROKEN_MINGW_CMDLINE=1
508508
RCC += -DBROKEN_MINGW_CMDLINE=1
509509
endif
510510
511511
# With HTTPS support
@@ -542,11 +542,11 @@
542542
# executable that will run in a chroot jail.
543543
#
544544
LIB = -static
545545
546546
# MinGW: If available, use the Unicode capable runtime startup code.
547
-ifndef BROKEN_MINGW_CMDLINE
547
+ifndef MINGW_IS_32BIT_ONLY
548548
LIB += -municode
549549
endif
550550
551551
# OpenSSL: Add the necessary libraries required, if enabled.
552552
ifdef FOSSIL_ENABLE_SSL
@@ -771,10 +771,11 @@
771771
}
772772
773773
774774
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
775775
set opt $SQLITE_OPTIONS
776
+append opt " -D_HAVE_SQLITE_CONFIG_H"
776777
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
777778
778779
set opt {}
779780
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
780781
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
781782
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -407,13 +407,13 @@
407 FOSSIL_TCL_SOURCE = 1
408
409 #### Check if the workaround for the MinGW command line handling needs to
410 # be enabled by default.
411 #
412 ifndef BROKEN_MINGW_CMDLINE
413 ifeq (,$(findstring w64-mingw32,$(PREFIX)))
414 BROKEN_MINGW_CMDLINE = 1
415 endif
416 endif
417
418 #### The directories where the zlib include and library files are located.
419 #
@@ -501,11 +501,11 @@
501 RCC += -I$(TCLINCDIR)
502 endif
503 endif
504
505 # With MinGW command line handling workaround
506 ifdef BROKEN_MINGW_CMDLINE
507 TCC += -DBROKEN_MINGW_CMDLINE=1
508 RCC += -DBROKEN_MINGW_CMDLINE=1
509 endif
510
511 # With HTTPS support
@@ -542,11 +542,11 @@
542 # executable that will run in a chroot jail.
543 #
544 LIB = -static
545
546 # MinGW: If available, use the Unicode capable runtime startup code.
547 ifndef BROKEN_MINGW_CMDLINE
548 LIB += -municode
549 endif
550
551 # OpenSSL: Add the necessary libraries required, if enabled.
552 ifdef FOSSIL_ENABLE_SSL
@@ -771,10 +771,11 @@
771 }
772
773
774 writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
775 set opt $SQLITE_OPTIONS
 
776 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
777
778 set opt {}
779 writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
780 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
781
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -407,13 +407,13 @@
407 FOSSIL_TCL_SOURCE = 1
408
409 #### Check if the workaround for the MinGW command line handling needs to
410 # be enabled by default.
411 #
412 ifndef MINGW_IS_32BIT_ONLY
413 ifeq (,$(findstring w64-mingw32,$(PREFIX)))
414 MINGW_IS_32BIT_ONLY = 1
415 endif
416 endif
417
418 #### The directories where the zlib include and library files are located.
419 #
@@ -501,11 +501,11 @@
501 RCC += -I$(TCLINCDIR)
502 endif
503 endif
504
505 # With MinGW command line handling workaround
506 ifdef MINGW_IS_32BIT_ONLY
507 TCC += -DBROKEN_MINGW_CMDLINE=1
508 RCC += -DBROKEN_MINGW_CMDLINE=1
509 endif
510
511 # With HTTPS support
@@ -542,11 +542,11 @@
542 # executable that will run in a chroot jail.
543 #
544 LIB = -static
545
546 # MinGW: If available, use the Unicode capable runtime startup code.
547 ifndef MINGW_IS_32BIT_ONLY
548 LIB += -municode
549 endif
550
551 # OpenSSL: Add the necessary libraries required, if enabled.
552 ifdef FOSSIL_ENABLE_SSL
@@ -771,10 +771,11 @@
771 }
772
773
774 writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
775 set opt $SQLITE_OPTIONS
776 append opt " -D_HAVE_SQLITE_CONFIG_H"
777 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
778
779 set opt {}
780 writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
781 writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
782
+4 -4
--- src/manifest.c
+++ src/manifest.c
@@ -955,11 +955,11 @@
955955
956956
/*
957957
** Get a manifest given the rid for the control artifact. Return
958958
** a pointer to the manifest on success or NULL if there is a failure.
959959
*/
960
-Manifest *manifest_get(int rid, int cfType){
960
+Manifest *manifest_get(int rid, int cfType, Blob *pErr){
961961
Blob content;
962962
Manifest *p;
963963
if( !rid ) return 0;
964964
p = manifest_cache_find(rid);
965965
if( p ){
@@ -968,11 +968,11 @@
968968
p = 0;
969969
}
970970
return p;
971971
}
972972
content_get(rid, &content);
973
- p = manifest_parse(&content, rid, 0);
973
+ p = manifest_parse(&content, rid, pErr);
974974
if( p && cfType!=CFTYPE_ANY && cfType!=p->type ){
975975
manifest_destroy(p);
976976
p = 0;
977977
}
978978
return p;
@@ -989,11 +989,11 @@
989989
rid = name_to_typed_rid(zName, "ci");
990990
if( !is_a_version(rid) ){
991991
fossil_fatal("no such checkin: %s", zName);
992992
}
993993
if( pRid ) *pRid = rid;
994
- p = manifest_get(rid, CFTYPE_MANIFEST);
994
+ p = manifest_get(rid, CFTYPE_MANIFEST, 0);
995995
if( p==0 ){
996996
fossil_fatal("cannot parse manifest for checkin: %s", zName);
997997
}
998998
return p;
999999
}
@@ -1036,11 +1036,11 @@
10361036
** and return 1 if throwError is false.
10371037
*/
10381038
static int fetch_baseline(Manifest *p, int throwError){
10391039
if( p->zBaseline!=0 && p->pBaseline==0 ){
10401040
int rid = uuid_to_rid(p->zBaseline, 1);
1041
- p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST);
1041
+ p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST, 0);
10421042
if( p->pBaseline==0 ){
10431043
if( !throwError ){
10441044
db_multi_exec(
10451045
"INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)",
10461046
p->rid, rid
10471047
--- src/manifest.c
+++ src/manifest.c
@@ -955,11 +955,11 @@
955
956 /*
957 ** Get a manifest given the rid for the control artifact. Return
958 ** a pointer to the manifest on success or NULL if there is a failure.
959 */
960 Manifest *manifest_get(int rid, int cfType){
961 Blob content;
962 Manifest *p;
963 if( !rid ) return 0;
964 p = manifest_cache_find(rid);
965 if( p ){
@@ -968,11 +968,11 @@
968 p = 0;
969 }
970 return p;
971 }
972 content_get(rid, &content);
973 p = manifest_parse(&content, rid, 0);
974 if( p && cfType!=CFTYPE_ANY && cfType!=p->type ){
975 manifest_destroy(p);
976 p = 0;
977 }
978 return p;
@@ -989,11 +989,11 @@
989 rid = name_to_typed_rid(zName, "ci");
990 if( !is_a_version(rid) ){
991 fossil_fatal("no such checkin: %s", zName);
992 }
993 if( pRid ) *pRid = rid;
994 p = manifest_get(rid, CFTYPE_MANIFEST);
995 if( p==0 ){
996 fossil_fatal("cannot parse manifest for checkin: %s", zName);
997 }
998 return p;
999 }
@@ -1036,11 +1036,11 @@
1036 ** and return 1 if throwError is false.
1037 */
1038 static int fetch_baseline(Manifest *p, int throwError){
1039 if( p->zBaseline!=0 && p->pBaseline==0 ){
1040 int rid = uuid_to_rid(p->zBaseline, 1);
1041 p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST);
1042 if( p->pBaseline==0 ){
1043 if( !throwError ){
1044 db_multi_exec(
1045 "INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)",
1046 p->rid, rid
1047
--- src/manifest.c
+++ src/manifest.c
@@ -955,11 +955,11 @@
955
956 /*
957 ** Get a manifest given the rid for the control artifact. Return
958 ** a pointer to the manifest on success or NULL if there is a failure.
959 */
960 Manifest *manifest_get(int rid, int cfType, Blob *pErr){
961 Blob content;
962 Manifest *p;
963 if( !rid ) return 0;
964 p = manifest_cache_find(rid);
965 if( p ){
@@ -968,11 +968,11 @@
968 p = 0;
969 }
970 return p;
971 }
972 content_get(rid, &content);
973 p = manifest_parse(&content, rid, pErr);
974 if( p && cfType!=CFTYPE_ANY && cfType!=p->type ){
975 manifest_destroy(p);
976 p = 0;
977 }
978 return p;
@@ -989,11 +989,11 @@
989 rid = name_to_typed_rid(zName, "ci");
990 if( !is_a_version(rid) ){
991 fossil_fatal("no such checkin: %s", zName);
992 }
993 if( pRid ) *pRid = rid;
994 p = manifest_get(rid, CFTYPE_MANIFEST, 0);
995 if( p==0 ){
996 fossil_fatal("cannot parse manifest for checkin: %s", zName);
997 }
998 return p;
999 }
@@ -1036,11 +1036,11 @@
1036 ** and return 1 if throwError is false.
1037 */
1038 static int fetch_baseline(Manifest *p, int throwError){
1039 if( p->zBaseline!=0 && p->pBaseline==0 ){
1040 int rid = uuid_to_rid(p->zBaseline, 1);
1041 p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST, 0);
1042 if( p->pBaseline==0 ){
1043 if( !throwError ){
1044 db_multi_exec(
1045 "INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)",
1046 p->rid, rid
1047
+4 -4
--- src/manifest.c
+++ src/manifest.c
@@ -955,11 +955,11 @@
955955
956956
/*
957957
** Get a manifest given the rid for the control artifact. Return
958958
** a pointer to the manifest on success or NULL if there is a failure.
959959
*/
960
-Manifest *manifest_get(int rid, int cfType){
960
+Manifest *manifest_get(int rid, int cfType, Blob *pErr){
961961
Blob content;
962962
Manifest *p;
963963
if( !rid ) return 0;
964964
p = manifest_cache_find(rid);
965965
if( p ){
@@ -968,11 +968,11 @@
968968
p = 0;
969969
}
970970
return p;
971971
}
972972
content_get(rid, &content);
973
- p = manifest_parse(&content, rid, 0);
973
+ p = manifest_parse(&content, rid, pErr);
974974
if( p && cfType!=CFTYPE_ANY && cfType!=p->type ){
975975
manifest_destroy(p);
976976
p = 0;
977977
}
978978
return p;
@@ -989,11 +989,11 @@
989989
rid = name_to_typed_rid(zName, "ci");
990990
if( !is_a_version(rid) ){
991991
fossil_fatal("no such checkin: %s", zName);
992992
}
993993
if( pRid ) *pRid = rid;
994
- p = manifest_get(rid, CFTYPE_MANIFEST);
994
+ p = manifest_get(rid, CFTYPE_MANIFEST, 0);
995995
if( p==0 ){
996996
fossil_fatal("cannot parse manifest for checkin: %s", zName);
997997
}
998998
return p;
999999
}
@@ -1036,11 +1036,11 @@
10361036
** and return 1 if throwError is false.
10371037
*/
10381038
static int fetch_baseline(Manifest *p, int throwError){
10391039
if( p->zBaseline!=0 && p->pBaseline==0 ){
10401040
int rid = uuid_to_rid(p->zBaseline, 1);
1041
- p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST);
1041
+ p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST, 0);
10421042
if( p->pBaseline==0 ){
10431043
if( !throwError ){
10441044
db_multi_exec(
10451045
"INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)",
10461046
p->rid, rid
10471047
--- src/manifest.c
+++ src/manifest.c
@@ -955,11 +955,11 @@
955
956 /*
957 ** Get a manifest given the rid for the control artifact. Return
958 ** a pointer to the manifest on success or NULL if there is a failure.
959 */
960 Manifest *manifest_get(int rid, int cfType){
961 Blob content;
962 Manifest *p;
963 if( !rid ) return 0;
964 p = manifest_cache_find(rid);
965 if( p ){
@@ -968,11 +968,11 @@
968 p = 0;
969 }
970 return p;
971 }
972 content_get(rid, &content);
973 p = manifest_parse(&content, rid, 0);
974 if( p && cfType!=CFTYPE_ANY && cfType!=p->type ){
975 manifest_destroy(p);
976 p = 0;
977 }
978 return p;
@@ -989,11 +989,11 @@
989 rid = name_to_typed_rid(zName, "ci");
990 if( !is_a_version(rid) ){
991 fossil_fatal("no such checkin: %s", zName);
992 }
993 if( pRid ) *pRid = rid;
994 p = manifest_get(rid, CFTYPE_MANIFEST);
995 if( p==0 ){
996 fossil_fatal("cannot parse manifest for checkin: %s", zName);
997 }
998 return p;
999 }
@@ -1036,11 +1036,11 @@
1036 ** and return 1 if throwError is false.
1037 */
1038 static int fetch_baseline(Manifest *p, int throwError){
1039 if( p->zBaseline!=0 && p->pBaseline==0 ){
1040 int rid = uuid_to_rid(p->zBaseline, 1);
1041 p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST);
1042 if( p->pBaseline==0 ){
1043 if( !throwError ){
1044 db_multi_exec(
1045 "INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)",
1046 p->rid, rid
1047
--- src/manifest.c
+++ src/manifest.c
@@ -955,11 +955,11 @@
955
956 /*
957 ** Get a manifest given the rid for the control artifact. Return
958 ** a pointer to the manifest on success or NULL if there is a failure.
959 */
960 Manifest *manifest_get(int rid, int cfType, Blob *pErr){
961 Blob content;
962 Manifest *p;
963 if( !rid ) return 0;
964 p = manifest_cache_find(rid);
965 if( p ){
@@ -968,11 +968,11 @@
968 p = 0;
969 }
970 return p;
971 }
972 content_get(rid, &content);
973 p = manifest_parse(&content, rid, pErr);
974 if( p && cfType!=CFTYPE_ANY && cfType!=p->type ){
975 manifest_destroy(p);
976 p = 0;
977 }
978 return p;
@@ -989,11 +989,11 @@
989 rid = name_to_typed_rid(zName, "ci");
990 if( !is_a_version(rid) ){
991 fossil_fatal("no such checkin: %s", zName);
992 }
993 if( pRid ) *pRid = rid;
994 p = manifest_get(rid, CFTYPE_MANIFEST, 0);
995 if( p==0 ){
996 fossil_fatal("cannot parse manifest for checkin: %s", zName);
997 }
998 return p;
999 }
@@ -1036,11 +1036,11 @@
1036 ** and return 1 if throwError is false.
1037 */
1038 static int fetch_baseline(Manifest *p, int throwError){
1039 if( p->zBaseline!=0 && p->pBaseline==0 ){
1040 int rid = uuid_to_rid(p->zBaseline, 1);
1041 p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST, 0);
1042 if( p->pBaseline==0 ){
1043 if( !throwError ){
1044 db_multi_exec(
1045 "INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)",
1046 p->rid, rid
1047
+1
--- src/md5.c
+++ src/md5.c
@@ -16,10 +16,11 @@
1616
* To compute the message digest of a chunk of bytes, declare an
1717
* MD5Context structure, pass it to MD5Init, call MD5Update as
1818
* needed on buffers full of bytes, and then call MD5Final, which
1919
* will fill a supplied 16-byte array with the digest.
2020
*/
21
+#include "config.h"
2122
#include <string.h>
2223
#include <stdio.h>
2324
#include <sqlite3.h>
2425
#include "md5.h"
2526
2627
--- src/md5.c
+++ src/md5.c
@@ -16,10 +16,11 @@
16 * To compute the message digest of a chunk of bytes, declare an
17 * MD5Context structure, pass it to MD5Init, call MD5Update as
18 * needed on buffers full of bytes, and then call MD5Final, which
19 * will fill a supplied 16-byte array with the digest.
20 */
 
21 #include <string.h>
22 #include <stdio.h>
23 #include <sqlite3.h>
24 #include "md5.h"
25
26
--- src/md5.c
+++ src/md5.c
@@ -16,10 +16,11 @@
16 * To compute the message digest of a chunk of bytes, declare an
17 * MD5Context structure, pass it to MD5Init, call MD5Update as
18 * needed on buffers full of bytes, and then call MD5Final, which
19 * will fill a supplied 16-byte array with the digest.
20 */
21 #include "config.h"
22 #include <string.h>
23 #include <stdio.h>
24 #include <sqlite3.h>
25 #include "md5.h"
26
27
--- src/popen.c
+++ src/popen.c
@@ -27,10 +27,13 @@
2727
** Print a fatal error and quit.
2828
*/
2929
static void win32_fatal_error(const char *zMsg){
3030
fossil_fatal("%s", zMsg);
3131
}
32
+#else
33
+#include <signal.h>
34
+#include <sys/wait.h>
3235
#endif
3336
3437
/*
3538
** The following macros are used to cast pointers to integers and
3639
** integers to pointers. The way you do this varies from one compiler
@@ -171,10 +174,11 @@
171174
close(pout[0]);
172175
close(pout[1]);
173176
*pChildPid = 0;
174177
return 1;
175178
}
179
+ signal(SIGPIPE,SIG_IGN);
176180
if( *pChildPid==0 ){
177181
int fd;
178182
int nErr = 0;
179183
/* This is the child process */
180184
close(0);
@@ -211,7 +215,8 @@
211215
fclose(pOut);
212216
#else
213217
close(fdIn);
214218
fclose(pOut);
215219
kill(childPid, SIGINT);
220
+ while( waitpid(0, 0, WNOHANG)>0 ) {}
216221
#endif
217222
}
218223
--- src/popen.c
+++ src/popen.c
@@ -27,10 +27,13 @@
27 ** Print a fatal error and quit.
28 */
29 static void win32_fatal_error(const char *zMsg){
30 fossil_fatal("%s", zMsg);
31 }
 
 
 
32 #endif
33
34 /*
35 ** The following macros are used to cast pointers to integers and
36 ** integers to pointers. The way you do this varies from one compiler
@@ -171,10 +174,11 @@
171 close(pout[0]);
172 close(pout[1]);
173 *pChildPid = 0;
174 return 1;
175 }
 
176 if( *pChildPid==0 ){
177 int fd;
178 int nErr = 0;
179 /* This is the child process */
180 close(0);
@@ -211,7 +215,8 @@
211 fclose(pOut);
212 #else
213 close(fdIn);
214 fclose(pOut);
215 kill(childPid, SIGINT);
 
216 #endif
217 }
218
--- src/popen.c
+++ src/popen.c
@@ -27,10 +27,13 @@
27 ** Print a fatal error and quit.
28 */
29 static void win32_fatal_error(const char *zMsg){
30 fossil_fatal("%s", zMsg);
31 }
32 #else
33 #include <signal.h>
34 #include <sys/wait.h>
35 #endif
36
37 /*
38 ** The following macros are used to cast pointers to integers and
39 ** integers to pointers. The way you do this varies from one compiler
@@ -171,10 +174,11 @@
174 close(pout[0]);
175 close(pout[1]);
176 *pChildPid = 0;
177 return 1;
178 }
179 signal(SIGPIPE,SIG_IGN);
180 if( *pChildPid==0 ){
181 int fd;
182 int nErr = 0;
183 /* This is the child process */
184 close(0);
@@ -211,7 +215,8 @@
215 fclose(pOut);
216 #else
217 close(fdIn);
218 fclose(pOut);
219 kill(childPid, SIGINT);
220 while( waitpid(0, 0, WNOHANG)>0 ) {}
221 #endif
222 }
223
+1 -1
--- src/rebuild.c
+++ src/rebuild.c
@@ -721,11 +721,11 @@
721721
Manifest *p;
722722
int rid = bag_first(&pending);
723723
int i;
724724
725725
bag_remove(&pending, rid);
726
- p = manifest_get(rid, CFTYPE_CLUSTER);
726
+ p = manifest_get(rid, CFTYPE_CLUSTER, 0);
727727
if( p==0 ){
728728
fossil_fatal("bad cluster: rid=%d", rid);
729729
}
730730
for(i=0; i<p->nCChild; i++){
731731
const char *zUuid = p->azCChild[i];
732732
--- src/rebuild.c
+++ src/rebuild.c
@@ -721,11 +721,11 @@
721 Manifest *p;
722 int rid = bag_first(&pending);
723 int i;
724
725 bag_remove(&pending, rid);
726 p = manifest_get(rid, CFTYPE_CLUSTER);
727 if( p==0 ){
728 fossil_fatal("bad cluster: rid=%d", rid);
729 }
730 for(i=0; i<p->nCChild; i++){
731 const char *zUuid = p->azCChild[i];
732
--- src/rebuild.c
+++ src/rebuild.c
@@ -721,11 +721,11 @@
721 Manifest *p;
722 int rid = bag_first(&pending);
723 int i;
724
725 bag_remove(&pending, rid);
726 p = manifest_get(rid, CFTYPE_CLUSTER, 0);
727 if( p==0 ){
728 fossil_fatal("bad cluster: rid=%d", rid);
729 }
730 for(i=0; i<p->nCChild; i++){
731 const char *zUuid = p->azCChild[i];
732
+13 -4
--- src/setup.c
+++ src/setup.c
@@ -15,12 +15,12 @@
1515
**
1616
*******************************************************************************
1717
**
1818
** Implementation of the Setup page
1919
*/
20
-#include <assert.h>
2120
#include "config.h"
21
+#include <assert.h>
2222
#include "setup.h"
2323
2424
/*
2525
** The table of web pages supported by this application is generated
2626
** automatically by the "mkindex" program and written into a file
@@ -727,11 +727,11 @@
727727
@ capabilities of the <span class="usertype">nobody</span> user are
728728
@ inherited by all users, regardless of whether or not they are logged in.
729729
@ To disable universal access to the repository, make sure no user named
730730
@ <span class="usertype">nobody</span> exists or that the
731731
@ <span class="usertype">nobody</span> user has no capabilities
732
- @ enabled. The password for <span class="usertype">nobody</span> is ignore.
732
+ @ enabled. The password for <span class="usertype">nobody</span> is ignored.
733733
@ To avoid problems with spiders overloading the server, it is recommended
734734
@ that the <span class="capability">h</span> (Hyperlinks) capability be
735735
@ turned off for the <span class="usertype">nobody</span> user.
736736
@ </p></li>
737737
@
@@ -1199,10 +1199,11 @@
11991199
login_check_credentials();
12001200
if( !g.perm.Setup ){
12011201
login_needed();
12021202
}
12031203
1204
+ (void) aCmdHelp; /* NOTE: Silence compiler warning. */
12041205
style_header("Settings");
12051206
db_open_local(0);
12061207
db_begin_transaction();
12071208
@ <p>This page provides a simple interface to the "fossil setting" command.
12081209
@ See the "fossil help setting" output below for further information on
@@ -1272,16 +1273,24 @@
12721273
@ <form action="%s(g.zTop)/setup_config" method="post"><div>
12731274
login_insert_csrf_secret();
12741275
@ <hr />
12751276
entry_attribute("Project Name", 60, "project-name", "pn", "", 0);
12761277
@ <p>Give your project a name so visitors know what this site is about.
1277
- @ The project name will also be used as the RSS feed title.</p>
1278
+ @ The project name will also be used as the RSS feed title.
1279
+ @ </p>
12781280
@ <hr />
12791281
textarea_attribute("Project Description", 3, 80,
12801282
"project-description", "pd", "", 0);
12811283
@ <p>Describe your project. This will be used in page headers for search
12821284
@ engines as well as a short RSS description.</p>
1285
+ @ <hr />
1286
+ entry_attribute("Tarball and ZIP-archive Prefix", 20, "short-project-name", "spn", "", 0);
1287
+ @ <p>This is used as a prefix on the names of generated tarballs and ZIP archive.
1288
+ @ For best results, keep this prefix brief and avoid special characters such
1289
+ @ as "/" and "\".
1290
+ @ If no tarball prefix is specified, then the full Project Name above is used.
1291
+ @ </p>
12831292
@ <hr />
12841293
onoff_attribute("Enable WYSIWYG Wiki Editing",
12851294
"wysiwyg-wiki", "wysiwyg-wiki", 0, 0);
12861295
@ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages.
12871296
@ The WYSIWYG editor generates HTML instead of markup, which makes
@@ -1487,11 +1496,11 @@
14871496
@ <p>When enabled, any change to tickets is subject to the approval
14881497
@ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
14891498
@ Ticket changes enter the system and are shown locally, but are not
14901499
@ synced until they are approved. The moderator has the option to
14911500
@ delete the change rather than approve it. Ticket changes made by
1492
- @ a user who hwas the Mod-Tkt privilege are never subject to
1501
+ @ a user who has the Mod-Tkt privilege are never subject to
14931502
@ moderation.
14941503
@
14951504
@ <hr />
14961505
onoff_attribute("Moderate wiki changes",
14971506
"modreq-wiki", "modreq-wiki", 0, 0);
14981507
--- src/setup.c
+++ src/setup.c
@@ -15,12 +15,12 @@
15 **
16 *******************************************************************************
17 **
18 ** Implementation of the Setup page
19 */
20 #include <assert.h>
21 #include "config.h"
 
22 #include "setup.h"
23
24 /*
25 ** The table of web pages supported by this application is generated
26 ** automatically by the "mkindex" program and written into a file
@@ -727,11 +727,11 @@
727 @ capabilities of the <span class="usertype">nobody</span> user are
728 @ inherited by all users, regardless of whether or not they are logged in.
729 @ To disable universal access to the repository, make sure no user named
730 @ <span class="usertype">nobody</span> exists or that the
731 @ <span class="usertype">nobody</span> user has no capabilities
732 @ enabled. The password for <span class="usertype">nobody</span> is ignore.
733 @ To avoid problems with spiders overloading the server, it is recommended
734 @ that the <span class="capability">h</span> (Hyperlinks) capability be
735 @ turned off for the <span class="usertype">nobody</span> user.
736 @ </p></li>
737 @
@@ -1199,10 +1199,11 @@
1199 login_check_credentials();
1200 if( !g.perm.Setup ){
1201 login_needed();
1202 }
1203
 
1204 style_header("Settings");
1205 db_open_local(0);
1206 db_begin_transaction();
1207 @ <p>This page provides a simple interface to the "fossil setting" command.
1208 @ See the "fossil help setting" output below for further information on
@@ -1272,16 +1273,24 @@
1272 @ <form action="%s(g.zTop)/setup_config" method="post"><div>
1273 login_insert_csrf_secret();
1274 @ <hr />
1275 entry_attribute("Project Name", 60, "project-name", "pn", "", 0);
1276 @ <p>Give your project a name so visitors know what this site is about.
1277 @ The project name will also be used as the RSS feed title.</p>
 
1278 @ <hr />
1279 textarea_attribute("Project Description", 3, 80,
1280 "project-description", "pd", "", 0);
1281 @ <p>Describe your project. This will be used in page headers for search
1282 @ engines as well as a short RSS description.</p>
 
 
 
 
 
 
 
1283 @ <hr />
1284 onoff_attribute("Enable WYSIWYG Wiki Editing",
1285 "wysiwyg-wiki", "wysiwyg-wiki", 0, 0);
1286 @ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages.
1287 @ The WYSIWYG editor generates HTML instead of markup, which makes
@@ -1487,11 +1496,11 @@
1487 @ <p>When enabled, any change to tickets is subject to the approval
1488 @ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
1489 @ Ticket changes enter the system and are shown locally, but are not
1490 @ synced until they are approved. The moderator has the option to
1491 @ delete the change rather than approve it. Ticket changes made by
1492 @ a user who hwas the Mod-Tkt privilege are never subject to
1493 @ moderation.
1494 @
1495 @ <hr />
1496 onoff_attribute("Moderate wiki changes",
1497 "modreq-wiki", "modreq-wiki", 0, 0);
1498
--- src/setup.c
+++ src/setup.c
@@ -15,12 +15,12 @@
15 **
16 *******************************************************************************
17 **
18 ** Implementation of the Setup page
19 */
 
20 #include "config.h"
21 #include <assert.h>
22 #include "setup.h"
23
24 /*
25 ** The table of web pages supported by this application is generated
26 ** automatically by the "mkindex" program and written into a file
@@ -727,11 +727,11 @@
727 @ capabilities of the <span class="usertype">nobody</span> user are
728 @ inherited by all users, regardless of whether or not they are logged in.
729 @ To disable universal access to the repository, make sure no user named
730 @ <span class="usertype">nobody</span> exists or that the
731 @ <span class="usertype">nobody</span> user has no capabilities
732 @ enabled. The password for <span class="usertype">nobody</span> is ignored.
733 @ To avoid problems with spiders overloading the server, it is recommended
734 @ that the <span class="capability">h</span> (Hyperlinks) capability be
735 @ turned off for the <span class="usertype">nobody</span> user.
736 @ </p></li>
737 @
@@ -1199,10 +1199,11 @@
1199 login_check_credentials();
1200 if( !g.perm.Setup ){
1201 login_needed();
1202 }
1203
1204 (void) aCmdHelp; /* NOTE: Silence compiler warning. */
1205 style_header("Settings");
1206 db_open_local(0);
1207 db_begin_transaction();
1208 @ <p>This page provides a simple interface to the "fossil setting" command.
1209 @ See the "fossil help setting" output below for further information on
@@ -1272,16 +1273,24 @@
1273 @ <form action="%s(g.zTop)/setup_config" method="post"><div>
1274 login_insert_csrf_secret();
1275 @ <hr />
1276 entry_attribute("Project Name", 60, "project-name", "pn", "", 0);
1277 @ <p>Give your project a name so visitors know what this site is about.
1278 @ The project name will also be used as the RSS feed title.
1279 @ </p>
1280 @ <hr />
1281 textarea_attribute("Project Description", 3, 80,
1282 "project-description", "pd", "", 0);
1283 @ <p>Describe your project. This will be used in page headers for search
1284 @ engines as well as a short RSS description.</p>
1285 @ <hr />
1286 entry_attribute("Tarball and ZIP-archive Prefix", 20, "short-project-name", "spn", "", 0);
1287 @ <p>This is used as a prefix on the names of generated tarballs and ZIP archive.
1288 @ For best results, keep this prefix brief and avoid special characters such
1289 @ as "/" and "\".
1290 @ If no tarball prefix is specified, then the full Project Name above is used.
1291 @ </p>
1292 @ <hr />
1293 onoff_attribute("Enable WYSIWYG Wiki Editing",
1294 "wysiwyg-wiki", "wysiwyg-wiki", 0, 0);
1295 @ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages.
1296 @ The WYSIWYG editor generates HTML instead of markup, which makes
@@ -1487,11 +1496,11 @@
1496 @ <p>When enabled, any change to tickets is subject to the approval
1497 @ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
1498 @ Ticket changes enter the system and are shown locally, but are not
1499 @ synced until they are approved. The moderator has the option to
1500 @ delete the change rather than approve it. Ticket changes made by
1501 @ a user who has the Mod-Tkt privilege are never subject to
1502 @ moderation.
1503 @
1504 @ <hr />
1505 onoff_attribute("Moderate wiki changes",
1506 "modreq-wiki", "modreq-wiki", 0, 0);
1507
+1 -1
--- src/sha1.c
+++ src/sha1.c
@@ -1,10 +1,10 @@
11
/*
22
** This implementation of SHA1.
33
*/
4
-#include <sys/types.h>
54
#include "config.h"
5
+#include <sys/types.h>
66
#include "sha1.h"
77
88
99
/*
1010
** The SHA1 implementation below is adapted from:
1111
--- src/sha1.c
+++ src/sha1.c
@@ -1,10 +1,10 @@
1 /*
2 ** This implementation of SHA1.
3 */
4 #include <sys/types.h>
5 #include "config.h"
 
6 #include "sha1.h"
7
8
9 /*
10 ** The SHA1 implementation below is adapted from:
11
--- src/sha1.c
+++ src/sha1.c
@@ -1,10 +1,10 @@
1 /*
2 ** This implementation of SHA1.
3 */
 
4 #include "config.h"
5 #include <sys/types.h>
6 #include "sha1.h"
7
8
9 /*
10 ** The SHA1 implementation below is adapted from:
11
+2 -2
--- src/shell.c
+++ src/shell.c
@@ -972,11 +972,11 @@
972972
int i;
973973
const char *z;
974974
rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
975975
if( rc!=SQLITE_OK || !pSelect ){
976976
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
977
- p->nErr++;
977
+ if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
978978
return rc;
979979
}
980980
rc = sqlite3_step(pSelect);
981981
nResult = sqlite3_column_count(pSelect);
982982
while( rc==SQLITE_ROW ){
@@ -999,11 +999,11 @@
999999
rc = sqlite3_step(pSelect);
10001000
}
10011001
rc = sqlite3_finalize(pSelect);
10021002
if( rc!=SQLITE_OK ){
10031003
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
1004
- p->nErr++;
1004
+ if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
10051005
}
10061006
return rc;
10071007
}
10081008
10091009
/*
10101010
--- src/shell.c
+++ src/shell.c
@@ -972,11 +972,11 @@
972 int i;
973 const char *z;
974 rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
975 if( rc!=SQLITE_OK || !pSelect ){
976 fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
977 p->nErr++;
978 return rc;
979 }
980 rc = sqlite3_step(pSelect);
981 nResult = sqlite3_column_count(pSelect);
982 while( rc==SQLITE_ROW ){
@@ -999,11 +999,11 @@
999 rc = sqlite3_step(pSelect);
1000 }
1001 rc = sqlite3_finalize(pSelect);
1002 if( rc!=SQLITE_OK ){
1003 fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
1004 p->nErr++;
1005 }
1006 return rc;
1007 }
1008
1009 /*
1010
--- src/shell.c
+++ src/shell.c
@@ -972,11 +972,11 @@
972 int i;
973 const char *z;
974 rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
975 if( rc!=SQLITE_OK || !pSelect ){
976 fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
977 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
978 return rc;
979 }
980 rc = sqlite3_step(pSelect);
981 nResult = sqlite3_column_count(pSelect);
982 while( rc==SQLITE_ROW ){
@@ -999,11 +999,11 @@
999 rc = sqlite3_step(pSelect);
1000 }
1001 rc = sqlite3_finalize(pSelect);
1002 if( rc!=SQLITE_OK ){
1003 fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
1004 if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
1005 }
1006 return rc;
1007 }
1008
1009 /*
1010
+1 -1
--- src/skins.c
+++ src/skins.c
@@ -15,12 +15,12 @@
1515
**
1616
*******************************************************************************
1717
**
1818
** Implementation of the Setup page for "skins".
1919
*/
20
-#include <assert.h>
2120
#include "config.h"
21
+#include <assert.h>
2222
#include "skins.h"
2323
2424
/* @-comment: ## */
2525
/*
2626
** A black-and-white theme with the project title in a bar across the top
2727
--- src/skins.c
+++ src/skins.c
@@ -15,12 +15,12 @@
15 **
16 *******************************************************************************
17 **
18 ** Implementation of the Setup page for "skins".
19 */
20 #include <assert.h>
21 #include "config.h"
 
22 #include "skins.h"
23
24 /* @-comment: ## */
25 /*
26 ** A black-and-white theme with the project title in a bar across the top
27
--- src/skins.c
+++ src/skins.c
@@ -15,12 +15,12 @@
15 **
16 *******************************************************************************
17 **
18 ** Implementation of the Setup page for "skins".
19 */
 
20 #include "config.h"
21 #include <assert.h>
22 #include "skins.h"
23
24 /* @-comment: ## */
25 /*
26 ** A black-and-white theme with the project title in a bar across the top
27
+1774 -1122
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -23,531 +23,10 @@
2323
# define SQLITE_PRIVATE static
2424
#endif
2525
#ifndef SQLITE_API
2626
# define SQLITE_API
2727
#endif
28
-/************** Begin file sqliteInt.h ***************************************/
29
-/*
30
-** 2001 September 15
31
-**
32
-** The author disclaims copyright to this source code. In place of
33
-** a legal notice, here is a blessing:
34
-**
35
-** May you do good and not evil.
36
-** May you find forgiveness for yourself and forgive others.
37
-** May you share freely, never taking more than you give.
38
-**
39
-*************************************************************************
40
-** Internal interface definitions for SQLite.
41
-**
42
-*/
43
-#ifndef _SQLITEINT_H_
44
-#define _SQLITEINT_H_
45
-
46
-/*
47
-** These #defines should enable >2GB file support on POSIX if the
48
-** underlying operating system supports it. If the OS lacks
49
-** large file support, or if the OS is windows, these should be no-ops.
50
-**
51
-** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any
52
-** system #includes. Hence, this block of code must be the very first
53
-** code in all source files.
54
-**
55
-** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
56
-** on the compiler command line. This is necessary if you are compiling
57
-** on a recent machine (ex: Red Hat 7.2) but you want your code to work
58
-** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2
59
-** without this option, LFS is enable. But LFS does not exist in the kernel
60
-** in Red Hat 6.0, so the code won't work. Hence, for maximum binary
61
-** portability you should omit LFS.
62
-**
63
-** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later.
64
-*/
65
-#ifndef SQLITE_DISABLE_LFS
66
-# define _LARGE_FILE 1
67
-# ifndef _FILE_OFFSET_BITS
68
-# define _FILE_OFFSET_BITS 64
69
-# endif
70
-# define _LARGEFILE_SOURCE 1
71
-#endif
72
-
73
-/*
74
-** Include the configuration header output by 'configure' if we're using the
75
-** autoconf-based build
76
-*/
77
-#ifdef _HAVE_SQLITE_CONFIG_H
78
-#include "config.h"
79
-#endif
80
-
81
-/************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/
82
-/************** Begin file sqliteLimit.h *************************************/
83
-/*
84
-** 2007 May 7
85
-**
86
-** The author disclaims copyright to this source code. In place of
87
-** a legal notice, here is a blessing:
88
-**
89
-** May you do good and not evil.
90
-** May you find forgiveness for yourself and forgive others.
91
-** May you share freely, never taking more than you give.
92
-**
93
-*************************************************************************
94
-**
95
-** This file defines various limits of what SQLite can process.
96
-*/
97
-
98
-/*
99
-** The maximum length of a TEXT or BLOB in bytes. This also
100
-** limits the size of a row in a table or index.
101
-**
102
-** The hard limit is the ability of a 32-bit signed integer
103
-** to count the size: 2^31-1 or 2147483647.
104
-*/
105
-#ifndef SQLITE_MAX_LENGTH
106
-# define SQLITE_MAX_LENGTH 1000000000
107
-#endif
108
-
109
-/*
110
-** This is the maximum number of
111
-**
112
-** * Columns in a table
113
-** * Columns in an index
114
-** * Columns in a view
115
-** * Terms in the SET clause of an UPDATE statement
116
-** * Terms in the result set of a SELECT statement
117
-** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
118
-** * Terms in the VALUES clause of an INSERT statement
119
-**
120
-** The hard upper limit here is 32676. Most database people will
121
-** tell you that in a well-normalized database, you usually should
122
-** not have more than a dozen or so columns in any table. And if
123
-** that is the case, there is no point in having more than a few
124
-** dozen values in any of the other situations described above.
125
-*/
126
-#ifndef SQLITE_MAX_COLUMN
127
-# define SQLITE_MAX_COLUMN 2000
128
-#endif
129
-
130
-/*
131
-** The maximum length of a single SQL statement in bytes.
132
-**
133
-** It used to be the case that setting this value to zero would
134
-** turn the limit off. That is no longer true. It is not possible
135
-** to turn this limit off.
136
-*/
137
-#ifndef SQLITE_MAX_SQL_LENGTH
138
-# define SQLITE_MAX_SQL_LENGTH 1000000000
139
-#endif
140
-
141
-/*
142
-** The maximum depth of an expression tree. This is limited to
143
-** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
144
-** want to place more severe limits on the complexity of an
145
-** expression.
146
-**
147
-** A value of 0 used to mean that the limit was not enforced.
148
-** But that is no longer true. The limit is now strictly enforced
149
-** at all times.
150
-*/
151
-#ifndef SQLITE_MAX_EXPR_DEPTH
152
-# define SQLITE_MAX_EXPR_DEPTH 1000
153
-#endif
154
-
155
-/*
156
-** The maximum number of terms in a compound SELECT statement.
157
-** The code generator for compound SELECT statements does one
158
-** level of recursion for each term. A stack overflow can result
159
-** if the number of terms is too large. In practice, most SQL
160
-** never has more than 3 or 4 terms. Use a value of 0 to disable
161
-** any limit on the number of terms in a compount SELECT.
162
-*/
163
-#ifndef SQLITE_MAX_COMPOUND_SELECT
164
-# define SQLITE_MAX_COMPOUND_SELECT 500
165
-#endif
166
-
167
-/*
168
-** The maximum number of opcodes in a VDBE program.
169
-** Not currently enforced.
170
-*/
171
-#ifndef SQLITE_MAX_VDBE_OP
172
-# define SQLITE_MAX_VDBE_OP 25000
173
-#endif
174
-
175
-/*
176
-** The maximum number of arguments to an SQL function.
177
-*/
178
-#ifndef SQLITE_MAX_FUNCTION_ARG
179
-# define SQLITE_MAX_FUNCTION_ARG 127
180
-#endif
181
-
182
-/*
183
-** The maximum number of in-memory pages to use for the main database
184
-** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
185
-*/
186
-#ifndef SQLITE_DEFAULT_CACHE_SIZE
187
-# define SQLITE_DEFAULT_CACHE_SIZE 2000
188
-#endif
189
-#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
190
-# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
191
-#endif
192
-
193
-/*
194
-** The default number of frames to accumulate in the log file before
195
-** checkpointing the database in WAL mode.
196
-*/
197
-#ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
198
-# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
199
-#endif
200
-
201
-/*
202
-** The maximum number of attached databases. This must be between 0
203
-** and 62. The upper bound on 62 is because a 64-bit integer bitmap
204
-** is used internally to track attached databases.
205
-*/
206
-#ifndef SQLITE_MAX_ATTACHED
207
-# define SQLITE_MAX_ATTACHED 10
208
-#endif
209
-
210
-
211
-/*
212
-** The maximum value of a ?nnn wildcard that the parser will accept.
213
-*/
214
-#ifndef SQLITE_MAX_VARIABLE_NUMBER
215
-# define SQLITE_MAX_VARIABLE_NUMBER 999
216
-#endif
217
-
218
-/* Maximum page size. The upper bound on this value is 65536. This a limit
219
-** imposed by the use of 16-bit offsets within each page.
220
-**
221
-** Earlier versions of SQLite allowed the user to change this value at
222
-** compile time. This is no longer permitted, on the grounds that it creates
223
-** a library that is technically incompatible with an SQLite library
224
-** compiled with a different limit. If a process operating on a database
225
-** with a page-size of 65536 bytes crashes, then an instance of SQLite
226
-** compiled with the default page-size limit will not be able to rollback
227
-** the aborted transaction. This could lead to database corruption.
228
-*/
229
-#ifdef SQLITE_MAX_PAGE_SIZE
230
-# undef SQLITE_MAX_PAGE_SIZE
231
-#endif
232
-#define SQLITE_MAX_PAGE_SIZE 65536
233
-
234
-
235
-/*
236
-** The default size of a database page.
237
-*/
238
-#ifndef SQLITE_DEFAULT_PAGE_SIZE
239
-# define SQLITE_DEFAULT_PAGE_SIZE 1024
240
-#endif
241
-#if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
242
-# undef SQLITE_DEFAULT_PAGE_SIZE
243
-# define SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
244
-#endif
245
-
246
-/*
247
-** Ordinarily, if no value is explicitly provided, SQLite creates databases
248
-** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain
249
-** device characteristics (sector-size and atomic write() support),
250
-** SQLite may choose a larger value. This constant is the maximum value
251
-** SQLite will choose on its own.
252
-*/
253
-#ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE
254
-# define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192
255
-#endif
256
-#if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
257
-# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
258
-# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
259
-#endif
260
-
261
-
262
-/*
263
-** Maximum number of pages in one database file.
264
-**
265
-** This is really just the default value for the max_page_count pragma.
266
-** This value can be lowered (or raised) at run-time using that the
267
-** max_page_count macro.
268
-*/
269
-#ifndef SQLITE_MAX_PAGE_COUNT
270
-# define SQLITE_MAX_PAGE_COUNT 1073741823
271
-#endif
272
-
273
-/*
274
-** Maximum length (in bytes) of the pattern in a LIKE or GLOB
275
-** operator.
276
-*/
277
-#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
278
-# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
279
-#endif
280
-
281
-/*
282
-** Maximum depth of recursion for triggers.
283
-**
284
-** A value of 1 means that a trigger program will not be able to itself
285
-** fire any triggers. A value of 0 means that no trigger programs at all
286
-** may be executed.
287
-*/
288
-#ifndef SQLITE_MAX_TRIGGER_DEPTH
289
-# define SQLITE_MAX_TRIGGER_DEPTH 1000
290
-#endif
291
-
292
-/************** End of sqliteLimit.h *****************************************/
293
-/************** Continuing where we left off in sqliteInt.h ******************/
294
-
295
-/* Disable nuisance warnings on Borland compilers */
296
-#if defined(__BORLANDC__)
297
-#pragma warn -rch /* unreachable code */
298
-#pragma warn -ccc /* Condition is always true or false */
299
-#pragma warn -aus /* Assigned value is never used */
300
-#pragma warn -csu /* Comparing signed and unsigned */
301
-#pragma warn -spa /* Suspicious pointer arithmetic */
302
-#endif
303
-
304
-/* Needed for various definitions... */
305
-#ifndef _GNU_SOURCE
306
-# define _GNU_SOURCE
307
-#endif
308
-
309
-#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
310
-# define _BSD_SOURCE
311
-#endif
312
-
313
-/*
314
-** Include standard header files as necessary
315
-*/
316
-#ifdef HAVE_STDINT_H
317
-#include <stdint.h>
318
-#endif
319
-#ifdef HAVE_INTTYPES_H
320
-#include <inttypes.h>
321
-#endif
322
-
323
-/*
324
-** The following macros are used to cast pointers to integers and
325
-** integers to pointers. The way you do this varies from one compiler
326
-** to the next, so we have developed the following set of #if statements
327
-** to generate appropriate macros for a wide range of compilers.
328
-**
329
-** The correct "ANSI" way to do this is to use the intptr_t type.
330
-** Unfortunately, that typedef is not available on all compilers, or
331
-** if it is available, it requires an #include of specific headers
332
-** that vary from one machine to the next.
333
-**
334
-** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
335
-** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
336
-** So we have to define the macros in different ways depending on the
337
-** compiler.
338
-*/
339
-#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
340
-# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
341
-# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
342
-#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
343
-# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
344
-# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
345
-#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
346
-# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
347
-# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
348
-#else /* Generates a warning - but it always works */
349
-# define SQLITE_INT_TO_PTR(X) ((void*)(X))
350
-# define SQLITE_PTR_TO_INT(X) ((int)(X))
351
-#endif
352
-
353
-/*
354
-** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
355
-** 0 means mutexes are permanently disable and the library is never
356
-** threadsafe. 1 means the library is serialized which is the highest
357
-** level of threadsafety. 2 means the library is multithreaded - multiple
358
-** threads can use SQLite as long as no two threads try to use the same
359
-** database connection at the same time.
360
-**
361
-** Older versions of SQLite used an optional THREADSAFE macro.
362
-** We support that for legacy.
363
-*/
364
-#if !defined(SQLITE_THREADSAFE)
365
-# if defined(THREADSAFE)
366
-# define SQLITE_THREADSAFE THREADSAFE
367
-# else
368
-# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
369
-# endif
370
-#endif
371
-
372
-/*
373
-** Powersafe overwrite is on by default. But can be turned off using
374
-** the -DSQLITE_POWERSAFE_OVERWRITE=0 command-line option.
375
-*/
376
-#ifndef SQLITE_POWERSAFE_OVERWRITE
377
-# define SQLITE_POWERSAFE_OVERWRITE 1
378
-#endif
379
-
380
-/*
381
-** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
382
-** It determines whether or not the features related to
383
-** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can
384
-** be overridden at runtime using the sqlite3_config() API.
385
-*/
386
-#if !defined(SQLITE_DEFAULT_MEMSTATUS)
387
-# define SQLITE_DEFAULT_MEMSTATUS 1
388
-#endif
389
-
390
-/*
391
-** Exactly one of the following macros must be defined in order to
392
-** specify which memory allocation subsystem to use.
393
-**
394
-** SQLITE_SYSTEM_MALLOC // Use normal system malloc()
395
-** SQLITE_WIN32_MALLOC // Use Win32 native heap API
396
-** SQLITE_ZERO_MALLOC // Use a stub allocator that always fails
397
-** SQLITE_MEMDEBUG // Debugging version of system malloc()
398
-**
399
-** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the
400
-** assert() macro is enabled, each call into the Win32 native heap subsystem
401
-** will cause HeapValidate to be called. If heap validation should fail, an
402
-** assertion will be triggered.
403
-**
404
-** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
405
-** the default.
406
-*/
407
-#if defined(SQLITE_SYSTEM_MALLOC) \
408
- + defined(SQLITE_WIN32_MALLOC) \
409
- + defined(SQLITE_ZERO_MALLOC) \
410
- + defined(SQLITE_MEMDEBUG)>1
411
-# error "Two or more of the following compile-time configuration options\
412
- are defined but at most one is allowed:\
413
- SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG,\
414
- SQLITE_ZERO_MALLOC"
415
-#endif
416
-#if defined(SQLITE_SYSTEM_MALLOC) \
417
- + defined(SQLITE_WIN32_MALLOC) \
418
- + defined(SQLITE_ZERO_MALLOC) \
419
- + defined(SQLITE_MEMDEBUG)==0
420
-# define SQLITE_SYSTEM_MALLOC 1
421
-#endif
422
-
423
-/*
424
-** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the
425
-** sizes of memory allocations below this value where possible.
426
-*/
427
-#if !defined(SQLITE_MALLOC_SOFT_LIMIT)
428
-# define SQLITE_MALLOC_SOFT_LIMIT 1024
429
-#endif
430
-
431
-/*
432
-** We need to define _XOPEN_SOURCE as follows in order to enable
433
-** recursive mutexes on most Unix systems and fchmod() on OpenBSD.
434
-** But _XOPEN_SOURCE define causes problems for Mac OS X, so omit
435
-** it.
436
-*/
437
-#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__)
438
-# define _XOPEN_SOURCE 600
439
-#endif
440
-
441
-/*
442
-** NDEBUG and SQLITE_DEBUG are opposites. It should always be true that
443
-** defined(NDEBUG)==!defined(SQLITE_DEBUG). If this is not currently true,
444
-** make it true by defining or undefining NDEBUG.
445
-**
446
-** Setting NDEBUG makes the code smaller and faster by disabling the
447
-** assert() statements in the code. So we want the default action
448
-** to be for NDEBUG to be set and NDEBUG to be undefined only if SQLITE_DEBUG
449
-** is set. Thus NDEBUG becomes an opt-in rather than an opt-out
450
-** feature.
451
-*/
452
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
453
-# define NDEBUG 1
454
-#endif
455
-#if defined(NDEBUG) && defined(SQLITE_DEBUG)
456
-# undef NDEBUG
457
-#endif
458
-
459
-/*
460
-** The testcase() macro is used to aid in coverage testing. When
461
-** doing coverage testing, the condition inside the argument to
462
-** testcase() must be evaluated both true and false in order to
463
-** get full branch coverage. The testcase() macro is inserted
464
-** to help ensure adequate test coverage in places where simple
465
-** condition/decision coverage is inadequate. For example, testcase()
466
-** can be used to make sure boundary values are tested. For
467
-** bitmask tests, testcase() can be used to make sure each bit
468
-** is significant and used at least once. On switch statements
469
-** where multiple cases go to the same block of code, testcase()
470
-** can insure that all cases are evaluated.
471
-**
472
-*/
473
-#ifdef SQLITE_COVERAGE_TEST
474
-SQLITE_PRIVATE void sqlite3Coverage(int);
475
-# define testcase(X) if( X ){ sqlite3Coverage(__LINE__); }
476
-#else
477
-# define testcase(X)
478
-#endif
479
-
480
-/*
481
-** The TESTONLY macro is used to enclose variable declarations or
482
-** other bits of code that are needed to support the arguments
483
-** within testcase() and assert() macros.
484
-*/
485
-#if !defined(NDEBUG) || defined(SQLITE_COVERAGE_TEST)
486
-# define TESTONLY(X) X
487
-#else
488
-# define TESTONLY(X)
489
-#endif
490
-
491
-/*
492
-** Sometimes we need a small amount of code such as a variable initialization
493
-** to setup for a later assert() statement. We do not want this code to
494
-** appear when assert() is disabled. The following macro is therefore
495
-** used to contain that setup code. The "VVA" acronym stands for
496
-** "Verification, Validation, and Accreditation". In other words, the
497
-** code within VVA_ONLY() will only run during verification processes.
498
-*/
499
-#ifndef NDEBUG
500
-# define VVA_ONLY(X) X
501
-#else
502
-# define VVA_ONLY(X)
503
-#endif
504
-
505
-/*
506
-** The ALWAYS and NEVER macros surround boolean expressions which
507
-** are intended to always be true or false, respectively. Such
508
-** expressions could be omitted from the code completely. But they
509
-** are included in a few cases in order to enhance the resilience
510
-** of SQLite to unexpected behavior - to make the code "self-healing"
511
-** or "ductile" rather than being "brittle" and crashing at the first
512
-** hint of unplanned behavior.
513
-**
514
-** In other words, ALWAYS and NEVER are added for defensive code.
515
-**
516
-** When doing coverage testing ALWAYS and NEVER are hard-coded to
517
-** be true and false so that the unreachable code they specify will
518
-** not be counted as untested code.
519
-*/
520
-#if defined(SQLITE_COVERAGE_TEST)
521
-# define ALWAYS(X) (1)
522
-# define NEVER(X) (0)
523
-#elif !defined(NDEBUG)
524
-# define ALWAYS(X) ((X)?1:(assert(0),0))
525
-# define NEVER(X) ((X)?(assert(0),1):0)
526
-#else
527
-# define ALWAYS(X) (X)
528
-# define NEVER(X) (X)
529
-#endif
530
-
531
-/*
532
-** Return true (non-zero) if the input is a integer that is too large
533
-** to fit in 32-bits. This macro is used inside of various testcase()
534
-** macros to verify that we have tested SQLite for large-file support.
535
-*/
536
-#define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0)
537
-
538
-/*
539
-** The macro unlikely() is a hint that surrounds a boolean
540
-** expression that is usually false. Macro likely() surrounds
541
-** a boolean expression that is usually true. These hints could,
542
-** in theory, be used by the compiler to generate better code, but
543
-** currently they are just comments for human readers.
544
-*/
545
-#define likely(X) (X)
546
-#define unlikely(X) (X)
547
-
548
-/************** Include sqlite3.h in the middle of sqliteInt.h ***************/
54928
/************** Begin file sqlite3.h *****************************************/
55029
/*
55130
** 2001 September 15
55231
**
55332
** The author disclaims copyright to this source code. In place of
@@ -656,11 +135,11 @@
656135
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657136
** [sqlite_version()] and [sqlite_source_id()].
658137
*/
659138
#define SQLITE_VERSION "3.8.1"
660139
#define SQLITE_VERSION_NUMBER 3008001
661
-#define SQLITE_SOURCE_ID "2013-09-16 12:57:19 daf6ba413cb3cb6065774ba07495eab4a28b49b0"
140
+#define SQLITE_SOURCE_ID "2013-10-11 13:27:26 03593817ab5abdd4bbaa5e47e2e4745eef025af9"
662141
663142
/*
664143
** CAPI3REF: Run-Time Library Version Numbers
665144
** KEYWORDS: sqlite3_version, sqlite3_sourceid
666145
**
@@ -7846,11 +7325,530 @@
78467325
78477326
#endif /* ifndef _SQLITE3RTREE_H_ */
78487327
78497328
78507329
/************** End of sqlite3.h *********************************************/
7330
+/************** Begin file sqliteInt.h ***************************************/
7331
+/*
7332
+** 2001 September 15
7333
+**
7334
+** The author disclaims copyright to this source code. In place of
7335
+** a legal notice, here is a blessing:
7336
+**
7337
+** May you do good and not evil.
7338
+** May you find forgiveness for yourself and forgive others.
7339
+** May you share freely, never taking more than you give.
7340
+**
7341
+*************************************************************************
7342
+** Internal interface definitions for SQLite.
7343
+**
7344
+*/
7345
+#ifndef _SQLITEINT_H_
7346
+#define _SQLITEINT_H_
7347
+
7348
+/*
7349
+** These #defines should enable >2GB file support on POSIX if the
7350
+** underlying operating system supports it. If the OS lacks
7351
+** large file support, or if the OS is windows, these should be no-ops.
7352
+**
7353
+** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any
7354
+** system #includes. Hence, this block of code must be the very first
7355
+** code in all source files.
7356
+**
7357
+** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
7358
+** on the compiler command line. This is necessary if you are compiling
7359
+** on a recent machine (ex: Red Hat 7.2) but you want your code to work
7360
+** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2
7361
+** without this option, LFS is enable. But LFS does not exist in the kernel
7362
+** in Red Hat 6.0, so the code won't work. Hence, for maximum binary
7363
+** portability you should omit LFS.
7364
+**
7365
+** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later.
7366
+*/
7367
+#ifndef SQLITE_DISABLE_LFS
7368
+# define _LARGE_FILE 1
7369
+# ifndef _FILE_OFFSET_BITS
7370
+# define _FILE_OFFSET_BITS 64
7371
+# endif
7372
+# define _LARGEFILE_SOURCE 1
7373
+#endif
7374
+
7375
+/*
7376
+** Include the configuration header output by 'configure' if we're using the
7377
+** autoconf-based build
7378
+*/
7379
+#ifdef _HAVE_SQLITE_CONFIG_H
7380
+#include "config.h"
7381
+#endif
7382
+
7383
+/************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/
7384
+/************** Begin file sqliteLimit.h *************************************/
7385
+/*
7386
+** 2007 May 7
7387
+**
7388
+** The author disclaims copyright to this source code. In place of
7389
+** a legal notice, here is a blessing:
7390
+**
7391
+** May you do good and not evil.
7392
+** May you find forgiveness for yourself and forgive others.
7393
+** May you share freely, never taking more than you give.
7394
+**
7395
+*************************************************************************
7396
+**
7397
+** This file defines various limits of what SQLite can process.
7398
+*/
7399
+
7400
+/*
7401
+** The maximum length of a TEXT or BLOB in bytes. This also
7402
+** limits the size of a row in a table or index.
7403
+**
7404
+** The hard limit is the ability of a 32-bit signed integer
7405
+** to count the size: 2^31-1 or 2147483647.
7406
+*/
7407
+#ifndef SQLITE_MAX_LENGTH
7408
+# define SQLITE_MAX_LENGTH 1000000000
7409
+#endif
7410
+
7411
+/*
7412
+** This is the maximum number of
7413
+**
7414
+** * Columns in a table
7415
+** * Columns in an index
7416
+** * Columns in a view
7417
+** * Terms in the SET clause of an UPDATE statement
7418
+** * Terms in the result set of a SELECT statement
7419
+** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
7420
+** * Terms in the VALUES clause of an INSERT statement
7421
+**
7422
+** The hard upper limit here is 32676. Most database people will
7423
+** tell you that in a well-normalized database, you usually should
7424
+** not have more than a dozen or so columns in any table. And if
7425
+** that is the case, there is no point in having more than a few
7426
+** dozen values in any of the other situations described above.
7427
+*/
7428
+#ifndef SQLITE_MAX_COLUMN
7429
+# define SQLITE_MAX_COLUMN 2000
7430
+#endif
7431
+
7432
+/*
7433
+** The maximum length of a single SQL statement in bytes.
7434
+**
7435
+** It used to be the case that setting this value to zero would
7436
+** turn the limit off. That is no longer true. It is not possible
7437
+** to turn this limit off.
7438
+*/
7439
+#ifndef SQLITE_MAX_SQL_LENGTH
7440
+# define SQLITE_MAX_SQL_LENGTH 1000000000
7441
+#endif
7442
+
7443
+/*
7444
+** The maximum depth of an expression tree. This is limited to
7445
+** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
7446
+** want to place more severe limits on the complexity of an
7447
+** expression.
7448
+**
7449
+** A value of 0 used to mean that the limit was not enforced.
7450
+** But that is no longer true. The limit is now strictly enforced
7451
+** at all times.
7452
+*/
7453
+#ifndef SQLITE_MAX_EXPR_DEPTH
7454
+# define SQLITE_MAX_EXPR_DEPTH 1000
7455
+#endif
7456
+
7457
+/*
7458
+** The maximum number of terms in a compound SELECT statement.
7459
+** The code generator for compound SELECT statements does one
7460
+** level of recursion for each term. A stack overflow can result
7461
+** if the number of terms is too large. In practice, most SQL
7462
+** never has more than 3 or 4 terms. Use a value of 0 to disable
7463
+** any limit on the number of terms in a compount SELECT.
7464
+*/
7465
+#ifndef SQLITE_MAX_COMPOUND_SELECT
7466
+# define SQLITE_MAX_COMPOUND_SELECT 500
7467
+#endif
7468
+
7469
+/*
7470
+** The maximum number of opcodes in a VDBE program.
7471
+** Not currently enforced.
7472
+*/
7473
+#ifndef SQLITE_MAX_VDBE_OP
7474
+# define SQLITE_MAX_VDBE_OP 25000
7475
+#endif
7476
+
7477
+/*
7478
+** The maximum number of arguments to an SQL function.
7479
+*/
7480
+#ifndef SQLITE_MAX_FUNCTION_ARG
7481
+# define SQLITE_MAX_FUNCTION_ARG 127
7482
+#endif
7483
+
7484
+/*
7485
+** The maximum number of in-memory pages to use for the main database
7486
+** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
7487
+*/
7488
+#ifndef SQLITE_DEFAULT_CACHE_SIZE
7489
+# define SQLITE_DEFAULT_CACHE_SIZE 2000
7490
+#endif
7491
+#ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
7492
+# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
7493
+#endif
7494
+
7495
+/*
7496
+** The default number of frames to accumulate in the log file before
7497
+** checkpointing the database in WAL mode.
7498
+*/
7499
+#ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
7500
+# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
7501
+#endif
7502
+
7503
+/*
7504
+** The maximum number of attached databases. This must be between 0
7505
+** and 62. The upper bound on 62 is because a 64-bit integer bitmap
7506
+** is used internally to track attached databases.
7507
+*/
7508
+#ifndef SQLITE_MAX_ATTACHED
7509
+# define SQLITE_MAX_ATTACHED 10
7510
+#endif
7511
+
7512
+
7513
+/*
7514
+** The maximum value of a ?nnn wildcard that the parser will accept.
7515
+*/
7516
+#ifndef SQLITE_MAX_VARIABLE_NUMBER
7517
+# define SQLITE_MAX_VARIABLE_NUMBER 999
7518
+#endif
7519
+
7520
+/* Maximum page size. The upper bound on this value is 65536. This a limit
7521
+** imposed by the use of 16-bit offsets within each page.
7522
+**
7523
+** Earlier versions of SQLite allowed the user to change this value at
7524
+** compile time. This is no longer permitted, on the grounds that it creates
7525
+** a library that is technically incompatible with an SQLite library
7526
+** compiled with a different limit. If a process operating on a database
7527
+** with a page-size of 65536 bytes crashes, then an instance of SQLite
7528
+** compiled with the default page-size limit will not be able to rollback
7529
+** the aborted transaction. This could lead to database corruption.
7530
+*/
7531
+#ifdef SQLITE_MAX_PAGE_SIZE
7532
+# undef SQLITE_MAX_PAGE_SIZE
7533
+#endif
7534
+#define SQLITE_MAX_PAGE_SIZE 65536
7535
+
7536
+
7537
+/*
7538
+** The default size of a database page.
7539
+*/
7540
+#ifndef SQLITE_DEFAULT_PAGE_SIZE
7541
+# define SQLITE_DEFAULT_PAGE_SIZE 1024
7542
+#endif
7543
+#if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
7544
+# undef SQLITE_DEFAULT_PAGE_SIZE
7545
+# define SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
7546
+#endif
7547
+
7548
+/*
7549
+** Ordinarily, if no value is explicitly provided, SQLite creates databases
7550
+** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain
7551
+** device characteristics (sector-size and atomic write() support),
7552
+** SQLite may choose a larger value. This constant is the maximum value
7553
+** SQLite will choose on its own.
7554
+*/
7555
+#ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE
7556
+# define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192
7557
+#endif
7558
+#if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
7559
+# undef SQLITE_MAX_DEFAULT_PAGE_SIZE
7560
+# define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
7561
+#endif
7562
+
7563
+
7564
+/*
7565
+** Maximum number of pages in one database file.
7566
+**
7567
+** This is really just the default value for the max_page_count pragma.
7568
+** This value can be lowered (or raised) at run-time using that the
7569
+** max_page_count macro.
7570
+*/
7571
+#ifndef SQLITE_MAX_PAGE_COUNT
7572
+# define SQLITE_MAX_PAGE_COUNT 1073741823
7573
+#endif
7574
+
7575
+/*
7576
+** Maximum length (in bytes) of the pattern in a LIKE or GLOB
7577
+** operator.
7578
+*/
7579
+#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
7580
+# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
7581
+#endif
7582
+
7583
+/*
7584
+** Maximum depth of recursion for triggers.
7585
+**
7586
+** A value of 1 means that a trigger program will not be able to itself
7587
+** fire any triggers. A value of 0 means that no trigger programs at all
7588
+** may be executed.
7589
+*/
7590
+#ifndef SQLITE_MAX_TRIGGER_DEPTH
7591
+# define SQLITE_MAX_TRIGGER_DEPTH 1000
7592
+#endif
7593
+
7594
+/************** End of sqliteLimit.h *****************************************/
78517595
/************** Continuing where we left off in sqliteInt.h ******************/
7596
+
7597
+/* Disable nuisance warnings on Borland compilers */
7598
+#if defined(__BORLANDC__)
7599
+#pragma warn -rch /* unreachable code */
7600
+#pragma warn -ccc /* Condition is always true or false */
7601
+#pragma warn -aus /* Assigned value is never used */
7602
+#pragma warn -csu /* Comparing signed and unsigned */
7603
+#pragma warn -spa /* Suspicious pointer arithmetic */
7604
+#endif
7605
+
7606
+/* Needed for various definitions... */
7607
+#ifndef _GNU_SOURCE
7608
+# define _GNU_SOURCE
7609
+#endif
7610
+
7611
+#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
7612
+# define _BSD_SOURCE
7613
+#endif
7614
+
7615
+/*
7616
+** Include standard header files as necessary
7617
+*/
7618
+#ifdef HAVE_STDINT_H
7619
+#include <stdint.h>
7620
+#endif
7621
+#ifdef HAVE_INTTYPES_H
7622
+#include <inttypes.h>
7623
+#endif
7624
+
7625
+/*
7626
+** The following macros are used to cast pointers to integers and
7627
+** integers to pointers. The way you do this varies from one compiler
7628
+** to the next, so we have developed the following set of #if statements
7629
+** to generate appropriate macros for a wide range of compilers.
7630
+**
7631
+** The correct "ANSI" way to do this is to use the intptr_t type.
7632
+** Unfortunately, that typedef is not available on all compilers, or
7633
+** if it is available, it requires an #include of specific headers
7634
+** that vary from one machine to the next.
7635
+**
7636
+** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
7637
+** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
7638
+** So we have to define the macros in different ways depending on the
7639
+** compiler.
7640
+*/
7641
+#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
7642
+# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
7643
+# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
7644
+#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
7645
+# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
7646
+# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
7647
+#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
7648
+# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
7649
+# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
7650
+#else /* Generates a warning - but it always works */
7651
+# define SQLITE_INT_TO_PTR(X) ((void*)(X))
7652
+# define SQLITE_PTR_TO_INT(X) ((int)(X))
7653
+#endif
7654
+
7655
+/*
7656
+** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
7657
+** 0 means mutexes are permanently disable and the library is never
7658
+** threadsafe. 1 means the library is serialized which is the highest
7659
+** level of threadsafety. 2 means the library is multithreaded - multiple
7660
+** threads can use SQLite as long as no two threads try to use the same
7661
+** database connection at the same time.
7662
+**
7663
+** Older versions of SQLite used an optional THREADSAFE macro.
7664
+** We support that for legacy.
7665
+*/
7666
+#if !defined(SQLITE_THREADSAFE)
7667
+# if defined(THREADSAFE)
7668
+# define SQLITE_THREADSAFE THREADSAFE
7669
+# else
7670
+# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
7671
+# endif
7672
+#endif
7673
+
7674
+/*
7675
+** Powersafe overwrite is on by default. But can be turned off using
7676
+** the -DSQLITE_POWERSAFE_OVERWRITE=0 command-line option.
7677
+*/
7678
+#ifndef SQLITE_POWERSAFE_OVERWRITE
7679
+# define SQLITE_POWERSAFE_OVERWRITE 1
7680
+#endif
7681
+
7682
+/*
7683
+** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
7684
+** It determines whether or not the features related to
7685
+** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can
7686
+** be overridden at runtime using the sqlite3_config() API.
7687
+*/
7688
+#if !defined(SQLITE_DEFAULT_MEMSTATUS)
7689
+# define SQLITE_DEFAULT_MEMSTATUS 1
7690
+#endif
7691
+
7692
+/*
7693
+** Exactly one of the following macros must be defined in order to
7694
+** specify which memory allocation subsystem to use.
7695
+**
7696
+** SQLITE_SYSTEM_MALLOC // Use normal system malloc()
7697
+** SQLITE_WIN32_MALLOC // Use Win32 native heap API
7698
+** SQLITE_ZERO_MALLOC // Use a stub allocator that always fails
7699
+** SQLITE_MEMDEBUG // Debugging version of system malloc()
7700
+**
7701
+** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the
7702
+** assert() macro is enabled, each call into the Win32 native heap subsystem
7703
+** will cause HeapValidate to be called. If heap validation should fail, an
7704
+** assertion will be triggered.
7705
+**
7706
+** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
7707
+** the default.
7708
+*/
7709
+#if defined(SQLITE_SYSTEM_MALLOC) \
7710
+ + defined(SQLITE_WIN32_MALLOC) \
7711
+ + defined(SQLITE_ZERO_MALLOC) \
7712
+ + defined(SQLITE_MEMDEBUG)>1
7713
+# error "Two or more of the following compile-time configuration options\
7714
+ are defined but at most one is allowed:\
7715
+ SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG,\
7716
+ SQLITE_ZERO_MALLOC"
7717
+#endif
7718
+#if defined(SQLITE_SYSTEM_MALLOC) \
7719
+ + defined(SQLITE_WIN32_MALLOC) \
7720
+ + defined(SQLITE_ZERO_MALLOC) \
7721
+ + defined(SQLITE_MEMDEBUG)==0
7722
+# define SQLITE_SYSTEM_MALLOC 1
7723
+#endif
7724
+
7725
+/*
7726
+** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the
7727
+** sizes of memory allocations below this value where possible.
7728
+*/
7729
+#if !defined(SQLITE_MALLOC_SOFT_LIMIT)
7730
+# define SQLITE_MALLOC_SOFT_LIMIT 1024
7731
+#endif
7732
+
7733
+/*
7734
+** We need to define _XOPEN_SOURCE as follows in order to enable
7735
+** recursive mutexes on most Unix systems and fchmod() on OpenBSD.
7736
+** But _XOPEN_SOURCE define causes problems for Mac OS X, so omit
7737
+** it.
7738
+*/
7739
+#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__)
7740
+# define _XOPEN_SOURCE 600
7741
+#endif
7742
+
7743
+/*
7744
+** NDEBUG and SQLITE_DEBUG are opposites. It should always be true that
7745
+** defined(NDEBUG)==!defined(SQLITE_DEBUG). If this is not currently true,
7746
+** make it true by defining or undefining NDEBUG.
7747
+**
7748
+** Setting NDEBUG makes the code smaller and faster by disabling the
7749
+** assert() statements in the code. So we want the default action
7750
+** to be for NDEBUG to be set and NDEBUG to be undefined only if SQLITE_DEBUG
7751
+** is set. Thus NDEBUG becomes an opt-in rather than an opt-out
7752
+** feature.
7753
+*/
7754
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
7755
+# define NDEBUG 1
7756
+#endif
7757
+#if defined(NDEBUG) && defined(SQLITE_DEBUG)
7758
+# undef NDEBUG
7759
+#endif
7760
+
7761
+/*
7762
+** The testcase() macro is used to aid in coverage testing. When
7763
+** doing coverage testing, the condition inside the argument to
7764
+** testcase() must be evaluated both true and false in order to
7765
+** get full branch coverage. The testcase() macro is inserted
7766
+** to help ensure adequate test coverage in places where simple
7767
+** condition/decision coverage is inadequate. For example, testcase()
7768
+** can be used to make sure boundary values are tested. For
7769
+** bitmask tests, testcase() can be used to make sure each bit
7770
+** is significant and used at least once. On switch statements
7771
+** where multiple cases go to the same block of code, testcase()
7772
+** can insure that all cases are evaluated.
7773
+**
7774
+*/
7775
+#ifdef SQLITE_COVERAGE_TEST
7776
+SQLITE_PRIVATE void sqlite3Coverage(int);
7777
+# define testcase(X) if( X ){ sqlite3Coverage(__LINE__); }
7778
+#else
7779
+# define testcase(X)
7780
+#endif
7781
+
7782
+/*
7783
+** The TESTONLY macro is used to enclose variable declarations or
7784
+** other bits of code that are needed to support the arguments
7785
+** within testcase() and assert() macros.
7786
+*/
7787
+#if !defined(NDEBUG) || defined(SQLITE_COVERAGE_TEST)
7788
+# define TESTONLY(X) X
7789
+#else
7790
+# define TESTONLY(X)
7791
+#endif
7792
+
7793
+/*
7794
+** Sometimes we need a small amount of code such as a variable initialization
7795
+** to setup for a later assert() statement. We do not want this code to
7796
+** appear when assert() is disabled. The following macro is therefore
7797
+** used to contain that setup code. The "VVA" acronym stands for
7798
+** "Verification, Validation, and Accreditation". In other words, the
7799
+** code within VVA_ONLY() will only run during verification processes.
7800
+*/
7801
+#ifndef NDEBUG
7802
+# define VVA_ONLY(X) X
7803
+#else
7804
+# define VVA_ONLY(X)
7805
+#endif
7806
+
7807
+/*
7808
+** The ALWAYS and NEVER macros surround boolean expressions which
7809
+** are intended to always be true or false, respectively. Such
7810
+** expressions could be omitted from the code completely. But they
7811
+** are included in a few cases in order to enhance the resilience
7812
+** of SQLite to unexpected behavior - to make the code "self-healing"
7813
+** or "ductile" rather than being "brittle" and crashing at the first
7814
+** hint of unplanned behavior.
7815
+**
7816
+** In other words, ALWAYS and NEVER are added for defensive code.
7817
+**
7818
+** When doing coverage testing ALWAYS and NEVER are hard-coded to
7819
+** be true and false so that the unreachable code they specify will
7820
+** not be counted as untested code.
7821
+*/
7822
+#if defined(SQLITE_COVERAGE_TEST)
7823
+# define ALWAYS(X) (1)
7824
+# define NEVER(X) (0)
7825
+#elif !defined(NDEBUG)
7826
+# define ALWAYS(X) ((X)?1:(assert(0),0))
7827
+# define NEVER(X) ((X)?(assert(0),1):0)
7828
+#else
7829
+# define ALWAYS(X) (X)
7830
+# define NEVER(X) (X)
7831
+#endif
7832
+
7833
+/*
7834
+** Return true (non-zero) if the input is a integer that is too large
7835
+** to fit in 32-bits. This macro is used inside of various testcase()
7836
+** macros to verify that we have tested SQLite for large-file support.
7837
+*/
7838
+#define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0)
7839
+
7840
+/*
7841
+** The macro unlikely() is a hint that surrounds a boolean
7842
+** expression that is usually false. Macro likely() surrounds
7843
+** a boolean expression that is usually true. These hints could,
7844
+** in theory, be used by the compiler to generate better code, but
7845
+** currently they are just comments for human readers.
7846
+*/
7847
+#define likely(X) (X)
7848
+#define unlikely(X) (X)
7849
+
78527850
/************** Include hash.h in the middle of sqliteInt.h ******************/
78537851
/************** Begin file hash.h ********************************************/
78547852
/*
78557853
** 2001 September 22
78567854
**
@@ -8272,10 +8270,35 @@
82728270
typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */
82738271
#else
82748272
typedef u32 tRowcnt; /* 32-bit is the default */
82758273
#endif
82768274
8275
+/*
8276
+** Estimated quantities used for query planning are stored as 16-bit
8277
+** logarithms. For quantity X, the value stored is 10*log2(X). This
8278
+** gives a possible range of values of approximately 1.0e986 to 1e-986.
8279
+** But the allowed values are "grainy". Not every value is representable.
8280
+** For example, quantities 16 and 17 are both represented by a LogEst
8281
+** of 40. However, since LogEst quantatites are suppose to be estimates,
8282
+** not exact values, this imprecision is not a problem.
8283
+**
8284
+** "LogEst" is short for "Logarithimic Estimate".
8285
+**
8286
+** Examples:
8287
+** 1 -> 0 20 -> 43 10000 -> 132
8288
+** 2 -> 10 25 -> 46 25000 -> 146
8289
+** 3 -> 16 100 -> 66 1000000 -> 199
8290
+** 4 -> 20 1000 -> 99 1048576 -> 200
8291
+** 10 -> 33 1024 -> 100 4294967296 -> 320
8292
+**
8293
+** The LogEst can be negative to indicate fractional values.
8294
+** Examples:
8295
+**
8296
+** 0.5 -> -10 0.1 -> -33 0.0625 -> -40
8297
+*/
8298
+typedef INT16_TYPE LogEst;
8299
+
82778300
/*
82788301
** Macros to determine whether the machine is big or little endian,
82798302
** evaluated at runtime.
82808303
*/
82818304
#ifdef SQLITE_AMALGAMATION
@@ -10419,11 +10442,12 @@
1041910442
char *zDflt; /* Original text of the default value */
1042010443
char *zType; /* Data type for this column */
1042110444
char *zColl; /* Collating sequence. If NULL, use the default */
1042210445
u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
1042310446
char affinity; /* One of the SQLITE_AFF_... values */
10424
- u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
10447
+ u8 szEst; /* Estimated size of this column. INT==1 */
10448
+ u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */
1042510449
};
1042610450
1042710451
/* Allowed values for Column.colFlags:
1042810452
*/
1042910453
#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
@@ -10583,10 +10607,11 @@
1058310607
tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
1058410608
int tnum; /* Root BTree node for this table (see note above) */
1058510609
i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
1058610610
i16 nCol; /* Number of columns in this table */
1058710611
u16 nRef; /* Number of pointers to this Table */
10612
+ LogEst szTabRow; /* Estimated size of each table row in bytes */
1058810613
u8 tabFlags; /* Mask of TF_* values */
1058910614
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
1059010615
#ifndef SQLITE_OMIT_ALTERTABLE
1059110616
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
1059210617
#endif
@@ -10694,11 +10719,11 @@
1069410719
#define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */
1069510720
#define OE_SetNull 7 /* Set the foreign key value to NULL */
1069610721
#define OE_SetDflt 8 /* Set the foreign key value to its default */
1069710722
#define OE_Cascade 9 /* Cascade the changes */
1069810723
10699
-#define OE_Default 99 /* Do whatever the default action is */
10724
+#define OE_Default 10 /* Do whatever the default action is */
1070010725
1070110726
1070210727
/*
1070310728
** An instance of the following structure is passed as the first
1070410729
** argument to sqlite3VdbeKeyCompare and is used to control the
@@ -10781,10 +10806,11 @@
1078110806
Schema *pSchema; /* Schema containing this index */
1078210807
u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
1078310808
char **azColl; /* Array of collation sequence names for index */
1078410809
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
1078510810
int tnum; /* DB Page containing root of this index */
10811
+ LogEst szIdxRow; /* Estimated average row size in bytes */
1078610812
u16 nColumn; /* Number of columns in table used by this index */
1078710813
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
1078810814
unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
1078910815
unsigned bUnordered:1; /* Use this index for == or IN queries only */
1079010816
unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
@@ -11636,10 +11662,11 @@
1163611662
*/
1163711663
typedef struct DbFixer DbFixer;
1163811664
struct DbFixer {
1163911665
Parse *pParse; /* The parsing context. Error messages written here */
1164011666
Schema *pSchema; /* Fix items to this schema */
11667
+ int bVarOnly; /* Check for variable references only */
1164111668
const char *zDb; /* Make sure all objects are contained in this database */
1164211669
const char *zType; /* Type of the container - used for error messages */
1164311670
const Token *pName; /* Name of the container - used for error messages */
1164411671
};
1164511672
@@ -12174,11 +12201,11 @@
1217412201
# define sqlite3AuthContextPush(a,b,c)
1217512202
# define sqlite3AuthContextPop(a) ((void)(a))
1217612203
#endif
1217712204
SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
1217812205
SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
12179
-SQLITE_PRIVATE int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
12206
+SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
1218012207
SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
1218112208
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
1218212209
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
1218312210
SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
1218412211
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
@@ -12186,10 +12213,16 @@
1218612213
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
1218712214
SQLITE_PRIVATE int sqlite3Atoi(const char*);
1218812215
SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
1218912216
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
1219012217
SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
12218
+SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
12219
+SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst);
12220
+#ifndef SQLITE_OMIT_VIRTUALTABLE
12221
+SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double);
12222
+#endif
12223
+SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst);
1219112224
1219212225
/*
1219312226
** Routines to read and write variable-length integers. These used to
1219412227
** be defined locally, but now we use the varint routines in the util.c
1219512228
** file. Code should use the MACRO forms below, as the Varint32 versions
@@ -12302,11 +12335,11 @@
1230212335
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
1230312336
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
1230412337
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
1230512338
SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
1230612339
SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
12307
-SQLITE_PRIVATE char sqlite3AffinityType(const char*);
12340
+SQLITE_PRIVATE char sqlite3AffinityType(const char*, u8*);
1230812341
SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
1230912342
SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
1231012343
SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
1231112344
SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
1231212345
SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
@@ -22387,10 +22420,87 @@
2238722420
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
2238822421
if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
2238922422
}
2239022423
}
2239122424
#endif
22425
+
22426
+/*
22427
+** Find (an approximate) sum of two LogEst values. This computation is
22428
+** not a simple "+" operator because LogEst is stored as a logarithmic
22429
+** value.
22430
+**
22431
+*/
22432
+SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){
22433
+ static const unsigned char x[] = {
22434
+ 10, 10, /* 0,1 */
22435
+ 9, 9, /* 2,3 */
22436
+ 8, 8, /* 4,5 */
22437
+ 7, 7, 7, /* 6,7,8 */
22438
+ 6, 6, 6, /* 9,10,11 */
22439
+ 5, 5, 5, /* 12-14 */
22440
+ 4, 4, 4, 4, /* 15-18 */
22441
+ 3, 3, 3, 3, 3, 3, /* 19-24 */
22442
+ 2, 2, 2, 2, 2, 2, 2, /* 25-31 */
22443
+ };
22444
+ if( a>=b ){
22445
+ if( a>b+49 ) return a;
22446
+ if( a>b+31 ) return a+1;
22447
+ return a+x[a-b];
22448
+ }else{
22449
+ if( b>a+49 ) return b;
22450
+ if( b>a+31 ) return b+1;
22451
+ return b+x[b-a];
22452
+ }
22453
+}
22454
+
22455
+/*
22456
+** Convert an integer into a LogEst. In other words, compute a
22457
+** good approximatation for 10*log2(x).
22458
+*/
22459
+SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){
22460
+ static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
22461
+ LogEst y = 40;
22462
+ if( x<8 ){
22463
+ if( x<2 ) return 0;
22464
+ while( x<8 ){ y -= 10; x <<= 1; }
22465
+ }else{
22466
+ while( x>255 ){ y += 40; x >>= 4; }
22467
+ while( x>15 ){ y += 10; x >>= 1; }
22468
+ }
22469
+ return a[x&7] + y - 10;
22470
+}
22471
+
22472
+#ifndef SQLITE_OMIT_VIRTUALTABLE
22473
+/*
22474
+** Convert a double into a LogEst
22475
+** In other words, compute an approximation for 10*log2(x).
22476
+*/
22477
+SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){
22478
+ u64 a;
22479
+ LogEst e;
22480
+ assert( sizeof(x)==8 && sizeof(a)==8 );
22481
+ if( x<=1 ) return 0;
22482
+ if( x<=2000000000 ) return sqlite3LogEst((u64)x);
22483
+ memcpy(&a, &x, 8);
22484
+ e = (a>>52) - 1022;
22485
+ return e*10;
22486
+}
22487
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
22488
+
22489
+/*
22490
+** Convert a LogEst into an integer.
22491
+*/
22492
+SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
22493
+ u64 n;
22494
+ if( x<10 ) return 1;
22495
+ n = x%10;
22496
+ x /= 10;
22497
+ if( n>=5 ) n -= 2;
22498
+ else if( n>=1 ) n -= 1;
22499
+ if( x>=3 ) return (n+8)<<(x-3);
22500
+ return (n+8)>>(3-x);
22501
+}
2239222502
2239322503
/************** End of util.c ************************************************/
2239422504
/************** Begin file hash.c ********************************************/
2239522505
/*
2239622506
** 2001 September 22
@@ -31382,11 +31492,11 @@
3138231492
#endif
3138331493
3138431494
#define osGetVersionExA ((BOOL(WINAPI*)( \
3138531495
LPOSVERSIONINFOA))aSyscall[34].pCurrent)
3138631496
31387
-#if defined(SQLITE_WIN32_HAS_WIDE)
31497
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
3138831498
{ "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
3138931499
#else
3139031500
{ "GetVersionExW", (SYSCALL)0, 0 },
3139131501
#endif
3139231502
@@ -48986,17 +49096,17 @@
4898649096
** page contain a special header (the "file header") that describes the file.
4898749097
** The format of the file header is as follows:
4898849098
**
4898949099
** OFFSET SIZE DESCRIPTION
4899049100
** 0 16 Header string: "SQLite format 3\000"
48991
-** 16 2 Page size in bytes.
49101
+** 16 2 Page size in bytes. (1 means 65536)
4899249102
** 18 1 File format write version
4899349103
** 19 1 File format read version
4899449104
** 20 1 Bytes of unused space at the end of each page
48995
-** 21 1 Max embedded payload fraction
48996
-** 22 1 Min embedded payload fraction
48997
-** 23 1 Min leaf payload fraction
49105
+** 21 1 Max embedded payload fraction (must be 64)
49106
+** 22 1 Min embedded payload fraction (must be 32)
49107
+** 23 1 Min leaf payload fraction (must be 32)
4899849108
** 24 4 File change counter
4899949109
** 28 4 Reserved for future use
4900049110
** 32 4 First freelist page
4900149111
** 36 4 Number of freelist pages in the file
4900249112
** 40 60 15 4-byte meta values passed to higher layers
@@ -49006,13 +49116,14 @@
4900649116
** 48 4 Size of page cache
4900749117
** 52 4 Largest root-page (auto/incr_vacuum)
4900849118
** 56 4 1=UTF-8 2=UTF16le 3=UTF16be
4900949119
** 60 4 User version
4901049120
** 64 4 Incremental vacuum mode
49011
-** 68 4 unused
49012
-** 72 4 unused
49013
-** 76 4 unused
49121
+** 68 4 Application-ID
49122
+** 72 20 unused
49123
+** 92 4 The version-valid-for number
49124
+** 96 4 SQLITE_VERSION_NUMBER
4901449125
**
4901549126
** All of the integer values are big-endian (most significant byte first).
4901649127
**
4901749128
** The file change counter is incremented when the database is changed
4901849129
** This counter allows other processes to know when the file has changed
@@ -52378,11 +52489,10 @@
5237852489
pBt->max1bytePayload = (u8)pBt->maxLocal;
5237952490
}
5238052491
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
5238152492
pBt->pPage1 = pPage1;
5238252493
pBt->nPage = nPage;
52383
-assert( pPage1->leaf==0 || pPage1->leaf==1 );
5238452494
return SQLITE_OK;
5238552495
5238652496
page1_init_failed:
5238752497
releasePage(pPage1);
5238852498
pBt->pPage1 = 0;
@@ -52538,11 +52648,11 @@
5253852648
** is requested, this is a no-op.
5253952649
*/
5254052650
if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
5254152651
goto trans_begun;
5254252652
}
52543
- assert( IfNotOmitAV(pBt->bDoTruncate)==0 );
52653
+ assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
5254452654
5254552655
/* Write transactions are not possible on a read-only database */
5254652656
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
5254752657
rc = SQLITE_READONLY;
5254852658
goto trans_begun;
@@ -62977,10 +63087,11 @@
6297763087
}
6297863088
fclose(out);
6297963089
}
6298063090
}
6298163091
#endif
63092
+ p->iCurrentTime = 0;
6298263093
p->magic = VDBE_MAGIC_INIT;
6298363094
return p->rc & db->errMask;
6298463095
}
6298563096
6298663097
/*
@@ -76082,11 +76193,11 @@
7608276193
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
7608376194
}
7608476195
#ifndef SQLITE_OMIT_CAST
7608576196
if( op==TK_CAST ){
7608676197
assert( !ExprHasProperty(pExpr, EP_IntValue) );
76087
- return sqlite3AffinityType(pExpr->u.zToken);
76198
+ return sqlite3AffinityType(pExpr->u.zToken, 0);
7608876199
}
7608976200
#endif
7609076201
if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER)
7609176202
&& pExpr->pTab!=0
7609276203
){
@@ -78502,11 +78613,11 @@
7850278613
case TK_CAST: {
7850378614
/* Expressions of the form: CAST(pLeft AS token) */
7850478615
int aff, to_op;
7850578616
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
7850678617
assert( !ExprHasProperty(pExpr, EP_IntValue) );
78507
- aff = sqlite3AffinityType(pExpr->u.zToken);
78618
+ aff = sqlite3AffinityType(pExpr->u.zToken, 0);
7850878619
to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
7850978620
assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
7851078621
assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE );
7851178622
assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
7851278623
assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER );
@@ -79169,11 +79280,11 @@
7916979280
}
7917079281
#ifndef SQLITE_OMIT_CAST
7917179282
case TK_CAST: {
7917279283
/* Expressions of the form: CAST(pLeft AS token) */
7917379284
const char *zAff = "unk";
79174
- switch( sqlite3AffinityType(pExpr->u.zToken) ){
79285
+ switch( sqlite3AffinityType(pExpr->u.zToken, 0) ){
7917579286
case SQLITE_AFF_TEXT: zAff = "TEXT"; break;
7917679287
case SQLITE_AFF_NONE: zAff = "NONE"; break;
7917779288
case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break;
7917879289
case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break;
7917979290
case SQLITE_AFF_REAL: zAff = "REAL"; break;
@@ -81884,16 +81995,16 @@
8188481995
if( zRet==0 ){
8188581996
sqlite3_result_error_nomem(context);
8188681997
return;
8188781998
}
8188881999
81889
- sqlite3_snprintf(24, zRet, "%lld", p->nRow);
82000
+ sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
8189082001
z = zRet + sqlite3Strlen30(zRet);
8189182002
for(i=0; i<(p->nCol-1); i++){
81892
- i64 nDistinct = p->current.anDLt[i] + 1;
81893
- i64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
81894
- sqlite3_snprintf(24, z, " %lld", iVal);
82003
+ u64 nDistinct = p->current.anDLt[i] + 1;
82004
+ u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
82005
+ sqlite3_snprintf(24, z, " %llu", iVal);
8189582006
z += sqlite3Strlen30(z);
8189682007
assert( p->current.anEq[i] );
8189782008
}
8189882009
assert( z[0]=='\0' && z>zRet );
8189982010
@@ -81930,11 +82041,11 @@
8193082041
sqlite3_result_error_nomem(context);
8193182042
}else{
8193282043
int i;
8193382044
char *z = zRet;
8193482045
for(i=0; i<p->nCol; i++){
81935
- sqlite3_snprintf(24, z, "%lld ", aCnt[i]);
82046
+ sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]);
8193682047
z += sqlite3Strlen30(z);
8193782048
}
8193882049
assert( z[0]=='\0' && z>zRet );
8193982050
z[-1] = '\0';
8194082051
sqlite3_result_text(context, zRet, -1, sqlite3_free);
@@ -82391,22 +82502,20 @@
8239182502
** The first argument points to a nul-terminated string containing a
8239282503
** list of space separated integers. Read the first nOut of these into
8239382504
** the array aOut[].
8239482505
*/
8239582506
static void decodeIntArray(
82396
- char *zIntArray,
82397
- int nOut,
82398
- tRowcnt *aOut,
82399
- int *pbUnordered
82507
+ char *zIntArray, /* String containing int array to decode */
82508
+ int nOut, /* Number of slots in aOut[] */
82509
+ tRowcnt *aOut, /* Store integers here */
82510
+ Index *pIndex /* Handle extra flags for this index, if not NULL */
8240082511
){
8240182512
char *z = zIntArray;
8240282513
int c;
8240382514
int i;
8240482515
tRowcnt v;
8240582516
82406
- assert( pbUnordered==0 || *pbUnordered==0 );
82407
-
8240882517
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
8240982518
if( z==0 ) z = "";
8241082519
#else
8241182520
if( NEVER(z==0) ) z = "";
8241282521
#endif
@@ -82417,12 +82526,23 @@
8241782526
z++;
8241882527
}
8241982528
aOut[i] = v;
8242082529
if( *z==' ' ) z++;
8242182530
}
82422
- if( pbUnordered && strcmp(z, "unordered")==0 ){
82423
- *pbUnordered = 1;
82531
+#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
82532
+ assert( pIndex!=0 );
82533
+#else
82534
+ if( pIndex )
82535
+#endif
82536
+ {
82537
+ if( strcmp(z, "unordered")==0 ){
82538
+ pIndex->bUnordered = 1;
82539
+ }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
82540
+ int v32 = 0;
82541
+ sqlite3GetInt32(z+3, &v32);
82542
+ pIndex->szIdxRow = sqlite3LogEst(v32);
82543
+ }
8242482544
}
8242582545
}
8242682546
8242782547
/*
8242882548
** This callback is invoked once for each index when reading the
@@ -82457,16 +82577,17 @@
8245782577
pIndex = 0;
8245882578
}
8245982579
z = argv[2];
8246082580
8246182581
if( pIndex ){
82462
- int bUnordered = 0;
82463
- decodeIntArray((char*)z, pIndex->nColumn+1, pIndex->aiRowEst,&bUnordered);
82582
+ decodeIntArray((char*)z, pIndex->nColumn+1, pIndex->aiRowEst, pIndex);
8246482583
if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0];
82465
- pIndex->bUnordered = bUnordered;
8246682584
}else{
82467
- decodeIntArray((char*)z, 1, &pTable->nRowEst, 0);
82585
+ Index fakeIdx;
82586
+ fakeIdx.szIdxRow = pTable->szTabRow;
82587
+ decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx);
82588
+ pTable->szTabRow = fakeIdx.szIdxRow;
8246882589
}
8246982590
8247082591
return 0;
8247182592
}
8247282593
@@ -83185,32 +83306,28 @@
8318583306
#endif /* SQLITE_OMIT_ATTACH */
8318683307
8318783308
/*
8318883309
** Initialize a DbFixer structure. This routine must be called prior
8318983310
** to passing the structure to one of the sqliteFixAAAA() routines below.
83190
-**
83191
-** The return value indicates whether or not fixation is required. TRUE
83192
-** means we do need to fix the database references, FALSE means we do not.
8319383311
*/
83194
-SQLITE_PRIVATE int sqlite3FixInit(
83312
+SQLITE_PRIVATE void sqlite3FixInit(
8319583313
DbFixer *pFix, /* The fixer to be initialized */
8319683314
Parse *pParse, /* Error messages will be written here */
8319783315
int iDb, /* This is the database that must be used */
8319883316
const char *zType, /* "view", "trigger", or "index" */
8319983317
const Token *pName /* Name of the view, trigger, or index */
8320083318
){
8320183319
sqlite3 *db;
8320283320
83203
- if( NEVER(iDb<0) || iDb==1 ) return 0;
8320483321
db = pParse->db;
8320583322
assert( db->nDb>iDb );
8320683323
pFix->pParse = pParse;
8320783324
pFix->zDb = db->aDb[iDb].zName;
8320883325
pFix->pSchema = db->aDb[iDb].pSchema;
8320983326
pFix->zType = zType;
8321083327
pFix->pName = pName;
83211
- return 1;
83328
+ pFix->bVarOnly = (iDb==1);
8321283329
}
8321383330
8321483331
/*
8321583332
** The following set of routines walk through the parse tree and assign
8321683333
** a specific database to all table references where the database name
@@ -83234,19 +83351,21 @@
8323483351
struct SrcList_item *pItem;
8323583352
8323683353
if( NEVER(pList==0) ) return 0;
8323783354
zDb = pFix->zDb;
8323883355
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
83239
- if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
83240
- sqlite3ErrorMsg(pFix->pParse,
83241
- "%s %T cannot reference objects in database %s",
83242
- pFix->zType, pFix->pName, pItem->zDatabase);
83243
- return 1;
83244
- }
83245
- sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
83246
- pItem->zDatabase = 0;
83247
- pItem->pSchema = pFix->pSchema;
83356
+ if( pFix->bVarOnly==0 ){
83357
+ if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
83358
+ sqlite3ErrorMsg(pFix->pParse,
83359
+ "%s %T cannot reference objects in database %s",
83360
+ pFix->zType, pFix->pName, pItem->zDatabase);
83361
+ return 1;
83362
+ }
83363
+ sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
83364
+ pItem->zDatabase = 0;
83365
+ pItem->pSchema = pFix->pSchema;
83366
+ }
8324883367
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
8324983368
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
8325083369
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
8325183370
#endif
8325283371
}
@@ -83264,13 +83383,25 @@
8326483383
if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
8326583384
return 1;
8326683385
}
8326783386
if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
8326883387
return 1;
83388
+ }
83389
+ if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){
83390
+ return 1;
8326983391
}
8327083392
if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
8327183393
return 1;
83394
+ }
83395
+ if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){
83396
+ return 1;
83397
+ }
83398
+ if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
83399
+ return 1;
83400
+ }
83401
+ if( sqlite3FixExpr(pFix, pSelect->pOffset) ){
83402
+ return 1;
8327283403
}
8327383404
pSelect = pSelect->pPrior;
8327483405
}
8327583406
return 0;
8327683407
}
@@ -83277,10 +83408,18 @@
8327783408
SQLITE_PRIVATE int sqlite3FixExpr(
8327883409
DbFixer *pFix, /* Context of the fixation */
8327983410
Expr *pExpr /* The expression to be fixed to one database */
8328083411
){
8328183412
while( pExpr ){
83413
+ if( pExpr->op==TK_VARIABLE ){
83414
+ if( pFix->pParse->db->init.busy ){
83415
+ pExpr->op = TK_NULL;
83416
+ }else{
83417
+ sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
83418
+ return 1;
83419
+ }
83420
+ }
8328283421
if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
8328383422
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
8328483423
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
8328583424
}else{
8328683425
if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
@@ -84460,11 +84599,11 @@
8446084599
}
8446184600
pTable->zName = zName;
8446284601
pTable->iPKey = -1;
8446384602
pTable->pSchema = db->aDb[iDb].pSchema;
8446484603
pTable->nRef = 1;
84465
- pTable->nRowEst = 1000000;
84604
+ pTable->nRowEst = 1048576;
8446684605
assert( pParse->pNewTable==0 );
8446784606
pParse->pNewTable = pTable;
8446884607
8446984608
/* If this is the magic sqlite_sequence table used by autoincrement,
8447084609
** then record a pointer to this table in the main database structure
@@ -84607,10 +84746,11 @@
8460784746
/* If there is no type specified, columns have the default affinity
8460884747
** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will
8460984748
** be called next to set pCol->affinity correctly.
8461084749
*/
8461184750
pCol->affinity = SQLITE_AFF_NONE;
84751
+ pCol->szEst = 1;
8461284752
p->nCol++;
8461384753
}
8461484754
8461584755
/*
8461684756
** This routine is called by the parser while in the middle of
@@ -84648,26 +84788,30 @@
8464884788
** 'DOUB' | SQLITE_AFF_REAL
8464984789
**
8465084790
** If none of the substrings in the above table are found,
8465184791
** SQLITE_AFF_NUMERIC is returned.
8465284792
*/
84653
-SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn){
84793
+SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
8465484794
u32 h = 0;
8465584795
char aff = SQLITE_AFF_NUMERIC;
84796
+ const char *zChar = 0;
8465684797
84657
- if( zIn ) while( zIn[0] ){
84798
+ if( zIn==0 ) return aff;
84799
+ while( zIn[0] ){
8465884800
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
8465984801
zIn++;
8466084802
if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
84661
- aff = SQLITE_AFF_TEXT;
84803
+ aff = SQLITE_AFF_TEXT;
84804
+ zChar = zIn;
8466284805
}else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */
8466384806
aff = SQLITE_AFF_TEXT;
8466484807
}else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */
8466584808
aff = SQLITE_AFF_TEXT;
8466684809
}else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
8466784810
&& (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
8466884811
aff = SQLITE_AFF_NONE;
84812
+ if( zIn[0]=='(' ) zChar = zIn;
8466984813
#ifndef SQLITE_OMIT_FLOATING_POINT
8467084814
}else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
8467184815
&& aff==SQLITE_AFF_NUMERIC ){
8467284816
aff = SQLITE_AFF_REAL;
8467384817
}else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */
@@ -84681,10 +84825,32 @@
8468184825
aff = SQLITE_AFF_INTEGER;
8468284826
break;
8468384827
}
8468484828
}
8468584829
84830
+ /* If pszEst is not NULL, store an estimate of the field size. The
84831
+ ** estimate is scaled so that the size of an integer is 1. */
84832
+ if( pszEst ){
84833
+ *pszEst = 1; /* default size is approx 4 bytes */
84834
+ if( aff<=SQLITE_AFF_NONE ){
84835
+ if( zChar ){
84836
+ while( zChar[0] ){
84837
+ if( sqlite3Isdigit(zChar[0]) ){
84838
+ int v;
84839
+ sqlite3GetInt32(zChar, &v);
84840
+ v = v/4 + 1;
84841
+ if( v>255 ) v = 255;
84842
+ *pszEst = v; /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */
84843
+ break;
84844
+ }
84845
+ zChar++;
84846
+ }
84847
+ }else{
84848
+ *pszEst = 5; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/
84849
+ }
84850
+ }
84851
+ }
8468684852
return aff;
8468784853
}
8468884854
8468984855
/*
8469084856
** This routine is called by the parser while in the middle of
@@ -84702,11 +84868,11 @@
8470284868
p = pParse->pNewTable;
8470384869
if( p==0 || NEVER(p->nCol<1) ) return;
8470484870
pCol = &p->aCol[p->nCol-1];
8470584871
assert( pCol->zType==0 );
8470684872
pCol->zType = sqlite3NameFromToken(pParse->db, pType);
84707
- pCol->affinity = sqlite3AffinityType(pCol->zType);
84873
+ pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
8470884874
}
8470984875
8471084876
/*
8471184877
** The expression is the default value for the most recently added column
8471284878
** of the table currently under construction.
@@ -85050,18 +85216,46 @@
8505085216
testcase( pCol->affinity==SQLITE_AFF_REAL );
8505185217
8505285218
zType = azType[pCol->affinity - SQLITE_AFF_TEXT];
8505385219
len = sqlite3Strlen30(zType);
8505485220
assert( pCol->affinity==SQLITE_AFF_NONE
85055
- || pCol->affinity==sqlite3AffinityType(zType) );
85221
+ || pCol->affinity==sqlite3AffinityType(zType, 0) );
8505685222
memcpy(&zStmt[k], zType, len);
8505785223
k += len;
8505885224
assert( k<=n );
8505985225
}
8506085226
sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
8506185227
return zStmt;
8506285228
}
85229
+
85230
+/*
85231
+** Estimate the total row width for a table.
85232
+*/
85233
+static void estimateTableWidth(Table *pTab){
85234
+ unsigned wTable = 0;
85235
+ const Column *pTabCol;
85236
+ int i;
85237
+ for(i=pTab->nCol, pTabCol=pTab->aCol; i>0; i--, pTabCol++){
85238
+ wTable += pTabCol->szEst;
85239
+ }
85240
+ if( pTab->iPKey<0 ) wTable++;
85241
+ pTab->szTabRow = sqlite3LogEst(wTable*4);
85242
+}
85243
+
85244
+/*
85245
+** Estimate the average size of a row for an index.
85246
+*/
85247
+static void estimateIndexWidth(Index *pIdx){
85248
+ unsigned wIndex = 1;
85249
+ int i;
85250
+ const Column *aCol = pIdx->pTable->aCol;
85251
+ for(i=0; i<pIdx->nColumn; i++){
85252
+ assert( pIdx->aiColumn[i]>=0 && pIdx->aiColumn[i]<pIdx->pTable->nCol );
85253
+ wIndex += aCol[pIdx->aiColumn[i]].szEst;
85254
+ }
85255
+ pIdx->szIdxRow = sqlite3LogEst(wIndex*4);
85256
+}
8506385257
8506485258
/*
8506585259
** This routine is called to report the final ")" that terminates
8506685260
** a CREATE TABLE statement.
8506785261
**
@@ -85085,13 +85279,14 @@
8508585279
Parse *pParse, /* Parse context */
8508685280
Token *pCons, /* The ',' token after the last column defn. */
8508785281
Token *pEnd, /* The final ')' token in the CREATE TABLE */
8508885282
Select *pSelect /* Select from a "CREATE ... AS SELECT" */
8508985283
){
85090
- Table *p;
85091
- sqlite3 *db = pParse->db;
85092
- int iDb;
85284
+ Table *p; /* The new table */
85285
+ sqlite3 *db = pParse->db; /* The database connection */
85286
+ int iDb; /* Database in which the table lives */
85287
+ Index *pIdx; /* An implied index of the table */
8509385288
8509485289
if( (pEnd==0 && pSelect==0) || db->mallocFailed ){
8509585290
return;
8509685291
}
8509785292
p = pParse->pNewTable;
@@ -85106,10 +85301,16 @@
8510685301
*/
8510785302
if( p->pCheck ){
8510885303
sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
8510985304
}
8511085305
#endif /* !defined(SQLITE_OMIT_CHECK) */
85306
+
85307
+ /* Estimate the average row size for the table and for all implied indices */
85308
+ estimateTableWidth(p);
85309
+ for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
85310
+ estimateIndexWidth(pIdx);
85311
+ }
8511185312
8511285313
/* If the db->init.busy is 1 it means we are reading the SQL off the
8511385314
** "sqlite_master" or "sqlite_temp_master" table on the disk.
8511485315
** So do not write to the disk again. Extract the root page number
8511585316
** for the table from the db->init.newTnum field. (The page number
@@ -85303,13 +85504,12 @@
8530385504
sqlite3SelectDelete(db, pSelect);
8530485505
return;
8530585506
}
8530685507
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
8530785508
iDb = sqlite3SchemaToIndex(db, p->pSchema);
85308
- if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
85309
- && sqlite3FixSelect(&sFix, pSelect)
85310
- ){
85509
+ sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
85510
+ if( sqlite3FixSelect(&sFix, pSelect) ){
8531185511
sqlite3SelectDelete(db, pSelect);
8531285512
return;
8531385513
}
8531485514
8531585515
/* Make a copy of the entire SELECT statement that defines the view.
@@ -86066,13 +86266,14 @@
8606686266
sqlite3 *db = pParse->db;
8606786267
Db *pDb; /* The specific table containing the indexed database */
8606886268
int iDb; /* Index of the database that is being written */
8606986269
Token *pName = 0; /* Unqualified name of the index to create */
8607086270
struct ExprList_item *pListItem; /* For looping over pList */
86071
- int nCol;
86072
- int nExtra = 0;
86073
- char *zExtra;
86271
+ const Column *pTabCol; /* A column in the table */
86272
+ int nCol; /* Number of columns */
86273
+ int nExtra = 0; /* Space allocated for zExtra[] */
86274
+ char *zExtra; /* Extra space after the Index object */
8607486275
8607586276
assert( pParse->nErr==0 ); /* Never called with prior errors */
8607686277
if( db->mallocFailed || IN_DECLARE_VTAB ){
8607786278
goto exit_create_index;
8607886279
}
@@ -86105,13 +86306,12 @@
8610586306
iDb = 1;
8610686307
}
8610786308
}
8610886309
#endif
8610986310
86110
- if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) &&
86111
- sqlite3FixSrcList(&sFix, pTblName)
86112
- ){
86311
+ sqlite3FixInit(&sFix, pParse, iDb, "index", pName);
86312
+ if( sqlite3FixSrcList(&sFix, pTblName) ){
8611386313
/* Because the parser constructs pTblName from a single identifier,
8611486314
** sqlite3FixSrcList can never fail. */
8611586315
assert(0);
8611686316
}
8611786317
pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
@@ -86296,11 +86496,10 @@
8629686496
** same column more than once cannot be an error because that would
8629786497
** break backwards compatibility - it needs to be a warning.
8629886498
*/
8629986499
for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
8630086500
const char *zColName = pListItem->zName;
86301
- Column *pTabCol;
8630286501
int requestedSortOrder;
8630386502
char *zColl; /* Collation sequence name */
8630486503
8630586504
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
8630686505
if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
@@ -86333,10 +86532,11 @@
8633386532
requestedSortOrder = pListItem->sortOrder & sortOrderMask;
8633486533
pIndex->aSortOrder[i] = (u8)requestedSortOrder;
8633586534
if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0;
8633686535
}
8633786536
sqlite3DefaultRowEst(pIndex);
86537
+ if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
8633886538
8633986539
if( pTab==pParse->pNewTable ){
8634086540
/* This routine has been called to create an automatic index as a
8634186541
** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
8634286542
** a PRIMARY KEY or UNIQUE clause following the column definitions.
@@ -88238,10 +88438,11 @@
8823888438
** API function sqlite3_count_changes) to be set incorrectly. */
8823988439
if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab)
8824088440
&& 0==sqlite3FkRequired(pParse, pTab, 0, 0)
8824188441
){
8824288442
assert( !isView );
88443
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
8824388444
sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt,
8824488445
pTab->zName, P4_STATIC);
8824588446
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
8824688447
assert( pIdx->pSchema==pTab->pSchema );
8824788448
sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
@@ -93487,10 +93688,11 @@
9348793688
(char*)pKey, P4_KEYINFO_HANDOFF);
9348893689
VdbeComment((v, "%s", pSrcIdx->zName));
9348993690
pKey = sqlite3IndexKeyinfo(pParse, pDestIdx);
9349093691
sqlite3VdbeAddOp4(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest,
9349193692
(char*)pKey, P4_KEYINFO_HANDOFF);
93693
+ sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
9349293694
VdbeComment((v, "%s", pDestIdx->zName));
9349393695
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
9349493696
sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
9349593697
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
9349693698
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
@@ -94974,181 +95176,363 @@
9497495176
#define PragTyp_HEXKEY 35
9497595177
#define PragTyp_KEY 36
9497695178
#define PragTyp_REKEY 37
9497795179
#define PragTyp_LOCK_STATUS 38
9497895180
#define PragTyp_PARSER_TRACE 39
95181
+#define PragFlag_NeedSchema 0x01
9497995182
static const struct sPragmaNames {
9498095183
const char *const zName; /* Name of pragma */
9498195184
u8 ePragTyp; /* PragTyp_XXX value */
95185
+ u8 mPragFlag; /* Zero or more PragFlag_XXX values */
9498295186
u32 iArg; /* Extra argument */
9498395187
} aPragmaNames[] = {
9498495188
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
94985
- { "activate_extensions", PragTyp_ACTIVATE_EXTENSIONS, 0 },
95189
+ { /* zName: */ "activate_extensions",
95190
+ /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
95191
+ /* ePragFlag: */ 0,
95192
+ /* iArg: */ 0 },
9498695193
#endif
9498795194
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
94988
- { "application_id", PragTyp_HEADER_VALUE, 0 },
95195
+ { /* zName: */ "application_id",
95196
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
95197
+ /* ePragFlag: */ 0,
95198
+ /* iArg: */ 0 },
9498995199
#endif
9499095200
#if !defined(SQLITE_OMIT_AUTOVACUUM)
94991
- { "auto_vacuum", PragTyp_AUTO_VACUUM, 0 },
95201
+ { /* zName: */ "auto_vacuum",
95202
+ /* ePragTyp: */ PragTyp_AUTO_VACUUM,
95203
+ /* ePragFlag: */ PragFlag_NeedSchema,
95204
+ /* iArg: */ 0 },
9499295205
#endif
9499395206
#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
94994
- { "automatic_index", PragTyp_FLAG,
94995
- SQLITE_AutoIndex },
95207
+ { /* zName: */ "automatic_index",
95208
+ /* ePragTyp: */ PragTyp_FLAG,
95209
+ /* ePragFlag: */ 0,
95210
+ /* iArg: */ SQLITE_AutoIndex },
9499695211
#endif
94997
- { "busy_timeout", PragTyp_BUSY_TIMEOUT, 0 },
95212
+ { /* zName: */ "busy_timeout",
95213
+ /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
95214
+ /* ePragFlag: */ 0,
95215
+ /* iArg: */ 0 },
9499895216
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
94999
- { "cache_size", PragTyp_CACHE_SIZE, 0 },
95217
+ { /* zName: */ "cache_size",
95218
+ /* ePragTyp: */ PragTyp_CACHE_SIZE,
95219
+ /* ePragFlag: */ PragFlag_NeedSchema,
95220
+ /* iArg: */ 0 },
9500095221
#endif
95001
- { "cache_spill", PragTyp_FLAG,
95002
- SQLITE_CacheSpill },
95003
- { "case_sensitive_like", PragTyp_CASE_SENSITIVE_LIKE, 0 },
95004
- { "checkpoint_fullfsync", PragTyp_FLAG,
95005
- SQLITE_CkptFullFSync },
95222
+ { /* zName: */ "cache_spill",
95223
+ /* ePragTyp: */ PragTyp_FLAG,
95224
+ /* ePragFlag: */ 0,
95225
+ /* iArg: */ SQLITE_CacheSpill },
95226
+ { /* zName: */ "case_sensitive_like",
95227
+ /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
95228
+ /* ePragFlag: */ 0,
95229
+ /* iArg: */ 0 },
95230
+ { /* zName: */ "checkpoint_fullfsync",
95231
+ /* ePragTyp: */ PragTyp_FLAG,
95232
+ /* ePragFlag: */ 0,
95233
+ /* iArg: */ SQLITE_CkptFullFSync },
9500695234
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95007
- { "collation_list", PragTyp_COLLATION_LIST, 0 },
95235
+ { /* zName: */ "collation_list",
95236
+ /* ePragTyp: */ PragTyp_COLLATION_LIST,
95237
+ /* ePragFlag: */ 0,
95238
+ /* iArg: */ 0 },
9500895239
#endif
9500995240
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
95010
- { "compile_options", PragTyp_COMPILE_OPTIONS, 0 },
95241
+ { /* zName: */ "compile_options",
95242
+ /* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
95243
+ /* ePragFlag: */ 0,
95244
+ /* iArg: */ 0 },
9501195245
#endif
95012
- { "count_changes", PragTyp_FLAG,
95013
- SQLITE_CountRows },
95246
+ { /* zName: */ "count_changes",
95247
+ /* ePragTyp: */ PragTyp_FLAG,
95248
+ /* ePragFlag: */ 0,
95249
+ /* iArg: */ SQLITE_CountRows },
9501495250
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
95015
- { "data_store_directory", PragTyp_DATA_STORE_DIRECTORY, 0 },
95251
+ { /* zName: */ "data_store_directory",
95252
+ /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
95253
+ /* ePragFlag: */ 0,
95254
+ /* iArg: */ 0 },
9501695255
#endif
9501795256
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95018
- { "database_list", PragTyp_DATABASE_LIST, 0 },
95257
+ { /* zName: */ "database_list",
95258
+ /* ePragTyp: */ PragTyp_DATABASE_LIST,
95259
+ /* ePragFlag: */ PragFlag_NeedSchema,
95260
+ /* iArg: */ 0 },
9501995261
#endif
9502095262
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
95021
- { "default_cache_size", PragTyp_DEFAULT_CACHE_SIZE, 0 },
95263
+ { /* zName: */ "default_cache_size",
95264
+ /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
95265
+ /* ePragFlag: */ PragFlag_NeedSchema,
95266
+ /* iArg: */ 0 },
9502295267
#endif
9502395268
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
95024
- { "defer_foreign_keys", PragTyp_FLAG,
95025
- SQLITE_DeferFKs },
95269
+ { /* zName: */ "defer_foreign_keys",
95270
+ /* ePragTyp: */ PragTyp_FLAG,
95271
+ /* ePragFlag: */ 0,
95272
+ /* iArg: */ SQLITE_DeferFKs },
9502695273
#endif
95027
- { "empty_result_callbacks", PragTyp_FLAG,
95028
- SQLITE_NullCallback },
95274
+ { /* zName: */ "empty_result_callbacks",
95275
+ /* ePragTyp: */ PragTyp_FLAG,
95276
+ /* ePragFlag: */ 0,
95277
+ /* iArg: */ SQLITE_NullCallback },
9502995278
#if !defined(SQLITE_OMIT_UTF16)
95030
- { "encoding", PragTyp_ENCODING, 0 },
95279
+ { /* zName: */ "encoding",
95280
+ /* ePragTyp: */ PragTyp_ENCODING,
95281
+ /* ePragFlag: */ 0,
95282
+ /* iArg: */ 0 },
9503195283
#endif
9503295284
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
95033
- { "foreign_key_check", PragTyp_FOREIGN_KEY_CHECK, 0 },
95285
+ { /* zName: */ "foreign_key_check",
95286
+ /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
95287
+ /* ePragFlag: */ PragFlag_NeedSchema,
95288
+ /* iArg: */ 0 },
9503495289
#endif
9503595290
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
95036
- { "foreign_key_list", PragTyp_FOREIGN_KEY_LIST, 0 },
95291
+ { /* zName: */ "foreign_key_list",
95292
+ /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
95293
+ /* ePragFlag: */ PragFlag_NeedSchema,
95294
+ /* iArg: */ 0 },
9503795295
#endif
9503895296
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
95039
- { "foreign_keys", PragTyp_FLAG,
95040
- SQLITE_ForeignKeys },
95297
+ { /* zName: */ "foreign_keys",
95298
+ /* ePragTyp: */ PragTyp_FLAG,
95299
+ /* ePragFlag: */ 0,
95300
+ /* iArg: */ SQLITE_ForeignKeys },
9504195301
#endif
9504295302
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95043
- { "freelist_count", PragTyp_HEADER_VALUE, 0 },
95303
+ { /* zName: */ "freelist_count",
95304
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
95305
+ /* ePragFlag: */ 0,
95306
+ /* iArg: */ 0 },
9504495307
#endif
95045
- { "full_column_names", PragTyp_FLAG,
95046
- SQLITE_FullColNames },
95047
- { "fullfsync", PragTyp_FLAG,
95048
- SQLITE_FullFSync },
95308
+ { /* zName: */ "full_column_names",
95309
+ /* ePragTyp: */ PragTyp_FLAG,
95310
+ /* ePragFlag: */ 0,
95311
+ /* iArg: */ SQLITE_FullColNames },
95312
+ { /* zName: */ "fullfsync",
95313
+ /* ePragTyp: */ PragTyp_FLAG,
95314
+ /* ePragFlag: */ 0,
95315
+ /* iArg: */ SQLITE_FullFSync },
9504995316
#if defined(SQLITE_HAS_CODEC)
95050
- { "hexkey", PragTyp_HEXKEY, 0 },
95317
+ { /* zName: */ "hexkey",
95318
+ /* ePragTyp: */ PragTyp_HEXKEY,
95319
+ /* ePragFlag: */ 0,
95320
+ /* iArg: */ 0 },
95321
+ { /* zName: */ "hexrekey",
95322
+ /* ePragTyp: */ PragTyp_HEXKEY,
95323
+ /* ePragFlag: */ 0,
95324
+ /* iArg: */ 0 },
9505195325
#endif
9505295326
#if !defined(SQLITE_OMIT_CHECK)
95053
- { "ignore_check_constraints", PragTyp_FLAG,
95054
- SQLITE_IgnoreChecks },
95327
+ { /* zName: */ "ignore_check_constraints",
95328
+ /* ePragTyp: */ PragTyp_FLAG,
95329
+ /* ePragFlag: */ 0,
95330
+ /* iArg: */ SQLITE_IgnoreChecks },
9505595331
#endif
9505695332
#if !defined(SQLITE_OMIT_AUTOVACUUM)
95057
- { "incremental_vacuum", PragTyp_INCREMENTAL_VACUUM, 0 },
95333
+ { /* zName: */ "incremental_vacuum",
95334
+ /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
95335
+ /* ePragFlag: */ PragFlag_NeedSchema,
95336
+ /* iArg: */ 0 },
9505895337
#endif
9505995338
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95060
- { "index_info", PragTyp_INDEX_INFO, 0 },
95061
- { "index_list", PragTyp_INDEX_LIST, 0 },
95339
+ { /* zName: */ "index_info",
95340
+ /* ePragTyp: */ PragTyp_INDEX_INFO,
95341
+ /* ePragFlag: */ PragFlag_NeedSchema,
95342
+ /* iArg: */ 0 },
95343
+ { /* zName: */ "index_list",
95344
+ /* ePragTyp: */ PragTyp_INDEX_LIST,
95345
+ /* ePragFlag: */ PragFlag_NeedSchema,
95346
+ /* iArg: */ 0 },
9506295347
#endif
9506395348
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
95064
- { "integrity_check", PragTyp_INTEGRITY_CHECK, 0 },
95349
+ { /* zName: */ "integrity_check",
95350
+ /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
95351
+ /* ePragFlag: */ PragFlag_NeedSchema,
95352
+ /* iArg: */ 0 },
9506595353
#endif
9506695354
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95067
- { "journal_mode", PragTyp_JOURNAL_MODE, 0 },
95068
- { "journal_size_limit", PragTyp_JOURNAL_SIZE_LIMIT, 0 },
95355
+ { /* zName: */ "journal_mode",
95356
+ /* ePragTyp: */ PragTyp_JOURNAL_MODE,
95357
+ /* ePragFlag: */ PragFlag_NeedSchema,
95358
+ /* iArg: */ 0 },
95359
+ { /* zName: */ "journal_size_limit",
95360
+ /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
95361
+ /* ePragFlag: */ 0,
95362
+ /* iArg: */ 0 },
9506995363
#endif
9507095364
#if defined(SQLITE_HAS_CODEC)
95071
- { "key", PragTyp_KEY, 0 },
95365
+ { /* zName: */ "key",
95366
+ /* ePragTyp: */ PragTyp_KEY,
95367
+ /* ePragFlag: */ 0,
95368
+ /* iArg: */ 0 },
9507295369
#endif
95073
- { "legacy_file_format", PragTyp_FLAG,
95074
- SQLITE_LegacyFileFmt },
95370
+ { /* zName: */ "legacy_file_format",
95371
+ /* ePragTyp: */ PragTyp_FLAG,
95372
+ /* ePragFlag: */ 0,
95373
+ /* iArg: */ SQLITE_LegacyFileFmt },
9507595374
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
95076
- { "lock_proxy_file", PragTyp_LOCK_PROXY_FILE, 0 },
95375
+ { /* zName: */ "lock_proxy_file",
95376
+ /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
95377
+ /* ePragFlag: */ 0,
95378
+ /* iArg: */ 0 },
9507795379
#endif
9507895380
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
95079
- { "lock_status", PragTyp_LOCK_STATUS, 0 },
95080
-#endif
95081
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95082
- { "locking_mode", PragTyp_LOCKING_MODE, 0 },
95083
- { "max_page_count", PragTyp_PAGE_COUNT, 0 },
95084
- { "mmap_size", PragTyp_MMAP_SIZE, 0 },
95085
- { "page_count", PragTyp_PAGE_COUNT, 0 },
95086
- { "page_size", PragTyp_PAGE_SIZE, 0 },
95087
-#endif
95088
-#if defined(SQLITE_DEBUG)
95089
- { "parser_trace", PragTyp_PARSER_TRACE, 0 },
95090
-#endif
95091
- { "query_only", PragTyp_FLAG,
95092
- SQLITE_QueryOnly },
95093
-#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
95094
- { "quick_check", PragTyp_INTEGRITY_CHECK, 0 },
95095
-#endif
95096
- { "read_uncommitted", PragTyp_FLAG,
95097
- SQLITE_ReadUncommitted },
95098
- { "recursive_triggers", PragTyp_FLAG,
95099
- SQLITE_RecTriggers },
95100
-#if defined(SQLITE_HAS_CODEC)
95101
- { "rekey", PragTyp_REKEY, 0 },
95102
-#endif
95103
- { "reverse_unordered_selects", PragTyp_FLAG,
95104
- SQLITE_ReverseOrder },
95105
-#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95106
- { "schema_version", PragTyp_HEADER_VALUE, 0 },
95107
-#endif
95108
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95109
- { "secure_delete", PragTyp_SECURE_DELETE, 0 },
95110
-#endif
95111
- { "short_column_names", PragTyp_FLAG,
95112
- SQLITE_ShortColNames },
95113
- { "shrink_memory", PragTyp_SHRINK_MEMORY, 0 },
95114
- { "soft_heap_limit", PragTyp_SOFT_HEAP_LIMIT, 0 },
95115
-#if defined(SQLITE_DEBUG)
95116
- { "sql_trace", PragTyp_FLAG,
95117
- SQLITE_SqlTrace },
95118
-#endif
95119
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95120
- { "synchronous", PragTyp_SYNCHRONOUS, 0 },
95381
+ { /* zName: */ "lock_status",
95382
+ /* ePragTyp: */ PragTyp_LOCK_STATUS,
95383
+ /* ePragFlag: */ 0,
95384
+ /* iArg: */ 0 },
95385
+#endif
95386
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95387
+ { /* zName: */ "locking_mode",
95388
+ /* ePragTyp: */ PragTyp_LOCKING_MODE,
95389
+ /* ePragFlag: */ 0,
95390
+ /* iArg: */ 0 },
95391
+ { /* zName: */ "max_page_count",
95392
+ /* ePragTyp: */ PragTyp_PAGE_COUNT,
95393
+ /* ePragFlag: */ PragFlag_NeedSchema,
95394
+ /* iArg: */ 0 },
95395
+ { /* zName: */ "mmap_size",
95396
+ /* ePragTyp: */ PragTyp_MMAP_SIZE,
95397
+ /* ePragFlag: */ 0,
95398
+ /* iArg: */ 0 },
95399
+ { /* zName: */ "page_count",
95400
+ /* ePragTyp: */ PragTyp_PAGE_COUNT,
95401
+ /* ePragFlag: */ PragFlag_NeedSchema,
95402
+ /* iArg: */ 0 },
95403
+ { /* zName: */ "page_size",
95404
+ /* ePragTyp: */ PragTyp_PAGE_SIZE,
95405
+ /* ePragFlag: */ 0,
95406
+ /* iArg: */ 0 },
95407
+#endif
95408
+#if defined(SQLITE_DEBUG)
95409
+ { /* zName: */ "parser_trace",
95410
+ /* ePragTyp: */ PragTyp_PARSER_TRACE,
95411
+ /* ePragFlag: */ 0,
95412
+ /* iArg: */ 0 },
95413
+#endif
95414
+ { /* zName: */ "query_only",
95415
+ /* ePragTyp: */ PragTyp_FLAG,
95416
+ /* ePragFlag: */ 0,
95417
+ /* iArg: */ SQLITE_QueryOnly },
95418
+#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
95419
+ { /* zName: */ "quick_check",
95420
+ /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
95421
+ /* ePragFlag: */ PragFlag_NeedSchema,
95422
+ /* iArg: */ 0 },
95423
+#endif
95424
+ { /* zName: */ "read_uncommitted",
95425
+ /* ePragTyp: */ PragTyp_FLAG,
95426
+ /* ePragFlag: */ 0,
95427
+ /* iArg: */ SQLITE_ReadUncommitted },
95428
+ { /* zName: */ "recursive_triggers",
95429
+ /* ePragTyp: */ PragTyp_FLAG,
95430
+ /* ePragFlag: */ 0,
95431
+ /* iArg: */ SQLITE_RecTriggers },
95432
+#if defined(SQLITE_HAS_CODEC)
95433
+ { /* zName: */ "rekey",
95434
+ /* ePragTyp: */ PragTyp_REKEY,
95435
+ /* ePragFlag: */ 0,
95436
+ /* iArg: */ 0 },
95437
+#endif
95438
+ { /* zName: */ "reverse_unordered_selects",
95439
+ /* ePragTyp: */ PragTyp_FLAG,
95440
+ /* ePragFlag: */ 0,
95441
+ /* iArg: */ SQLITE_ReverseOrder },
95442
+#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95443
+ { /* zName: */ "schema_version",
95444
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
95445
+ /* ePragFlag: */ 0,
95446
+ /* iArg: */ 0 },
95447
+#endif
95448
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95449
+ { /* zName: */ "secure_delete",
95450
+ /* ePragTyp: */ PragTyp_SECURE_DELETE,
95451
+ /* ePragFlag: */ 0,
95452
+ /* iArg: */ 0 },
95453
+#endif
95454
+ { /* zName: */ "short_column_names",
95455
+ /* ePragTyp: */ PragTyp_FLAG,
95456
+ /* ePragFlag: */ 0,
95457
+ /* iArg: */ SQLITE_ShortColNames },
95458
+ { /* zName: */ "shrink_memory",
95459
+ /* ePragTyp: */ PragTyp_SHRINK_MEMORY,
95460
+ /* ePragFlag: */ 0,
95461
+ /* iArg: */ 0 },
95462
+ { /* zName: */ "soft_heap_limit",
95463
+ /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
95464
+ /* ePragFlag: */ 0,
95465
+ /* iArg: */ 0 },
95466
+#if defined(SQLITE_DEBUG)
95467
+ { /* zName: */ "sql_trace",
95468
+ /* ePragTyp: */ PragTyp_FLAG,
95469
+ /* ePragFlag: */ 0,
95470
+ /* iArg: */ SQLITE_SqlTrace },
95471
+#endif
95472
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95473
+ { /* zName: */ "synchronous",
95474
+ /* ePragTyp: */ PragTyp_SYNCHRONOUS,
95475
+ /* ePragFlag: */ PragFlag_NeedSchema,
95476
+ /* iArg: */ 0 },
9512195477
#endif
9512295478
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95123
- { "table_info", PragTyp_TABLE_INFO, 0 },
95479
+ { /* zName: */ "table_info",
95480
+ /* ePragTyp: */ PragTyp_TABLE_INFO,
95481
+ /* ePragFlag: */ PragFlag_NeedSchema,
95482
+ /* iArg: */ 0 },
9512495483
#endif
9512595484
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95126
- { "temp_store", PragTyp_TEMP_STORE, 0 },
95127
- { "temp_store_directory", PragTyp_TEMP_STORE_DIRECTORY, 0 },
95485
+ { /* zName: */ "temp_store",
95486
+ /* ePragTyp: */ PragTyp_TEMP_STORE,
95487
+ /* ePragFlag: */ 0,
95488
+ /* iArg: */ 0 },
95489
+ { /* zName: */ "temp_store_directory",
95490
+ /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
95491
+ /* ePragFlag: */ 0,
95492
+ /* iArg: */ 0 },
9512895493
#endif
9512995494
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95130
- { "user_version", PragTyp_HEADER_VALUE, 0 },
95495
+ { /* zName: */ "user_version",
95496
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
95497
+ /* ePragFlag: */ 0,
95498
+ /* iArg: */ 0 },
9513195499
#endif
9513295500
#if defined(SQLITE_DEBUG)
95133
- { "vdbe_addoptrace", PragTyp_FLAG,
95134
- SQLITE_VdbeAddopTrace },
95135
- { "vdbe_debug", PragTyp_FLAG,
95136
- SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
95137
- { "vdbe_listing", PragTyp_FLAG,
95138
- SQLITE_VdbeListing },
95139
- { "vdbe_trace", PragTyp_FLAG,
95140
- SQLITE_VdbeTrace },
95501
+ { /* zName: */ "vdbe_addoptrace",
95502
+ /* ePragTyp: */ PragTyp_FLAG,
95503
+ /* ePragFlag: */ 0,
95504
+ /* iArg: */ SQLITE_VdbeAddopTrace },
95505
+ { /* zName: */ "vdbe_debug",
95506
+ /* ePragTyp: */ PragTyp_FLAG,
95507
+ /* ePragFlag: */ 0,
95508
+ /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
95509
+ { /* zName: */ "vdbe_listing",
95510
+ /* ePragTyp: */ PragTyp_FLAG,
95511
+ /* ePragFlag: */ 0,
95512
+ /* iArg: */ SQLITE_VdbeListing },
95513
+ { /* zName: */ "vdbe_trace",
95514
+ /* ePragTyp: */ PragTyp_FLAG,
95515
+ /* ePragFlag: */ 0,
95516
+ /* iArg: */ SQLITE_VdbeTrace },
9514195517
#endif
9514295518
#if !defined(SQLITE_OMIT_WAL)
95143
- { "wal_autocheckpoint", PragTyp_WAL_AUTOCHECKPOINT, 0 },
95144
- { "wal_checkpoint", PragTyp_WAL_CHECKPOINT, 0 },
95519
+ { /* zName: */ "wal_autocheckpoint",
95520
+ /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
95521
+ /* ePragFlag: */ 0,
95522
+ /* iArg: */ 0 },
95523
+ { /* zName: */ "wal_checkpoint",
95524
+ /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
95525
+ /* ePragFlag: */ PragFlag_NeedSchema,
95526
+ /* iArg: */ 0 },
9514595527
#endif
95146
- { "writable_schema", PragTyp_FLAG,
95147
- SQLITE_WriteSchema|SQLITE_RecoveryMode },
95528
+ { /* zName: */ "writable_schema",
95529
+ /* ePragTyp: */ PragTyp_FLAG,
95530
+ /* ePragFlag: */ 0,
95531
+ /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
9514895532
};
95149
-/* Number of pragmas: 55 on by default, 66 total. */
95533
+/* Number of pragmas: 55 on by default, 67 total. */
9515095534
/* End of the automatically generated pragma table.
9515195535
***************************************************************************/
9515295536
9515395537
/*
9515495538
** Interpret the given string as a safety level. Return 0 for OFF,
@@ -95476,10 +95860,15 @@
9547695860
}else{
9547795861
lwr = mid + 1;
9547895862
}
9547995863
}
9548095864
if( lwr>upr ) goto pragma_out;
95865
+
95866
+ /* Make sure the database schema is loaded if the pragma requires that */
95867
+ if( (aPragmaNames[mid].mPragFlag & PragFlag_NeedSchema)!=0 ){
95868
+ if( sqlite3ReadSchema(pParse) ) goto pragma_out;
95869
+ }
9548195870
9548295871
/* Jump to the appropriate pragma handler */
9548395872
switch( aPragmaNames[mid].ePragTyp ){
9548495873
9548595874
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
@@ -95510,11 +95899,10 @@
9551095899
{ OP_Integer, 0, 1, 0}, /* 6 */
9551195900
{ OP_Noop, 0, 0, 0},
9551295901
{ OP_ResultRow, 1, 1, 0},
9551395902
};
9551495903
int addr;
95515
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9551695904
sqlite3VdbeUsesBtree(v, iDb);
9551795905
if( !zRight ){
9551895906
sqlite3VdbeSetNumCols(v, 1);
9551995907
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC);
9552095908
pParse->nMem += 2;
@@ -95606,11 +95994,10 @@
9560695994
**
9560795995
** Return the number of pages in the specified database.
9560895996
*/
9560995997
case PragTyp_PAGE_COUNT: {
9561095998
int iReg;
95611
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9561295999
sqlite3CodeVerifySchema(pParse, iDb);
9561396000
iReg = ++pParse->nMem;
9561496001
if( sqlite3Tolower(zLeft[0])=='p' ){
9561596002
sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
9561696003
}else{
@@ -95679,18 +96066,10 @@
9567996066
*/
9568096067
case PragTyp_JOURNAL_MODE: {
9568196068
int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
9568296069
int ii; /* Loop counter */
9568396070
95684
- /* Force the schema to be loaded on all databases. This causes all
95685
- ** database files to be opened and the journal_modes set. This is
95686
- ** necessary because subsequent processing must know if the databases
95687
- ** are in WAL mode. */
95688
- if( sqlite3ReadSchema(pParse) ){
95689
- goto pragma_out;
95690
- }
95691
-
9569296071
sqlite3VdbeSetNumCols(v, 1);
9569396072
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
9569496073
9569596074
if( zRight==0 ){
9569696075
/* If there is no "=MODE" part of the pragma, do a query for the
@@ -95752,55 +96131,44 @@
9575296131
*/
9575396132
#ifndef SQLITE_OMIT_AUTOVACUUM
9575496133
case PragTyp_AUTO_VACUUM: {
9575596134
Btree *pBt = pDb->pBt;
9575696135
assert( pBt!=0 );
95757
- if( sqlite3ReadSchema(pParse) ){
95758
- goto pragma_out;
95759
- }
9576096136
if( !zRight ){
95761
- int auto_vacuum;
95762
- if( ALWAYS(pBt) ){
95763
- auto_vacuum = sqlite3BtreeGetAutoVacuum(pBt);
95764
- }else{
95765
- auto_vacuum = SQLITE_DEFAULT_AUTOVACUUM;
95766
- }
95767
- returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
96137
+ returnSingleInt(pParse, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
9576896138
}else{
9576996139
int eAuto = getAutoVacuum(zRight);
9577096140
assert( eAuto>=0 && eAuto<=2 );
9577196141
db->nextAutovac = (u8)eAuto;
95772
- if( ALWAYS(eAuto>=0) ){
95773
- /* Call SetAutoVacuum() to set initialize the internal auto and
95774
- ** incr-vacuum flags. This is required in case this connection
95775
- ** creates the database file. It is important that it is created
95776
- ** as an auto-vacuum capable db.
95777
- */
95778
- rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
95779
- if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
95780
- /* When setting the auto_vacuum mode to either "full" or
95781
- ** "incremental", write the value of meta[6] in the database
95782
- ** file. Before writing to meta[6], check that meta[3] indicates
95783
- ** that this really is an auto-vacuum capable database.
95784
- */
95785
- static const VdbeOpList setMeta6[] = {
95786
- { OP_Transaction, 0, 1, 0}, /* 0 */
95787
- { OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
95788
- { OP_If, 1, 0, 0}, /* 2 */
95789
- { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
95790
- { OP_Integer, 0, 1, 0}, /* 4 */
95791
- { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
95792
- };
95793
- int iAddr;
95794
- iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
95795
- sqlite3VdbeChangeP1(v, iAddr, iDb);
95796
- sqlite3VdbeChangeP1(v, iAddr+1, iDb);
95797
- sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
95798
- sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
95799
- sqlite3VdbeChangeP1(v, iAddr+5, iDb);
95800
- sqlite3VdbeUsesBtree(v, iDb);
95801
- }
96142
+ /* Call SetAutoVacuum() to set initialize the internal auto and
96143
+ ** incr-vacuum flags. This is required in case this connection
96144
+ ** creates the database file. It is important that it is created
96145
+ ** as an auto-vacuum capable db.
96146
+ */
96147
+ rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
96148
+ if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
96149
+ /* When setting the auto_vacuum mode to either "full" or
96150
+ ** "incremental", write the value of meta[6] in the database
96151
+ ** file. Before writing to meta[6], check that meta[3] indicates
96152
+ ** that this really is an auto-vacuum capable database.
96153
+ */
96154
+ static const VdbeOpList setMeta6[] = {
96155
+ { OP_Transaction, 0, 1, 0}, /* 0 */
96156
+ { OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
96157
+ { OP_If, 1, 0, 0}, /* 2 */
96158
+ { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
96159
+ { OP_Integer, 0, 1, 0}, /* 4 */
96160
+ { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
96161
+ };
96162
+ int iAddr;
96163
+ iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
96164
+ sqlite3VdbeChangeP1(v, iAddr, iDb);
96165
+ sqlite3VdbeChangeP1(v, iAddr+1, iDb);
96166
+ sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
96167
+ sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
96168
+ sqlite3VdbeChangeP1(v, iAddr+5, iDb);
96169
+ sqlite3VdbeUsesBtree(v, iDb);
9580296170
}
9580396171
}
9580496172
break;
9580596173
}
9580696174
#endif
@@ -95811,13 +96179,10 @@
9581196179
** Do N steps of incremental vacuuming on a database.
9581296180
*/
9581396181
#ifndef SQLITE_OMIT_AUTOVACUUM
9581496182
case PragTyp_INCREMENTAL_VACUUM: {
9581596183
int iLimit, addr;
95816
- if( sqlite3ReadSchema(pParse) ){
95817
- goto pragma_out;
95818
- }
9581996184
if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
9582096185
iLimit = 0x7fffffff;
9582196186
}
9582296187
sqlite3BeginWriteOperation(pParse, 0, iDb);
9582396188
sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1);
@@ -95841,11 +96206,10 @@
9584196206
** number of pages in the cache. If N is negative, then the
9584296207
** number of pages is adjusted so that the cache uses -N kibibytes
9584396208
** of memory.
9584496209
*/
9584596210
case PragTyp_CACHE_SIZE: {
95846
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9584796211
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
9584896212
if( !zRight ){
9584996213
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
9585096214
}else{
9585196215
int size = sqlite3Atoi(zRight);
@@ -96062,11 +96426,10 @@
9606296426
** the local value does not make changes to the disk file and the
9606396427
** default value will be restored the next time the database is
9606496428
** opened.
9606596429
*/
9606696430
case PragTyp_SYNCHRONOUS: {
96067
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9606896431
if( !zRight ){
9606996432
returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
9607096433
}else{
9607196434
if( !db->autoCommit ){
9607296435
sqlite3ErrorMsg(pParse,
@@ -96124,11 +96487,10 @@
9612496487
** notnull: True if 'NOT NULL' is part of column declaration
9612596488
** dflt_value: The default value for the column, if any.
9612696489
*/
9612796490
case PragTyp_TABLE_INFO: if( zRight ){
9612896491
Table *pTab;
96129
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9613096492
pTab = sqlite3FindTable(db, zRight, zDb);
9613196493
if( pTab ){
9613296494
int i, k;
9613396495
int nHidden = 0;
9613496496
Column *pCol;
@@ -96174,11 +96536,10 @@
9617496536
break;
9617596537
9617696538
case PragTyp_INDEX_INFO: if( zRight ){
9617796539
Index *pIdx;
9617896540
Table *pTab;
96179
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9618096541
pIdx = sqlite3FindIndex(db, zRight, zDb);
9618196542
if( pIdx ){
9618296543
int i;
9618396544
pTab = pIdx->pTable;
9618496545
sqlite3VdbeSetNumCols(v, 3);
@@ -96200,39 +96561,41 @@
9620096561
break;
9620196562
9620296563
case PragTyp_INDEX_LIST: if( zRight ){
9620396564
Index *pIdx;
9620496565
Table *pTab;
96205
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96566
+ int i;
9620696567
pTab = sqlite3FindTable(db, zRight, zDb);
9620796568
if( pTab ){
9620896569
v = sqlite3GetVdbe(pParse);
96209
- pIdx = pTab->pIndex;
96210
- if( pIdx ){
96211
- int i = 0;
96212
- sqlite3VdbeSetNumCols(v, 3);
96213
- pParse->nMem = 3;
96214
- sqlite3CodeVerifySchema(pParse, iDb);
96215
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
96216
- sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
96217
- sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
96218
- while(pIdx){
96219
- sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
96220
- sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
96221
- sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
96222
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
96223
- ++i;
96224
- pIdx = pIdx->pNext;
96225
- }
96570
+ sqlite3VdbeSetNumCols(v, 4);
96571
+ pParse->nMem = 4;
96572
+ sqlite3CodeVerifySchema(pParse, iDb);
96573
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
96574
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
96575
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
96576
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "avgrowsize", SQLITE_STATIC);
96577
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, 1);
96578
+ sqlite3VdbeAddOp2(v, OP_Null, 0, 2);
96579
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, 3);
96580
+ sqlite3VdbeAddOp2(v, OP_Integer,
96581
+ (int)sqlite3LogEstToInt(pTab->szTabRow), 4);
96582
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
96583
+ for(pIdx=pTab->pIndex, i=1; pIdx; pIdx=pIdx->pNext, i++){
96584
+ sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
96585
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
96586
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
96587
+ sqlite3VdbeAddOp2(v, OP_Integer,
96588
+ (int)sqlite3LogEstToInt(pIdx->szIdxRow), 4);
96589
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
9622696590
}
9622796591
}
9622896592
}
9622996593
break;
9623096594
9623196595
case PragTyp_DATABASE_LIST: {
9623296596
int i;
96233
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9623496597
sqlite3VdbeSetNumCols(v, 3);
9623596598
pParse->nMem = 3;
9623696599
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
9623796600
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
9623896601
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", SQLITE_STATIC);
@@ -96267,11 +96630,10 @@
9626796630
9626896631
#ifndef SQLITE_OMIT_FOREIGN_KEY
9626996632
case PragTyp_FOREIGN_KEY_LIST: if( zRight ){
9627096633
FKey *pFK;
9627196634
Table *pTab;
96272
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9627396635
pTab = sqlite3FindTable(db, zRight, zDb);
9627496636
if( pTab ){
9627596637
v = sqlite3GetVdbe(pParse);
9627696638
pFK = pTab->pFKey;
9627796639
if( pFK ){
@@ -96329,11 +96691,10 @@
9632996691
int regRow; /* Registers to hold a row from pTab */
9633096692
int addrTop; /* Top of a loop checking foreign keys */
9633196693
int addrOk; /* Jump here if the key is OK */
9633296694
int *aiCols; /* child to parent column mapping */
9633396695
96334
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9633596696
regResult = pParse->nMem+1;
9633696697
pParse->nMem += 4;
9633796698
regKey = ++pParse->nMem;
9633896699
regRow = ++pParse->nMem;
9633996700
v = sqlite3GetVdbe(pParse);
@@ -96490,11 +96851,10 @@
9649096851
assert( iDb>=0 );
9649196852
assert( iDb==0 || pId2->z );
9649296853
if( pId2->z==0 ) iDb = -1;
9649396854
9649496855
/* Initialize the VDBE program */
96495
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9649696856
pParse->nMem = 6;
9649796857
sqlite3VdbeSetNumCols(v, 1);
9649896858
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", SQLITE_STATIC);
9649996859
9650096860
/* Set the maximum error count */
@@ -96814,11 +97174,10 @@
9681497174
eMode = SQLITE_CHECKPOINT_FULL;
9681597175
}else if( sqlite3StrICmp(zRight, "restart")==0 ){
9681697176
eMode = SQLITE_CHECKPOINT_RESTART;
9681797177
}
9681897178
}
96819
- if( sqlite3ReadSchema(pParse) ) goto pragma_out;
9682097179
sqlite3VdbeSetNumCols(v, 3);
9682197180
pParse->nMem = 3;
9682297181
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "busy", SQLITE_STATIC);
9682397182
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "log", SQLITE_STATIC);
9682497183
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "checkpointed", SQLITE_STATIC);
@@ -96934,16 +97293,16 @@
9693497293
if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight));
9693597294
break;
9693697295
}
9693797296
case PragTyp_HEXKEY: {
9693897297
if( zRight ){
96939
- int i, h1, h2;
97298
+ u8 iByte;
97299
+ int i;
9694097300
char zKey[40];
96941
- for(i=0; (h1 = zRight[i])!=0 && (h2 = zRight[i+1])!=0; i+=2){
96942
- h1 += 9*(1&(h1>>6));
96943
- h2 += 9*(1&(h2>>6));
96944
- zKey[i/2] = (h2 & 0x0f) | ((h1 & 0xf)<<4);
97301
+ for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zRight[i]); i++){
97302
+ iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
97303
+ if( (i&1)!=0 ) zKey[i/2] = iByte;
9694597304
}
9694697305
if( (zLeft[3] & 0xf)==0xb ){
9694797306
sqlite3_key_v2(db, zDb, zKey, i/2);
9694897307
}else{
9694997308
sqlite3_rekey_v2(db, zDb, zKey, i/2);
@@ -98913,10 +99272,13 @@
9891399272
}
9891499273
9891599274
/*
9891699275
** Return a pointer to a string containing the 'declaration type' of the
9891799276
** expression pExpr. The string may be treated as static by the caller.
99277
+**
99278
+** Also try to estimate the size of the returned value and return that
99279
+** result in *pEstWidth.
9891899280
**
9891999281
** The declaration type is the exact datatype definition extracted from the
9892099282
** original CREATE TABLE statement if the expression is a column. The
9892199283
** declaration type for a ROWID field is INTEGER. Exactly when an expression
9892299284
** is considered a column can be complex in the presence of subqueries. The
@@ -98927,25 +99289,40 @@
9892799289
** SELECT (SELECT col FROM tbl;
9892899290
** SELECT (SELECT col FROM tbl);
9892999291
** SELECT abc FROM (SELECT col AS abc FROM tbl);
9893099292
**
9893199293
** The declaration type for any expression other than a column is NULL.
99294
+**
99295
+** This routine has either 3 or 6 parameters depending on whether or not
99296
+** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
9893299297
*/
98933
-static const char *columnType(
99298
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
99299
+# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
99300
+static const char *columnTypeImpl(
99301
+ NameContext *pNC,
99302
+ Expr *pExpr,
99303
+ const char **pzOrigDb,
99304
+ const char **pzOrigTab,
99305
+ const char **pzOrigCol,
99306
+ u8 *pEstWidth
99307
+){
99308
+ char const *zOrigDb = 0;
99309
+ char const *zOrigTab = 0;
99310
+ char const *zOrigCol = 0;
99311
+#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
99312
+# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
99313
+static const char *columnTypeImpl(
9893499314
NameContext *pNC,
9893599315
Expr *pExpr,
98936
- const char **pzOriginDb,
98937
- const char **pzOriginTab,
98938
- const char **pzOriginCol
99316
+ u8 *pEstWidth
9893999317
){
99318
+#endif /* !defined(SQLITE_ENABLE_COLUMN_METADATA) */
9894099319
char const *zType = 0;
98941
- char const *zOriginDb = 0;
98942
- char const *zOriginTab = 0;
98943
- char const *zOriginCol = 0;
9894499320
int j;
99321
+ u8 estWidth = 1;
99322
+
9894599323
if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
98946
-
9894799324
switch( pExpr->op ){
9894899325
case TK_AGG_COLUMN:
9894999326
case TK_COLUMN: {
9895099327
/* The expression is a column. Locate the table the column is being
9895199328
** extracted from in NameContext.pSrcList. This table may be real
@@ -99002,29 +99379,39 @@
9900299379
NameContext sNC;
9900399380
Expr *p = pS->pEList->a[iCol].pExpr;
9900499381
sNC.pSrcList = pS->pSrc;
9900599382
sNC.pNext = pNC;
9900699383
sNC.pParse = pNC->pParse;
99007
- zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
99384
+ zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth);
9900899385
}
9900999386
}else if( ALWAYS(pTab->pSchema) ){
9901099387
/* A real table */
9901199388
assert( !pS );
9901299389
if( iCol<0 ) iCol = pTab->iPKey;
9901399390
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
99391
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
9901499392
if( iCol<0 ){
9901599393
zType = "INTEGER";
99016
- zOriginCol = "rowid";
99394
+ zOrigCol = "rowid";
9901799395
}else{
9901899396
zType = pTab->aCol[iCol].zType;
99019
- zOriginCol = pTab->aCol[iCol].zName;
99397
+ zOrigCol = pTab->aCol[iCol].zName;
99398
+ estWidth = pTab->aCol[iCol].szEst;
9902099399
}
99021
- zOriginTab = pTab->zName;
99400
+ zOrigTab = pTab->zName;
9902299401
if( pNC->pParse ){
9902399402
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
99024
- zOriginDb = pNC->pParse->db->aDb[iDb].zName;
99403
+ zOrigDb = pNC->pParse->db->aDb[iDb].zName;
9902599404
}
99405
+#else
99406
+ if( iCol<0 ){
99407
+ zType = "INTEGER";
99408
+ }else{
99409
+ zType = pTab->aCol[iCol].zType;
99410
+ estWidth = pTab->aCol[iCol].szEst;
99411
+ }
99412
+#endif
9902699413
}
9902799414
break;
9902899415
}
9902999416
#ifndef SQLITE_OMIT_SUBQUERY
9903099417
case TK_SELECT: {
@@ -99037,22 +99424,25 @@
9903799424
Expr *p = pS->pEList->a[0].pExpr;
9903899425
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
9903999426
sNC.pSrcList = pS->pSrc;
9904099427
sNC.pNext = pNC;
9904199428
sNC.pParse = pNC->pParse;
99042
- zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
99429
+ zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth);
9904399430
break;
9904499431
}
9904599432
#endif
9904699433
}
99047
-
99048
- if( pzOriginDb ){
99049
- assert( pzOriginTab && pzOriginCol );
99050
- *pzOriginDb = zOriginDb;
99051
- *pzOriginTab = zOriginTab;
99052
- *pzOriginCol = zOriginCol;
99434
+
99435
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
99436
+ if( pzOrigDb ){
99437
+ assert( pzOrigTab && pzOrigCol );
99438
+ *pzOrigDb = zOrigDb;
99439
+ *pzOrigTab = zOrigTab;
99440
+ *pzOrigCol = zOrigCol;
9905399441
}
99442
+#endif
99443
+ if( pEstWidth ) *pEstWidth = estWidth;
9905499444
return zType;
9905599445
}
9905699446
9905799447
/*
9905899448
** Generate code that will tell the VDBE the declaration types of columns
@@ -99074,25 +99464,25 @@
9907499464
const char *zType;
9907599465
#ifdef SQLITE_ENABLE_COLUMN_METADATA
9907699466
const char *zOrigDb = 0;
9907799467
const char *zOrigTab = 0;
9907899468
const char *zOrigCol = 0;
99079
- zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
99469
+ zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0);
9908099470
9908199471
/* The vdbe must make its own copy of the column-type and other
9908299472
** column specific strings, in case the schema is reset before this
9908399473
** virtual machine is deleted.
9908499474
*/
9908599475
sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, SQLITE_TRANSIENT);
9908699476
sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
9908799477
sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
9908899478
#else
99089
- zType = columnType(&sNC, p, 0, 0, 0);
99479
+ zType = columnType(&sNC, p, 0, 0, 0, 0);
9909099480
#endif
9909199481
sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
9909299482
}
99093
-#endif /* SQLITE_OMIT_DECLTYPE */
99483
+#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
9909499484
}
9909599485
9909699486
/*
9909799487
** Generate code that will tell the VDBE the names of columns
9909899488
** in the result set. This information is used to provide the
@@ -99277,39 +99667,41 @@
9927799667
** This routine requires that all identifiers in the SELECT
9927899668
** statement be resolved.
9927999669
*/
9928099670
static void selectAddColumnTypeAndCollation(
9928199671
Parse *pParse, /* Parsing contexts */
99282
- int nCol, /* Number of columns */
99283
- Column *aCol, /* List of columns */
99672
+ Table *pTab, /* Add column type information to this table */
9928499673
Select *pSelect /* SELECT used to determine types and collations */
9928599674
){
9928699675
sqlite3 *db = pParse->db;
9928799676
NameContext sNC;
9928899677
Column *pCol;
9928999678
CollSeq *pColl;
9929099679
int i;
9929199680
Expr *p;
9929299681
struct ExprList_item *a;
99682
+ u64 szAll = 0;
9929399683
9929499684
assert( pSelect!=0 );
9929599685
assert( (pSelect->selFlags & SF_Resolved)!=0 );
99296
- assert( nCol==pSelect->pEList->nExpr || db->mallocFailed );
99686
+ assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed );
9929799687
if( db->mallocFailed ) return;
9929899688
memset(&sNC, 0, sizeof(sNC));
9929999689
sNC.pSrcList = pSelect->pSrc;
9930099690
a = pSelect->pEList->a;
99301
- for(i=0, pCol=aCol; i<nCol; i++, pCol++){
99691
+ for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
9930299692
p = a[i].pExpr;
99303
- pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p, 0, 0, 0));
99693
+ pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst));
99694
+ szAll += pCol->szEst;
9930499695
pCol->affinity = sqlite3ExprAffinity(p);
9930599696
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE;
9930699697
pColl = sqlite3ExprCollSeq(pParse, p);
9930799698
if( pColl ){
9930899699
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
9930999700
}
9931099701
}
99702
+ pTab->szTabRow = sqlite3LogEst(szAll*4);
9931199703
}
9931299704
9931399705
/*
9931499706
** Given a SELECT statement, generate a Table structure that describes
9931599707
** the result set of that SELECT.
@@ -99333,13 +99725,13 @@
9933399725
/* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
9933499726
** is disabled */
9933599727
assert( db->lookaside.bEnabled==0 );
9933699728
pTab->nRef = 1;
9933799729
pTab->zName = 0;
99338
- pTab->nRowEst = 1000000;
99730
+ pTab->nRowEst = 1048576;
9933999731
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
99340
- selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSelect);
99732
+ selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
9934199733
pTab->iPKey = -1;
9934299734
if( db->mallocFailed ){
9934399735
sqlite3DeleteTable(db, pTab);
9934499736
return 0;
9934599737
}
@@ -101247,15 +101639,15 @@
101247101639
assert( pFrom->pTab==0 );
101248101640
sqlite3WalkSelect(pWalker, pSel);
101249101641
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
101250101642
if( pTab==0 ) return WRC_Abort;
101251101643
pTab->nRef = 1;
101252
- pTab->zName = sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pTab);
101644
+ pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
101253101645
while( pSel->pPrior ){ pSel = pSel->pPrior; }
101254101646
selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
101255101647
pTab->iPKey = -1;
101256
- pTab->nRowEst = 1000000;
101648
+ pTab->nRowEst = 1048576;
101257101649
pTab->tabFlags |= TF_Ephemeral;
101258101650
#endif
101259101651
}else{
101260101652
/* An ordinary table or view name in the FROM clause */
101261101653
assert( pFrom->pTab==0 );
@@ -101535,11 +101927,11 @@
101535101927
if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
101536101928
/* A sub-query in the FROM clause of a SELECT */
101537101929
Select *pSel = pFrom->pSelect;
101538101930
assert( pSel );
101539101931
while( pSel->pPrior ) pSel = pSel->pPrior;
101540
- selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
101932
+ selectAddColumnTypeAndCollation(pParse, pTab, pSel);
101541101933
}
101542101934
}
101543101935
}
101544101936
return WRC_Continue;
101545101937
}
@@ -102450,29 +102842,29 @@
102450102842
int iRoot = pTab->tnum; /* Root page of scanned b-tree */
102451102843
102452102844
sqlite3CodeVerifySchema(pParse, iDb);
102453102845
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
102454102846
102455
- /* Search for the index that has the least amount of columns. If
102456
- ** there is such an index, and it has less columns than the table
102457
- ** does, then we can assume that it consumes less space on disk and
102458
- ** will therefore be cheaper to scan to determine the query result.
102459
- ** In this case set iRoot to the root page number of the index b-tree
102460
- ** and pKeyInfo to the KeyInfo structure required to navigate the
102461
- ** index.
102847
+ /* Search for the index that has the lowest scan cost.
102462102848
**
102463102849
** (2011-04-15) Do not do a full scan of an unordered index.
102850
+ **
102851
+ ** (2013-10-03) Do not count the entires in a partial index.
102464102852
**
102465102853
** In practice the KeyInfo structure will not be used. It is only
102466102854
** passed to keep OP_OpenRead happy.
102467102855
*/
102468102856
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
102469
- if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){
102857
+ if( pIdx->bUnordered==0
102858
+ && pIdx->szIdxRow<pTab->szTabRow
102859
+ && pIdx->pPartIdxWhere==0
102860
+ && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
102861
+ ){
102470102862
pBest = pIdx;
102471102863
}
102472102864
}
102473
- if( pBest && pBest->nColumn<pTab->nCol ){
102865
+ if( pBest ){
102474102866
iRoot = pBest->tnum;
102475102867
pKeyInfo = sqlite3IndexKeyinfo(pParse, pBest);
102476102868
}
102477102869
102478102870
/* Open a read-only cursor, execute the OP_Count, close the cursor. */
@@ -103046,12 +103438,12 @@
103046103438
}
103047103439
103048103440
/* Ensure the table name matches database name and that the table exists */
103049103441
if( db->mallocFailed ) goto trigger_cleanup;
103050103442
assert( pTableName->nSrc==1 );
103051
- if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
103052
- sqlite3FixSrcList(&sFix, pTableName) ){
103443
+ sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName);
103444
+ if( sqlite3FixSrcList(&sFix, pTableName) ){
103053103445
goto trigger_cleanup;
103054103446
}
103055103447
pTab = sqlite3SrcListLookup(pParse, pTableName);
103056103448
if( !pTab ){
103057103449
/* The table does not exist. */
@@ -103189,12 +103581,14 @@
103189103581
pStepList->pTrig = pTrig;
103190103582
pStepList = pStepList->pNext;
103191103583
}
103192103584
nameToken.z = pTrig->zName;
103193103585
nameToken.n = sqlite3Strlen30(nameToken.z);
103194
- if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken)
103195
- && sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
103586
+ sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken);
103587
+ if( sqlite3FixTriggerStep(&sFix, pTrig->step_list)
103588
+ || sqlite3FixExpr(&sFix, pTrig->pWhen)
103589
+ ){
103196103590
goto triggerfinish_cleanup;
103197103591
}
103198103592
103199103593
/* if we are not initializing,
103200103594
** build the sqlite_master entry
@@ -104781,18 +105175,38 @@
104781105175
104782105176
return vacuumFinalize(db, pStmt, pzErrMsg);
104783105177
}
104784105178
104785105179
/*
104786
-** The non-standard VACUUM command is used to clean up the database,
105180
+** The VACUUM command is used to clean up the database,
104787105181
** collapse free space, etc. It is modelled after the VACUUM command
104788
-** in PostgreSQL.
105182
+** in PostgreSQL. The VACUUM command works as follows:
104789105183
**
104790
-** In version 1.0.x of SQLite, the VACUUM command would call
104791
-** gdbm_reorganize() on all the database tables. But beginning
104792
-** with 2.0.0, SQLite no longer uses GDBM so this command has
104793
-** become a no-op.
105184
+** (1) Create a new transient database file
105185
+** (2) Copy all content from the database being vacuumed into
105186
+** the new transient database file
105187
+** (3) Copy content from the transient database back into the
105188
+** original database.
105189
+**
105190
+** The transient database requires temporary disk space approximately
105191
+** equal to the size of the original database. The copy operation of
105192
+** step (3) requires additional temporary disk space approximately equal
105193
+** to the size of the original database for the rollback journal.
105194
+** Hence, temporary disk space that is approximately 2x the size of the
105195
+** orginal database is required. Every page of the database is written
105196
+** approximately 3 times: Once for step (2) and twice for step (3).
105197
+** Two writes per page are required in step (3) because the original
105198
+** database content must be written into the rollback journal prior to
105199
+** overwriting the database with the vacuumed content.
105200
+**
105201
+** Only 1x temporary space and only 1x writes would be required if
105202
+** the copy of step (3) were replace by deleting the original database
105203
+** and renaming the transient database as the original. But that will
105204
+** not work if other processes are attached to the original database.
105205
+** And a power loss in between deleting the original and renaming the
105206
+** transient would cause the database file to appear to be deleted
105207
+** following reboot.
104794105208
*/
104795105209
SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
104796105210
Vdbe *v = sqlite3GetVdbe(pParse);
104797105211
if( v ){
104798105212
sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
@@ -106206,30 +106620,10 @@
106206106620
typedef struct WhereLoopBuilder WhereLoopBuilder;
106207106621
typedef struct WhereScan WhereScan;
106208106622
typedef struct WhereOrCost WhereOrCost;
106209106623
typedef struct WhereOrSet WhereOrSet;
106210106624
106211
-/*
106212
-** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The
106213
-** maximum cost for ordinary tables is 64*(2**63) which becomes 6900.
106214
-** (Virtual tables can return a larger cost, but let's assume they do not.)
106215
-** So all costs can be stored in a 16-bit integer without risk
106216
-** of overflow.
106217
-**
106218
-** Costs are estimates, so no effort is made to compute 10*log2(X) exactly.
106219
-** Instead, a close estimate is used. Any value of X=1 is stored as 0.
106220
-** X=2 is 10. X=3 is 16. X=1000 is 99. etc. Negative values are allowed.
106221
-** A WhereCost of -10 means 0.5. WhereCost of -20 means 0.25. And so forth.
106222
-**
106223
-** The tool/wherecosttest.c source file implements a command-line program
106224
-** that will convert WhereCosts to integers, convert integers to WhereCosts
106225
-** and do addition and multiplication on WhereCost values. The wherecosttest
106226
-** command-line program is a useful utility to have around when working with
106227
-** this module.
106228
-*/
106229
-typedef short int WhereCost;
106230
-
106231106625
/*
106232106626
** This object contains information needed to implement a single nested
106233106627
** loop in WHERE clause.
106234106628
**
106235106629
** Contrast this object with WhereLoop. This object describes the
@@ -106290,13 +106684,13 @@
106290106684
#ifdef SQLITE_DEBUG
106291106685
char cId; /* Symbolic ID of this loop for debugging use */
106292106686
#endif
106293106687
u8 iTab; /* Position in FROM clause of table for this loop */
106294106688
u8 iSortIdx; /* Sorting index number. 0==None */
106295
- WhereCost rSetup; /* One-time setup cost (ex: create transient index) */
106296
- WhereCost rRun; /* Cost of running each loop */
106297
- WhereCost nOut; /* Estimated number of output rows */
106689
+ LogEst rSetup; /* One-time setup cost (ex: create transient index) */
106690
+ LogEst rRun; /* Cost of running each loop */
106691
+ LogEst nOut; /* Estimated number of output rows */
106298106692
union {
106299106693
struct { /* Information for internal btree tables */
106300106694
int nEq; /* Number of equality constraints */
106301106695
Index *pIndex; /* Index used, or NULL */
106302106696
} btree;
@@ -106322,12 +106716,12 @@
106322106716
** subquery on one operand of an OR operator in the WHERE clause.
106323106717
** See WhereOrSet for additional information
106324106718
*/
106325106719
struct WhereOrCost {
106326106720
Bitmask prereq; /* Prerequisites */
106327
- WhereCost rRun; /* Cost of running this subquery */
106328
- WhereCost nOut; /* Number of outputs for this subquery */
106721
+ LogEst rRun; /* Cost of running this subquery */
106722
+ LogEst nOut; /* Number of outputs for this subquery */
106329106723
};
106330106724
106331106725
/* The WhereOrSet object holds a set of possible WhereOrCosts that
106332106726
** correspond to the subquery(s) of OR-clause processing. Only the
106333106727
** best N_OR_COST elements are retained.
@@ -106361,12 +106755,12 @@
106361106755
** at the end is the choosen query plan.
106362106756
*/
106363106757
struct WherePath {
106364106758
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
106365106759
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
106366
- WhereCost nRow; /* Estimated number of rows generated by this path */
106367
- WhereCost rCost; /* Total cost of this path */
106760
+ LogEst nRow; /* Estimated number of rows generated by this path */
106761
+ LogEst rCost; /* Total cost of this path */
106368106762
u8 isOrdered; /* True if this path satisfies ORDER BY */
106369106763
u8 isOrderedValid; /* True if the isOrdered field is valid */
106370106764
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
106371106765
};
106372106766
@@ -106428,11 +106822,11 @@
106428106822
union {
106429106823
int leftColumn; /* Column number of X in "X <op> <expr>" */
106430106824
WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
106431106825
WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
106432106826
} u;
106433
- WhereCost truthProb; /* Probability of truth for this expression */
106827
+ LogEst truthProb; /* Probability of truth for this expression */
106434106828
u16 eOperator; /* A WO_xx value describing <op> */
106435106829
u8 wtFlags; /* TERM_xxx bit flags. See below */
106436106830
u8 nChild; /* Number of children that must disable us */
106437106831
WhereClause *pWC; /* The clause this term is part of */
106438106832
Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */
@@ -106576,11 +106970,11 @@
106576106970
SrcList *pTabList; /* List of tables in the join */
106577106971
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
106578106972
ExprList *pResultSet; /* Result set. DISTINCT operates on these */
106579106973
WhereLoop *pLoops; /* List of all WhereLoop objects */
106580106974
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
106581
- WhereCost nRowOut; /* Estimated number of output rows */
106975
+ LogEst nRowOut; /* Estimated number of output rows */
106582106976
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
106583106977
u8 bOBSat; /* ORDER BY satisfied by indices */
106584106978
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
106585106979
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
106586106980
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
@@ -106636,30 +107030,15 @@
106636107030
#define WHERE_IN_ABLE 0x00000800 /* Able to support an IN operator */
106637107031
#define WHERE_ONEROW 0x00001000 /* Selects no more than one row */
106638107032
#define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */
106639107033
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
106640107034
106641
-
106642
-/* Convert a WhereCost value (10 times log2(X)) into its integer value X.
106643
-** A rough approximation is used. The value returned is not exact.
106644
-*/
106645
-static u64 whereCostToInt(WhereCost x){
106646
- u64 n;
106647
- if( x<10 ) return 1;
106648
- n = x%10;
106649
- x /= 10;
106650
- if( n>=5 ) n -= 2;
106651
- else if( n>=1 ) n -= 1;
106652
- if( x>=3 ) return (n+8)<<(x-3);
106653
- return (n+8)>>(3-x);
106654
-}
106655
-
106656107035
/*
106657107036
** Return the estimated number of output rows from a WHERE clause
106658107037
*/
106659107038
SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
106660
- return whereCostToInt(pWInfo->nRowOut);
107039
+ return sqlite3LogEstToInt(pWInfo->nRowOut);
106661107040
}
106662107041
106663107042
/*
106664107043
** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this
106665107044
** WHERE clause returns outputs for DISTINCT processing.
@@ -106717,12 +107096,12 @@
106717107096
** so that pSet keeps the N_OR_COST best entries seen so far.
106718107097
*/
106719107098
static int whereOrInsert(
106720107099
WhereOrSet *pSet, /* The WhereOrSet to be updated */
106721107100
Bitmask prereq, /* Prerequisites of the new entry */
106722
- WhereCost rRun, /* Run-cost of the new entry */
106723
- WhereCost nOut /* Number of outputs for the new entry */
107101
+ LogEst rRun, /* Run-cost of the new entry */
107102
+ LogEst nOut /* Number of outputs for the new entry */
106724107103
){
106725107104
u16 i;
106726107105
WhereOrCost *p;
106727107106
for(i=pSet->n, p=pSet->a; i>0; i--, p++){
106728107107
if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){
@@ -106803,13 +107182,10 @@
106803107182
if( pWC->a!=pWC->aStatic ){
106804107183
sqlite3DbFree(db, pWC->a);
106805107184
}
106806107185
}
106807107186
106808
-/* Forward declaration */
106809
-static WhereCost whereCost(tRowcnt x);
106810
-
106811107187
/*
106812107188
** Add a single new WhereTerm entry to the WhereClause object pWC.
106813107189
** The new WhereTerm object is constructed from Expr p and with wtFlags.
106814107190
** The index in pWC->a[] of the new WhereTerm is returned on success.
106815107191
** 0 is returned if the new WhereTerm could not be added due to a memory
@@ -106848,11 +107224,11 @@
106848107224
}
106849107225
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
106850107226
}
106851107227
pTerm = &pWC->a[idx = pWC->nTerm++];
106852107228
if( p && ExprHasProperty(p, EP_Unlikely) ){
106853
- pTerm->truthProb = whereCost(p->iTable) - 99;
107229
+ pTerm->truthProb = sqlite3LogEst(p->iTable) - 99;
106854107230
}else{
106855107231
pTerm->truthProb = -1;
106856107232
}
106857107233
pTerm->pExpr = sqlite3ExprSkipCollate(p);
106858107234
pTerm->wtFlags = wtFlags;
@@ -108112,79 +108488,16 @@
108112108488
}
108113108489
108114108490
return 0;
108115108491
}
108116108492
108117
-/*
108118
-** Find (an approximate) sum of two WhereCosts. This computation is
108119
-** not a simple "+" operator because WhereCost is stored as a logarithmic
108120
-** value.
108121
-**
108122
-*/
108123
-static WhereCost whereCostAdd(WhereCost a, WhereCost b){
108124
- static const unsigned char x[] = {
108125
- 10, 10, /* 0,1 */
108126
- 9, 9, /* 2,3 */
108127
- 8, 8, /* 4,5 */
108128
- 7, 7, 7, /* 6,7,8 */
108129
- 6, 6, 6, /* 9,10,11 */
108130
- 5, 5, 5, /* 12-14 */
108131
- 4, 4, 4, 4, /* 15-18 */
108132
- 3, 3, 3, 3, 3, 3, /* 19-24 */
108133
- 2, 2, 2, 2, 2, 2, 2, /* 25-31 */
108134
- };
108135
- if( a>=b ){
108136
- if( a>b+49 ) return a;
108137
- if( a>b+31 ) return a+1;
108138
- return a+x[a-b];
108139
- }else{
108140
- if( b>a+49 ) return b;
108141
- if( b>a+31 ) return b+1;
108142
- return b+x[b-a];
108143
- }
108144
-}
108145
-
108146
-/*
108147
-** Convert an integer into a WhereCost. In other words, compute a
108148
-** good approximatation for 10*log2(x).
108149
-*/
108150
-static WhereCost whereCost(tRowcnt x){
108151
- static WhereCost a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
108152
- WhereCost y = 40;
108153
- if( x<8 ){
108154
- if( x<2 ) return 0;
108155
- while( x<8 ){ y -= 10; x <<= 1; }
108156
- }else{
108157
- while( x>255 ){ y += 40; x >>= 4; }
108158
- while( x>15 ){ y += 10; x >>= 1; }
108159
- }
108160
- return a[x&7] + y - 10;
108161
-}
108162
-
108163
-#ifndef SQLITE_OMIT_VIRTUALTABLE
108164
-/*
108165
-** Convert a double (as received from xBestIndex of a virtual table)
108166
-** into a WhereCost. In other words, compute an approximation for
108167
-** 10*log2(x).
108168
-*/
108169
-static WhereCost whereCostFromDouble(double x){
108170
- u64 a;
108171
- WhereCost e;
108172
- assert( sizeof(x)==8 && sizeof(a)==8 );
108173
- if( x<=1 ) return 0;
108174
- if( x<=2000000000 ) return whereCost((tRowcnt)x);
108175
- memcpy(&a, &x, 8);
108176
- e = (a>>52) - 1022;
108177
- return e*10;
108178
-}
108179
-#endif /* SQLITE_OMIT_VIRTUALTABLE */
108180108493
108181108494
/*
108182108495
** Estimate the logarithm of the input value to base 2.
108183108496
*/
108184
-static WhereCost estLog(WhereCost N){
108185
- WhereCost x = whereCost(N);
108497
+static LogEst estLog(LogEst N){
108498
+ LogEst x = sqlite3LogEst(N);
108186108499
return x>33 ? x - 33 : 0;
108187108500
}
108188108501
108189108502
/*
108190108503
** Two routines for printing the content of an sqlite3_index_info
@@ -108693,11 +109006,11 @@
108693109006
**
108694109007
** ... FROM t1 WHERE a > ? AND a < ? ...
108695109008
**
108696109009
** then nEq is set to 0.
108697109010
**
108698
-** When this function is called, *pnOut is set to the whereCost() of the
109011
+** When this function is called, *pnOut is set to the sqlite3LogEst() of the
108699109012
** number of rows that the index scan is expected to visit without
108700109013
** considering the range constraints. If nEq is 0, this is the number of
108701109014
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
108702109015
** to account for the range contraints pLower and pUpper.
108703109016
**
@@ -108709,19 +109022,19 @@
108709109022
static int whereRangeScanEst(
108710109023
Parse *pParse, /* Parsing & code generating context */
108711109024
WhereLoopBuilder *pBuilder,
108712109025
WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
108713109026
WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */
108714
- WhereCost *pnOut /* IN/OUT: Number of rows visited */
109027
+ WhereLoop *pLoop /* Modify the .nOut and maybe .rRun fields */
108715109028
){
108716109029
int rc = SQLITE_OK;
108717
- int nOut = (int)*pnOut;
108718
- WhereCost nNew;
109030
+ int nOut = pLoop->nOut;
109031
+ int nEq = pLoop->u.btree.nEq;
109032
+ LogEst nNew;
108719109033
108720109034
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
108721
- Index *p = pBuilder->pNew->u.btree.pIndex;
108722
- int nEq = pBuilder->pNew->u.btree.nEq;
109035
+ Index *p = pLoop->u.btree.pIndex;
108723109036
108724109037
if( p->nSample>0
108725109038
&& nEq==pBuilder->nRecValid
108726109039
&& nEq<p->nSampleCol
108727109040
&& OptimizationEnabled(pParse->db, SQLITE_Stat3)
@@ -108798,18 +109111,18 @@
108798109111
}
108799109112
108800109113
pBuilder->pRec = pRec;
108801109114
if( rc==SQLITE_OK ){
108802109115
if( iUpper>iLower ){
108803
- nNew = whereCost(iUpper - iLower);
109116
+ nNew = sqlite3LogEst(iUpper - iLower);
108804109117
}else{
108805
- nNew = 10; assert( 10==whereCost(2) );
109118
+ nNew = 10; assert( 10==sqlite3LogEst(2) );
108806109119
}
108807109120
if( nNew<nOut ){
108808109121
nOut = nNew;
108809109122
}
108810
- *pnOut = (WhereCost)nOut;
109123
+ pLoop->nOut = (LogEst)nOut;
108811109124
WHERETRACE(0x100, ("range scan regions: %u..%u est=%d\n",
108812109125
(u32)iLower, (u32)iUpper, nOut));
108813109126
return SQLITE_OK;
108814109127
}
108815109128
}
@@ -108820,20 +109133,20 @@
108820109133
assert( pLower || pUpper );
108821109134
/* TUNING: Each inequality constraint reduces the search space 4-fold.
108822109135
** A BETWEEN operator, therefore, reduces the search space 16-fold */
108823109136
nNew = nOut;
108824109137
if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){
108825
- nNew -= 20; assert( 20==whereCost(4) );
109138
+ nNew -= 20; assert( 20==sqlite3LogEst(4) );
108826109139
nOut--;
108827109140
}
108828109141
if( pUpper ){
108829
- nNew -= 20; assert( 20==whereCost(4) );
109142
+ nNew -= 20; assert( 20==sqlite3LogEst(4) );
108830109143
nOut--;
108831109144
}
108832109145
if( nNew<10 ) nNew = 10;
108833109146
if( nNew<nOut ) nOut = nNew;
108834
- *pnOut = (WhereCost)nOut;
109147
+ pLoop->nOut = (LogEst)nOut;
108835109148
return rc;
108836109149
}
108837109150
108838109151
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
108839109152
/*
@@ -110473,11 +110786,11 @@
110473110786
*/
110474110787
static int whereLoopAddBtreeIndex(
110475110788
WhereLoopBuilder *pBuilder, /* The WhereLoop factory */
110476110789
struct SrcList_item *pSrc, /* FROM clause term being analyzed */
110477110790
Index *pProbe, /* An index on pSrc */
110478
- WhereCost nInMul /* log(Number of iterations due to IN) */
110791
+ LogEst nInMul /* log(Number of iterations due to IN) */
110479110792
){
110480110793
WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */
110481110794
Parse *pParse = pWInfo->pParse; /* Parsing context */
110482110795
sqlite3 *db = pParse->db; /* Database connection malloc context */
110483110796
WhereLoop *pNew; /* Template WhereLoop under construction */
@@ -110486,15 +110799,15 @@
110486110799
WhereScan scan; /* Iterator for WHERE terms */
110487110800
Bitmask saved_prereq; /* Original value of pNew->prereq */
110488110801
u16 saved_nLTerm; /* Original value of pNew->nLTerm */
110489110802
int saved_nEq; /* Original value of pNew->u.btree.nEq */
110490110803
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
110491
- WhereCost saved_nOut; /* Original value of pNew->nOut */
110804
+ LogEst saved_nOut; /* Original value of pNew->nOut */
110492110805
int iCol; /* Index of the column in the table */
110493110806
int rc = SQLITE_OK; /* Return code */
110494
- WhereCost nRowEst; /* Estimated index selectivity */
110495
- WhereCost rLogSize; /* Logarithm of table size */
110807
+ LogEst nRowEst; /* Estimated index selectivity */
110808
+ LogEst rLogSize; /* Logarithm of table size */
110496110809
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
110497110810
110498110811
pNew = pBuilder->pNew;
110499110812
if( db->mallocFailed ) return SQLITE_NOMEM;
110500110813
@@ -110510,11 +110823,11 @@
110510110823
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
110511110824
110512110825
assert( pNew->u.btree.nEq<=pProbe->nColumn );
110513110826
if( pNew->u.btree.nEq < pProbe->nColumn ){
110514110827
iCol = pProbe->aiColumn[pNew->u.btree.nEq];
110515
- nRowEst = whereCost(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
110828
+ nRowEst = sqlite3LogEst(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
110516110829
if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1;
110517110830
}else{
110518110831
iCol = -1;
110519110832
nRowEst = 0;
110520110833
}
@@ -110524,11 +110837,11 @@
110524110837
saved_nLTerm = pNew->nLTerm;
110525110838
saved_wsFlags = pNew->wsFlags;
110526110839
saved_prereq = pNew->prereq;
110527110840
saved_nOut = pNew->nOut;
110528110841
pNew->rSetup = 0;
110529
- rLogSize = estLog(whereCost(pProbe->aiRowEst[0]));
110842
+ rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0]));
110530110843
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
110531110844
int nIn = 0;
110532110845
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
110533110846
int nRecValid = pBuilder->nRecValid;
110534110847
#endif
@@ -110551,14 +110864,14 @@
110551110864
if( pTerm->eOperator & WO_IN ){
110552110865
Expr *pExpr = pTerm->pExpr;
110553110866
pNew->wsFlags |= WHERE_COLUMN_IN;
110554110867
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
110555110868
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
110556
- nIn = 46; assert( 46==whereCost(25) );
110869
+ nIn = 46; assert( 46==sqlite3LogEst(25) );
110557110870
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
110558110871
/* "x IN (value, value, ...)" */
110559
- nIn = whereCost(pExpr->x.pList->nExpr);
110872
+ nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
110560110873
}
110561110874
pNew->rRun += nIn;
110562110875
pNew->u.btree.nEq++;
110563110876
pNew->nOut = nRowEst + nInMul + nIn;
110564110877
}else if( pTerm->eOperator & (WO_EQ) ){
@@ -110576,11 +110889,11 @@
110576110889
pNew->nOut = nRowEst + nInMul;
110577110890
}else if( pTerm->eOperator & (WO_ISNULL) ){
110578110891
pNew->wsFlags |= WHERE_COLUMN_NULL;
110579110892
pNew->u.btree.nEq++;
110580110893
/* TUNING: IS NULL selects 2 rows */
110581
- nIn = 10; assert( 10==whereCost(2) );
110894
+ nIn = 10; assert( 10==sqlite3LogEst(2) );
110582110895
pNew->nOut = nRowEst + nInMul + nIn;
110583110896
}else if( pTerm->eOperator & (WO_GT|WO_GE) ){
110584110897
testcase( pTerm->eOperator & WO_GT );
110585110898
testcase( pTerm->eOperator & WO_GE );
110586110899
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
@@ -110596,11 +110909,11 @@
110596110909
pNew->aLTerm[pNew->nLTerm-2] : 0;
110597110910
}
110598110911
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
110599110912
/* Adjust nOut and rRun for STAT3 range values */
110600110913
assert( pNew->nOut==saved_nOut );
110601
- whereRangeScanEst(pParse, pBuilder, pBtm, pTop, &pNew->nOut);
110914
+ whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew);
110602110915
}
110603110916
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
110604110917
if( nInMul==0
110605110918
&& pProbe->nSample
110606110919
&& pNew->u.btree.nEq<=pProbe->nSampleCol
@@ -110616,22 +110929,22 @@
110616110929
&& !ExprHasProperty(pExpr, EP_xIsSelect) ){
110617110930
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
110618110931
}
110619110932
assert( nOut==0 || rc==SQLITE_OK );
110620110933
if( nOut ){
110621
- nOut = whereCost(nOut);
110934
+ nOut = sqlite3LogEst(nOut);
110622110935
pNew->nOut = MIN(nOut, saved_nOut);
110623110936
}
110624110937
}
110625110938
#endif
110626110939
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
110627110940
/* Each row involves a step of the index, then a binary search of
110628110941
** the main table */
110629
- pNew->rRun = whereCostAdd(pNew->rRun, rLogSize>27 ? rLogSize-17 : 10);
110942
+ pNew->rRun = sqlite3LogEstAdd(pNew->rRun,rLogSize>27 ? rLogSize-17 : 10);
110630110943
}
110631110944
/* Step cost for each output row */
110632
- pNew->rRun = whereCostAdd(pNew->rRun, pNew->nOut);
110945
+ pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut);
110633110946
whereLoopOutputAdjust(pBuilder->pWC, pNew, pSrc->iCursor);
110634110947
rc = whereLoopInsert(pBuilder, pNew);
110635110948
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
110636110949
&& pNew->u.btree.nEq<(pProbe->nColumn + (pProbe->zName!=0))
110637110950
){
@@ -110727,18 +111040,20 @@
110727111040
struct SrcList_item *pSrc; /* The FROM clause btree term to add */
110728111041
WhereLoop *pNew; /* Template WhereLoop object */
110729111042
int rc = SQLITE_OK; /* Return code */
110730111043
int iSortIdx = 1; /* Index number */
110731111044
int b; /* A boolean value */
110732
- WhereCost rSize; /* number of rows in the table */
110733
- WhereCost rLogSize; /* Logarithm of the number of rows in the table */
111045
+ LogEst rSize; /* number of rows in the table */
111046
+ LogEst rLogSize; /* Logarithm of the number of rows in the table */
110734111047
WhereClause *pWC; /* The parsed WHERE clause */
111048
+ Table *pTab; /* Table being queried */
110735111049
110736111050
pNew = pBuilder->pNew;
110737111051
pWInfo = pBuilder->pWInfo;
110738111052
pTabList = pWInfo->pTabList;
110739111053
pSrc = pTabList->a + pNew->iTab;
111054
+ pTab = pSrc->pTab;
110740111055
pWC = pBuilder->pWC;
110741111056
assert( !IsVirtual(pSrc->pTab) );
110742111057
110743111058
if( pSrc->pIndex ){
110744111059
/* An INDEXED BY clause specifies a particular index to use */
@@ -110752,22 +111067,22 @@
110752111067
memset(&sPk, 0, sizeof(Index));
110753111068
sPk.nColumn = 1;
110754111069
sPk.aiColumn = &aiColumnPk;
110755111070
sPk.aiRowEst = aiRowEstPk;
110756111071
sPk.onError = OE_Replace;
110757
- sPk.pTable = pSrc->pTab;
110758
- aiRowEstPk[0] = pSrc->pTab->nRowEst;
111072
+ sPk.pTable = pTab;
111073
+ aiRowEstPk[0] = pTab->nRowEst;
110759111074
aiRowEstPk[1] = 1;
110760111075
pFirst = pSrc->pTab->pIndex;
110761111076
if( pSrc->notIndexed==0 ){
110762111077
/* The real indices of the table are only considered if the
110763111078
** NOT INDEXED qualifier is omitted from the FROM clause */
110764111079
sPk.pNext = pFirst;
110765111080
}
110766111081
pProbe = &sPk;
110767111082
}
110768
- rSize = whereCost(pSrc->pTab->nRowEst);
111083
+ rSize = sqlite3LogEst(pTab->nRowEst);
110769111084
rLogSize = estLog(rSize);
110770111085
110771111086
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
110772111087
/* Automatic indexes */
110773111088
if( !pBuilder->pOrSet
@@ -110788,17 +111103,17 @@
110788111103
pNew->nLTerm = 1;
110789111104
pNew->aLTerm[0] = pTerm;
110790111105
/* TUNING: One-time cost for computing the automatic index is
110791111106
** approximately 7*N*log2(N) where N is the number of rows in
110792111107
** the table being indexed. */
110793
- pNew->rSetup = rLogSize + rSize + 28; assert( 28==whereCost(7) );
111108
+ pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) );
110794111109
/* TUNING: Each index lookup yields 20 rows in the table. This
110795111110
** is more than the usual guess of 10 rows, since we have no way
110796111111
** of knowning how selective the index will ultimately be. It would
110797111112
** not be unreasonable to make this value much larger. */
110798
- pNew->nOut = 43; assert( 43==whereCost(20) );
110799
- pNew->rRun = whereCostAdd(rLogSize,pNew->nOut);
111113
+ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
111114
+ pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
110800111115
pNew->wsFlags = WHERE_AUTO_INDEX;
110801111116
pNew->prereq = mExtra | pTerm->prereqRight;
110802111117
rc = whereLoopInsert(pBuilder, pNew);
110803111118
}
110804111119
}
@@ -110828,14 +111143,12 @@
110828111143
110829111144
/* Full table scan */
110830111145
pNew->iSortIdx = b ? iSortIdx : 0;
110831111146
/* TUNING: Cost of full table scan is 3*(N + log2(N)).
110832111147
** + The extra 3 factor is to encourage the use of indexed lookups
110833
- ** over full scans. A smaller constant 2 is used for covering
110834
- ** index scans so that a covering index scan will be favored over
110835
- ** a table scan. */
110836
- pNew->rRun = whereCostAdd(rSize,rLogSize) + 16;
111148
+ ** over full scans. FIXME */
111149
+ pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 16;
110837111150
whereLoopOutputAdjust(pWC, pNew, pSrc->iCursor);
110838111151
rc = whereLoopInsert(pBuilder, pNew);
110839111152
pNew->nOut = rSize;
110840111153
if( rc ) break;
110841111154
}else{
@@ -110844,26 +111157,25 @@
110844111157
110845111158
/* Full scan via index */
110846111159
if( b
110847111160
|| ( m==0
110848111161
&& pProbe->bUnordered==0
111162
+ && pProbe->szIdxRow<pTab->szTabRow
110849111163
&& (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0
110850111164
&& sqlite3GlobalConfig.bUseCis
110851111165
&& OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan)
110852111166
)
110853111167
){
110854111168
pNew->iSortIdx = b ? iSortIdx : 0;
110855111169
if( m==0 ){
110856
- /* TUNING: Cost of a covering index scan is 2*(N + log2(N)).
110857
- ** + The extra 2 factor is to encourage the use of indexed lookups
110858
- ** over index scans. A table scan uses a factor of 3 so that
110859
- ** index scans are favored over table scans.
110860
- ** + If this covering index might also help satisfy the ORDER BY
110861
- ** clause, then the cost is fudged down slightly so that this
110862
- ** index is favored above other indices that have no hope of
110863
- ** helping with the ORDER BY. */
110864
- pNew->rRun = 10 + whereCostAdd(rSize,rLogSize) - b;
111170
+ /* TUNING: Cost of a covering index scan is K*(N + log2(N)).
111171
+ ** + The extra factor K of between 1.1 and 3.0 that depends
111172
+ ** on the relative sizes of the table and the index. K
111173
+ ** is smaller for smaller indices, thus favoring them.
111174
+ */
111175
+ pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 1 +
111176
+ (15*pProbe->szIdxRow)/pTab->szTabRow;
110865111177
}else{
110866111178
assert( b!=0 );
110867111179
/* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N)
110868111180
** which we will simplify to just N*log2(N) */
110869111181
pNew->rRun = rSize + rLogSize;
@@ -111037,13 +111349,13 @@
111037111349
pIdxInfo->needToFreeIdxStr = 0;
111038111350
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
111039111351
pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0)
111040111352
&& pIdxInfo->orderByConsumed);
111041111353
pNew->rSetup = 0;
111042
- pNew->rRun = whereCostFromDouble(pIdxInfo->estimatedCost);
111354
+ pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
111043111355
/* TUNING: Every virtual table query returns 25 rows */
111044
- pNew->nOut = 46; assert( 46==whereCost(25) );
111356
+ pNew->nOut = 46; assert( 46==sqlite3LogEst(25) );
111045111357
whereLoopInsert(pBuilder, pNew);
111046111358
if( pNew->u.vtab.needFree ){
111047111359
sqlite3_free(pNew->u.vtab.idxStr);
111048111360
pNew->u.vtab.needFree = 0;
111049111361
}
@@ -111076,10 +111388,12 @@
111076111388
pWC = pBuilder->pWC;
111077111389
if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
111078111390
pWCEnd = pWC->a + pWC->nTerm;
111079111391
pNew = pBuilder->pNew;
111080111392
memset(&sSum, 0, sizeof(sSum));
111393
+ pItem = pWInfo->pTabList->a + pNew->iTab;
111394
+ iCur = pItem->iCursor;
111081111395
111082111396
for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
111083111397
if( (pTerm->eOperator & WO_OR)!=0
111084111398
&& (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
111085111399
){
@@ -111087,12 +111401,10 @@
111087111401
WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
111088111402
WhereTerm *pOrTerm;
111089111403
int once = 1;
111090111404
int i, j;
111091111405
111092
- pItem = pWInfo->pTabList->a + pNew->iTab;
111093
- iCur = pItem->iCursor;
111094111406
sSubBuild = *pBuilder;
111095111407
sSubBuild.pOrderBy = 0;
111096111408
sSubBuild.pOrSet = &sCur;
111097111409
111098111410
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
@@ -111129,12 +111441,12 @@
111129111441
whereOrMove(&sPrev, &sSum);
111130111442
sSum.n = 0;
111131111443
for(i=0; i<sPrev.n; i++){
111132111444
for(j=0; j<sCur.n; j++){
111133111445
whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq,
111134
- whereCostAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
111135
- whereCostAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
111446
+ sqlite3LogEstAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
111447
+ sqlite3LogEstAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
111136111448
}
111137111449
}
111138111450
}
111139111451
}
111140111452
pNew->nLTerm = 1;
@@ -111468,23 +111780,23 @@
111468111780
** costs if nRowEst==0.
111469111781
**
111470111782
** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation
111471111783
** error occurs.
111472111784
*/
111473
-static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
111785
+static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
111474111786
int mxChoice; /* Maximum number of simultaneous paths tracked */
111475111787
int nLoop; /* Number of terms in the join */
111476111788
Parse *pParse; /* Parsing context */
111477111789
sqlite3 *db; /* The database connection */
111478111790
int iLoop; /* Loop counter over the terms of the join */
111479111791
int ii, jj; /* Loop counters */
111480111792
int mxI = 0; /* Index of next entry to replace */
111481
- WhereCost rCost; /* Cost of a path */
111482
- WhereCost nOut; /* Number of outputs */
111483
- WhereCost mxCost = 0; /* Maximum cost of a set of paths */
111484
- WhereCost mxOut = 0; /* Maximum nOut value on the set of paths */
111485
- WhereCost rSortCost; /* Cost to do a sort */
111793
+ LogEst rCost; /* Cost of a path */
111794
+ LogEst nOut; /* Number of outputs */
111795
+ LogEst mxCost = 0; /* Maximum cost of a set of paths */
111796
+ LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
111797
+ LogEst rSortCost; /* Cost to do a sort */
111486111798
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
111487111799
WherePath *aFrom; /* All nFrom paths at the previous level */
111488111800
WherePath *aTo; /* The nTo best paths at the current level */
111489111801
WherePath *pFrom; /* An element of aFrom[] that we are working on */
111490111802
WherePath *pTo; /* An element of aTo[] that we are working on */
@@ -111517,21 +111829,23 @@
111517111829
/* Seed the search with a single WherePath containing zero WhereLoops.
111518111830
**
111519111831
** TUNING: Do not let the number of iterations go above 25. If the cost
111520111832
** of computing an automatic index is not paid back within the first 25
111521111833
** rows, then do not use the automatic index. */
111522
- aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==whereCost(25) );
111834
+ aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
111523111835
nFrom = 1;
111524111836
111525111837
/* Precompute the cost of sorting the final result set, if the caller
111526111838
** to sqlite3WhereBegin() was concerned about sorting */
111527111839
rSortCost = 0;
111528111840
if( pWInfo->pOrderBy==0 || nRowEst==0 ){
111529111841
aFrom[0].isOrderedValid = 1;
111530111842
}else{
111531
- /* TUNING: Estimated cost of sorting is N*log2(N) where N is the
111532
- ** number of output rows. */
111843
+ /* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the
111844
+ ** number of output rows. The 48 is the expected size of a row to sort.
111845
+ ** FIXME: compute a better estimate of the 48 multiplier based on the
111846
+ ** result set expressions. */
111533111847
rSortCost = nRowEst + estLog(nRowEst);
111534111848
WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost));
111535111849
}
111536111850
111537111851
/* Compute successively longer WherePaths using the previous generation
@@ -111547,12 +111861,12 @@
111547111861
u8 isOrdered = pFrom->isOrdered;
111548111862
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
111549111863
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
111550111864
/* At this point, pWLoop is a candidate to be the next loop.
111551111865
** Compute its cost */
111552
- rCost = whereCostAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
111553
- rCost = whereCostAdd(rCost, pFrom->rCost);
111866
+ rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
111867
+ rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
111554111868
nOut = pFrom->nRow + pWLoop->nOut;
111555111869
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
111556111870
if( !isOrderedValid ){
111557111871
switch( wherePathSatisfiesOrderBy(pWInfo,
111558111872
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
@@ -111562,11 +111876,11 @@
111562111876
isOrderedValid = 1;
111563111877
break;
111564111878
case 0: /* No. pFrom+pWLoop will require a separate sort */
111565111879
isOrdered = 0;
111566111880
isOrderedValid = 1;
111567
- rCost = whereCostAdd(rCost, rSortCost);
111881
+ rCost = sqlite3LogEstAdd(rCost, rSortCost);
111568111882
break;
111569111883
default: /* Cannot tell yet. Try again on the next iteration */
111570111884
break;
111571111885
}
111572111886
}else{
@@ -111769,11 +112083,11 @@
111769112083
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
111770112084
pLoop->aLTerm[0] = pTerm;
111771112085
pLoop->nLTerm = 1;
111772112086
pLoop->u.btree.nEq = 1;
111773112087
/* TUNING: Cost of a rowid lookup is 10 */
111774
- pLoop->rRun = 33; /* 33==whereCost(10) */
112088
+ pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */
111775112089
}else{
111776112090
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
111777112091
assert( pLoop->aLTermSpace==pLoop->aLTerm );
111778112092
assert( ArraySize(pLoop->aLTermSpace)==4 );
111779112093
if( pIdx->onError==OE_None
@@ -111792,16 +112106,16 @@
111792112106
}
111793112107
pLoop->nLTerm = j;
111794112108
pLoop->u.btree.nEq = j;
111795112109
pLoop->u.btree.pIndex = pIdx;
111796112110
/* TUNING: Cost of a unique index lookup is 15 */
111797
- pLoop->rRun = 39; /* 39==whereCost(15) */
112111
+ pLoop->rRun = 39; /* 39==sqlite3LogEst(15) */
111798112112
break;
111799112113
}
111800112114
}
111801112115
if( pLoop->wsFlags ){
111802
- pLoop->nOut = (WhereCost)1;
112116
+ pLoop->nOut = (LogEst)1;
111803112117
pWInfo->a[0].pWLoop = pLoop;
111804112118
pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
111805112119
pWInfo->a[0].iTabCur = iCur;
111806112120
pWInfo->nRowOut = 1;
111807112121
if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1;
@@ -112165,11 +112479,11 @@
112165112479
WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
112166112480
pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;
112167112481
112168112482
/* If the caller is an UPDATE or DELETE statement that is requesting
112169112483
** to use a one-pass algorithm, determine if this is appropriate.
112170
- ** The one-pass algorithm only works if the WHERE clause constraints
112484
+ ** The one-pass algorithm only works if the WHERE clause constrains
112171112485
** the statement to update a single row.
112172112486
*/
112173112487
assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
112174112488
if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
112175112489
&& (pWInfo->a[0].pWLoop->wsFlags & WHERE_ONEROW)!=0 ){
@@ -121583,10 +121897,16 @@
121583121897
** verifying the operation of the SQLite core.
121584121898
*/
121585121899
int inTransaction; /* True after xBegin but before xCommit/xRollback */
121586121900
int mxSavepoint; /* Largest valid xSavepoint integer */
121587121901
#endif
121902
+
121903
+#ifdef SQLITE_TEST
121904
+ /* True to disable the incremental doclist optimization. This is controled
121905
+ ** by special insert command 'test-no-incr-doclist'. */
121906
+ int bNoIncrDoclist;
121907
+#endif
121588121908
};
121589121909
121590121910
/*
121591121911
** When the core wants to read from the virtual table, it creates a
121592121912
** virtual table cursor (an instance of the following structure) using
@@ -121608,11 +121928,12 @@
121608121928
int nDoclist; /* Size of buffer at aDoclist */
121609121929
u8 bDesc; /* True to sort in descending order */
121610121930
int eEvalmode; /* An FTS3_EVAL_XX constant */
121611121931
int nRowAvg; /* Average size of database rows, in pages */
121612121932
sqlite3_int64 nDoc; /* Documents in table */
121613
-
121933
+ i64 iMinDocid; /* Minimum docid to return */
121934
+ i64 iMaxDocid; /* Maximum docid to return */
121614121935
int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
121615121936
u32 *aMatchinfo; /* Information about most recent match */
121616121937
int nMatchinfo; /* Number of elements in aMatchinfo[] */
121617121938
char *zMatchinfo; /* Matchinfo specification */
121618121939
};
@@ -121638,10 +121959,19 @@
121638121959
*/
121639121960
#define FTS3_FULLSCAN_SEARCH 0 /* Linear scan of %_content table */
121640121961
#define FTS3_DOCID_SEARCH 1 /* Lookup by rowid on %_content table */
121641121962
#define FTS3_FULLTEXT_SEARCH 2 /* Full-text index search */
121642121963
121964
+/*
121965
+** The lower 16-bits of the sqlite3_index_info.idxNum value set by
121966
+** the xBestIndex() method contains the Fts3Cursor.eSearch value described
121967
+** above. The upper 16-bits contain a combination of the following
121968
+** bits, used to describe extra constraints on full-text searches.
121969
+*/
121970
+#define FTS3_HAVE_LANGID 0x00010000 /* languageid=? */
121971
+#define FTS3_HAVE_DOCID_GE 0x00020000 /* docid>=? */
121972
+#define FTS3_HAVE_DOCID_LE 0x00040000 /* docid<=? */
121643121973
121644121974
struct Fts3Doclist {
121645121975
char *aAll; /* Array containing doclist (or NULL) */
121646121976
int nAll; /* Size of a[] in bytes */
121647121977
char *pNextDocid; /* Pointer to next docid */
@@ -123058,27 +123388,31 @@
123058123388
*/
123059123389
static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
123060123390
Fts3Table *p = (Fts3Table *)pVTab;
123061123391
int i; /* Iterator variable */
123062123392
int iCons = -1; /* Index of constraint to use */
123393
+
123063123394
int iLangidCons = -1; /* Index of langid=x constraint, if present */
123395
+ int iDocidGe = -1; /* Index of docid>=x constraint, if present */
123396
+ int iDocidLe = -1; /* Index of docid<=x constraint, if present */
123397
+ int iIdx;
123064123398
123065123399
/* By default use a full table scan. This is an expensive option,
123066123400
** so search through the constraints to see if a more efficient
123067123401
** strategy is possible.
123068123402
*/
123069123403
pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
123070123404
pInfo->estimatedCost = 5000000;
123071123405
for(i=0; i<pInfo->nConstraint; i++){
123406
+ int bDocid; /* True if this constraint is on docid */
123072123407
struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i];
123073123408
if( pCons->usable==0 ) continue;
123409
+
123410
+ bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1);
123074123411
123075123412
/* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */
123076
- if( iCons<0
123077
- && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
123078
- && (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1 )
123079
- ){
123413
+ if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){
123080123414
pInfo->idxNum = FTS3_DOCID_SEARCH;
123081123415
pInfo->estimatedCost = 1.0;
123082123416
iCons = i;
123083123417
}
123084123418
@@ -123103,18 +123437,42 @@
123103123437
if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
123104123438
&& pCons->iColumn==p->nColumn + 2
123105123439
){
123106123440
iLangidCons = i;
123107123441
}
123442
+
123443
+ if( bDocid ){
123444
+ switch( pCons->op ){
123445
+ case SQLITE_INDEX_CONSTRAINT_GE:
123446
+ case SQLITE_INDEX_CONSTRAINT_GT:
123447
+ iDocidGe = i;
123448
+ break;
123449
+
123450
+ case SQLITE_INDEX_CONSTRAINT_LE:
123451
+ case SQLITE_INDEX_CONSTRAINT_LT:
123452
+ iDocidLe = i;
123453
+ break;
123454
+ }
123455
+ }
123108123456
}
123109123457
123458
+ iIdx = 1;
123110123459
if( iCons>=0 ){
123111
- pInfo->aConstraintUsage[iCons].argvIndex = 1;
123460
+ pInfo->aConstraintUsage[iCons].argvIndex = iIdx++;
123112123461
pInfo->aConstraintUsage[iCons].omit = 1;
123113123462
}
123114123463
if( iLangidCons>=0 ){
123115
- pInfo->aConstraintUsage[iLangidCons].argvIndex = 2;
123464
+ pInfo->idxNum |= FTS3_HAVE_LANGID;
123465
+ pInfo->aConstraintUsage[iLangidCons].argvIndex = iIdx++;
123466
+ }
123467
+ if( iDocidGe>=0 ){
123468
+ pInfo->idxNum |= FTS3_HAVE_DOCID_GE;
123469
+ pInfo->aConstraintUsage[iDocidGe].argvIndex = iIdx++;
123470
+ }
123471
+ if( iDocidLe>=0 ){
123472
+ pInfo->idxNum |= FTS3_HAVE_DOCID_LE;
123473
+ pInfo->aConstraintUsage[iDocidLe].argvIndex = iIdx++;
123116123474
}
123117123475
123118123476
/* Regardless of the strategy selected, FTS can deliver rows in rowid (or
123119123477
** docid) order. Both ascending and descending are possible.
123120123478
*/
@@ -124556,10 +124914,37 @@
124556124914
rc = fts3EvalNext((Fts3Cursor *)pCursor);
124557124915
}
124558124916
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
124559124917
return rc;
124560124918
}
124919
+
124920
+/*
124921
+** The following are copied from sqliteInt.h.
124922
+**
124923
+** Constants for the largest and smallest possible 64-bit signed integers.
124924
+** These macros are designed to work correctly on both 32-bit and 64-bit
124925
+** compilers.
124926
+*/
124927
+#ifndef SQLITE_AMALGAMATION
124928
+# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
124929
+# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
124930
+#endif
124931
+
124932
+/*
124933
+** If the numeric type of argument pVal is "integer", then return it
124934
+** converted to a 64-bit signed integer. Otherwise, return a copy of
124935
+** the second parameter, iDefault.
124936
+*/
124937
+static sqlite3_int64 fts3DocidRange(sqlite3_value *pVal, i64 iDefault){
124938
+ if( pVal ){
124939
+ int eType = sqlite3_value_numeric_type(pVal);
124940
+ if( eType==SQLITE_INTEGER ){
124941
+ return sqlite3_value_int64(pVal);
124942
+ }
124943
+ }
124944
+ return iDefault;
124945
+}
124561124946
124562124947
/*
124563124948
** This is the xFilter interface for the virtual table. See
124564124949
** the virtual table xFilter method documentation for additional
124565124950
** information.
@@ -124582,44 +124967,62 @@
124582124967
int nVal, /* Number of elements in apVal */
124583124968
sqlite3_value **apVal /* Arguments for the indexing scheme */
124584124969
){
124585124970
int rc;
124586124971
char *zSql; /* SQL statement used to access %_content */
124972
+ int eSearch;
124587124973
Fts3Table *p = (Fts3Table *)pCursor->pVtab;
124588124974
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
124975
+
124976
+ sqlite3_value *pCons = 0; /* The MATCH or rowid constraint, if any */
124977
+ sqlite3_value *pLangid = 0; /* The "langid = ?" constraint, if any */
124978
+ sqlite3_value *pDocidGe = 0; /* The "docid >= ?" constraint, if any */
124979
+ sqlite3_value *pDocidLe = 0; /* The "docid <= ?" constraint, if any */
124980
+ int iIdx;
124589124981
124590124982
UNUSED_PARAMETER(idxStr);
124591124983
UNUSED_PARAMETER(nVal);
124592124984
124593
- assert( idxNum>=0 && idxNum<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
124594
- assert( nVal==0 || nVal==1 || nVal==2 );
124595
- assert( (nVal==0)==(idxNum==FTS3_FULLSCAN_SEARCH) );
124985
+ eSearch = (idxNum & 0x0000FFFF);
124986
+ assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
124596124987
assert( p->pSegments==0 );
124988
+
124989
+ /* Collect arguments into local variables */
124990
+ iIdx = 0;
124991
+ if( eSearch!=FTS3_FULLSCAN_SEARCH ) pCons = apVal[iIdx++];
124992
+ if( idxNum & FTS3_HAVE_LANGID ) pLangid = apVal[iIdx++];
124993
+ if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++];
124994
+ if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++];
124995
+ assert( iIdx==nVal );
124597124996
124598124997
/* In case the cursor has been used before, clear it now. */
124599124998
sqlite3_finalize(pCsr->pStmt);
124600124999
sqlite3_free(pCsr->aDoclist);
124601125000
sqlite3Fts3ExprFree(pCsr->pExpr);
124602125001
memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
124603125002
125003
+ /* Set the lower and upper bounds on docids to return */
125004
+ pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64);
125005
+ pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64);
125006
+
124604125007
if( idxStr ){
124605125008
pCsr->bDesc = (idxStr[0]=='D');
124606125009
}else{
124607125010
pCsr->bDesc = p->bDescIdx;
124608125011
}
124609
- pCsr->eSearch = (i16)idxNum;
125012
+ pCsr->eSearch = (i16)eSearch;
124610125013
124611
- if( idxNum!=FTS3_DOCID_SEARCH && idxNum!=FTS3_FULLSCAN_SEARCH ){
124612
- int iCol = idxNum-FTS3_FULLTEXT_SEARCH;
124613
- const char *zQuery = (const char *)sqlite3_value_text(apVal[0]);
125014
+ if( eSearch!=FTS3_DOCID_SEARCH && eSearch!=FTS3_FULLSCAN_SEARCH ){
125015
+ int iCol = eSearch-FTS3_FULLTEXT_SEARCH;
125016
+ const char *zQuery = (const char *)sqlite3_value_text(pCons);
124614125017
124615
- if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
125018
+ if( zQuery==0 && sqlite3_value_type(pCons)!=SQLITE_NULL ){
124616125019
return SQLITE_NOMEM;
124617125020
}
124618125021
124619125022
pCsr->iLangid = 0;
124620
- if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]);
125023
+ if( pLangid ) pCsr->iLangid = sqlite3_value_int(pLangid);
124621125024
124622125025
assert( p->base.zErrMsg==0 );
124623125026
rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
124624125027
p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr,
124625125028
&p->base.zErrMsg
@@ -124638,11 +125041,11 @@
124638125041
/* Compile a SELECT statement for this cursor. For a full-table-scan, the
124639125042
** statement loops through all rows of the %_content table. For a
124640125043
** full-text query or docid lookup, the statement retrieves a single
124641125044
** row by docid.
124642125045
*/
124643
- if( idxNum==FTS3_FULLSCAN_SEARCH ){
125046
+ if( eSearch==FTS3_FULLSCAN_SEARCH ){
124644125047
zSql = sqlite3_mprintf(
124645125048
"SELECT %s ORDER BY rowid %s",
124646125049
p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
124647125050
);
124648125051
if( zSql ){
@@ -124649,14 +125052,14 @@
124649125052
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
124650125053
sqlite3_free(zSql);
124651125054
}else{
124652125055
rc = SQLITE_NOMEM;
124653125056
}
124654
- }else if( idxNum==FTS3_DOCID_SEARCH ){
125057
+ }else if( eSearch==FTS3_DOCID_SEARCH ){
124655125058
rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
124656125059
if( rc==SQLITE_OK ){
124657
- rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
125060
+ rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons);
124658125061
}
124659125062
}
124660125063
if( rc!=SQLITE_OK ) return rc;
124661125064
124662125065
return fts3NextMethod(pCursor);
@@ -125543,10 +125946,16 @@
125543125946
}
125544125947
125545125948
return SQLITE_OK;
125546125949
}
125547125950
125951
+/*
125952
+** Maximum number of tokens a phrase may have to be considered for the
125953
+** incremental doclists strategy.
125954
+*/
125955
+#define MAX_INCR_PHRASE_TOKENS 4
125956
+
125548125957
/*
125549125958
** This function is called for each Fts3Phrase in a full-text query
125550125959
** expression to initialize the mechanism for returning rows. Once this
125551125960
** function has been called successfully on an Fts3Phrase, it may be
125552125961
** used with fts3EvalPhraseNext() to iterate through the matching docids.
@@ -125556,27 +125965,47 @@
125556125965
** memory within this call.
125557125966
**
125558125967
** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
125559125968
*/
125560125969
static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
125561
- int rc; /* Error code */
125562
- Fts3PhraseToken *pFirst = &p->aToken[0];
125563125970
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
125564
-
125565
- if( pCsr->bDesc==pTab->bDescIdx
125566
- && bOptOk==1
125567
- && p->nToken==1
125568
- && pFirst->pSegcsr
125569
- && pFirst->pSegcsr->bLookup
125570
- && pFirst->bFirst==0
125571
- ){
125971
+ int rc = SQLITE_OK; /* Error code */
125972
+ int i;
125973
+
125974
+ /* Determine if doclists may be loaded from disk incrementally. This is
125975
+ ** possible if the bOptOk argument is true, the FTS doclists will be
125976
+ ** scanned in forward order, and the phrase consists of
125977
+ ** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first"
125978
+ ** tokens or prefix tokens that cannot use a prefix-index. */
125979
+ int bHaveIncr = 0;
125980
+ int bIncrOk = (bOptOk
125981
+ && pCsr->bDesc==pTab->bDescIdx
125982
+ && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
125983
+ && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
125984
+#ifdef SQLITE_TEST
125985
+ && pTab->bNoIncrDoclist==0
125986
+#endif
125987
+ );
125988
+ for(i=0; bIncrOk==1 && i<p->nToken; i++){
125989
+ Fts3PhraseToken *pToken = &p->aToken[i];
125990
+ if( pToken->bFirst || (pToken->pSegcsr!=0 && !pToken->pSegcsr->bLookup) ){
125991
+ bIncrOk = 0;
125992
+ }
125993
+ if( pToken->pSegcsr ) bHaveIncr = 1;
125994
+ }
125995
+
125996
+ if( bIncrOk && bHaveIncr ){
125572125997
/* Use the incremental approach. */
125573125998
int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
125574
- rc = sqlite3Fts3MsrIncrStart(
125575
- pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n);
125999
+ for(i=0; rc==SQLITE_OK && i<p->nToken; i++){
126000
+ Fts3PhraseToken *pToken = &p->aToken[i];
126001
+ Fts3MultiSegReader *pSegcsr = pToken->pSegcsr;
126002
+ if( pSegcsr ){
126003
+ rc = sqlite3Fts3MsrIncrStart(pTab, pSegcsr, iCol, pToken->z, pToken->n);
126004
+ }
126005
+ }
125576126006
p->bIncr = 1;
125577
-
125578126007
}else{
125579126008
/* Load the full doclist for the phrase into memory. */
125580126009
rc = fts3EvalPhraseLoad(pCsr, p);
125581126010
p->bIncr = 0;
125582126011
}
@@ -125680,10 +126109,220 @@
125680126109
}
125681126110
}
125682126111
125683126112
*ppIter = p;
125684126113
}
126114
+
126115
+/*
126116
+** Advance the iterator pDL to the next entry in pDL->aAll/nAll. Set *pbEof
126117
+** to true if EOF is reached.
126118
+*/
126119
+static void fts3EvalDlPhraseNext(
126120
+ Fts3Table *pTab,
126121
+ Fts3Doclist *pDL,
126122
+ u8 *pbEof
126123
+){
126124
+ char *pIter; /* Used to iterate through aAll */
126125
+ char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
126126
+
126127
+ if( pDL->pNextDocid ){
126128
+ pIter = pDL->pNextDocid;
126129
+ }else{
126130
+ pIter = pDL->aAll;
126131
+ }
126132
+
126133
+ if( pIter>=pEnd ){
126134
+ /* We have already reached the end of this doclist. EOF. */
126135
+ *pbEof = 1;
126136
+ }else{
126137
+ sqlite3_int64 iDelta;
126138
+ pIter += sqlite3Fts3GetVarint(pIter, &iDelta);
126139
+ if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
126140
+ pDL->iDocid += iDelta;
126141
+ }else{
126142
+ pDL->iDocid -= iDelta;
126143
+ }
126144
+ pDL->pList = pIter;
126145
+ fts3PoslistCopy(0, &pIter);
126146
+ pDL->nList = (int)(pIter - pDL->pList);
126147
+
126148
+ /* pIter now points just past the 0x00 that terminates the position-
126149
+ ** list for document pDL->iDocid. However, if this position-list was
126150
+ ** edited in place by fts3EvalNearTrim(), then pIter may not actually
126151
+ ** point to the start of the next docid value. The following line deals
126152
+ ** with this case by advancing pIter past the zero-padding added by
126153
+ ** fts3EvalNearTrim(). */
126154
+ while( pIter<pEnd && *pIter==0 ) pIter++;
126155
+
126156
+ pDL->pNextDocid = pIter;
126157
+ assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter );
126158
+ *pbEof = 0;
126159
+ }
126160
+}
126161
+
126162
+/*
126163
+** Helper type used by fts3EvalIncrPhraseNext() and incrPhraseTokenNext().
126164
+*/
126165
+typedef struct TokenDoclist TokenDoclist;
126166
+struct TokenDoclist {
126167
+ int bIgnore;
126168
+ sqlite3_int64 iDocid;
126169
+ char *pList;
126170
+ int nList;
126171
+};
126172
+
126173
+/*
126174
+** Token pToken is an incrementally loaded token that is part of a
126175
+** multi-token phrase. Advance it to the next matching document in the
126176
+** database and populate output variable *p with the details of the new
126177
+** entry. Or, if the iterator has reached EOF, set *pbEof to true.
126178
+**
126179
+** If an error occurs, return an SQLite error code. Otherwise, return
126180
+** SQLITE_OK.
126181
+*/
126182
+static int incrPhraseTokenNext(
126183
+ Fts3Table *pTab, /* Virtual table handle */
126184
+ Fts3Phrase *pPhrase, /* Phrase to advance token of */
126185
+ int iToken, /* Specific token to advance */
126186
+ TokenDoclist *p, /* OUT: Docid and doclist for new entry */
126187
+ u8 *pbEof /* OUT: True if iterator is at EOF */
126188
+){
126189
+ int rc = SQLITE_OK;
126190
+
126191
+ if( pPhrase->iDoclistToken==iToken ){
126192
+ assert( p->bIgnore==0 );
126193
+ assert( pPhrase->aToken[iToken].pSegcsr==0 );
126194
+ fts3EvalDlPhraseNext(pTab, &pPhrase->doclist, pbEof);
126195
+ p->pList = pPhrase->doclist.pList;
126196
+ p->nList = pPhrase->doclist.nList;
126197
+ p->iDocid = pPhrase->doclist.iDocid;
126198
+ }else{
126199
+ Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
126200
+ assert( pToken->pDeferred==0 );
126201
+ assert( pToken->pSegcsr || pPhrase->iDoclistToken>=0 );
126202
+ if( pToken->pSegcsr ){
126203
+ assert( p->bIgnore==0 );
126204
+ rc = sqlite3Fts3MsrIncrNext(
126205
+ pTab, pToken->pSegcsr, &p->iDocid, &p->pList, &p->nList
126206
+ );
126207
+ if( p->pList==0 ) *pbEof = 1;
126208
+ }else{
126209
+ p->bIgnore = 1;
126210
+ }
126211
+ }
126212
+
126213
+ return rc;
126214
+}
126215
+
126216
+
126217
+/*
126218
+** The phrase iterator passed as the second argument:
126219
+**
126220
+** * features at least one token that uses an incremental doclist, and
126221
+**
126222
+** * does not contain any deferred tokens.
126223
+**
126224
+** Advance it to the next matching documnent in the database and populate
126225
+** the Fts3Doclist.pList and nList fields.
126226
+**
126227
+** If there is no "next" entry and no error occurs, then *pbEof is set to
126228
+** 1 before returning. Otherwise, if no error occurs and the iterator is
126229
+** successfully advanced, *pbEof is set to 0.
126230
+**
126231
+** If an error occurs, return an SQLite error code. Otherwise, return
126232
+** SQLITE_OK.
126233
+*/
126234
+static int fts3EvalIncrPhraseNext(
126235
+ Fts3Cursor *pCsr, /* FTS Cursor handle */
126236
+ Fts3Phrase *p, /* Phrase object to advance to next docid */
126237
+ u8 *pbEof /* OUT: Set to 1 if EOF */
126238
+){
126239
+ int rc = SQLITE_OK;
126240
+ Fts3Doclist *pDL = &p->doclist;
126241
+ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
126242
+ u8 bEof = 0;
126243
+
126244
+ /* This is only called if it is guaranteed that the phrase has at least
126245
+ ** one incremental token. In which case the bIncr flag is set. */
126246
+ assert( p->bIncr==1 );
126247
+
126248
+ if( p->nToken==1 && p->bIncr ){
126249
+ rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
126250
+ &pDL->iDocid, &pDL->pList, &pDL->nList
126251
+ );
126252
+ if( pDL->pList==0 ) bEof = 1;
126253
+ }else{
126254
+ int bDescDoclist = pCsr->bDesc;
126255
+ struct TokenDoclist a[MAX_INCR_PHRASE_TOKENS];
126256
+
126257
+ memset(a, 0, sizeof(a));
126258
+ assert( p->nToken<=MAX_INCR_PHRASE_TOKENS );
126259
+ assert( p->iDoclistToken<MAX_INCR_PHRASE_TOKENS );
126260
+
126261
+ while( bEof==0 ){
126262
+ int bMaxSet = 0;
126263
+ sqlite3_int64 iMax; /* Largest docid for all iterators */
126264
+ int i; /* Used to iterate through tokens */
126265
+
126266
+ /* Advance the iterator for each token in the phrase once. */
126267
+ for(i=0; rc==SQLITE_OK && i<p->nToken; i++){
126268
+ rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
126269
+ if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){
126270
+ iMax = a[i].iDocid;
126271
+ bMaxSet = 1;
126272
+ }
126273
+ }
126274
+ assert( rc!=SQLITE_OK || a[p->nToken-1].bIgnore==0 );
126275
+ assert( rc!=SQLITE_OK || bMaxSet );
126276
+
126277
+ /* Keep advancing iterators until they all point to the same document */
126278
+ for(i=0; i<p->nToken; i++){
126279
+ while( rc==SQLITE_OK && bEof==0
126280
+ && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0
126281
+ ){
126282
+ rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
126283
+ if( DOCID_CMP(a[i].iDocid, iMax)>0 ){
126284
+ iMax = a[i].iDocid;
126285
+ i = 0;
126286
+ }
126287
+ }
126288
+ }
126289
+
126290
+ /* Check if the current entries really are a phrase match */
126291
+ if( bEof==0 ){
126292
+ int nList = 0;
126293
+ int nByte = a[p->nToken-1].nList;
126294
+ char *aDoclist = sqlite3_malloc(nByte+1);
126295
+ if( !aDoclist ) return SQLITE_NOMEM;
126296
+ memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
126297
+
126298
+ for(i=0; i<(p->nToken-1); i++){
126299
+ if( a[i].bIgnore==0 ){
126300
+ char *pL = a[i].pList;
126301
+ char *pR = aDoclist;
126302
+ char *pOut = aDoclist;
126303
+ int nDist = p->nToken-1-i;
126304
+ int res = fts3PoslistPhraseMerge(&pOut, nDist, 0, 1, &pL, &pR);
126305
+ if( res==0 ) break;
126306
+ nList = (pOut - aDoclist);
126307
+ }
126308
+ }
126309
+ if( i==(p->nToken-1) ){
126310
+ pDL->iDocid = iMax;
126311
+ pDL->pList = aDoclist;
126312
+ pDL->nList = nList;
126313
+ pDL->bFreeList = 1;
126314
+ break;
126315
+ }
126316
+ sqlite3_free(aDoclist);
126317
+ }
126318
+ }
126319
+ }
126320
+
126321
+ *pbEof = bEof;
126322
+ return rc;
126323
+}
125685126324
125686126325
/*
125687126326
** Attempt to move the phrase iterator to point to the next matching docid.
125688126327
** If an error occurs, return an SQLite error code. Otherwise, return
125689126328
** SQLITE_OK.
@@ -125700,59 +126339,18 @@
125700126339
int rc = SQLITE_OK;
125701126340
Fts3Doclist *pDL = &p->doclist;
125702126341
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
125703126342
125704126343
if( p->bIncr ){
125705
- assert( p->nToken==1 );
125706
- assert( pDL->pNextDocid==0 );
125707
- rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
125708
- &pDL->iDocid, &pDL->pList, &pDL->nList
125709
- );
125710
- if( rc==SQLITE_OK && !pDL->pList ){
125711
- *pbEof = 1;
125712
- }
126344
+ rc = fts3EvalIncrPhraseNext(pCsr, p, pbEof);
125713126345
}else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){
125714126346
sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll,
125715126347
&pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof
125716126348
);
125717126349
pDL->pList = pDL->pNextDocid;
125718126350
}else{
125719
- char *pIter; /* Used to iterate through aAll */
125720
- char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
125721
- if( pDL->pNextDocid ){
125722
- pIter = pDL->pNextDocid;
125723
- }else{
125724
- pIter = pDL->aAll;
125725
- }
125726
-
125727
- if( pIter>=pEnd ){
125728
- /* We have already reached the end of this doclist. EOF. */
125729
- *pbEof = 1;
125730
- }else{
125731
- sqlite3_int64 iDelta;
125732
- pIter += sqlite3Fts3GetVarint(pIter, &iDelta);
125733
- if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
125734
- pDL->iDocid += iDelta;
125735
- }else{
125736
- pDL->iDocid -= iDelta;
125737
- }
125738
- pDL->pList = pIter;
125739
- fts3PoslistCopy(0, &pIter);
125740
- pDL->nList = (int)(pIter - pDL->pList);
125741
-
125742
- /* pIter now points just past the 0x00 that terminates the position-
125743
- ** list for document pDL->iDocid. However, if this position-list was
125744
- ** edited in place by fts3EvalNearTrim(), then pIter may not actually
125745
- ** point to the start of the next docid value. The following line deals
125746
- ** with this case by advancing pIter past the zero-padding added by
125747
- ** fts3EvalNearTrim(). */
125748
- while( pIter<pEnd && *pIter==0 ) pIter++;
125749
-
125750
- pDL->pNextDocid = pIter;
125751
- assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter );
125752
- *pbEof = 0;
125753
- }
126351
+ fts3EvalDlPhraseNext(pTab, pDL, pbEof);
125754126352
}
125755126353
125756126354
return rc;
125757126355
}
125758126356
@@ -125773,11 +126371,10 @@
125773126371
** code before returning.
125774126372
*/
125775126373
static void fts3EvalStartReaders(
125776126374
Fts3Cursor *pCsr, /* FTS Cursor handle */
125777126375
Fts3Expr *pExpr, /* Expression to initialize phrases in */
125778
- int bOptOk, /* True to enable incremental loading */
125779126376
int *pRc /* IN/OUT: Error code */
125780126377
){
125781126378
if( pExpr && SQLITE_OK==*pRc ){
125782126379
if( pExpr->eType==FTSQUERY_PHRASE ){
125783126380
int i;
@@ -125784,14 +126381,14 @@
125784126381
int nToken = pExpr->pPhrase->nToken;
125785126382
for(i=0; i<nToken; i++){
125786126383
if( pExpr->pPhrase->aToken[i].pDeferred==0 ) break;
125787126384
}
125788126385
pExpr->bDeferred = (i==nToken);
125789
- *pRc = fts3EvalPhraseStart(pCsr, bOptOk, pExpr->pPhrase);
126386
+ *pRc = fts3EvalPhraseStart(pCsr, 1, pExpr->pPhrase);
125790126387
}else{
125791
- fts3EvalStartReaders(pCsr, pExpr->pLeft, bOptOk, pRc);
125792
- fts3EvalStartReaders(pCsr, pExpr->pRight, bOptOk, pRc);
126388
+ fts3EvalStartReaders(pCsr, pExpr->pLeft, pRc);
126389
+ fts3EvalStartReaders(pCsr, pExpr->pRight, pRc);
125793126390
pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred);
125794126391
}
125795126392
}
125796126393
}
125797126394
@@ -126029,11 +126626,11 @@
126029126626
/* Set nLoad4 to the value of (4^nOther) for the next iteration of the
126030126627
** for-loop. Except, limit the value to 2^24 to prevent it from
126031126628
** overflowing the 32-bit integer it is stored in. */
126032126629
if( ii<12 ) nLoad4 = nLoad4*4;
126033126630
126034
- if( ii==0 || pTC->pPhrase->nToken>1 ){
126631
+ if( ii==0 || (pTC->pPhrase->nToken>1 && ii!=nToken-1) ){
126035126632
/* Either this is the cheapest token in the entire query, or it is
126036126633
** part of a multi-token phrase. Either way, the entire doclist will
126037126634
** (eventually) be loaded into memory. It may as well be now. */
126038126635
Fts3PhraseToken *pToken = pTC->pToken;
126039126636
int nList = 0;
@@ -126109,11 +126706,11 @@
126109126706
sqlite3_free(aTC);
126110126707
}
126111126708
}
126112126709
#endif
126113126710
126114
- fts3EvalStartReaders(pCsr, pCsr->pExpr, 1, &rc);
126711
+ fts3EvalStartReaders(pCsr, pCsr->pExpr, &rc);
126115126712
return rc;
126116126713
}
126117126714
126118126715
/*
126119126716
** Invalidate the current position list for phrase pPhrase.
@@ -126592,10 +127189,20 @@
126592127189
pCsr->isRequireSeek = 1;
126593127190
pCsr->isMatchinfoNeeded = 1;
126594127191
pCsr->iPrevId = pExpr->iDocid;
126595127192
}while( pCsr->isEof==0 && fts3EvalTestDeferredAndNear(pCsr, &rc) );
126596127193
}
127194
+
127195
+ /* Check if the cursor is past the end of the docid range specified
127196
+ ** by Fts3Cursor.iMinDocid/iMaxDocid. If so, set the EOF flag. */
127197
+ if( rc==SQLITE_OK && (
127198
+ (pCsr->bDesc==0 && pCsr->iPrevId>pCsr->iMaxDocid)
127199
+ || (pCsr->bDesc!=0 && pCsr->iPrevId<pCsr->iMinDocid)
127200
+ )){
127201
+ pCsr->isEof = 1;
127202
+ }
127203
+
126597127204
return rc;
126598127205
}
126599127206
126600127207
/*
126601127208
** Restart interation for expression pExpr so that the next call to
@@ -126615,16 +127222,20 @@
126615127222
Fts3Phrase *pPhrase = pExpr->pPhrase;
126616127223
126617127224
if( pPhrase ){
126618127225
fts3EvalInvalidatePoslist(pPhrase);
126619127226
if( pPhrase->bIncr ){
126620
- assert( pPhrase->nToken==1 );
126621
- assert( pPhrase->aToken[0].pSegcsr );
126622
- sqlite3Fts3MsrIncrRestart(pPhrase->aToken[0].pSegcsr);
127227
+ int i;
127228
+ for(i=0; i<pPhrase->nToken; i++){
127229
+ Fts3PhraseToken *pToken = &pPhrase->aToken[i];
127230
+ assert( pToken->pDeferred==0 );
127231
+ if( pToken->pSegcsr ){
127232
+ sqlite3Fts3MsrIncrRestart(pToken->pSegcsr);
127233
+ }
127234
+ }
126623127235
*pRc = fts3EvalPhraseStart(pCsr, 0, pPhrase);
126624127236
}
126625
-
126626127237
pPhrase->doclist.pNextDocid = 0;
126627127238
pPhrase->doclist.iDocid = 0;
126628127239
}
126629127240
126630127241
pExpr->iDocid = 0;
@@ -126869,19 +127480,27 @@
126869127480
126870127481
iDocid = pExpr->iDocid;
126871127482
pIter = pPhrase->doclist.pList;
126872127483
if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
126873127484
int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
127485
+ int iMul; /* +1 if csr dir matches index dir, else -1 */
126874127486
int bOr = 0;
126875127487
u8 bEof = 0;
126876
- Fts3Expr *p;
127488
+ u8 bTreeEof = 0;
127489
+ Fts3Expr *p; /* Used to iterate from pExpr to root */
127490
+ Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
126877127491
126878127492
/* Check if this phrase descends from an OR expression node. If not,
126879127493
** return NULL. Otherwise, the entry that corresponds to docid
126880
- ** pCsr->iPrevId may lie earlier in the doclist buffer. */
127494
+ ** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the
127495
+ ** tree that the node is part of has been marked as EOF, but the node
127496
+ ** itself is not EOF, then it may point to an earlier entry. */
127497
+ pNear = pExpr;
126881127498
for(p=pExpr->pParent; p; p=p->pParent){
126882127499
if( p->eType==FTSQUERY_OR ) bOr = 1;
127500
+ if( p->eType==FTSQUERY_NEAR ) pNear = p;
127501
+ if( p->bEof ) bTreeEof = 1;
126883127502
}
126884127503
if( bOr==0 ) return SQLITE_OK;
126885127504
126886127505
/* This is the descendent of an OR node. In this case we cannot use
126887127506
** an incremental phrase. Load the entire doclist for the phrase
@@ -126896,33 +127515,63 @@
126896127515
}
126897127516
pIter = pPhrase->doclist.pList;
126898127517
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
126899127518
if( rc!=SQLITE_OK ) return rc;
126900127519
}
127520
+
127521
+ iMul = ((pCsr->bDesc==bDescDoclist) ? 1 : -1);
127522
+ while( bTreeEof==1
127523
+ && pNear->bEof==0
127524
+ && (DOCID_CMP(pNear->iDocid, pCsr->iPrevId) * iMul)<0
127525
+ ){
127526
+ int rc = SQLITE_OK;
127527
+ fts3EvalNextRow(pCsr, pExpr, &rc);
127528
+ if( rc!=SQLITE_OK ) return rc;
127529
+ iDocid = pExpr->iDocid;
127530
+ pIter = pPhrase->doclist.pList;
127531
+ }
126901127532
126902
- if( pExpr->bEof ){
126903
- pIter = 0;
126904
- iDocid = 0;
126905
- }
126906127533
bEof = (pPhrase->doclist.nAll==0);
126907127534
assert( bDescDoclist==0 || bDescDoclist==1 );
126908127535
assert( pCsr->bDesc==0 || pCsr->bDesc==1 );
126909127536
126910
- if( pCsr->bDesc==bDescDoclist ){
126911
- int dummy;
126912
- while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
126913
- sqlite3Fts3DoclistPrev(
126914
- bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
126915
- &pIter, &iDocid, &dummy, &bEof
126916
- );
126917
- }
126918
- }else{
126919
- while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
126920
- sqlite3Fts3DoclistNext(
126921
- bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
126922
- &pIter, &iDocid, &bEof
126923
- );
127537
+ if( bEof==0 ){
127538
+ if( pCsr->bDesc==bDescDoclist ){
127539
+ int dummy;
127540
+ if( pNear->bEof ){
127541
+ /* This expression is already at EOF. So position it to point to the
127542
+ ** last entry in the doclist at pPhrase->doclist.aAll[]. Variable
127543
+ ** iDocid is already set for this entry, so all that is required is
127544
+ ** to set pIter to point to the first byte of the last position-list
127545
+ ** in the doclist.
127546
+ **
127547
+ ** It would also be correct to set pIter and iDocid to zero. In
127548
+ ** this case, the first call to sqltie3Fts4DoclistPrev() below
127549
+ ** would also move the iterator to point to the last entry in the
127550
+ ** doclist. However, this is expensive, as to do so it has to
127551
+ ** iterate through the entire doclist from start to finish (since
127552
+ ** it does not know the docid for the last entry). */
127553
+ pIter = &pPhrase->doclist.aAll[pPhrase->doclist.nAll-1];
127554
+ fts3ReversePoslist(pPhrase->doclist.aAll, &pIter);
127555
+ }
127556
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
127557
+ sqlite3Fts3DoclistPrev(
127558
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
127559
+ &pIter, &iDocid, &dummy, &bEof
127560
+ );
127561
+ }
127562
+ }else{
127563
+ if( pNear->bEof ){
127564
+ pIter = 0;
127565
+ iDocid = 0;
127566
+ }
127567
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
127568
+ sqlite3Fts3DoclistNext(
127569
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
127570
+ &pIter, &iDocid, &bEof
127571
+ );
127572
+ }
126924127573
}
126925127574
}
126926127575
126927127576
if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
126928127577
}
@@ -135756,11 +136405,11 @@
135756136405
assert( p->bFts4==0 );
135757136406
sqlite3Fts3CreateStatTable(&rc, p);
135758136407
if( rc ) return rc;
135759136408
}
135760136409
rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
135761
- if( rc ) return rc;;
136410
+ if( rc ) return rc;
135762136411
sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
135763136412
sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge);
135764136413
sqlite3_step(pStmt);
135765136414
rc = sqlite3_reset(pStmt);
135766136415
return rc;
@@ -136025,10 +136674,13 @@
136025136674
}else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
136026136675
p->nNodeSize = atoi(&zVal[9]);
136027136676
rc = SQLITE_OK;
136028136677
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
136029136678
p->nMaxPendingData = atoi(&zVal[11]);
136679
+ rc = SQLITE_OK;
136680
+ }else if( nVal>21 && 0==sqlite3_strnicmp(zVal, "test-no-incr-doclist=", 21) ){
136681
+ p->bNoIncrDoclist = atoi(&zVal[21]);
136030136682
rc = SQLITE_OK;
136031136683
#endif
136032136684
}else{
136033136685
rc = SQLITE_ERROR;
136034136686
}
136035136687
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -23,531 +23,10 @@
23 # define SQLITE_PRIVATE static
24 #endif
25 #ifndef SQLITE_API
26 # define SQLITE_API
27 #endif
28 /************** Begin file sqliteInt.h ***************************************/
29 /*
30 ** 2001 September 15
31 **
32 ** The author disclaims copyright to this source code. In place of
33 ** a legal notice, here is a blessing:
34 **
35 ** May you do good and not evil.
36 ** May you find forgiveness for yourself and forgive others.
37 ** May you share freely, never taking more than you give.
38 **
39 *************************************************************************
40 ** Internal interface definitions for SQLite.
41 **
42 */
43 #ifndef _SQLITEINT_H_
44 #define _SQLITEINT_H_
45
46 /*
47 ** These #defines should enable >2GB file support on POSIX if the
48 ** underlying operating system supports it. If the OS lacks
49 ** large file support, or if the OS is windows, these should be no-ops.
50 **
51 ** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any
52 ** system #includes. Hence, this block of code must be the very first
53 ** code in all source files.
54 **
55 ** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
56 ** on the compiler command line. This is necessary if you are compiling
57 ** on a recent machine (ex: Red Hat 7.2) but you want your code to work
58 ** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2
59 ** without this option, LFS is enable. But LFS does not exist in the kernel
60 ** in Red Hat 6.0, so the code won't work. Hence, for maximum binary
61 ** portability you should omit LFS.
62 **
63 ** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later.
64 */
65 #ifndef SQLITE_DISABLE_LFS
66 # define _LARGE_FILE 1
67 # ifndef _FILE_OFFSET_BITS
68 # define _FILE_OFFSET_BITS 64
69 # endif
70 # define _LARGEFILE_SOURCE 1
71 #endif
72
73 /*
74 ** Include the configuration header output by 'configure' if we're using the
75 ** autoconf-based build
76 */
77 #ifdef _HAVE_SQLITE_CONFIG_H
78 #include "config.h"
79 #endif
80
81 /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/
82 /************** Begin file sqliteLimit.h *************************************/
83 /*
84 ** 2007 May 7
85 **
86 ** The author disclaims copyright to this source code. In place of
87 ** a legal notice, here is a blessing:
88 **
89 ** May you do good and not evil.
90 ** May you find forgiveness for yourself and forgive others.
91 ** May you share freely, never taking more than you give.
92 **
93 *************************************************************************
94 **
95 ** This file defines various limits of what SQLite can process.
96 */
97
98 /*
99 ** The maximum length of a TEXT or BLOB in bytes. This also
100 ** limits the size of a row in a table or index.
101 **
102 ** The hard limit is the ability of a 32-bit signed integer
103 ** to count the size: 2^31-1 or 2147483647.
104 */
105 #ifndef SQLITE_MAX_LENGTH
106 # define SQLITE_MAX_LENGTH 1000000000
107 #endif
108
109 /*
110 ** This is the maximum number of
111 **
112 ** * Columns in a table
113 ** * Columns in an index
114 ** * Columns in a view
115 ** * Terms in the SET clause of an UPDATE statement
116 ** * Terms in the result set of a SELECT statement
117 ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
118 ** * Terms in the VALUES clause of an INSERT statement
119 **
120 ** The hard upper limit here is 32676. Most database people will
121 ** tell you that in a well-normalized database, you usually should
122 ** not have more than a dozen or so columns in any table. And if
123 ** that is the case, there is no point in having more than a few
124 ** dozen values in any of the other situations described above.
125 */
126 #ifndef SQLITE_MAX_COLUMN
127 # define SQLITE_MAX_COLUMN 2000
128 #endif
129
130 /*
131 ** The maximum length of a single SQL statement in bytes.
132 **
133 ** It used to be the case that setting this value to zero would
134 ** turn the limit off. That is no longer true. It is not possible
135 ** to turn this limit off.
136 */
137 #ifndef SQLITE_MAX_SQL_LENGTH
138 # define SQLITE_MAX_SQL_LENGTH 1000000000
139 #endif
140
141 /*
142 ** The maximum depth of an expression tree. This is limited to
143 ** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
144 ** want to place more severe limits on the complexity of an
145 ** expression.
146 **
147 ** A value of 0 used to mean that the limit was not enforced.
148 ** But that is no longer true. The limit is now strictly enforced
149 ** at all times.
150 */
151 #ifndef SQLITE_MAX_EXPR_DEPTH
152 # define SQLITE_MAX_EXPR_DEPTH 1000
153 #endif
154
155 /*
156 ** The maximum number of terms in a compound SELECT statement.
157 ** The code generator for compound SELECT statements does one
158 ** level of recursion for each term. A stack overflow can result
159 ** if the number of terms is too large. In practice, most SQL
160 ** never has more than 3 or 4 terms. Use a value of 0 to disable
161 ** any limit on the number of terms in a compount SELECT.
162 */
163 #ifndef SQLITE_MAX_COMPOUND_SELECT
164 # define SQLITE_MAX_COMPOUND_SELECT 500
165 #endif
166
167 /*
168 ** The maximum number of opcodes in a VDBE program.
169 ** Not currently enforced.
170 */
171 #ifndef SQLITE_MAX_VDBE_OP
172 # define SQLITE_MAX_VDBE_OP 25000
173 #endif
174
175 /*
176 ** The maximum number of arguments to an SQL function.
177 */
178 #ifndef SQLITE_MAX_FUNCTION_ARG
179 # define SQLITE_MAX_FUNCTION_ARG 127
180 #endif
181
182 /*
183 ** The maximum number of in-memory pages to use for the main database
184 ** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
185 */
186 #ifndef SQLITE_DEFAULT_CACHE_SIZE
187 # define SQLITE_DEFAULT_CACHE_SIZE 2000
188 #endif
189 #ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
190 # define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
191 #endif
192
193 /*
194 ** The default number of frames to accumulate in the log file before
195 ** checkpointing the database in WAL mode.
196 */
197 #ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
198 # define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
199 #endif
200
201 /*
202 ** The maximum number of attached databases. This must be between 0
203 ** and 62. The upper bound on 62 is because a 64-bit integer bitmap
204 ** is used internally to track attached databases.
205 */
206 #ifndef SQLITE_MAX_ATTACHED
207 # define SQLITE_MAX_ATTACHED 10
208 #endif
209
210
211 /*
212 ** The maximum value of a ?nnn wildcard that the parser will accept.
213 */
214 #ifndef SQLITE_MAX_VARIABLE_NUMBER
215 # define SQLITE_MAX_VARIABLE_NUMBER 999
216 #endif
217
218 /* Maximum page size. The upper bound on this value is 65536. This a limit
219 ** imposed by the use of 16-bit offsets within each page.
220 **
221 ** Earlier versions of SQLite allowed the user to change this value at
222 ** compile time. This is no longer permitted, on the grounds that it creates
223 ** a library that is technically incompatible with an SQLite library
224 ** compiled with a different limit. If a process operating on a database
225 ** with a page-size of 65536 bytes crashes, then an instance of SQLite
226 ** compiled with the default page-size limit will not be able to rollback
227 ** the aborted transaction. This could lead to database corruption.
228 */
229 #ifdef SQLITE_MAX_PAGE_SIZE
230 # undef SQLITE_MAX_PAGE_SIZE
231 #endif
232 #define SQLITE_MAX_PAGE_SIZE 65536
233
234
235 /*
236 ** The default size of a database page.
237 */
238 #ifndef SQLITE_DEFAULT_PAGE_SIZE
239 # define SQLITE_DEFAULT_PAGE_SIZE 1024
240 #endif
241 #if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
242 # undef SQLITE_DEFAULT_PAGE_SIZE
243 # define SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
244 #endif
245
246 /*
247 ** Ordinarily, if no value is explicitly provided, SQLite creates databases
248 ** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain
249 ** device characteristics (sector-size and atomic write() support),
250 ** SQLite may choose a larger value. This constant is the maximum value
251 ** SQLite will choose on its own.
252 */
253 #ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE
254 # define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192
255 #endif
256 #if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
257 # undef SQLITE_MAX_DEFAULT_PAGE_SIZE
258 # define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
259 #endif
260
261
262 /*
263 ** Maximum number of pages in one database file.
264 **
265 ** This is really just the default value for the max_page_count pragma.
266 ** This value can be lowered (or raised) at run-time using that the
267 ** max_page_count macro.
268 */
269 #ifndef SQLITE_MAX_PAGE_COUNT
270 # define SQLITE_MAX_PAGE_COUNT 1073741823
271 #endif
272
273 /*
274 ** Maximum length (in bytes) of the pattern in a LIKE or GLOB
275 ** operator.
276 */
277 #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
278 # define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
279 #endif
280
281 /*
282 ** Maximum depth of recursion for triggers.
283 **
284 ** A value of 1 means that a trigger program will not be able to itself
285 ** fire any triggers. A value of 0 means that no trigger programs at all
286 ** may be executed.
287 */
288 #ifndef SQLITE_MAX_TRIGGER_DEPTH
289 # define SQLITE_MAX_TRIGGER_DEPTH 1000
290 #endif
291
292 /************** End of sqliteLimit.h *****************************************/
293 /************** Continuing where we left off in sqliteInt.h ******************/
294
295 /* Disable nuisance warnings on Borland compilers */
296 #if defined(__BORLANDC__)
297 #pragma warn -rch /* unreachable code */
298 #pragma warn -ccc /* Condition is always true or false */
299 #pragma warn -aus /* Assigned value is never used */
300 #pragma warn -csu /* Comparing signed and unsigned */
301 #pragma warn -spa /* Suspicious pointer arithmetic */
302 #endif
303
304 /* Needed for various definitions... */
305 #ifndef _GNU_SOURCE
306 # define _GNU_SOURCE
307 #endif
308
309 #if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
310 # define _BSD_SOURCE
311 #endif
312
313 /*
314 ** Include standard header files as necessary
315 */
316 #ifdef HAVE_STDINT_H
317 #include <stdint.h>
318 #endif
319 #ifdef HAVE_INTTYPES_H
320 #include <inttypes.h>
321 #endif
322
323 /*
324 ** The following macros are used to cast pointers to integers and
325 ** integers to pointers. The way you do this varies from one compiler
326 ** to the next, so we have developed the following set of #if statements
327 ** to generate appropriate macros for a wide range of compilers.
328 **
329 ** The correct "ANSI" way to do this is to use the intptr_t type.
330 ** Unfortunately, that typedef is not available on all compilers, or
331 ** if it is available, it requires an #include of specific headers
332 ** that vary from one machine to the next.
333 **
334 ** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
335 ** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
336 ** So we have to define the macros in different ways depending on the
337 ** compiler.
338 */
339 #if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
340 # define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
341 # define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
342 #elif !defined(__GNUC__) /* Works for compilers other than LLVM */
343 # define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
344 # define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
345 #elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
346 # define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
347 # define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
348 #else /* Generates a warning - but it always works */
349 # define SQLITE_INT_TO_PTR(X) ((void*)(X))
350 # define SQLITE_PTR_TO_INT(X) ((int)(X))
351 #endif
352
353 /*
354 ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
355 ** 0 means mutexes are permanently disable and the library is never
356 ** threadsafe. 1 means the library is serialized which is the highest
357 ** level of threadsafety. 2 means the library is multithreaded - multiple
358 ** threads can use SQLite as long as no two threads try to use the same
359 ** database connection at the same time.
360 **
361 ** Older versions of SQLite used an optional THREADSAFE macro.
362 ** We support that for legacy.
363 */
364 #if !defined(SQLITE_THREADSAFE)
365 # if defined(THREADSAFE)
366 # define SQLITE_THREADSAFE THREADSAFE
367 # else
368 # define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
369 # endif
370 #endif
371
372 /*
373 ** Powersafe overwrite is on by default. But can be turned off using
374 ** the -DSQLITE_POWERSAFE_OVERWRITE=0 command-line option.
375 */
376 #ifndef SQLITE_POWERSAFE_OVERWRITE
377 # define SQLITE_POWERSAFE_OVERWRITE 1
378 #endif
379
380 /*
381 ** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
382 ** It determines whether or not the features related to
383 ** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can
384 ** be overridden at runtime using the sqlite3_config() API.
385 */
386 #if !defined(SQLITE_DEFAULT_MEMSTATUS)
387 # define SQLITE_DEFAULT_MEMSTATUS 1
388 #endif
389
390 /*
391 ** Exactly one of the following macros must be defined in order to
392 ** specify which memory allocation subsystem to use.
393 **
394 ** SQLITE_SYSTEM_MALLOC // Use normal system malloc()
395 ** SQLITE_WIN32_MALLOC // Use Win32 native heap API
396 ** SQLITE_ZERO_MALLOC // Use a stub allocator that always fails
397 ** SQLITE_MEMDEBUG // Debugging version of system malloc()
398 **
399 ** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the
400 ** assert() macro is enabled, each call into the Win32 native heap subsystem
401 ** will cause HeapValidate to be called. If heap validation should fail, an
402 ** assertion will be triggered.
403 **
404 ** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
405 ** the default.
406 */
407 #if defined(SQLITE_SYSTEM_MALLOC) \
408 + defined(SQLITE_WIN32_MALLOC) \
409 + defined(SQLITE_ZERO_MALLOC) \
410 + defined(SQLITE_MEMDEBUG)>1
411 # error "Two or more of the following compile-time configuration options\
412 are defined but at most one is allowed:\
413 SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG,\
414 SQLITE_ZERO_MALLOC"
415 #endif
416 #if defined(SQLITE_SYSTEM_MALLOC) \
417 + defined(SQLITE_WIN32_MALLOC) \
418 + defined(SQLITE_ZERO_MALLOC) \
419 + defined(SQLITE_MEMDEBUG)==0
420 # define SQLITE_SYSTEM_MALLOC 1
421 #endif
422
423 /*
424 ** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the
425 ** sizes of memory allocations below this value where possible.
426 */
427 #if !defined(SQLITE_MALLOC_SOFT_LIMIT)
428 # define SQLITE_MALLOC_SOFT_LIMIT 1024
429 #endif
430
431 /*
432 ** We need to define _XOPEN_SOURCE as follows in order to enable
433 ** recursive mutexes on most Unix systems and fchmod() on OpenBSD.
434 ** But _XOPEN_SOURCE define causes problems for Mac OS X, so omit
435 ** it.
436 */
437 #if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__)
438 # define _XOPEN_SOURCE 600
439 #endif
440
441 /*
442 ** NDEBUG and SQLITE_DEBUG are opposites. It should always be true that
443 ** defined(NDEBUG)==!defined(SQLITE_DEBUG). If this is not currently true,
444 ** make it true by defining or undefining NDEBUG.
445 **
446 ** Setting NDEBUG makes the code smaller and faster by disabling the
447 ** assert() statements in the code. So we want the default action
448 ** to be for NDEBUG to be set and NDEBUG to be undefined only if SQLITE_DEBUG
449 ** is set. Thus NDEBUG becomes an opt-in rather than an opt-out
450 ** feature.
451 */
452 #if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
453 # define NDEBUG 1
454 #endif
455 #if defined(NDEBUG) && defined(SQLITE_DEBUG)
456 # undef NDEBUG
457 #endif
458
459 /*
460 ** The testcase() macro is used to aid in coverage testing. When
461 ** doing coverage testing, the condition inside the argument to
462 ** testcase() must be evaluated both true and false in order to
463 ** get full branch coverage. The testcase() macro is inserted
464 ** to help ensure adequate test coverage in places where simple
465 ** condition/decision coverage is inadequate. For example, testcase()
466 ** can be used to make sure boundary values are tested. For
467 ** bitmask tests, testcase() can be used to make sure each bit
468 ** is significant and used at least once. On switch statements
469 ** where multiple cases go to the same block of code, testcase()
470 ** can insure that all cases are evaluated.
471 **
472 */
473 #ifdef SQLITE_COVERAGE_TEST
474 SQLITE_PRIVATE void sqlite3Coverage(int);
475 # define testcase(X) if( X ){ sqlite3Coverage(__LINE__); }
476 #else
477 # define testcase(X)
478 #endif
479
480 /*
481 ** The TESTONLY macro is used to enclose variable declarations or
482 ** other bits of code that are needed to support the arguments
483 ** within testcase() and assert() macros.
484 */
485 #if !defined(NDEBUG) || defined(SQLITE_COVERAGE_TEST)
486 # define TESTONLY(X) X
487 #else
488 # define TESTONLY(X)
489 #endif
490
491 /*
492 ** Sometimes we need a small amount of code such as a variable initialization
493 ** to setup for a later assert() statement. We do not want this code to
494 ** appear when assert() is disabled. The following macro is therefore
495 ** used to contain that setup code. The "VVA" acronym stands for
496 ** "Verification, Validation, and Accreditation". In other words, the
497 ** code within VVA_ONLY() will only run during verification processes.
498 */
499 #ifndef NDEBUG
500 # define VVA_ONLY(X) X
501 #else
502 # define VVA_ONLY(X)
503 #endif
504
505 /*
506 ** The ALWAYS and NEVER macros surround boolean expressions which
507 ** are intended to always be true or false, respectively. Such
508 ** expressions could be omitted from the code completely. But they
509 ** are included in a few cases in order to enhance the resilience
510 ** of SQLite to unexpected behavior - to make the code "self-healing"
511 ** or "ductile" rather than being "brittle" and crashing at the first
512 ** hint of unplanned behavior.
513 **
514 ** In other words, ALWAYS and NEVER are added for defensive code.
515 **
516 ** When doing coverage testing ALWAYS and NEVER are hard-coded to
517 ** be true and false so that the unreachable code they specify will
518 ** not be counted as untested code.
519 */
520 #if defined(SQLITE_COVERAGE_TEST)
521 # define ALWAYS(X) (1)
522 # define NEVER(X) (0)
523 #elif !defined(NDEBUG)
524 # define ALWAYS(X) ((X)?1:(assert(0),0))
525 # define NEVER(X) ((X)?(assert(0),1):0)
526 #else
527 # define ALWAYS(X) (X)
528 # define NEVER(X) (X)
529 #endif
530
531 /*
532 ** Return true (non-zero) if the input is a integer that is too large
533 ** to fit in 32-bits. This macro is used inside of various testcase()
534 ** macros to verify that we have tested SQLite for large-file support.
535 */
536 #define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0)
537
538 /*
539 ** The macro unlikely() is a hint that surrounds a boolean
540 ** expression that is usually false. Macro likely() surrounds
541 ** a boolean expression that is usually true. These hints could,
542 ** in theory, be used by the compiler to generate better code, but
543 ** currently they are just comments for human readers.
544 */
545 #define likely(X) (X)
546 #define unlikely(X) (X)
547
548 /************** Include sqlite3.h in the middle of sqliteInt.h ***************/
549 /************** Begin file sqlite3.h *****************************************/
550 /*
551 ** 2001 September 15
552 **
553 ** The author disclaims copyright to this source code. In place of
@@ -656,11 +135,11 @@
656 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657 ** [sqlite_version()] and [sqlite_source_id()].
658 */
659 #define SQLITE_VERSION "3.8.1"
660 #define SQLITE_VERSION_NUMBER 3008001
661 #define SQLITE_SOURCE_ID "2013-09-16 12:57:19 daf6ba413cb3cb6065774ba07495eab4a28b49b0"
662
663 /*
664 ** CAPI3REF: Run-Time Library Version Numbers
665 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
666 **
@@ -7846,11 +7325,530 @@
7846
7847 #endif /* ifndef _SQLITE3RTREE_H_ */
7848
7849
7850 /************** End of sqlite3.h *********************************************/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7851 /************** Continuing where we left off in sqliteInt.h ******************/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7852 /************** Include hash.h in the middle of sqliteInt.h ******************/
7853 /************** Begin file hash.h ********************************************/
7854 /*
7855 ** 2001 September 22
7856 **
@@ -8272,10 +8270,35 @@
8272 typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */
8273 #else
8274 typedef u32 tRowcnt; /* 32-bit is the default */
8275 #endif
8276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8277 /*
8278 ** Macros to determine whether the machine is big or little endian,
8279 ** evaluated at runtime.
8280 */
8281 #ifdef SQLITE_AMALGAMATION
@@ -10419,11 +10442,12 @@
10419 char *zDflt; /* Original text of the default value */
10420 char *zType; /* Data type for this column */
10421 char *zColl; /* Collating sequence. If NULL, use the default */
10422 u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
10423 char affinity; /* One of the SQLITE_AFF_... values */
10424 u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
 
10425 };
10426
10427 /* Allowed values for Column.colFlags:
10428 */
10429 #define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
@@ -10583,10 +10607,11 @@
10583 tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
10584 int tnum; /* Root BTree node for this table (see note above) */
10585 i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
10586 i16 nCol; /* Number of columns in this table */
10587 u16 nRef; /* Number of pointers to this Table */
 
10588 u8 tabFlags; /* Mask of TF_* values */
10589 u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
10590 #ifndef SQLITE_OMIT_ALTERTABLE
10591 int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
10592 #endif
@@ -10694,11 +10719,11 @@
10694 #define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */
10695 #define OE_SetNull 7 /* Set the foreign key value to NULL */
10696 #define OE_SetDflt 8 /* Set the foreign key value to its default */
10697 #define OE_Cascade 9 /* Cascade the changes */
10698
10699 #define OE_Default 99 /* Do whatever the default action is */
10700
10701
10702 /*
10703 ** An instance of the following structure is passed as the first
10704 ** argument to sqlite3VdbeKeyCompare and is used to control the
@@ -10781,10 +10806,11 @@
10781 Schema *pSchema; /* Schema containing this index */
10782 u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
10783 char **azColl; /* Array of collation sequence names for index */
10784 Expr *pPartIdxWhere; /* WHERE clause for partial indices */
10785 int tnum; /* DB Page containing root of this index */
 
10786 u16 nColumn; /* Number of columns in table used by this index */
10787 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10788 unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
10789 unsigned bUnordered:1; /* Use this index for == or IN queries only */
10790 unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
@@ -11636,10 +11662,11 @@
11636 */
11637 typedef struct DbFixer DbFixer;
11638 struct DbFixer {
11639 Parse *pParse; /* The parsing context. Error messages written here */
11640 Schema *pSchema; /* Fix items to this schema */
 
11641 const char *zDb; /* Make sure all objects are contained in this database */
11642 const char *zType; /* Type of the container - used for error messages */
11643 const Token *pName; /* Name of the container - used for error messages */
11644 };
11645
@@ -12174,11 +12201,11 @@
12174 # define sqlite3AuthContextPush(a,b,c)
12175 # define sqlite3AuthContextPop(a) ((void)(a))
12176 #endif
12177 SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
12178 SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
12179 SQLITE_PRIVATE int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
12180 SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
12181 SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
12182 SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
12183 SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
12184 SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
@@ -12186,10 +12213,16 @@
12186 SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
12187 SQLITE_PRIVATE int sqlite3Atoi(const char*);
12188 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
12189 SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
12190 SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
 
 
 
 
 
 
12191
12192 /*
12193 ** Routines to read and write variable-length integers. These used to
12194 ** be defined locally, but now we use the varint routines in the util.c
12195 ** file. Code should use the MACRO forms below, as the Varint32 versions
@@ -12302,11 +12335,11 @@
12302 SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
12303 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
12304 SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
12305 SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
12306 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
12307 SQLITE_PRIVATE char sqlite3AffinityType(const char*);
12308 SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
12309 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
12310 SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
12311 SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
12312 SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
@@ -22387,10 +22420,87 @@
22387 for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
22388 if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
22389 }
22390 }
22391 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22392
22393 /************** End of util.c ************************************************/
22394 /************** Begin file hash.c ********************************************/
22395 /*
22396 ** 2001 September 22
@@ -31382,11 +31492,11 @@
31382 #endif
31383
31384 #define osGetVersionExA ((BOOL(WINAPI*)( \
31385 LPOSVERSIONINFOA))aSyscall[34].pCurrent)
31386
31387 #if defined(SQLITE_WIN32_HAS_WIDE)
31388 { "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
31389 #else
31390 { "GetVersionExW", (SYSCALL)0, 0 },
31391 #endif
31392
@@ -48986,17 +49096,17 @@
48986 ** page contain a special header (the "file header") that describes the file.
48987 ** The format of the file header is as follows:
48988 **
48989 ** OFFSET SIZE DESCRIPTION
48990 ** 0 16 Header string: "SQLite format 3\000"
48991 ** 16 2 Page size in bytes.
48992 ** 18 1 File format write version
48993 ** 19 1 File format read version
48994 ** 20 1 Bytes of unused space at the end of each page
48995 ** 21 1 Max embedded payload fraction
48996 ** 22 1 Min embedded payload fraction
48997 ** 23 1 Min leaf payload fraction
48998 ** 24 4 File change counter
48999 ** 28 4 Reserved for future use
49000 ** 32 4 First freelist page
49001 ** 36 4 Number of freelist pages in the file
49002 ** 40 60 15 4-byte meta values passed to higher layers
@@ -49006,13 +49116,14 @@
49006 ** 48 4 Size of page cache
49007 ** 52 4 Largest root-page (auto/incr_vacuum)
49008 ** 56 4 1=UTF-8 2=UTF16le 3=UTF16be
49009 ** 60 4 User version
49010 ** 64 4 Incremental vacuum mode
49011 ** 68 4 unused
49012 ** 72 4 unused
49013 ** 76 4 unused
 
49014 **
49015 ** All of the integer values are big-endian (most significant byte first).
49016 **
49017 ** The file change counter is incremented when the database is changed
49018 ** This counter allows other processes to know when the file has changed
@@ -52378,11 +52489,10 @@
52378 pBt->max1bytePayload = (u8)pBt->maxLocal;
52379 }
52380 assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
52381 pBt->pPage1 = pPage1;
52382 pBt->nPage = nPage;
52383 assert( pPage1->leaf==0 || pPage1->leaf==1 );
52384 return SQLITE_OK;
52385
52386 page1_init_failed:
52387 releasePage(pPage1);
52388 pBt->pPage1 = 0;
@@ -52538,11 +52648,11 @@
52538 ** is requested, this is a no-op.
52539 */
52540 if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
52541 goto trans_begun;
52542 }
52543 assert( IfNotOmitAV(pBt->bDoTruncate)==0 );
52544
52545 /* Write transactions are not possible on a read-only database */
52546 if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
52547 rc = SQLITE_READONLY;
52548 goto trans_begun;
@@ -62977,10 +63087,11 @@
62977 }
62978 fclose(out);
62979 }
62980 }
62981 #endif
 
62982 p->magic = VDBE_MAGIC_INIT;
62983 return p->rc & db->errMask;
62984 }
62985
62986 /*
@@ -76082,11 +76193,11 @@
76082 return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
76083 }
76084 #ifndef SQLITE_OMIT_CAST
76085 if( op==TK_CAST ){
76086 assert( !ExprHasProperty(pExpr, EP_IntValue) );
76087 return sqlite3AffinityType(pExpr->u.zToken);
76088 }
76089 #endif
76090 if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER)
76091 && pExpr->pTab!=0
76092 ){
@@ -78502,11 +78613,11 @@
78502 case TK_CAST: {
78503 /* Expressions of the form: CAST(pLeft AS token) */
78504 int aff, to_op;
78505 inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
78506 assert( !ExprHasProperty(pExpr, EP_IntValue) );
78507 aff = sqlite3AffinityType(pExpr->u.zToken);
78508 to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
78509 assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
78510 assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE );
78511 assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
78512 assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER );
@@ -79169,11 +79280,11 @@
79169 }
79170 #ifndef SQLITE_OMIT_CAST
79171 case TK_CAST: {
79172 /* Expressions of the form: CAST(pLeft AS token) */
79173 const char *zAff = "unk";
79174 switch( sqlite3AffinityType(pExpr->u.zToken) ){
79175 case SQLITE_AFF_TEXT: zAff = "TEXT"; break;
79176 case SQLITE_AFF_NONE: zAff = "NONE"; break;
79177 case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break;
79178 case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break;
79179 case SQLITE_AFF_REAL: zAff = "REAL"; break;
@@ -81884,16 +81995,16 @@
81884 if( zRet==0 ){
81885 sqlite3_result_error_nomem(context);
81886 return;
81887 }
81888
81889 sqlite3_snprintf(24, zRet, "%lld", p->nRow);
81890 z = zRet + sqlite3Strlen30(zRet);
81891 for(i=0; i<(p->nCol-1); i++){
81892 i64 nDistinct = p->current.anDLt[i] + 1;
81893 i64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
81894 sqlite3_snprintf(24, z, " %lld", iVal);
81895 z += sqlite3Strlen30(z);
81896 assert( p->current.anEq[i] );
81897 }
81898 assert( z[0]=='\0' && z>zRet );
81899
@@ -81930,11 +82041,11 @@
81930 sqlite3_result_error_nomem(context);
81931 }else{
81932 int i;
81933 char *z = zRet;
81934 for(i=0; i<p->nCol; i++){
81935 sqlite3_snprintf(24, z, "%lld ", aCnt[i]);
81936 z += sqlite3Strlen30(z);
81937 }
81938 assert( z[0]=='\0' && z>zRet );
81939 z[-1] = '\0';
81940 sqlite3_result_text(context, zRet, -1, sqlite3_free);
@@ -82391,22 +82502,20 @@
82391 ** The first argument points to a nul-terminated string containing a
82392 ** list of space separated integers. Read the first nOut of these into
82393 ** the array aOut[].
82394 */
82395 static void decodeIntArray(
82396 char *zIntArray,
82397 int nOut,
82398 tRowcnt *aOut,
82399 int *pbUnordered
82400 ){
82401 char *z = zIntArray;
82402 int c;
82403 int i;
82404 tRowcnt v;
82405
82406 assert( pbUnordered==0 || *pbUnordered==0 );
82407
82408 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
82409 if( z==0 ) z = "";
82410 #else
82411 if( NEVER(z==0) ) z = "";
82412 #endif
@@ -82417,12 +82526,23 @@
82417 z++;
82418 }
82419 aOut[i] = v;
82420 if( *z==' ' ) z++;
82421 }
82422 if( pbUnordered && strcmp(z, "unordered")==0 ){
82423 *pbUnordered = 1;
 
 
 
 
 
 
 
 
 
 
 
82424 }
82425 }
82426
82427 /*
82428 ** This callback is invoked once for each index when reading the
@@ -82457,16 +82577,17 @@
82457 pIndex = 0;
82458 }
82459 z = argv[2];
82460
82461 if( pIndex ){
82462 int bUnordered = 0;
82463 decodeIntArray((char*)z, pIndex->nColumn+1, pIndex->aiRowEst,&bUnordered);
82464 if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0];
82465 pIndex->bUnordered = bUnordered;
82466 }else{
82467 decodeIntArray((char*)z, 1, &pTable->nRowEst, 0);
 
 
 
82468 }
82469
82470 return 0;
82471 }
82472
@@ -83185,32 +83306,28 @@
83185 #endif /* SQLITE_OMIT_ATTACH */
83186
83187 /*
83188 ** Initialize a DbFixer structure. This routine must be called prior
83189 ** to passing the structure to one of the sqliteFixAAAA() routines below.
83190 **
83191 ** The return value indicates whether or not fixation is required. TRUE
83192 ** means we do need to fix the database references, FALSE means we do not.
83193 */
83194 SQLITE_PRIVATE int sqlite3FixInit(
83195 DbFixer *pFix, /* The fixer to be initialized */
83196 Parse *pParse, /* Error messages will be written here */
83197 int iDb, /* This is the database that must be used */
83198 const char *zType, /* "view", "trigger", or "index" */
83199 const Token *pName /* Name of the view, trigger, or index */
83200 ){
83201 sqlite3 *db;
83202
83203 if( NEVER(iDb<0) || iDb==1 ) return 0;
83204 db = pParse->db;
83205 assert( db->nDb>iDb );
83206 pFix->pParse = pParse;
83207 pFix->zDb = db->aDb[iDb].zName;
83208 pFix->pSchema = db->aDb[iDb].pSchema;
83209 pFix->zType = zType;
83210 pFix->pName = pName;
83211 return 1;
83212 }
83213
83214 /*
83215 ** The following set of routines walk through the parse tree and assign
83216 ** a specific database to all table references where the database name
@@ -83234,19 +83351,21 @@
83234 struct SrcList_item *pItem;
83235
83236 if( NEVER(pList==0) ) return 0;
83237 zDb = pFix->zDb;
83238 for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
83239 if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
83240 sqlite3ErrorMsg(pFix->pParse,
83241 "%s %T cannot reference objects in database %s",
83242 pFix->zType, pFix->pName, pItem->zDatabase);
83243 return 1;
83244 }
83245 sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
83246 pItem->zDatabase = 0;
83247 pItem->pSchema = pFix->pSchema;
 
 
83248 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
83249 if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
83250 if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
83251 #endif
83252 }
@@ -83264,13 +83383,25 @@
83264 if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
83265 return 1;
83266 }
83267 if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
83268 return 1;
 
 
 
83269 }
83270 if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
83271 return 1;
 
 
 
 
 
 
 
 
 
83272 }
83273 pSelect = pSelect->pPrior;
83274 }
83275 return 0;
83276 }
@@ -83277,10 +83408,18 @@
83277 SQLITE_PRIVATE int sqlite3FixExpr(
83278 DbFixer *pFix, /* Context of the fixation */
83279 Expr *pExpr /* The expression to be fixed to one database */
83280 ){
83281 while( pExpr ){
 
 
 
 
 
 
 
 
83282 if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
83283 if( ExprHasProperty(pExpr, EP_xIsSelect) ){
83284 if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
83285 }else{
83286 if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
@@ -84460,11 +84599,11 @@
84460 }
84461 pTable->zName = zName;
84462 pTable->iPKey = -1;
84463 pTable->pSchema = db->aDb[iDb].pSchema;
84464 pTable->nRef = 1;
84465 pTable->nRowEst = 1000000;
84466 assert( pParse->pNewTable==0 );
84467 pParse->pNewTable = pTable;
84468
84469 /* If this is the magic sqlite_sequence table used by autoincrement,
84470 ** then record a pointer to this table in the main database structure
@@ -84607,10 +84746,11 @@
84607 /* If there is no type specified, columns have the default affinity
84608 ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will
84609 ** be called next to set pCol->affinity correctly.
84610 */
84611 pCol->affinity = SQLITE_AFF_NONE;
 
84612 p->nCol++;
84613 }
84614
84615 /*
84616 ** This routine is called by the parser while in the middle of
@@ -84648,26 +84788,30 @@
84648 ** 'DOUB' | SQLITE_AFF_REAL
84649 **
84650 ** If none of the substrings in the above table are found,
84651 ** SQLITE_AFF_NUMERIC is returned.
84652 */
84653 SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn){
84654 u32 h = 0;
84655 char aff = SQLITE_AFF_NUMERIC;
 
84656
84657 if( zIn ) while( zIn[0] ){
 
84658 h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
84659 zIn++;
84660 if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
84661 aff = SQLITE_AFF_TEXT;
 
84662 }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */
84663 aff = SQLITE_AFF_TEXT;
84664 }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */
84665 aff = SQLITE_AFF_TEXT;
84666 }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
84667 && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
84668 aff = SQLITE_AFF_NONE;
 
84669 #ifndef SQLITE_OMIT_FLOATING_POINT
84670 }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
84671 && aff==SQLITE_AFF_NUMERIC ){
84672 aff = SQLITE_AFF_REAL;
84673 }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */
@@ -84681,10 +84825,32 @@
84681 aff = SQLITE_AFF_INTEGER;
84682 break;
84683 }
84684 }
84685
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84686 return aff;
84687 }
84688
84689 /*
84690 ** This routine is called by the parser while in the middle of
@@ -84702,11 +84868,11 @@
84702 p = pParse->pNewTable;
84703 if( p==0 || NEVER(p->nCol<1) ) return;
84704 pCol = &p->aCol[p->nCol-1];
84705 assert( pCol->zType==0 );
84706 pCol->zType = sqlite3NameFromToken(pParse->db, pType);
84707 pCol->affinity = sqlite3AffinityType(pCol->zType);
84708 }
84709
84710 /*
84711 ** The expression is the default value for the most recently added column
84712 ** of the table currently under construction.
@@ -85050,18 +85216,46 @@
85050 testcase( pCol->affinity==SQLITE_AFF_REAL );
85051
85052 zType = azType[pCol->affinity - SQLITE_AFF_TEXT];
85053 len = sqlite3Strlen30(zType);
85054 assert( pCol->affinity==SQLITE_AFF_NONE
85055 || pCol->affinity==sqlite3AffinityType(zType) );
85056 memcpy(&zStmt[k], zType, len);
85057 k += len;
85058 assert( k<=n );
85059 }
85060 sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
85061 return zStmt;
85062 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85063
85064 /*
85065 ** This routine is called to report the final ")" that terminates
85066 ** a CREATE TABLE statement.
85067 **
@@ -85085,13 +85279,14 @@
85085 Parse *pParse, /* Parse context */
85086 Token *pCons, /* The ',' token after the last column defn. */
85087 Token *pEnd, /* The final ')' token in the CREATE TABLE */
85088 Select *pSelect /* Select from a "CREATE ... AS SELECT" */
85089 ){
85090 Table *p;
85091 sqlite3 *db = pParse->db;
85092 int iDb;
 
85093
85094 if( (pEnd==0 && pSelect==0) || db->mallocFailed ){
85095 return;
85096 }
85097 p = pParse->pNewTable;
@@ -85106,10 +85301,16 @@
85106 */
85107 if( p->pCheck ){
85108 sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
85109 }
85110 #endif /* !defined(SQLITE_OMIT_CHECK) */
 
 
 
 
 
 
85111
85112 /* If the db->init.busy is 1 it means we are reading the SQL off the
85113 ** "sqlite_master" or "sqlite_temp_master" table on the disk.
85114 ** So do not write to the disk again. Extract the root page number
85115 ** for the table from the db->init.newTnum field. (The page number
@@ -85303,13 +85504,12 @@
85303 sqlite3SelectDelete(db, pSelect);
85304 return;
85305 }
85306 sqlite3TwoPartName(pParse, pName1, pName2, &pName);
85307 iDb = sqlite3SchemaToIndex(db, p->pSchema);
85308 if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
85309 && sqlite3FixSelect(&sFix, pSelect)
85310 ){
85311 sqlite3SelectDelete(db, pSelect);
85312 return;
85313 }
85314
85315 /* Make a copy of the entire SELECT statement that defines the view.
@@ -86066,13 +86266,14 @@
86066 sqlite3 *db = pParse->db;
86067 Db *pDb; /* The specific table containing the indexed database */
86068 int iDb; /* Index of the database that is being written */
86069 Token *pName = 0; /* Unqualified name of the index to create */
86070 struct ExprList_item *pListItem; /* For looping over pList */
86071 int nCol;
86072 int nExtra = 0;
86073 char *zExtra;
 
86074
86075 assert( pParse->nErr==0 ); /* Never called with prior errors */
86076 if( db->mallocFailed || IN_DECLARE_VTAB ){
86077 goto exit_create_index;
86078 }
@@ -86105,13 +86306,12 @@
86105 iDb = 1;
86106 }
86107 }
86108 #endif
86109
86110 if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) &&
86111 sqlite3FixSrcList(&sFix, pTblName)
86112 ){
86113 /* Because the parser constructs pTblName from a single identifier,
86114 ** sqlite3FixSrcList can never fail. */
86115 assert(0);
86116 }
86117 pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
@@ -86296,11 +86496,10 @@
86296 ** same column more than once cannot be an error because that would
86297 ** break backwards compatibility - it needs to be a warning.
86298 */
86299 for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
86300 const char *zColName = pListItem->zName;
86301 Column *pTabCol;
86302 int requestedSortOrder;
86303 char *zColl; /* Collation sequence name */
86304
86305 for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
86306 if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
@@ -86333,10 +86532,11 @@
86333 requestedSortOrder = pListItem->sortOrder & sortOrderMask;
86334 pIndex->aSortOrder[i] = (u8)requestedSortOrder;
86335 if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0;
86336 }
86337 sqlite3DefaultRowEst(pIndex);
 
86338
86339 if( pTab==pParse->pNewTable ){
86340 /* This routine has been called to create an automatic index as a
86341 ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
86342 ** a PRIMARY KEY or UNIQUE clause following the column definitions.
@@ -88238,10 +88438,11 @@
88238 ** API function sqlite3_count_changes) to be set incorrectly. */
88239 if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab)
88240 && 0==sqlite3FkRequired(pParse, pTab, 0, 0)
88241 ){
88242 assert( !isView );
 
88243 sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt,
88244 pTab->zName, P4_STATIC);
88245 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
88246 assert( pIdx->pSchema==pTab->pSchema );
88247 sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
@@ -93487,10 +93688,11 @@
93487 (char*)pKey, P4_KEYINFO_HANDOFF);
93488 VdbeComment((v, "%s", pSrcIdx->zName));
93489 pKey = sqlite3IndexKeyinfo(pParse, pDestIdx);
93490 sqlite3VdbeAddOp4(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest,
93491 (char*)pKey, P4_KEYINFO_HANDOFF);
 
93492 VdbeComment((v, "%s", pDestIdx->zName));
93493 addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
93494 sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
93495 sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
93496 sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
@@ -94974,181 +95176,363 @@
94974 #define PragTyp_HEXKEY 35
94975 #define PragTyp_KEY 36
94976 #define PragTyp_REKEY 37
94977 #define PragTyp_LOCK_STATUS 38
94978 #define PragTyp_PARSER_TRACE 39
 
94979 static const struct sPragmaNames {
94980 const char *const zName; /* Name of pragma */
94981 u8 ePragTyp; /* PragTyp_XXX value */
 
94982 u32 iArg; /* Extra argument */
94983 } aPragmaNames[] = {
94984 #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
94985 { "activate_extensions", PragTyp_ACTIVATE_EXTENSIONS, 0 },
 
 
 
94986 #endif
94987 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
94988 { "application_id", PragTyp_HEADER_VALUE, 0 },
 
 
 
94989 #endif
94990 #if !defined(SQLITE_OMIT_AUTOVACUUM)
94991 { "auto_vacuum", PragTyp_AUTO_VACUUM, 0 },
 
 
 
94992 #endif
94993 #if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
94994 { "automatic_index", PragTyp_FLAG,
94995 SQLITE_AutoIndex },
 
 
94996 #endif
94997 { "busy_timeout", PragTyp_BUSY_TIMEOUT, 0 },
 
 
 
94998 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
94999 { "cache_size", PragTyp_CACHE_SIZE, 0 },
 
 
 
95000 #endif
95001 { "cache_spill", PragTyp_FLAG,
95002 SQLITE_CacheSpill },
95003 { "case_sensitive_like", PragTyp_CASE_SENSITIVE_LIKE, 0 },
95004 { "checkpoint_fullfsync", PragTyp_FLAG,
95005 SQLITE_CkptFullFSync },
 
 
 
 
 
 
 
95006 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95007 { "collation_list", PragTyp_COLLATION_LIST, 0 },
 
 
 
95008 #endif
95009 #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
95010 { "compile_options", PragTyp_COMPILE_OPTIONS, 0 },
 
 
 
95011 #endif
95012 { "count_changes", PragTyp_FLAG,
95013 SQLITE_CountRows },
 
 
95014 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
95015 { "data_store_directory", PragTyp_DATA_STORE_DIRECTORY, 0 },
 
 
 
95016 #endif
95017 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95018 { "database_list", PragTyp_DATABASE_LIST, 0 },
 
 
 
95019 #endif
95020 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
95021 { "default_cache_size", PragTyp_DEFAULT_CACHE_SIZE, 0 },
 
 
 
95022 #endif
95023 #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
95024 { "defer_foreign_keys", PragTyp_FLAG,
95025 SQLITE_DeferFKs },
 
 
95026 #endif
95027 { "empty_result_callbacks", PragTyp_FLAG,
95028 SQLITE_NullCallback },
 
 
95029 #if !defined(SQLITE_OMIT_UTF16)
95030 { "encoding", PragTyp_ENCODING, 0 },
 
 
 
95031 #endif
95032 #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
95033 { "foreign_key_check", PragTyp_FOREIGN_KEY_CHECK, 0 },
 
 
 
95034 #endif
95035 #if !defined(SQLITE_OMIT_FOREIGN_KEY)
95036 { "foreign_key_list", PragTyp_FOREIGN_KEY_LIST, 0 },
 
 
 
95037 #endif
95038 #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
95039 { "foreign_keys", PragTyp_FLAG,
95040 SQLITE_ForeignKeys },
 
 
95041 #endif
95042 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95043 { "freelist_count", PragTyp_HEADER_VALUE, 0 },
 
 
 
95044 #endif
95045 { "full_column_names", PragTyp_FLAG,
95046 SQLITE_FullColNames },
95047 { "fullfsync", PragTyp_FLAG,
95048 SQLITE_FullFSync },
 
 
 
 
95049 #if defined(SQLITE_HAS_CODEC)
95050 { "hexkey", PragTyp_HEXKEY, 0 },
 
 
 
 
 
 
 
95051 #endif
95052 #if !defined(SQLITE_OMIT_CHECK)
95053 { "ignore_check_constraints", PragTyp_FLAG,
95054 SQLITE_IgnoreChecks },
 
 
95055 #endif
95056 #if !defined(SQLITE_OMIT_AUTOVACUUM)
95057 { "incremental_vacuum", PragTyp_INCREMENTAL_VACUUM, 0 },
 
 
 
95058 #endif
95059 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95060 { "index_info", PragTyp_INDEX_INFO, 0 },
95061 { "index_list", PragTyp_INDEX_LIST, 0 },
 
 
 
 
 
 
95062 #endif
95063 #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
95064 { "integrity_check", PragTyp_INTEGRITY_CHECK, 0 },
 
 
 
95065 #endif
95066 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95067 { "journal_mode", PragTyp_JOURNAL_MODE, 0 },
95068 { "journal_size_limit", PragTyp_JOURNAL_SIZE_LIMIT, 0 },
 
 
 
 
 
 
95069 #endif
95070 #if defined(SQLITE_HAS_CODEC)
95071 { "key", PragTyp_KEY, 0 },
 
 
 
95072 #endif
95073 { "legacy_file_format", PragTyp_FLAG,
95074 SQLITE_LegacyFileFmt },
 
 
95075 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
95076 { "lock_proxy_file", PragTyp_LOCK_PROXY_FILE, 0 },
 
 
 
95077 #endif
95078 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
95079 { "lock_status", PragTyp_LOCK_STATUS, 0 },
95080 #endif
95081 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95082 { "locking_mode", PragTyp_LOCKING_MODE, 0 },
95083 { "max_page_count", PragTyp_PAGE_COUNT, 0 },
95084 { "mmap_size", PragTyp_MMAP_SIZE, 0 },
95085 { "page_count", PragTyp_PAGE_COUNT, 0 },
95086 { "page_size", PragTyp_PAGE_SIZE, 0 },
95087 #endif
95088 #if defined(SQLITE_DEBUG)
95089 { "parser_trace", PragTyp_PARSER_TRACE, 0 },
95090 #endif
95091 { "query_only", PragTyp_FLAG,
95092 SQLITE_QueryOnly },
95093 #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
95094 { "quick_check", PragTyp_INTEGRITY_CHECK, 0 },
95095 #endif
95096 { "read_uncommitted", PragTyp_FLAG,
95097 SQLITE_ReadUncommitted },
95098 { "recursive_triggers", PragTyp_FLAG,
95099 SQLITE_RecTriggers },
95100 #if defined(SQLITE_HAS_CODEC)
95101 { "rekey", PragTyp_REKEY, 0 },
95102 #endif
95103 { "reverse_unordered_selects", PragTyp_FLAG,
95104 SQLITE_ReverseOrder },
95105 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95106 { "schema_version", PragTyp_HEADER_VALUE, 0 },
95107 #endif
95108 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95109 { "secure_delete", PragTyp_SECURE_DELETE, 0 },
95110 #endif
95111 { "short_column_names", PragTyp_FLAG,
95112 SQLITE_ShortColNames },
95113 { "shrink_memory", PragTyp_SHRINK_MEMORY, 0 },
95114 { "soft_heap_limit", PragTyp_SOFT_HEAP_LIMIT, 0 },
95115 #if defined(SQLITE_DEBUG)
95116 { "sql_trace", PragTyp_FLAG,
95117 SQLITE_SqlTrace },
95118 #endif
95119 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95120 { "synchronous", PragTyp_SYNCHRONOUS, 0 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95121 #endif
95122 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95123 { "table_info", PragTyp_TABLE_INFO, 0 },
 
 
 
95124 #endif
95125 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95126 { "temp_store", PragTyp_TEMP_STORE, 0 },
95127 { "temp_store_directory", PragTyp_TEMP_STORE_DIRECTORY, 0 },
 
 
 
 
 
 
95128 #endif
95129 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95130 { "user_version", PragTyp_HEADER_VALUE, 0 },
 
 
 
95131 #endif
95132 #if defined(SQLITE_DEBUG)
95133 { "vdbe_addoptrace", PragTyp_FLAG,
95134 SQLITE_VdbeAddopTrace },
95135 { "vdbe_debug", PragTyp_FLAG,
95136 SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
95137 { "vdbe_listing", PragTyp_FLAG,
95138 SQLITE_VdbeListing },
95139 { "vdbe_trace", PragTyp_FLAG,
95140 SQLITE_VdbeTrace },
 
 
 
 
 
 
 
 
95141 #endif
95142 #if !defined(SQLITE_OMIT_WAL)
95143 { "wal_autocheckpoint", PragTyp_WAL_AUTOCHECKPOINT, 0 },
95144 { "wal_checkpoint", PragTyp_WAL_CHECKPOINT, 0 },
 
 
 
 
 
 
95145 #endif
95146 { "writable_schema", PragTyp_FLAG,
95147 SQLITE_WriteSchema|SQLITE_RecoveryMode },
 
 
95148 };
95149 /* Number of pragmas: 55 on by default, 66 total. */
95150 /* End of the automatically generated pragma table.
95151 ***************************************************************************/
95152
95153 /*
95154 ** Interpret the given string as a safety level. Return 0 for OFF,
@@ -95476,10 +95860,15 @@
95476 }else{
95477 lwr = mid + 1;
95478 }
95479 }
95480 if( lwr>upr ) goto pragma_out;
 
 
 
 
 
95481
95482 /* Jump to the appropriate pragma handler */
95483 switch( aPragmaNames[mid].ePragTyp ){
95484
95485 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
@@ -95510,11 +95899,10 @@
95510 { OP_Integer, 0, 1, 0}, /* 6 */
95511 { OP_Noop, 0, 0, 0},
95512 { OP_ResultRow, 1, 1, 0},
95513 };
95514 int addr;
95515 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
95516 sqlite3VdbeUsesBtree(v, iDb);
95517 if( !zRight ){
95518 sqlite3VdbeSetNumCols(v, 1);
95519 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC);
95520 pParse->nMem += 2;
@@ -95606,11 +95994,10 @@
95606 **
95607 ** Return the number of pages in the specified database.
95608 */
95609 case PragTyp_PAGE_COUNT: {
95610 int iReg;
95611 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
95612 sqlite3CodeVerifySchema(pParse, iDb);
95613 iReg = ++pParse->nMem;
95614 if( sqlite3Tolower(zLeft[0])=='p' ){
95615 sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
95616 }else{
@@ -95679,18 +96066,10 @@
95679 */
95680 case PragTyp_JOURNAL_MODE: {
95681 int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
95682 int ii; /* Loop counter */
95683
95684 /* Force the schema to be loaded on all databases. This causes all
95685 ** database files to be opened and the journal_modes set. This is
95686 ** necessary because subsequent processing must know if the databases
95687 ** are in WAL mode. */
95688 if( sqlite3ReadSchema(pParse) ){
95689 goto pragma_out;
95690 }
95691
95692 sqlite3VdbeSetNumCols(v, 1);
95693 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
95694
95695 if( zRight==0 ){
95696 /* If there is no "=MODE" part of the pragma, do a query for the
@@ -95752,55 +96131,44 @@
95752 */
95753 #ifndef SQLITE_OMIT_AUTOVACUUM
95754 case PragTyp_AUTO_VACUUM: {
95755 Btree *pBt = pDb->pBt;
95756 assert( pBt!=0 );
95757 if( sqlite3ReadSchema(pParse) ){
95758 goto pragma_out;
95759 }
95760 if( !zRight ){
95761 int auto_vacuum;
95762 if( ALWAYS(pBt) ){
95763 auto_vacuum = sqlite3BtreeGetAutoVacuum(pBt);
95764 }else{
95765 auto_vacuum = SQLITE_DEFAULT_AUTOVACUUM;
95766 }
95767 returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
95768 }else{
95769 int eAuto = getAutoVacuum(zRight);
95770 assert( eAuto>=0 && eAuto<=2 );
95771 db->nextAutovac = (u8)eAuto;
95772 if( ALWAYS(eAuto>=0) ){
95773 /* Call SetAutoVacuum() to set initialize the internal auto and
95774 ** incr-vacuum flags. This is required in case this connection
95775 ** creates the database file. It is important that it is created
95776 ** as an auto-vacuum capable db.
95777 */
95778 rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
95779 if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
95780 /* When setting the auto_vacuum mode to either "full" or
95781 ** "incremental", write the value of meta[6] in the database
95782 ** file. Before writing to meta[6], check that meta[3] indicates
95783 ** that this really is an auto-vacuum capable database.
95784 */
95785 static const VdbeOpList setMeta6[] = {
95786 { OP_Transaction, 0, 1, 0}, /* 0 */
95787 { OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
95788 { OP_If, 1, 0, 0}, /* 2 */
95789 { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
95790 { OP_Integer, 0, 1, 0}, /* 4 */
95791 { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
95792 };
95793 int iAddr;
95794 iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
95795 sqlite3VdbeChangeP1(v, iAddr, iDb);
95796 sqlite3VdbeChangeP1(v, iAddr+1, iDb);
95797 sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
95798 sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
95799 sqlite3VdbeChangeP1(v, iAddr+5, iDb);
95800 sqlite3VdbeUsesBtree(v, iDb);
95801 }
95802 }
95803 }
95804 break;
95805 }
95806 #endif
@@ -95811,13 +96179,10 @@
95811 ** Do N steps of incremental vacuuming on a database.
95812 */
95813 #ifndef SQLITE_OMIT_AUTOVACUUM
95814 case PragTyp_INCREMENTAL_VACUUM: {
95815 int iLimit, addr;
95816 if( sqlite3ReadSchema(pParse) ){
95817 goto pragma_out;
95818 }
95819 if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
95820 iLimit = 0x7fffffff;
95821 }
95822 sqlite3BeginWriteOperation(pParse, 0, iDb);
95823 sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1);
@@ -95841,11 +96206,10 @@
95841 ** number of pages in the cache. If N is negative, then the
95842 ** number of pages is adjusted so that the cache uses -N kibibytes
95843 ** of memory.
95844 */
95845 case PragTyp_CACHE_SIZE: {
95846 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
95847 assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
95848 if( !zRight ){
95849 returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
95850 }else{
95851 int size = sqlite3Atoi(zRight);
@@ -96062,11 +96426,10 @@
96062 ** the local value does not make changes to the disk file and the
96063 ** default value will be restored the next time the database is
96064 ** opened.
96065 */
96066 case PragTyp_SYNCHRONOUS: {
96067 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96068 if( !zRight ){
96069 returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
96070 }else{
96071 if( !db->autoCommit ){
96072 sqlite3ErrorMsg(pParse,
@@ -96124,11 +96487,10 @@
96124 ** notnull: True if 'NOT NULL' is part of column declaration
96125 ** dflt_value: The default value for the column, if any.
96126 */
96127 case PragTyp_TABLE_INFO: if( zRight ){
96128 Table *pTab;
96129 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96130 pTab = sqlite3FindTable(db, zRight, zDb);
96131 if( pTab ){
96132 int i, k;
96133 int nHidden = 0;
96134 Column *pCol;
@@ -96174,11 +96536,10 @@
96174 break;
96175
96176 case PragTyp_INDEX_INFO: if( zRight ){
96177 Index *pIdx;
96178 Table *pTab;
96179 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96180 pIdx = sqlite3FindIndex(db, zRight, zDb);
96181 if( pIdx ){
96182 int i;
96183 pTab = pIdx->pTable;
96184 sqlite3VdbeSetNumCols(v, 3);
@@ -96200,39 +96561,41 @@
96200 break;
96201
96202 case PragTyp_INDEX_LIST: if( zRight ){
96203 Index *pIdx;
96204 Table *pTab;
96205 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96206 pTab = sqlite3FindTable(db, zRight, zDb);
96207 if( pTab ){
96208 v = sqlite3GetVdbe(pParse);
96209 pIdx = pTab->pIndex;
96210 if( pIdx ){
96211 int i = 0;
96212 sqlite3VdbeSetNumCols(v, 3);
96213 pParse->nMem = 3;
96214 sqlite3CodeVerifySchema(pParse, iDb);
96215 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
96216 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
96217 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
96218 while(pIdx){
96219 sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
96220 sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
96221 sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
96222 sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
96223 ++i;
96224 pIdx = pIdx->pNext;
96225 }
 
 
 
96226 }
96227 }
96228 }
96229 break;
96230
96231 case PragTyp_DATABASE_LIST: {
96232 int i;
96233 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96234 sqlite3VdbeSetNumCols(v, 3);
96235 pParse->nMem = 3;
96236 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
96237 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
96238 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", SQLITE_STATIC);
@@ -96267,11 +96630,10 @@
96267
96268 #ifndef SQLITE_OMIT_FOREIGN_KEY
96269 case PragTyp_FOREIGN_KEY_LIST: if( zRight ){
96270 FKey *pFK;
96271 Table *pTab;
96272 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96273 pTab = sqlite3FindTable(db, zRight, zDb);
96274 if( pTab ){
96275 v = sqlite3GetVdbe(pParse);
96276 pFK = pTab->pFKey;
96277 if( pFK ){
@@ -96329,11 +96691,10 @@
96329 int regRow; /* Registers to hold a row from pTab */
96330 int addrTop; /* Top of a loop checking foreign keys */
96331 int addrOk; /* Jump here if the key is OK */
96332 int *aiCols; /* child to parent column mapping */
96333
96334 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96335 regResult = pParse->nMem+1;
96336 pParse->nMem += 4;
96337 regKey = ++pParse->nMem;
96338 regRow = ++pParse->nMem;
96339 v = sqlite3GetVdbe(pParse);
@@ -96490,11 +96851,10 @@
96490 assert( iDb>=0 );
96491 assert( iDb==0 || pId2->z );
96492 if( pId2->z==0 ) iDb = -1;
96493
96494 /* Initialize the VDBE program */
96495 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96496 pParse->nMem = 6;
96497 sqlite3VdbeSetNumCols(v, 1);
96498 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", SQLITE_STATIC);
96499
96500 /* Set the maximum error count */
@@ -96814,11 +97174,10 @@
96814 eMode = SQLITE_CHECKPOINT_FULL;
96815 }else if( sqlite3StrICmp(zRight, "restart")==0 ){
96816 eMode = SQLITE_CHECKPOINT_RESTART;
96817 }
96818 }
96819 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
96820 sqlite3VdbeSetNumCols(v, 3);
96821 pParse->nMem = 3;
96822 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "busy", SQLITE_STATIC);
96823 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "log", SQLITE_STATIC);
96824 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "checkpointed", SQLITE_STATIC);
@@ -96934,16 +97293,16 @@
96934 if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight));
96935 break;
96936 }
96937 case PragTyp_HEXKEY: {
96938 if( zRight ){
96939 int i, h1, h2;
 
96940 char zKey[40];
96941 for(i=0; (h1 = zRight[i])!=0 && (h2 = zRight[i+1])!=0; i+=2){
96942 h1 += 9*(1&(h1>>6));
96943 h2 += 9*(1&(h2>>6));
96944 zKey[i/2] = (h2 & 0x0f) | ((h1 & 0xf)<<4);
96945 }
96946 if( (zLeft[3] & 0xf)==0xb ){
96947 sqlite3_key_v2(db, zDb, zKey, i/2);
96948 }else{
96949 sqlite3_rekey_v2(db, zDb, zKey, i/2);
@@ -98913,10 +99272,13 @@
98913 }
98914
98915 /*
98916 ** Return a pointer to a string containing the 'declaration type' of the
98917 ** expression pExpr. The string may be treated as static by the caller.
 
 
 
98918 **
98919 ** The declaration type is the exact datatype definition extracted from the
98920 ** original CREATE TABLE statement if the expression is a column. The
98921 ** declaration type for a ROWID field is INTEGER. Exactly when an expression
98922 ** is considered a column can be complex in the presence of subqueries. The
@@ -98927,25 +99289,40 @@
98927 ** SELECT (SELECT col FROM tbl;
98928 ** SELECT (SELECT col FROM tbl);
98929 ** SELECT abc FROM (SELECT col AS abc FROM tbl);
98930 **
98931 ** The declaration type for any expression other than a column is NULL.
 
 
 
98932 */
98933 static const char *columnType(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98934 NameContext *pNC,
98935 Expr *pExpr,
98936 const char **pzOriginDb,
98937 const char **pzOriginTab,
98938 const char **pzOriginCol
98939 ){
 
98940 char const *zType = 0;
98941 char const *zOriginDb = 0;
98942 char const *zOriginTab = 0;
98943 char const *zOriginCol = 0;
98944 int j;
 
 
98945 if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
98946
98947 switch( pExpr->op ){
98948 case TK_AGG_COLUMN:
98949 case TK_COLUMN: {
98950 /* The expression is a column. Locate the table the column is being
98951 ** extracted from in NameContext.pSrcList. This table may be real
@@ -99002,29 +99379,39 @@
99002 NameContext sNC;
99003 Expr *p = pS->pEList->a[iCol].pExpr;
99004 sNC.pSrcList = pS->pSrc;
99005 sNC.pNext = pNC;
99006 sNC.pParse = pNC->pParse;
99007 zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
99008 }
99009 }else if( ALWAYS(pTab->pSchema) ){
99010 /* A real table */
99011 assert( !pS );
99012 if( iCol<0 ) iCol = pTab->iPKey;
99013 assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
 
99014 if( iCol<0 ){
99015 zType = "INTEGER";
99016 zOriginCol = "rowid";
99017 }else{
99018 zType = pTab->aCol[iCol].zType;
99019 zOriginCol = pTab->aCol[iCol].zName;
 
99020 }
99021 zOriginTab = pTab->zName;
99022 if( pNC->pParse ){
99023 int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
99024 zOriginDb = pNC->pParse->db->aDb[iDb].zName;
99025 }
 
 
 
 
 
 
 
 
99026 }
99027 break;
99028 }
99029 #ifndef SQLITE_OMIT_SUBQUERY
99030 case TK_SELECT: {
@@ -99037,22 +99424,25 @@
99037 Expr *p = pS->pEList->a[0].pExpr;
99038 assert( ExprHasProperty(pExpr, EP_xIsSelect) );
99039 sNC.pSrcList = pS->pSrc;
99040 sNC.pNext = pNC;
99041 sNC.pParse = pNC->pParse;
99042 zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol);
99043 break;
99044 }
99045 #endif
99046 }
99047
99048 if( pzOriginDb ){
99049 assert( pzOriginTab && pzOriginCol );
99050 *pzOriginDb = zOriginDb;
99051 *pzOriginTab = zOriginTab;
99052 *pzOriginCol = zOriginCol;
 
99053 }
 
 
99054 return zType;
99055 }
99056
99057 /*
99058 ** Generate code that will tell the VDBE the declaration types of columns
@@ -99074,25 +99464,25 @@
99074 const char *zType;
99075 #ifdef SQLITE_ENABLE_COLUMN_METADATA
99076 const char *zOrigDb = 0;
99077 const char *zOrigTab = 0;
99078 const char *zOrigCol = 0;
99079 zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
99080
99081 /* The vdbe must make its own copy of the column-type and other
99082 ** column specific strings, in case the schema is reset before this
99083 ** virtual machine is deleted.
99084 */
99085 sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, SQLITE_TRANSIENT);
99086 sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
99087 sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
99088 #else
99089 zType = columnType(&sNC, p, 0, 0, 0);
99090 #endif
99091 sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
99092 }
99093 #endif /* SQLITE_OMIT_DECLTYPE */
99094 }
99095
99096 /*
99097 ** Generate code that will tell the VDBE the names of columns
99098 ** in the result set. This information is used to provide the
@@ -99277,39 +99667,41 @@
99277 ** This routine requires that all identifiers in the SELECT
99278 ** statement be resolved.
99279 */
99280 static void selectAddColumnTypeAndCollation(
99281 Parse *pParse, /* Parsing contexts */
99282 int nCol, /* Number of columns */
99283 Column *aCol, /* List of columns */
99284 Select *pSelect /* SELECT used to determine types and collations */
99285 ){
99286 sqlite3 *db = pParse->db;
99287 NameContext sNC;
99288 Column *pCol;
99289 CollSeq *pColl;
99290 int i;
99291 Expr *p;
99292 struct ExprList_item *a;
 
99293
99294 assert( pSelect!=0 );
99295 assert( (pSelect->selFlags & SF_Resolved)!=0 );
99296 assert( nCol==pSelect->pEList->nExpr || db->mallocFailed );
99297 if( db->mallocFailed ) return;
99298 memset(&sNC, 0, sizeof(sNC));
99299 sNC.pSrcList = pSelect->pSrc;
99300 a = pSelect->pEList->a;
99301 for(i=0, pCol=aCol; i<nCol; i++, pCol++){
99302 p = a[i].pExpr;
99303 pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p, 0, 0, 0));
 
99304 pCol->affinity = sqlite3ExprAffinity(p);
99305 if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE;
99306 pColl = sqlite3ExprCollSeq(pParse, p);
99307 if( pColl ){
99308 pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
99309 }
99310 }
 
99311 }
99312
99313 /*
99314 ** Given a SELECT statement, generate a Table structure that describes
99315 ** the result set of that SELECT.
@@ -99333,13 +99725,13 @@
99333 /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
99334 ** is disabled */
99335 assert( db->lookaside.bEnabled==0 );
99336 pTab->nRef = 1;
99337 pTab->zName = 0;
99338 pTab->nRowEst = 1000000;
99339 selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
99340 selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSelect);
99341 pTab->iPKey = -1;
99342 if( db->mallocFailed ){
99343 sqlite3DeleteTable(db, pTab);
99344 return 0;
99345 }
@@ -101247,15 +101639,15 @@
101247 assert( pFrom->pTab==0 );
101248 sqlite3WalkSelect(pWalker, pSel);
101249 pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
101250 if( pTab==0 ) return WRC_Abort;
101251 pTab->nRef = 1;
101252 pTab->zName = sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pTab);
101253 while( pSel->pPrior ){ pSel = pSel->pPrior; }
101254 selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
101255 pTab->iPKey = -1;
101256 pTab->nRowEst = 1000000;
101257 pTab->tabFlags |= TF_Ephemeral;
101258 #endif
101259 }else{
101260 /* An ordinary table or view name in the FROM clause */
101261 assert( pFrom->pTab==0 );
@@ -101535,11 +101927,11 @@
101535 if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
101536 /* A sub-query in the FROM clause of a SELECT */
101537 Select *pSel = pFrom->pSelect;
101538 assert( pSel );
101539 while( pSel->pPrior ) pSel = pSel->pPrior;
101540 selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
101541 }
101542 }
101543 }
101544 return WRC_Continue;
101545 }
@@ -102450,29 +102842,29 @@
102450 int iRoot = pTab->tnum; /* Root page of scanned b-tree */
102451
102452 sqlite3CodeVerifySchema(pParse, iDb);
102453 sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
102454
102455 /* Search for the index that has the least amount of columns. If
102456 ** there is such an index, and it has less columns than the table
102457 ** does, then we can assume that it consumes less space on disk and
102458 ** will therefore be cheaper to scan to determine the query result.
102459 ** In this case set iRoot to the root page number of the index b-tree
102460 ** and pKeyInfo to the KeyInfo structure required to navigate the
102461 ** index.
102462 **
102463 ** (2011-04-15) Do not do a full scan of an unordered index.
 
 
102464 **
102465 ** In practice the KeyInfo structure will not be used. It is only
102466 ** passed to keep OP_OpenRead happy.
102467 */
102468 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
102469 if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){
 
 
 
 
102470 pBest = pIdx;
102471 }
102472 }
102473 if( pBest && pBest->nColumn<pTab->nCol ){
102474 iRoot = pBest->tnum;
102475 pKeyInfo = sqlite3IndexKeyinfo(pParse, pBest);
102476 }
102477
102478 /* Open a read-only cursor, execute the OP_Count, close the cursor. */
@@ -103046,12 +103438,12 @@
103046 }
103047
103048 /* Ensure the table name matches database name and that the table exists */
103049 if( db->mallocFailed ) goto trigger_cleanup;
103050 assert( pTableName->nSrc==1 );
103051 if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) &&
103052 sqlite3FixSrcList(&sFix, pTableName) ){
103053 goto trigger_cleanup;
103054 }
103055 pTab = sqlite3SrcListLookup(pParse, pTableName);
103056 if( !pTab ){
103057 /* The table does not exist. */
@@ -103189,12 +103581,14 @@
103189 pStepList->pTrig = pTrig;
103190 pStepList = pStepList->pNext;
103191 }
103192 nameToken.z = pTrig->zName;
103193 nameToken.n = sqlite3Strlen30(nameToken.z);
103194 if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken)
103195 && sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){
 
 
103196 goto triggerfinish_cleanup;
103197 }
103198
103199 /* if we are not initializing,
103200 ** build the sqlite_master entry
@@ -104781,18 +105175,38 @@
104781
104782 return vacuumFinalize(db, pStmt, pzErrMsg);
104783 }
104784
104785 /*
104786 ** The non-standard VACUUM command is used to clean up the database,
104787 ** collapse free space, etc. It is modelled after the VACUUM command
104788 ** in PostgreSQL.
104789 **
104790 ** In version 1.0.x of SQLite, the VACUUM command would call
104791 ** gdbm_reorganize() on all the database tables. But beginning
104792 ** with 2.0.0, SQLite no longer uses GDBM so this command has
104793 ** become a no-op.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104794 */
104795 SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
104796 Vdbe *v = sqlite3GetVdbe(pParse);
104797 if( v ){
104798 sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
@@ -106206,30 +106620,10 @@
106206 typedef struct WhereLoopBuilder WhereLoopBuilder;
106207 typedef struct WhereScan WhereScan;
106208 typedef struct WhereOrCost WhereOrCost;
106209 typedef struct WhereOrSet WhereOrSet;
106210
106211 /*
106212 ** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The
106213 ** maximum cost for ordinary tables is 64*(2**63) which becomes 6900.
106214 ** (Virtual tables can return a larger cost, but let's assume they do not.)
106215 ** So all costs can be stored in a 16-bit integer without risk
106216 ** of overflow.
106217 **
106218 ** Costs are estimates, so no effort is made to compute 10*log2(X) exactly.
106219 ** Instead, a close estimate is used. Any value of X=1 is stored as 0.
106220 ** X=2 is 10. X=3 is 16. X=1000 is 99. etc. Negative values are allowed.
106221 ** A WhereCost of -10 means 0.5. WhereCost of -20 means 0.25. And so forth.
106222 **
106223 ** The tool/wherecosttest.c source file implements a command-line program
106224 ** that will convert WhereCosts to integers, convert integers to WhereCosts
106225 ** and do addition and multiplication on WhereCost values. The wherecosttest
106226 ** command-line program is a useful utility to have around when working with
106227 ** this module.
106228 */
106229 typedef short int WhereCost;
106230
106231 /*
106232 ** This object contains information needed to implement a single nested
106233 ** loop in WHERE clause.
106234 **
106235 ** Contrast this object with WhereLoop. This object describes the
@@ -106290,13 +106684,13 @@
106290 #ifdef SQLITE_DEBUG
106291 char cId; /* Symbolic ID of this loop for debugging use */
106292 #endif
106293 u8 iTab; /* Position in FROM clause of table for this loop */
106294 u8 iSortIdx; /* Sorting index number. 0==None */
106295 WhereCost rSetup; /* One-time setup cost (ex: create transient index) */
106296 WhereCost rRun; /* Cost of running each loop */
106297 WhereCost nOut; /* Estimated number of output rows */
106298 union {
106299 struct { /* Information for internal btree tables */
106300 int nEq; /* Number of equality constraints */
106301 Index *pIndex; /* Index used, or NULL */
106302 } btree;
@@ -106322,12 +106716,12 @@
106322 ** subquery on one operand of an OR operator in the WHERE clause.
106323 ** See WhereOrSet for additional information
106324 */
106325 struct WhereOrCost {
106326 Bitmask prereq; /* Prerequisites */
106327 WhereCost rRun; /* Cost of running this subquery */
106328 WhereCost nOut; /* Number of outputs for this subquery */
106329 };
106330
106331 /* The WhereOrSet object holds a set of possible WhereOrCosts that
106332 ** correspond to the subquery(s) of OR-clause processing. Only the
106333 ** best N_OR_COST elements are retained.
@@ -106361,12 +106755,12 @@
106361 ** at the end is the choosen query plan.
106362 */
106363 struct WherePath {
106364 Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
106365 Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
106366 WhereCost nRow; /* Estimated number of rows generated by this path */
106367 WhereCost rCost; /* Total cost of this path */
106368 u8 isOrdered; /* True if this path satisfies ORDER BY */
106369 u8 isOrderedValid; /* True if the isOrdered field is valid */
106370 WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
106371 };
106372
@@ -106428,11 +106822,11 @@
106428 union {
106429 int leftColumn; /* Column number of X in "X <op> <expr>" */
106430 WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
106431 WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
106432 } u;
106433 WhereCost truthProb; /* Probability of truth for this expression */
106434 u16 eOperator; /* A WO_xx value describing <op> */
106435 u8 wtFlags; /* TERM_xxx bit flags. See below */
106436 u8 nChild; /* Number of children that must disable us */
106437 WhereClause *pWC; /* The clause this term is part of */
106438 Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */
@@ -106576,11 +106970,11 @@
106576 SrcList *pTabList; /* List of tables in the join */
106577 ExprList *pOrderBy; /* The ORDER BY clause or NULL */
106578 ExprList *pResultSet; /* Result set. DISTINCT operates on these */
106579 WhereLoop *pLoops; /* List of all WhereLoop objects */
106580 Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
106581 WhereCost nRowOut; /* Estimated number of output rows */
106582 u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
106583 u8 bOBSat; /* ORDER BY satisfied by indices */
106584 u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
106585 u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
106586 u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
@@ -106636,30 +107030,15 @@
106636 #define WHERE_IN_ABLE 0x00000800 /* Able to support an IN operator */
106637 #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */
106638 #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */
106639 #define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
106640
106641
106642 /* Convert a WhereCost value (10 times log2(X)) into its integer value X.
106643 ** A rough approximation is used. The value returned is not exact.
106644 */
106645 static u64 whereCostToInt(WhereCost x){
106646 u64 n;
106647 if( x<10 ) return 1;
106648 n = x%10;
106649 x /= 10;
106650 if( n>=5 ) n -= 2;
106651 else if( n>=1 ) n -= 1;
106652 if( x>=3 ) return (n+8)<<(x-3);
106653 return (n+8)>>(3-x);
106654 }
106655
106656 /*
106657 ** Return the estimated number of output rows from a WHERE clause
106658 */
106659 SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
106660 return whereCostToInt(pWInfo->nRowOut);
106661 }
106662
106663 /*
106664 ** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this
106665 ** WHERE clause returns outputs for DISTINCT processing.
@@ -106717,12 +107096,12 @@
106717 ** so that pSet keeps the N_OR_COST best entries seen so far.
106718 */
106719 static int whereOrInsert(
106720 WhereOrSet *pSet, /* The WhereOrSet to be updated */
106721 Bitmask prereq, /* Prerequisites of the new entry */
106722 WhereCost rRun, /* Run-cost of the new entry */
106723 WhereCost nOut /* Number of outputs for the new entry */
106724 ){
106725 u16 i;
106726 WhereOrCost *p;
106727 for(i=pSet->n, p=pSet->a; i>0; i--, p++){
106728 if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){
@@ -106803,13 +107182,10 @@
106803 if( pWC->a!=pWC->aStatic ){
106804 sqlite3DbFree(db, pWC->a);
106805 }
106806 }
106807
106808 /* Forward declaration */
106809 static WhereCost whereCost(tRowcnt x);
106810
106811 /*
106812 ** Add a single new WhereTerm entry to the WhereClause object pWC.
106813 ** The new WhereTerm object is constructed from Expr p and with wtFlags.
106814 ** The index in pWC->a[] of the new WhereTerm is returned on success.
106815 ** 0 is returned if the new WhereTerm could not be added due to a memory
@@ -106848,11 +107224,11 @@
106848 }
106849 pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
106850 }
106851 pTerm = &pWC->a[idx = pWC->nTerm++];
106852 if( p && ExprHasProperty(p, EP_Unlikely) ){
106853 pTerm->truthProb = whereCost(p->iTable) - 99;
106854 }else{
106855 pTerm->truthProb = -1;
106856 }
106857 pTerm->pExpr = sqlite3ExprSkipCollate(p);
106858 pTerm->wtFlags = wtFlags;
@@ -108112,79 +108488,16 @@
108112 }
108113
108114 return 0;
108115 }
108116
108117 /*
108118 ** Find (an approximate) sum of two WhereCosts. This computation is
108119 ** not a simple "+" operator because WhereCost is stored as a logarithmic
108120 ** value.
108121 **
108122 */
108123 static WhereCost whereCostAdd(WhereCost a, WhereCost b){
108124 static const unsigned char x[] = {
108125 10, 10, /* 0,1 */
108126 9, 9, /* 2,3 */
108127 8, 8, /* 4,5 */
108128 7, 7, 7, /* 6,7,8 */
108129 6, 6, 6, /* 9,10,11 */
108130 5, 5, 5, /* 12-14 */
108131 4, 4, 4, 4, /* 15-18 */
108132 3, 3, 3, 3, 3, 3, /* 19-24 */
108133 2, 2, 2, 2, 2, 2, 2, /* 25-31 */
108134 };
108135 if( a>=b ){
108136 if( a>b+49 ) return a;
108137 if( a>b+31 ) return a+1;
108138 return a+x[a-b];
108139 }else{
108140 if( b>a+49 ) return b;
108141 if( b>a+31 ) return b+1;
108142 return b+x[b-a];
108143 }
108144 }
108145
108146 /*
108147 ** Convert an integer into a WhereCost. In other words, compute a
108148 ** good approximatation for 10*log2(x).
108149 */
108150 static WhereCost whereCost(tRowcnt x){
108151 static WhereCost a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
108152 WhereCost y = 40;
108153 if( x<8 ){
108154 if( x<2 ) return 0;
108155 while( x<8 ){ y -= 10; x <<= 1; }
108156 }else{
108157 while( x>255 ){ y += 40; x >>= 4; }
108158 while( x>15 ){ y += 10; x >>= 1; }
108159 }
108160 return a[x&7] + y - 10;
108161 }
108162
108163 #ifndef SQLITE_OMIT_VIRTUALTABLE
108164 /*
108165 ** Convert a double (as received from xBestIndex of a virtual table)
108166 ** into a WhereCost. In other words, compute an approximation for
108167 ** 10*log2(x).
108168 */
108169 static WhereCost whereCostFromDouble(double x){
108170 u64 a;
108171 WhereCost e;
108172 assert( sizeof(x)==8 && sizeof(a)==8 );
108173 if( x<=1 ) return 0;
108174 if( x<=2000000000 ) return whereCost((tRowcnt)x);
108175 memcpy(&a, &x, 8);
108176 e = (a>>52) - 1022;
108177 return e*10;
108178 }
108179 #endif /* SQLITE_OMIT_VIRTUALTABLE */
108180
108181 /*
108182 ** Estimate the logarithm of the input value to base 2.
108183 */
108184 static WhereCost estLog(WhereCost N){
108185 WhereCost x = whereCost(N);
108186 return x>33 ? x - 33 : 0;
108187 }
108188
108189 /*
108190 ** Two routines for printing the content of an sqlite3_index_info
@@ -108693,11 +109006,11 @@
108693 **
108694 ** ... FROM t1 WHERE a > ? AND a < ? ...
108695 **
108696 ** then nEq is set to 0.
108697 **
108698 ** When this function is called, *pnOut is set to the whereCost() of the
108699 ** number of rows that the index scan is expected to visit without
108700 ** considering the range constraints. If nEq is 0, this is the number of
108701 ** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
108702 ** to account for the range contraints pLower and pUpper.
108703 **
@@ -108709,19 +109022,19 @@
108709 static int whereRangeScanEst(
108710 Parse *pParse, /* Parsing & code generating context */
108711 WhereLoopBuilder *pBuilder,
108712 WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
108713 WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */
108714 WhereCost *pnOut /* IN/OUT: Number of rows visited */
108715 ){
108716 int rc = SQLITE_OK;
108717 int nOut = (int)*pnOut;
108718 WhereCost nNew;
 
108719
108720 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
108721 Index *p = pBuilder->pNew->u.btree.pIndex;
108722 int nEq = pBuilder->pNew->u.btree.nEq;
108723
108724 if( p->nSample>0
108725 && nEq==pBuilder->nRecValid
108726 && nEq<p->nSampleCol
108727 && OptimizationEnabled(pParse->db, SQLITE_Stat3)
@@ -108798,18 +109111,18 @@
108798 }
108799
108800 pBuilder->pRec = pRec;
108801 if( rc==SQLITE_OK ){
108802 if( iUpper>iLower ){
108803 nNew = whereCost(iUpper - iLower);
108804 }else{
108805 nNew = 10; assert( 10==whereCost(2) );
108806 }
108807 if( nNew<nOut ){
108808 nOut = nNew;
108809 }
108810 *pnOut = (WhereCost)nOut;
108811 WHERETRACE(0x100, ("range scan regions: %u..%u est=%d\n",
108812 (u32)iLower, (u32)iUpper, nOut));
108813 return SQLITE_OK;
108814 }
108815 }
@@ -108820,20 +109133,20 @@
108820 assert( pLower || pUpper );
108821 /* TUNING: Each inequality constraint reduces the search space 4-fold.
108822 ** A BETWEEN operator, therefore, reduces the search space 16-fold */
108823 nNew = nOut;
108824 if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){
108825 nNew -= 20; assert( 20==whereCost(4) );
108826 nOut--;
108827 }
108828 if( pUpper ){
108829 nNew -= 20; assert( 20==whereCost(4) );
108830 nOut--;
108831 }
108832 if( nNew<10 ) nNew = 10;
108833 if( nNew<nOut ) nOut = nNew;
108834 *pnOut = (WhereCost)nOut;
108835 return rc;
108836 }
108837
108838 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
108839 /*
@@ -110473,11 +110786,11 @@
110473 */
110474 static int whereLoopAddBtreeIndex(
110475 WhereLoopBuilder *pBuilder, /* The WhereLoop factory */
110476 struct SrcList_item *pSrc, /* FROM clause term being analyzed */
110477 Index *pProbe, /* An index on pSrc */
110478 WhereCost nInMul /* log(Number of iterations due to IN) */
110479 ){
110480 WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */
110481 Parse *pParse = pWInfo->pParse; /* Parsing context */
110482 sqlite3 *db = pParse->db; /* Database connection malloc context */
110483 WhereLoop *pNew; /* Template WhereLoop under construction */
@@ -110486,15 +110799,15 @@
110486 WhereScan scan; /* Iterator for WHERE terms */
110487 Bitmask saved_prereq; /* Original value of pNew->prereq */
110488 u16 saved_nLTerm; /* Original value of pNew->nLTerm */
110489 int saved_nEq; /* Original value of pNew->u.btree.nEq */
110490 u32 saved_wsFlags; /* Original value of pNew->wsFlags */
110491 WhereCost saved_nOut; /* Original value of pNew->nOut */
110492 int iCol; /* Index of the column in the table */
110493 int rc = SQLITE_OK; /* Return code */
110494 WhereCost nRowEst; /* Estimated index selectivity */
110495 WhereCost rLogSize; /* Logarithm of table size */
110496 WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
110497
110498 pNew = pBuilder->pNew;
110499 if( db->mallocFailed ) return SQLITE_NOMEM;
110500
@@ -110510,11 +110823,11 @@
110510 if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
110511
110512 assert( pNew->u.btree.nEq<=pProbe->nColumn );
110513 if( pNew->u.btree.nEq < pProbe->nColumn ){
110514 iCol = pProbe->aiColumn[pNew->u.btree.nEq];
110515 nRowEst = whereCost(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
110516 if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1;
110517 }else{
110518 iCol = -1;
110519 nRowEst = 0;
110520 }
@@ -110524,11 +110837,11 @@
110524 saved_nLTerm = pNew->nLTerm;
110525 saved_wsFlags = pNew->wsFlags;
110526 saved_prereq = pNew->prereq;
110527 saved_nOut = pNew->nOut;
110528 pNew->rSetup = 0;
110529 rLogSize = estLog(whereCost(pProbe->aiRowEst[0]));
110530 for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
110531 int nIn = 0;
110532 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
110533 int nRecValid = pBuilder->nRecValid;
110534 #endif
@@ -110551,14 +110864,14 @@
110551 if( pTerm->eOperator & WO_IN ){
110552 Expr *pExpr = pTerm->pExpr;
110553 pNew->wsFlags |= WHERE_COLUMN_IN;
110554 if( ExprHasProperty(pExpr, EP_xIsSelect) ){
110555 /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
110556 nIn = 46; assert( 46==whereCost(25) );
110557 }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
110558 /* "x IN (value, value, ...)" */
110559 nIn = whereCost(pExpr->x.pList->nExpr);
110560 }
110561 pNew->rRun += nIn;
110562 pNew->u.btree.nEq++;
110563 pNew->nOut = nRowEst + nInMul + nIn;
110564 }else if( pTerm->eOperator & (WO_EQ) ){
@@ -110576,11 +110889,11 @@
110576 pNew->nOut = nRowEst + nInMul;
110577 }else if( pTerm->eOperator & (WO_ISNULL) ){
110578 pNew->wsFlags |= WHERE_COLUMN_NULL;
110579 pNew->u.btree.nEq++;
110580 /* TUNING: IS NULL selects 2 rows */
110581 nIn = 10; assert( 10==whereCost(2) );
110582 pNew->nOut = nRowEst + nInMul + nIn;
110583 }else if( pTerm->eOperator & (WO_GT|WO_GE) ){
110584 testcase( pTerm->eOperator & WO_GT );
110585 testcase( pTerm->eOperator & WO_GE );
110586 pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
@@ -110596,11 +110909,11 @@
110596 pNew->aLTerm[pNew->nLTerm-2] : 0;
110597 }
110598 if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
110599 /* Adjust nOut and rRun for STAT3 range values */
110600 assert( pNew->nOut==saved_nOut );
110601 whereRangeScanEst(pParse, pBuilder, pBtm, pTop, &pNew->nOut);
110602 }
110603 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
110604 if( nInMul==0
110605 && pProbe->nSample
110606 && pNew->u.btree.nEq<=pProbe->nSampleCol
@@ -110616,22 +110929,22 @@
110616 && !ExprHasProperty(pExpr, EP_xIsSelect) ){
110617 rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
110618 }
110619 assert( nOut==0 || rc==SQLITE_OK );
110620 if( nOut ){
110621 nOut = whereCost(nOut);
110622 pNew->nOut = MIN(nOut, saved_nOut);
110623 }
110624 }
110625 #endif
110626 if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
110627 /* Each row involves a step of the index, then a binary search of
110628 ** the main table */
110629 pNew->rRun = whereCostAdd(pNew->rRun, rLogSize>27 ? rLogSize-17 : 10);
110630 }
110631 /* Step cost for each output row */
110632 pNew->rRun = whereCostAdd(pNew->rRun, pNew->nOut);
110633 whereLoopOutputAdjust(pBuilder->pWC, pNew, pSrc->iCursor);
110634 rc = whereLoopInsert(pBuilder, pNew);
110635 if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
110636 && pNew->u.btree.nEq<(pProbe->nColumn + (pProbe->zName!=0))
110637 ){
@@ -110727,18 +111040,20 @@
110727 struct SrcList_item *pSrc; /* The FROM clause btree term to add */
110728 WhereLoop *pNew; /* Template WhereLoop object */
110729 int rc = SQLITE_OK; /* Return code */
110730 int iSortIdx = 1; /* Index number */
110731 int b; /* A boolean value */
110732 WhereCost rSize; /* number of rows in the table */
110733 WhereCost rLogSize; /* Logarithm of the number of rows in the table */
110734 WhereClause *pWC; /* The parsed WHERE clause */
 
110735
110736 pNew = pBuilder->pNew;
110737 pWInfo = pBuilder->pWInfo;
110738 pTabList = pWInfo->pTabList;
110739 pSrc = pTabList->a + pNew->iTab;
 
110740 pWC = pBuilder->pWC;
110741 assert( !IsVirtual(pSrc->pTab) );
110742
110743 if( pSrc->pIndex ){
110744 /* An INDEXED BY clause specifies a particular index to use */
@@ -110752,22 +111067,22 @@
110752 memset(&sPk, 0, sizeof(Index));
110753 sPk.nColumn = 1;
110754 sPk.aiColumn = &aiColumnPk;
110755 sPk.aiRowEst = aiRowEstPk;
110756 sPk.onError = OE_Replace;
110757 sPk.pTable = pSrc->pTab;
110758 aiRowEstPk[0] = pSrc->pTab->nRowEst;
110759 aiRowEstPk[1] = 1;
110760 pFirst = pSrc->pTab->pIndex;
110761 if( pSrc->notIndexed==0 ){
110762 /* The real indices of the table are only considered if the
110763 ** NOT INDEXED qualifier is omitted from the FROM clause */
110764 sPk.pNext = pFirst;
110765 }
110766 pProbe = &sPk;
110767 }
110768 rSize = whereCost(pSrc->pTab->nRowEst);
110769 rLogSize = estLog(rSize);
110770
110771 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
110772 /* Automatic indexes */
110773 if( !pBuilder->pOrSet
@@ -110788,17 +111103,17 @@
110788 pNew->nLTerm = 1;
110789 pNew->aLTerm[0] = pTerm;
110790 /* TUNING: One-time cost for computing the automatic index is
110791 ** approximately 7*N*log2(N) where N is the number of rows in
110792 ** the table being indexed. */
110793 pNew->rSetup = rLogSize + rSize + 28; assert( 28==whereCost(7) );
110794 /* TUNING: Each index lookup yields 20 rows in the table. This
110795 ** is more than the usual guess of 10 rows, since we have no way
110796 ** of knowning how selective the index will ultimately be. It would
110797 ** not be unreasonable to make this value much larger. */
110798 pNew->nOut = 43; assert( 43==whereCost(20) );
110799 pNew->rRun = whereCostAdd(rLogSize,pNew->nOut);
110800 pNew->wsFlags = WHERE_AUTO_INDEX;
110801 pNew->prereq = mExtra | pTerm->prereqRight;
110802 rc = whereLoopInsert(pBuilder, pNew);
110803 }
110804 }
@@ -110828,14 +111143,12 @@
110828
110829 /* Full table scan */
110830 pNew->iSortIdx = b ? iSortIdx : 0;
110831 /* TUNING: Cost of full table scan is 3*(N + log2(N)).
110832 ** + The extra 3 factor is to encourage the use of indexed lookups
110833 ** over full scans. A smaller constant 2 is used for covering
110834 ** index scans so that a covering index scan will be favored over
110835 ** a table scan. */
110836 pNew->rRun = whereCostAdd(rSize,rLogSize) + 16;
110837 whereLoopOutputAdjust(pWC, pNew, pSrc->iCursor);
110838 rc = whereLoopInsert(pBuilder, pNew);
110839 pNew->nOut = rSize;
110840 if( rc ) break;
110841 }else{
@@ -110844,26 +111157,25 @@
110844
110845 /* Full scan via index */
110846 if( b
110847 || ( m==0
110848 && pProbe->bUnordered==0
 
110849 && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0
110850 && sqlite3GlobalConfig.bUseCis
110851 && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan)
110852 )
110853 ){
110854 pNew->iSortIdx = b ? iSortIdx : 0;
110855 if( m==0 ){
110856 /* TUNING: Cost of a covering index scan is 2*(N + log2(N)).
110857 ** + The extra 2 factor is to encourage the use of indexed lookups
110858 ** over index scans. A table scan uses a factor of 3 so that
110859 ** index scans are favored over table scans.
110860 ** + If this covering index might also help satisfy the ORDER BY
110861 ** clause, then the cost is fudged down slightly so that this
110862 ** index is favored above other indices that have no hope of
110863 ** helping with the ORDER BY. */
110864 pNew->rRun = 10 + whereCostAdd(rSize,rLogSize) - b;
110865 }else{
110866 assert( b!=0 );
110867 /* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N)
110868 ** which we will simplify to just N*log2(N) */
110869 pNew->rRun = rSize + rLogSize;
@@ -111037,13 +111349,13 @@
111037 pIdxInfo->needToFreeIdxStr = 0;
111038 pNew->u.vtab.idxStr = pIdxInfo->idxStr;
111039 pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0)
111040 && pIdxInfo->orderByConsumed);
111041 pNew->rSetup = 0;
111042 pNew->rRun = whereCostFromDouble(pIdxInfo->estimatedCost);
111043 /* TUNING: Every virtual table query returns 25 rows */
111044 pNew->nOut = 46; assert( 46==whereCost(25) );
111045 whereLoopInsert(pBuilder, pNew);
111046 if( pNew->u.vtab.needFree ){
111047 sqlite3_free(pNew->u.vtab.idxStr);
111048 pNew->u.vtab.needFree = 0;
111049 }
@@ -111076,10 +111388,12 @@
111076 pWC = pBuilder->pWC;
111077 if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
111078 pWCEnd = pWC->a + pWC->nTerm;
111079 pNew = pBuilder->pNew;
111080 memset(&sSum, 0, sizeof(sSum));
 
 
111081
111082 for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
111083 if( (pTerm->eOperator & WO_OR)!=0
111084 && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
111085 ){
@@ -111087,12 +111401,10 @@
111087 WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
111088 WhereTerm *pOrTerm;
111089 int once = 1;
111090 int i, j;
111091
111092 pItem = pWInfo->pTabList->a + pNew->iTab;
111093 iCur = pItem->iCursor;
111094 sSubBuild = *pBuilder;
111095 sSubBuild.pOrderBy = 0;
111096 sSubBuild.pOrSet = &sCur;
111097
111098 for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
@@ -111129,12 +111441,12 @@
111129 whereOrMove(&sPrev, &sSum);
111130 sSum.n = 0;
111131 for(i=0; i<sPrev.n; i++){
111132 for(j=0; j<sCur.n; j++){
111133 whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq,
111134 whereCostAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
111135 whereCostAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
111136 }
111137 }
111138 }
111139 }
111140 pNew->nLTerm = 1;
@@ -111468,23 +111780,23 @@
111468 ** costs if nRowEst==0.
111469 **
111470 ** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation
111471 ** error occurs.
111472 */
111473 static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){
111474 int mxChoice; /* Maximum number of simultaneous paths tracked */
111475 int nLoop; /* Number of terms in the join */
111476 Parse *pParse; /* Parsing context */
111477 sqlite3 *db; /* The database connection */
111478 int iLoop; /* Loop counter over the terms of the join */
111479 int ii, jj; /* Loop counters */
111480 int mxI = 0; /* Index of next entry to replace */
111481 WhereCost rCost; /* Cost of a path */
111482 WhereCost nOut; /* Number of outputs */
111483 WhereCost mxCost = 0; /* Maximum cost of a set of paths */
111484 WhereCost mxOut = 0; /* Maximum nOut value on the set of paths */
111485 WhereCost rSortCost; /* Cost to do a sort */
111486 int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
111487 WherePath *aFrom; /* All nFrom paths at the previous level */
111488 WherePath *aTo; /* The nTo best paths at the current level */
111489 WherePath *pFrom; /* An element of aFrom[] that we are working on */
111490 WherePath *pTo; /* An element of aTo[] that we are working on */
@@ -111517,21 +111829,23 @@
111517 /* Seed the search with a single WherePath containing zero WhereLoops.
111518 **
111519 ** TUNING: Do not let the number of iterations go above 25. If the cost
111520 ** of computing an automatic index is not paid back within the first 25
111521 ** rows, then do not use the automatic index. */
111522 aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==whereCost(25) );
111523 nFrom = 1;
111524
111525 /* Precompute the cost of sorting the final result set, if the caller
111526 ** to sqlite3WhereBegin() was concerned about sorting */
111527 rSortCost = 0;
111528 if( pWInfo->pOrderBy==0 || nRowEst==0 ){
111529 aFrom[0].isOrderedValid = 1;
111530 }else{
111531 /* TUNING: Estimated cost of sorting is N*log2(N) where N is the
111532 ** number of output rows. */
 
 
111533 rSortCost = nRowEst + estLog(nRowEst);
111534 WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost));
111535 }
111536
111537 /* Compute successively longer WherePaths using the previous generation
@@ -111547,12 +111861,12 @@
111547 u8 isOrdered = pFrom->isOrdered;
111548 if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
111549 if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
111550 /* At this point, pWLoop is a candidate to be the next loop.
111551 ** Compute its cost */
111552 rCost = whereCostAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
111553 rCost = whereCostAdd(rCost, pFrom->rCost);
111554 nOut = pFrom->nRow + pWLoop->nOut;
111555 maskNew = pFrom->maskLoop | pWLoop->maskSelf;
111556 if( !isOrderedValid ){
111557 switch( wherePathSatisfiesOrderBy(pWInfo,
111558 pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
@@ -111562,11 +111876,11 @@
111562 isOrderedValid = 1;
111563 break;
111564 case 0: /* No. pFrom+pWLoop will require a separate sort */
111565 isOrdered = 0;
111566 isOrderedValid = 1;
111567 rCost = whereCostAdd(rCost, rSortCost);
111568 break;
111569 default: /* Cannot tell yet. Try again on the next iteration */
111570 break;
111571 }
111572 }else{
@@ -111769,11 +112083,11 @@
111769 pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
111770 pLoop->aLTerm[0] = pTerm;
111771 pLoop->nLTerm = 1;
111772 pLoop->u.btree.nEq = 1;
111773 /* TUNING: Cost of a rowid lookup is 10 */
111774 pLoop->rRun = 33; /* 33==whereCost(10) */
111775 }else{
111776 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
111777 assert( pLoop->aLTermSpace==pLoop->aLTerm );
111778 assert( ArraySize(pLoop->aLTermSpace)==4 );
111779 if( pIdx->onError==OE_None
@@ -111792,16 +112106,16 @@
111792 }
111793 pLoop->nLTerm = j;
111794 pLoop->u.btree.nEq = j;
111795 pLoop->u.btree.pIndex = pIdx;
111796 /* TUNING: Cost of a unique index lookup is 15 */
111797 pLoop->rRun = 39; /* 39==whereCost(15) */
111798 break;
111799 }
111800 }
111801 if( pLoop->wsFlags ){
111802 pLoop->nOut = (WhereCost)1;
111803 pWInfo->a[0].pWLoop = pLoop;
111804 pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
111805 pWInfo->a[0].iTabCur = iCur;
111806 pWInfo->nRowOut = 1;
111807 if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1;
@@ -112165,11 +112479,11 @@
112165 WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
112166 pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;
112167
112168 /* If the caller is an UPDATE or DELETE statement that is requesting
112169 ** to use a one-pass algorithm, determine if this is appropriate.
112170 ** The one-pass algorithm only works if the WHERE clause constraints
112171 ** the statement to update a single row.
112172 */
112173 assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
112174 if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
112175 && (pWInfo->a[0].pWLoop->wsFlags & WHERE_ONEROW)!=0 ){
@@ -121583,10 +121897,16 @@
121583 ** verifying the operation of the SQLite core.
121584 */
121585 int inTransaction; /* True after xBegin but before xCommit/xRollback */
121586 int mxSavepoint; /* Largest valid xSavepoint integer */
121587 #endif
 
 
 
 
 
 
121588 };
121589
121590 /*
121591 ** When the core wants to read from the virtual table, it creates a
121592 ** virtual table cursor (an instance of the following structure) using
@@ -121608,11 +121928,12 @@
121608 int nDoclist; /* Size of buffer at aDoclist */
121609 u8 bDesc; /* True to sort in descending order */
121610 int eEvalmode; /* An FTS3_EVAL_XX constant */
121611 int nRowAvg; /* Average size of database rows, in pages */
121612 sqlite3_int64 nDoc; /* Documents in table */
121613
 
121614 int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
121615 u32 *aMatchinfo; /* Information about most recent match */
121616 int nMatchinfo; /* Number of elements in aMatchinfo[] */
121617 char *zMatchinfo; /* Matchinfo specification */
121618 };
@@ -121638,10 +121959,19 @@
121638 */
121639 #define FTS3_FULLSCAN_SEARCH 0 /* Linear scan of %_content table */
121640 #define FTS3_DOCID_SEARCH 1 /* Lookup by rowid on %_content table */
121641 #define FTS3_FULLTEXT_SEARCH 2 /* Full-text index search */
121642
 
 
 
 
 
 
 
 
 
121643
121644 struct Fts3Doclist {
121645 char *aAll; /* Array containing doclist (or NULL) */
121646 int nAll; /* Size of a[] in bytes */
121647 char *pNextDocid; /* Pointer to next docid */
@@ -123058,27 +123388,31 @@
123058 */
123059 static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
123060 Fts3Table *p = (Fts3Table *)pVTab;
123061 int i; /* Iterator variable */
123062 int iCons = -1; /* Index of constraint to use */
 
123063 int iLangidCons = -1; /* Index of langid=x constraint, if present */
 
 
 
123064
123065 /* By default use a full table scan. This is an expensive option,
123066 ** so search through the constraints to see if a more efficient
123067 ** strategy is possible.
123068 */
123069 pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
123070 pInfo->estimatedCost = 5000000;
123071 for(i=0; i<pInfo->nConstraint; i++){
 
123072 struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i];
123073 if( pCons->usable==0 ) continue;
 
 
123074
123075 /* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */
123076 if( iCons<0
123077 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
123078 && (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1 )
123079 ){
123080 pInfo->idxNum = FTS3_DOCID_SEARCH;
123081 pInfo->estimatedCost = 1.0;
123082 iCons = i;
123083 }
123084
@@ -123103,18 +123437,42 @@
123103 if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
123104 && pCons->iColumn==p->nColumn + 2
123105 ){
123106 iLangidCons = i;
123107 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123108 }
123109
 
123110 if( iCons>=0 ){
123111 pInfo->aConstraintUsage[iCons].argvIndex = 1;
123112 pInfo->aConstraintUsage[iCons].omit = 1;
123113 }
123114 if( iLangidCons>=0 ){
123115 pInfo->aConstraintUsage[iLangidCons].argvIndex = 2;
 
 
 
 
 
 
 
 
 
123116 }
123117
123118 /* Regardless of the strategy selected, FTS can deliver rows in rowid (or
123119 ** docid) order. Both ascending and descending are possible.
123120 */
@@ -124556,10 +124914,37 @@
124556 rc = fts3EvalNext((Fts3Cursor *)pCursor);
124557 }
124558 assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
124559 return rc;
124560 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124561
124562 /*
124563 ** This is the xFilter interface for the virtual table. See
124564 ** the virtual table xFilter method documentation for additional
124565 ** information.
@@ -124582,44 +124967,62 @@
124582 int nVal, /* Number of elements in apVal */
124583 sqlite3_value **apVal /* Arguments for the indexing scheme */
124584 ){
124585 int rc;
124586 char *zSql; /* SQL statement used to access %_content */
 
124587 Fts3Table *p = (Fts3Table *)pCursor->pVtab;
124588 Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
 
 
 
 
 
 
124589
124590 UNUSED_PARAMETER(idxStr);
124591 UNUSED_PARAMETER(nVal);
124592
124593 assert( idxNum>=0 && idxNum<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
124594 assert( nVal==0 || nVal==1 || nVal==2 );
124595 assert( (nVal==0)==(idxNum==FTS3_FULLSCAN_SEARCH) );
124596 assert( p->pSegments==0 );
 
 
 
 
 
 
 
 
124597
124598 /* In case the cursor has been used before, clear it now. */
124599 sqlite3_finalize(pCsr->pStmt);
124600 sqlite3_free(pCsr->aDoclist);
124601 sqlite3Fts3ExprFree(pCsr->pExpr);
124602 memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
124603
 
 
 
 
124604 if( idxStr ){
124605 pCsr->bDesc = (idxStr[0]=='D');
124606 }else{
124607 pCsr->bDesc = p->bDescIdx;
124608 }
124609 pCsr->eSearch = (i16)idxNum;
124610
124611 if( idxNum!=FTS3_DOCID_SEARCH && idxNum!=FTS3_FULLSCAN_SEARCH ){
124612 int iCol = idxNum-FTS3_FULLTEXT_SEARCH;
124613 const char *zQuery = (const char *)sqlite3_value_text(apVal[0]);
124614
124615 if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
124616 return SQLITE_NOMEM;
124617 }
124618
124619 pCsr->iLangid = 0;
124620 if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]);
124621
124622 assert( p->base.zErrMsg==0 );
124623 rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
124624 p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr,
124625 &p->base.zErrMsg
@@ -124638,11 +125041,11 @@
124638 /* Compile a SELECT statement for this cursor. For a full-table-scan, the
124639 ** statement loops through all rows of the %_content table. For a
124640 ** full-text query or docid lookup, the statement retrieves a single
124641 ** row by docid.
124642 */
124643 if( idxNum==FTS3_FULLSCAN_SEARCH ){
124644 zSql = sqlite3_mprintf(
124645 "SELECT %s ORDER BY rowid %s",
124646 p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
124647 );
124648 if( zSql ){
@@ -124649,14 +125052,14 @@
124649 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
124650 sqlite3_free(zSql);
124651 }else{
124652 rc = SQLITE_NOMEM;
124653 }
124654 }else if( idxNum==FTS3_DOCID_SEARCH ){
124655 rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
124656 if( rc==SQLITE_OK ){
124657 rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
124658 }
124659 }
124660 if( rc!=SQLITE_OK ) return rc;
124661
124662 return fts3NextMethod(pCursor);
@@ -125543,10 +125946,16 @@
125543 }
125544
125545 return SQLITE_OK;
125546 }
125547
 
 
 
 
 
 
125548 /*
125549 ** This function is called for each Fts3Phrase in a full-text query
125550 ** expression to initialize the mechanism for returning rows. Once this
125551 ** function has been called successfully on an Fts3Phrase, it may be
125552 ** used with fts3EvalPhraseNext() to iterate through the matching docids.
@@ -125556,27 +125965,47 @@
125556 ** memory within this call.
125557 **
125558 ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
125559 */
125560 static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
125561 int rc; /* Error code */
125562 Fts3PhraseToken *pFirst = &p->aToken[0];
125563 Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
125564
125565 if( pCsr->bDesc==pTab->bDescIdx
125566 && bOptOk==1
125567 && p->nToken==1
125568 && pFirst->pSegcsr
125569 && pFirst->pSegcsr->bLookup
125570 && pFirst->bFirst==0
125571 ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125572 /* Use the incremental approach. */
125573 int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
125574 rc = sqlite3Fts3MsrIncrStart(
125575 pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n);
 
 
 
 
 
125576 p->bIncr = 1;
125577
125578 }else{
125579 /* Load the full doclist for the phrase into memory. */
125580 rc = fts3EvalPhraseLoad(pCsr, p);
125581 p->bIncr = 0;
125582 }
@@ -125680,10 +126109,220 @@
125680 }
125681 }
125682
125683 *ppIter = p;
125684 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125685
125686 /*
125687 ** Attempt to move the phrase iterator to point to the next matching docid.
125688 ** If an error occurs, return an SQLite error code. Otherwise, return
125689 ** SQLITE_OK.
@@ -125700,59 +126339,18 @@
125700 int rc = SQLITE_OK;
125701 Fts3Doclist *pDL = &p->doclist;
125702 Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
125703
125704 if( p->bIncr ){
125705 assert( p->nToken==1 );
125706 assert( pDL->pNextDocid==0 );
125707 rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
125708 &pDL->iDocid, &pDL->pList, &pDL->nList
125709 );
125710 if( rc==SQLITE_OK && !pDL->pList ){
125711 *pbEof = 1;
125712 }
125713 }else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){
125714 sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll,
125715 &pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof
125716 );
125717 pDL->pList = pDL->pNextDocid;
125718 }else{
125719 char *pIter; /* Used to iterate through aAll */
125720 char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
125721 if( pDL->pNextDocid ){
125722 pIter = pDL->pNextDocid;
125723 }else{
125724 pIter = pDL->aAll;
125725 }
125726
125727 if( pIter>=pEnd ){
125728 /* We have already reached the end of this doclist. EOF. */
125729 *pbEof = 1;
125730 }else{
125731 sqlite3_int64 iDelta;
125732 pIter += sqlite3Fts3GetVarint(pIter, &iDelta);
125733 if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
125734 pDL->iDocid += iDelta;
125735 }else{
125736 pDL->iDocid -= iDelta;
125737 }
125738 pDL->pList = pIter;
125739 fts3PoslistCopy(0, &pIter);
125740 pDL->nList = (int)(pIter - pDL->pList);
125741
125742 /* pIter now points just past the 0x00 that terminates the position-
125743 ** list for document pDL->iDocid. However, if this position-list was
125744 ** edited in place by fts3EvalNearTrim(), then pIter may not actually
125745 ** point to the start of the next docid value. The following line deals
125746 ** with this case by advancing pIter past the zero-padding added by
125747 ** fts3EvalNearTrim(). */
125748 while( pIter<pEnd && *pIter==0 ) pIter++;
125749
125750 pDL->pNextDocid = pIter;
125751 assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter );
125752 *pbEof = 0;
125753 }
125754 }
125755
125756 return rc;
125757 }
125758
@@ -125773,11 +126371,10 @@
125773 ** code before returning.
125774 */
125775 static void fts3EvalStartReaders(
125776 Fts3Cursor *pCsr, /* FTS Cursor handle */
125777 Fts3Expr *pExpr, /* Expression to initialize phrases in */
125778 int bOptOk, /* True to enable incremental loading */
125779 int *pRc /* IN/OUT: Error code */
125780 ){
125781 if( pExpr && SQLITE_OK==*pRc ){
125782 if( pExpr->eType==FTSQUERY_PHRASE ){
125783 int i;
@@ -125784,14 +126381,14 @@
125784 int nToken = pExpr->pPhrase->nToken;
125785 for(i=0; i<nToken; i++){
125786 if( pExpr->pPhrase->aToken[i].pDeferred==0 ) break;
125787 }
125788 pExpr->bDeferred = (i==nToken);
125789 *pRc = fts3EvalPhraseStart(pCsr, bOptOk, pExpr->pPhrase);
125790 }else{
125791 fts3EvalStartReaders(pCsr, pExpr->pLeft, bOptOk, pRc);
125792 fts3EvalStartReaders(pCsr, pExpr->pRight, bOptOk, pRc);
125793 pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred);
125794 }
125795 }
125796 }
125797
@@ -126029,11 +126626,11 @@
126029 /* Set nLoad4 to the value of (4^nOther) for the next iteration of the
126030 ** for-loop. Except, limit the value to 2^24 to prevent it from
126031 ** overflowing the 32-bit integer it is stored in. */
126032 if( ii<12 ) nLoad4 = nLoad4*4;
126033
126034 if( ii==0 || pTC->pPhrase->nToken>1 ){
126035 /* Either this is the cheapest token in the entire query, or it is
126036 ** part of a multi-token phrase. Either way, the entire doclist will
126037 ** (eventually) be loaded into memory. It may as well be now. */
126038 Fts3PhraseToken *pToken = pTC->pToken;
126039 int nList = 0;
@@ -126109,11 +126706,11 @@
126109 sqlite3_free(aTC);
126110 }
126111 }
126112 #endif
126113
126114 fts3EvalStartReaders(pCsr, pCsr->pExpr, 1, &rc);
126115 return rc;
126116 }
126117
126118 /*
126119 ** Invalidate the current position list for phrase pPhrase.
@@ -126592,10 +127189,20 @@
126592 pCsr->isRequireSeek = 1;
126593 pCsr->isMatchinfoNeeded = 1;
126594 pCsr->iPrevId = pExpr->iDocid;
126595 }while( pCsr->isEof==0 && fts3EvalTestDeferredAndNear(pCsr, &rc) );
126596 }
 
 
 
 
 
 
 
 
 
 
126597 return rc;
126598 }
126599
126600 /*
126601 ** Restart interation for expression pExpr so that the next call to
@@ -126615,16 +127222,20 @@
126615 Fts3Phrase *pPhrase = pExpr->pPhrase;
126616
126617 if( pPhrase ){
126618 fts3EvalInvalidatePoslist(pPhrase);
126619 if( pPhrase->bIncr ){
126620 assert( pPhrase->nToken==1 );
126621 assert( pPhrase->aToken[0].pSegcsr );
126622 sqlite3Fts3MsrIncrRestart(pPhrase->aToken[0].pSegcsr);
 
 
 
 
 
126623 *pRc = fts3EvalPhraseStart(pCsr, 0, pPhrase);
126624 }
126625
126626 pPhrase->doclist.pNextDocid = 0;
126627 pPhrase->doclist.iDocid = 0;
126628 }
126629
126630 pExpr->iDocid = 0;
@@ -126869,19 +127480,27 @@
126869
126870 iDocid = pExpr->iDocid;
126871 pIter = pPhrase->doclist.pList;
126872 if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
126873 int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
 
126874 int bOr = 0;
126875 u8 bEof = 0;
126876 Fts3Expr *p;
 
 
126877
126878 /* Check if this phrase descends from an OR expression node. If not,
126879 ** return NULL. Otherwise, the entry that corresponds to docid
126880 ** pCsr->iPrevId may lie earlier in the doclist buffer. */
 
 
 
126881 for(p=pExpr->pParent; p; p=p->pParent){
126882 if( p->eType==FTSQUERY_OR ) bOr = 1;
 
 
126883 }
126884 if( bOr==0 ) return SQLITE_OK;
126885
126886 /* This is the descendent of an OR node. In this case we cannot use
126887 ** an incremental phrase. Load the entire doclist for the phrase
@@ -126896,33 +127515,63 @@
126896 }
126897 pIter = pPhrase->doclist.pList;
126898 assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
126899 if( rc!=SQLITE_OK ) return rc;
126900 }
 
 
 
 
 
 
 
 
 
 
 
 
126901
126902 if( pExpr->bEof ){
126903 pIter = 0;
126904 iDocid = 0;
126905 }
126906 bEof = (pPhrase->doclist.nAll==0);
126907 assert( bDescDoclist==0 || bDescDoclist==1 );
126908 assert( pCsr->bDesc==0 || pCsr->bDesc==1 );
126909
126910 if( pCsr->bDesc==bDescDoclist ){
126911 int dummy;
126912 while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
126913 sqlite3Fts3DoclistPrev(
126914 bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
126915 &pIter, &iDocid, &dummy, &bEof
126916 );
126917 }
126918 }else{
126919 while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
126920 sqlite3Fts3DoclistNext(
126921 bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
126922 &pIter, &iDocid, &bEof
126923 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126924 }
126925 }
126926
126927 if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
126928 }
@@ -135756,11 +136405,11 @@
135756 assert( p->bFts4==0 );
135757 sqlite3Fts3CreateStatTable(&rc, p);
135758 if( rc ) return rc;
135759 }
135760 rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
135761 if( rc ) return rc;;
135762 sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
135763 sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge);
135764 sqlite3_step(pStmt);
135765 rc = sqlite3_reset(pStmt);
135766 return rc;
@@ -136025,10 +136674,13 @@
136025 }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
136026 p->nNodeSize = atoi(&zVal[9]);
136027 rc = SQLITE_OK;
136028 }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
136029 p->nMaxPendingData = atoi(&zVal[11]);
 
 
 
136030 rc = SQLITE_OK;
136031 #endif
136032 }else{
136033 rc = SQLITE_ERROR;
136034 }
136035
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -23,531 +23,10 @@
23 # define SQLITE_PRIVATE static
24 #endif
25 #ifndef SQLITE_API
26 # define SQLITE_API
27 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28 /************** Begin file sqlite3.h *****************************************/
29 /*
30 ** 2001 September 15
31 **
32 ** The author disclaims copyright to this source code. In place of
@@ -656,11 +135,11 @@
135 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
136 ** [sqlite_version()] and [sqlite_source_id()].
137 */
138 #define SQLITE_VERSION "3.8.1"
139 #define SQLITE_VERSION_NUMBER 3008001
140 #define SQLITE_SOURCE_ID "2013-10-11 13:27:26 03593817ab5abdd4bbaa5e47e2e4745eef025af9"
141
142 /*
143 ** CAPI3REF: Run-Time Library Version Numbers
144 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
145 **
@@ -7846,11 +7325,530 @@
7325
7326 #endif /* ifndef _SQLITE3RTREE_H_ */
7327
7328
7329 /************** End of sqlite3.h *********************************************/
7330 /************** Begin file sqliteInt.h ***************************************/
7331 /*
7332 ** 2001 September 15
7333 **
7334 ** The author disclaims copyright to this source code. In place of
7335 ** a legal notice, here is a blessing:
7336 **
7337 ** May you do good and not evil.
7338 ** May you find forgiveness for yourself and forgive others.
7339 ** May you share freely, never taking more than you give.
7340 **
7341 *************************************************************************
7342 ** Internal interface definitions for SQLite.
7343 **
7344 */
7345 #ifndef _SQLITEINT_H_
7346 #define _SQLITEINT_H_
7347
7348 /*
7349 ** These #defines should enable >2GB file support on POSIX if the
7350 ** underlying operating system supports it. If the OS lacks
7351 ** large file support, or if the OS is windows, these should be no-ops.
7352 **
7353 ** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any
7354 ** system #includes. Hence, this block of code must be the very first
7355 ** code in all source files.
7356 **
7357 ** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
7358 ** on the compiler command line. This is necessary if you are compiling
7359 ** on a recent machine (ex: Red Hat 7.2) but you want your code to work
7360 ** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2
7361 ** without this option, LFS is enable. But LFS does not exist in the kernel
7362 ** in Red Hat 6.0, so the code won't work. Hence, for maximum binary
7363 ** portability you should omit LFS.
7364 **
7365 ** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later.
7366 */
7367 #ifndef SQLITE_DISABLE_LFS
7368 # define _LARGE_FILE 1
7369 # ifndef _FILE_OFFSET_BITS
7370 # define _FILE_OFFSET_BITS 64
7371 # endif
7372 # define _LARGEFILE_SOURCE 1
7373 #endif
7374
7375 /*
7376 ** Include the configuration header output by 'configure' if we're using the
7377 ** autoconf-based build
7378 */
7379 #ifdef _HAVE_SQLITE_CONFIG_H
7380 #include "config.h"
7381 #endif
7382
7383 /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/
7384 /************** Begin file sqliteLimit.h *************************************/
7385 /*
7386 ** 2007 May 7
7387 **
7388 ** The author disclaims copyright to this source code. In place of
7389 ** a legal notice, here is a blessing:
7390 **
7391 ** May you do good and not evil.
7392 ** May you find forgiveness for yourself and forgive others.
7393 ** May you share freely, never taking more than you give.
7394 **
7395 *************************************************************************
7396 **
7397 ** This file defines various limits of what SQLite can process.
7398 */
7399
7400 /*
7401 ** The maximum length of a TEXT or BLOB in bytes. This also
7402 ** limits the size of a row in a table or index.
7403 **
7404 ** The hard limit is the ability of a 32-bit signed integer
7405 ** to count the size: 2^31-1 or 2147483647.
7406 */
7407 #ifndef SQLITE_MAX_LENGTH
7408 # define SQLITE_MAX_LENGTH 1000000000
7409 #endif
7410
7411 /*
7412 ** This is the maximum number of
7413 **
7414 ** * Columns in a table
7415 ** * Columns in an index
7416 ** * Columns in a view
7417 ** * Terms in the SET clause of an UPDATE statement
7418 ** * Terms in the result set of a SELECT statement
7419 ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
7420 ** * Terms in the VALUES clause of an INSERT statement
7421 **
7422 ** The hard upper limit here is 32676. Most database people will
7423 ** tell you that in a well-normalized database, you usually should
7424 ** not have more than a dozen or so columns in any table. And if
7425 ** that is the case, there is no point in having more than a few
7426 ** dozen values in any of the other situations described above.
7427 */
7428 #ifndef SQLITE_MAX_COLUMN
7429 # define SQLITE_MAX_COLUMN 2000
7430 #endif
7431
7432 /*
7433 ** The maximum length of a single SQL statement in bytes.
7434 **
7435 ** It used to be the case that setting this value to zero would
7436 ** turn the limit off. That is no longer true. It is not possible
7437 ** to turn this limit off.
7438 */
7439 #ifndef SQLITE_MAX_SQL_LENGTH
7440 # define SQLITE_MAX_SQL_LENGTH 1000000000
7441 #endif
7442
7443 /*
7444 ** The maximum depth of an expression tree. This is limited to
7445 ** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
7446 ** want to place more severe limits on the complexity of an
7447 ** expression.
7448 **
7449 ** A value of 0 used to mean that the limit was not enforced.
7450 ** But that is no longer true. The limit is now strictly enforced
7451 ** at all times.
7452 */
7453 #ifndef SQLITE_MAX_EXPR_DEPTH
7454 # define SQLITE_MAX_EXPR_DEPTH 1000
7455 #endif
7456
7457 /*
7458 ** The maximum number of terms in a compound SELECT statement.
7459 ** The code generator for compound SELECT statements does one
7460 ** level of recursion for each term. A stack overflow can result
7461 ** if the number of terms is too large. In practice, most SQL
7462 ** never has more than 3 or 4 terms. Use a value of 0 to disable
7463 ** any limit on the number of terms in a compount SELECT.
7464 */
7465 #ifndef SQLITE_MAX_COMPOUND_SELECT
7466 # define SQLITE_MAX_COMPOUND_SELECT 500
7467 #endif
7468
7469 /*
7470 ** The maximum number of opcodes in a VDBE program.
7471 ** Not currently enforced.
7472 */
7473 #ifndef SQLITE_MAX_VDBE_OP
7474 # define SQLITE_MAX_VDBE_OP 25000
7475 #endif
7476
7477 /*
7478 ** The maximum number of arguments to an SQL function.
7479 */
7480 #ifndef SQLITE_MAX_FUNCTION_ARG
7481 # define SQLITE_MAX_FUNCTION_ARG 127
7482 #endif
7483
7484 /*
7485 ** The maximum number of in-memory pages to use for the main database
7486 ** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE
7487 */
7488 #ifndef SQLITE_DEFAULT_CACHE_SIZE
7489 # define SQLITE_DEFAULT_CACHE_SIZE 2000
7490 #endif
7491 #ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE
7492 # define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
7493 #endif
7494
7495 /*
7496 ** The default number of frames to accumulate in the log file before
7497 ** checkpointing the database in WAL mode.
7498 */
7499 #ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
7500 # define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
7501 #endif
7502
7503 /*
7504 ** The maximum number of attached databases. This must be between 0
7505 ** and 62. The upper bound on 62 is because a 64-bit integer bitmap
7506 ** is used internally to track attached databases.
7507 */
7508 #ifndef SQLITE_MAX_ATTACHED
7509 # define SQLITE_MAX_ATTACHED 10
7510 #endif
7511
7512
7513 /*
7514 ** The maximum value of a ?nnn wildcard that the parser will accept.
7515 */
7516 #ifndef SQLITE_MAX_VARIABLE_NUMBER
7517 # define SQLITE_MAX_VARIABLE_NUMBER 999
7518 #endif
7519
7520 /* Maximum page size. The upper bound on this value is 65536. This a limit
7521 ** imposed by the use of 16-bit offsets within each page.
7522 **
7523 ** Earlier versions of SQLite allowed the user to change this value at
7524 ** compile time. This is no longer permitted, on the grounds that it creates
7525 ** a library that is technically incompatible with an SQLite library
7526 ** compiled with a different limit. If a process operating on a database
7527 ** with a page-size of 65536 bytes crashes, then an instance of SQLite
7528 ** compiled with the default page-size limit will not be able to rollback
7529 ** the aborted transaction. This could lead to database corruption.
7530 */
7531 #ifdef SQLITE_MAX_PAGE_SIZE
7532 # undef SQLITE_MAX_PAGE_SIZE
7533 #endif
7534 #define SQLITE_MAX_PAGE_SIZE 65536
7535
7536
7537 /*
7538 ** The default size of a database page.
7539 */
7540 #ifndef SQLITE_DEFAULT_PAGE_SIZE
7541 # define SQLITE_DEFAULT_PAGE_SIZE 1024
7542 #endif
7543 #if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
7544 # undef SQLITE_DEFAULT_PAGE_SIZE
7545 # define SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
7546 #endif
7547
7548 /*
7549 ** Ordinarily, if no value is explicitly provided, SQLite creates databases
7550 ** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain
7551 ** device characteristics (sector-size and atomic write() support),
7552 ** SQLite may choose a larger value. This constant is the maximum value
7553 ** SQLite will choose on its own.
7554 */
7555 #ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE
7556 # define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192
7557 #endif
7558 #if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
7559 # undef SQLITE_MAX_DEFAULT_PAGE_SIZE
7560 # define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE
7561 #endif
7562
7563
7564 /*
7565 ** Maximum number of pages in one database file.
7566 **
7567 ** This is really just the default value for the max_page_count pragma.
7568 ** This value can be lowered (or raised) at run-time using that the
7569 ** max_page_count macro.
7570 */
7571 #ifndef SQLITE_MAX_PAGE_COUNT
7572 # define SQLITE_MAX_PAGE_COUNT 1073741823
7573 #endif
7574
7575 /*
7576 ** Maximum length (in bytes) of the pattern in a LIKE or GLOB
7577 ** operator.
7578 */
7579 #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
7580 # define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
7581 #endif
7582
7583 /*
7584 ** Maximum depth of recursion for triggers.
7585 **
7586 ** A value of 1 means that a trigger program will not be able to itself
7587 ** fire any triggers. A value of 0 means that no trigger programs at all
7588 ** may be executed.
7589 */
7590 #ifndef SQLITE_MAX_TRIGGER_DEPTH
7591 # define SQLITE_MAX_TRIGGER_DEPTH 1000
7592 #endif
7593
7594 /************** End of sqliteLimit.h *****************************************/
7595 /************** Continuing where we left off in sqliteInt.h ******************/
7596
7597 /* Disable nuisance warnings on Borland compilers */
7598 #if defined(__BORLANDC__)
7599 #pragma warn -rch /* unreachable code */
7600 #pragma warn -ccc /* Condition is always true or false */
7601 #pragma warn -aus /* Assigned value is never used */
7602 #pragma warn -csu /* Comparing signed and unsigned */
7603 #pragma warn -spa /* Suspicious pointer arithmetic */
7604 #endif
7605
7606 /* Needed for various definitions... */
7607 #ifndef _GNU_SOURCE
7608 # define _GNU_SOURCE
7609 #endif
7610
7611 #if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
7612 # define _BSD_SOURCE
7613 #endif
7614
7615 /*
7616 ** Include standard header files as necessary
7617 */
7618 #ifdef HAVE_STDINT_H
7619 #include <stdint.h>
7620 #endif
7621 #ifdef HAVE_INTTYPES_H
7622 #include <inttypes.h>
7623 #endif
7624
7625 /*
7626 ** The following macros are used to cast pointers to integers and
7627 ** integers to pointers. The way you do this varies from one compiler
7628 ** to the next, so we have developed the following set of #if statements
7629 ** to generate appropriate macros for a wide range of compilers.
7630 **
7631 ** The correct "ANSI" way to do this is to use the intptr_t type.
7632 ** Unfortunately, that typedef is not available on all compilers, or
7633 ** if it is available, it requires an #include of specific headers
7634 ** that vary from one machine to the next.
7635 **
7636 ** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
7637 ** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
7638 ** So we have to define the macros in different ways depending on the
7639 ** compiler.
7640 */
7641 #if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
7642 # define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
7643 # define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
7644 #elif !defined(__GNUC__) /* Works for compilers other than LLVM */
7645 # define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
7646 # define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
7647 #elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
7648 # define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
7649 # define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
7650 #else /* Generates a warning - but it always works */
7651 # define SQLITE_INT_TO_PTR(X) ((void*)(X))
7652 # define SQLITE_PTR_TO_INT(X) ((int)(X))
7653 #endif
7654
7655 /*
7656 ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
7657 ** 0 means mutexes are permanently disable and the library is never
7658 ** threadsafe. 1 means the library is serialized which is the highest
7659 ** level of threadsafety. 2 means the library is multithreaded - multiple
7660 ** threads can use SQLite as long as no two threads try to use the same
7661 ** database connection at the same time.
7662 **
7663 ** Older versions of SQLite used an optional THREADSAFE macro.
7664 ** We support that for legacy.
7665 */
7666 #if !defined(SQLITE_THREADSAFE)
7667 # if defined(THREADSAFE)
7668 # define SQLITE_THREADSAFE THREADSAFE
7669 # else
7670 # define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
7671 # endif
7672 #endif
7673
7674 /*
7675 ** Powersafe overwrite is on by default. But can be turned off using
7676 ** the -DSQLITE_POWERSAFE_OVERWRITE=0 command-line option.
7677 */
7678 #ifndef SQLITE_POWERSAFE_OVERWRITE
7679 # define SQLITE_POWERSAFE_OVERWRITE 1
7680 #endif
7681
7682 /*
7683 ** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
7684 ** It determines whether or not the features related to
7685 ** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can
7686 ** be overridden at runtime using the sqlite3_config() API.
7687 */
7688 #if !defined(SQLITE_DEFAULT_MEMSTATUS)
7689 # define SQLITE_DEFAULT_MEMSTATUS 1
7690 #endif
7691
7692 /*
7693 ** Exactly one of the following macros must be defined in order to
7694 ** specify which memory allocation subsystem to use.
7695 **
7696 ** SQLITE_SYSTEM_MALLOC // Use normal system malloc()
7697 ** SQLITE_WIN32_MALLOC // Use Win32 native heap API
7698 ** SQLITE_ZERO_MALLOC // Use a stub allocator that always fails
7699 ** SQLITE_MEMDEBUG // Debugging version of system malloc()
7700 **
7701 ** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the
7702 ** assert() macro is enabled, each call into the Win32 native heap subsystem
7703 ** will cause HeapValidate to be called. If heap validation should fail, an
7704 ** assertion will be triggered.
7705 **
7706 ** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
7707 ** the default.
7708 */
7709 #if defined(SQLITE_SYSTEM_MALLOC) \
7710 + defined(SQLITE_WIN32_MALLOC) \
7711 + defined(SQLITE_ZERO_MALLOC) \
7712 + defined(SQLITE_MEMDEBUG)>1
7713 # error "Two or more of the following compile-time configuration options\
7714 are defined but at most one is allowed:\
7715 SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG,\
7716 SQLITE_ZERO_MALLOC"
7717 #endif
7718 #if defined(SQLITE_SYSTEM_MALLOC) \
7719 + defined(SQLITE_WIN32_MALLOC) \
7720 + defined(SQLITE_ZERO_MALLOC) \
7721 + defined(SQLITE_MEMDEBUG)==0
7722 # define SQLITE_SYSTEM_MALLOC 1
7723 #endif
7724
7725 /*
7726 ** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the
7727 ** sizes of memory allocations below this value where possible.
7728 */
7729 #if !defined(SQLITE_MALLOC_SOFT_LIMIT)
7730 # define SQLITE_MALLOC_SOFT_LIMIT 1024
7731 #endif
7732
7733 /*
7734 ** We need to define _XOPEN_SOURCE as follows in order to enable
7735 ** recursive mutexes on most Unix systems and fchmod() on OpenBSD.
7736 ** But _XOPEN_SOURCE define causes problems for Mac OS X, so omit
7737 ** it.
7738 */
7739 #if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__)
7740 # define _XOPEN_SOURCE 600
7741 #endif
7742
7743 /*
7744 ** NDEBUG and SQLITE_DEBUG are opposites. It should always be true that
7745 ** defined(NDEBUG)==!defined(SQLITE_DEBUG). If this is not currently true,
7746 ** make it true by defining or undefining NDEBUG.
7747 **
7748 ** Setting NDEBUG makes the code smaller and faster by disabling the
7749 ** assert() statements in the code. So we want the default action
7750 ** to be for NDEBUG to be set and NDEBUG to be undefined only if SQLITE_DEBUG
7751 ** is set. Thus NDEBUG becomes an opt-in rather than an opt-out
7752 ** feature.
7753 */
7754 #if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
7755 # define NDEBUG 1
7756 #endif
7757 #if defined(NDEBUG) && defined(SQLITE_DEBUG)
7758 # undef NDEBUG
7759 #endif
7760
7761 /*
7762 ** The testcase() macro is used to aid in coverage testing. When
7763 ** doing coverage testing, the condition inside the argument to
7764 ** testcase() must be evaluated both true and false in order to
7765 ** get full branch coverage. The testcase() macro is inserted
7766 ** to help ensure adequate test coverage in places where simple
7767 ** condition/decision coverage is inadequate. For example, testcase()
7768 ** can be used to make sure boundary values are tested. For
7769 ** bitmask tests, testcase() can be used to make sure each bit
7770 ** is significant and used at least once. On switch statements
7771 ** where multiple cases go to the same block of code, testcase()
7772 ** can insure that all cases are evaluated.
7773 **
7774 */
7775 #ifdef SQLITE_COVERAGE_TEST
7776 SQLITE_PRIVATE void sqlite3Coverage(int);
7777 # define testcase(X) if( X ){ sqlite3Coverage(__LINE__); }
7778 #else
7779 # define testcase(X)
7780 #endif
7781
7782 /*
7783 ** The TESTONLY macro is used to enclose variable declarations or
7784 ** other bits of code that are needed to support the arguments
7785 ** within testcase() and assert() macros.
7786 */
7787 #if !defined(NDEBUG) || defined(SQLITE_COVERAGE_TEST)
7788 # define TESTONLY(X) X
7789 #else
7790 # define TESTONLY(X)
7791 #endif
7792
7793 /*
7794 ** Sometimes we need a small amount of code such as a variable initialization
7795 ** to setup for a later assert() statement. We do not want this code to
7796 ** appear when assert() is disabled. The following macro is therefore
7797 ** used to contain that setup code. The "VVA" acronym stands for
7798 ** "Verification, Validation, and Accreditation". In other words, the
7799 ** code within VVA_ONLY() will only run during verification processes.
7800 */
7801 #ifndef NDEBUG
7802 # define VVA_ONLY(X) X
7803 #else
7804 # define VVA_ONLY(X)
7805 #endif
7806
7807 /*
7808 ** The ALWAYS and NEVER macros surround boolean expressions which
7809 ** are intended to always be true or false, respectively. Such
7810 ** expressions could be omitted from the code completely. But they
7811 ** are included in a few cases in order to enhance the resilience
7812 ** of SQLite to unexpected behavior - to make the code "self-healing"
7813 ** or "ductile" rather than being "brittle" and crashing at the first
7814 ** hint of unplanned behavior.
7815 **
7816 ** In other words, ALWAYS and NEVER are added for defensive code.
7817 **
7818 ** When doing coverage testing ALWAYS and NEVER are hard-coded to
7819 ** be true and false so that the unreachable code they specify will
7820 ** not be counted as untested code.
7821 */
7822 #if defined(SQLITE_COVERAGE_TEST)
7823 # define ALWAYS(X) (1)
7824 # define NEVER(X) (0)
7825 #elif !defined(NDEBUG)
7826 # define ALWAYS(X) ((X)?1:(assert(0),0))
7827 # define NEVER(X) ((X)?(assert(0),1):0)
7828 #else
7829 # define ALWAYS(X) (X)
7830 # define NEVER(X) (X)
7831 #endif
7832
7833 /*
7834 ** Return true (non-zero) if the input is a integer that is too large
7835 ** to fit in 32-bits. This macro is used inside of various testcase()
7836 ** macros to verify that we have tested SQLite for large-file support.
7837 */
7838 #define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0)
7839
7840 /*
7841 ** The macro unlikely() is a hint that surrounds a boolean
7842 ** expression that is usually false. Macro likely() surrounds
7843 ** a boolean expression that is usually true. These hints could,
7844 ** in theory, be used by the compiler to generate better code, but
7845 ** currently they are just comments for human readers.
7846 */
7847 #define likely(X) (X)
7848 #define unlikely(X) (X)
7849
7850 /************** Include hash.h in the middle of sqliteInt.h ******************/
7851 /************** Begin file hash.h ********************************************/
7852 /*
7853 ** 2001 September 22
7854 **
@@ -8272,10 +8270,35 @@
8270 typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */
8271 #else
8272 typedef u32 tRowcnt; /* 32-bit is the default */
8273 #endif
8274
8275 /*
8276 ** Estimated quantities used for query planning are stored as 16-bit
8277 ** logarithms. For quantity X, the value stored is 10*log2(X). This
8278 ** gives a possible range of values of approximately 1.0e986 to 1e-986.
8279 ** But the allowed values are "grainy". Not every value is representable.
8280 ** For example, quantities 16 and 17 are both represented by a LogEst
8281 ** of 40. However, since LogEst quantatites are suppose to be estimates,
8282 ** not exact values, this imprecision is not a problem.
8283 **
8284 ** "LogEst" is short for "Logarithimic Estimate".
8285 **
8286 ** Examples:
8287 ** 1 -> 0 20 -> 43 10000 -> 132
8288 ** 2 -> 10 25 -> 46 25000 -> 146
8289 ** 3 -> 16 100 -> 66 1000000 -> 199
8290 ** 4 -> 20 1000 -> 99 1048576 -> 200
8291 ** 10 -> 33 1024 -> 100 4294967296 -> 320
8292 **
8293 ** The LogEst can be negative to indicate fractional values.
8294 ** Examples:
8295 **
8296 ** 0.5 -> -10 0.1 -> -33 0.0625 -> -40
8297 */
8298 typedef INT16_TYPE LogEst;
8299
8300 /*
8301 ** Macros to determine whether the machine is big or little endian,
8302 ** evaluated at runtime.
8303 */
8304 #ifdef SQLITE_AMALGAMATION
@@ -10419,11 +10442,12 @@
10442 char *zDflt; /* Original text of the default value */
10443 char *zType; /* Data type for this column */
10444 char *zColl; /* Collating sequence. If NULL, use the default */
10445 u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
10446 char affinity; /* One of the SQLITE_AFF_... values */
10447 u8 szEst; /* Estimated size of this column. INT==1 */
10448 u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */
10449 };
10450
10451 /* Allowed values for Column.colFlags:
10452 */
10453 #define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
@@ -10583,10 +10607,11 @@
10607 tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
10608 int tnum; /* Root BTree node for this table (see note above) */
10609 i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
10610 i16 nCol; /* Number of columns in this table */
10611 u16 nRef; /* Number of pointers to this Table */
10612 LogEst szTabRow; /* Estimated size of each table row in bytes */
10613 u8 tabFlags; /* Mask of TF_* values */
10614 u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
10615 #ifndef SQLITE_OMIT_ALTERTABLE
10616 int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
10617 #endif
@@ -10694,11 +10719,11 @@
10719 #define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */
10720 #define OE_SetNull 7 /* Set the foreign key value to NULL */
10721 #define OE_SetDflt 8 /* Set the foreign key value to its default */
10722 #define OE_Cascade 9 /* Cascade the changes */
10723
10724 #define OE_Default 10 /* Do whatever the default action is */
10725
10726
10727 /*
10728 ** An instance of the following structure is passed as the first
10729 ** argument to sqlite3VdbeKeyCompare and is used to control the
@@ -10781,10 +10806,11 @@
10806 Schema *pSchema; /* Schema containing this index */
10807 u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
10808 char **azColl; /* Array of collation sequence names for index */
10809 Expr *pPartIdxWhere; /* WHERE clause for partial indices */
10810 int tnum; /* DB Page containing root of this index */
10811 LogEst szIdxRow; /* Estimated average row size in bytes */
10812 u16 nColumn; /* Number of columns in table used by this index */
10813 u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
10814 unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
10815 unsigned bUnordered:1; /* Use this index for == or IN queries only */
10816 unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
@@ -11636,10 +11662,11 @@
11662 */
11663 typedef struct DbFixer DbFixer;
11664 struct DbFixer {
11665 Parse *pParse; /* The parsing context. Error messages written here */
11666 Schema *pSchema; /* Fix items to this schema */
11667 int bVarOnly; /* Check for variable references only */
11668 const char *zDb; /* Make sure all objects are contained in this database */
11669 const char *zType; /* Type of the container - used for error messages */
11670 const Token *pName; /* Name of the container - used for error messages */
11671 };
11672
@@ -12174,11 +12201,11 @@
12201 # define sqlite3AuthContextPush(a,b,c)
12202 # define sqlite3AuthContextPop(a) ((void)(a))
12203 #endif
12204 SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
12205 SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
12206 SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
12207 SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
12208 SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
12209 SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
12210 SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
12211 SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
@@ -12186,10 +12213,16 @@
12213 SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
12214 SQLITE_PRIVATE int sqlite3Atoi(const char*);
12215 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
12216 SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
12217 SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
12218 SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
12219 SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst);
12220 #ifndef SQLITE_OMIT_VIRTUALTABLE
12221 SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double);
12222 #endif
12223 SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst);
12224
12225 /*
12226 ** Routines to read and write variable-length integers. These used to
12227 ** be defined locally, but now we use the varint routines in the util.c
12228 ** file. Code should use the MACRO forms below, as the Varint32 versions
@@ -12302,11 +12335,11 @@
12335 SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
12336 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
12337 SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
12338 SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
12339 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
12340 SQLITE_PRIVATE char sqlite3AffinityType(const char*, u8*);
12341 SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
12342 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
12343 SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
12344 SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
12345 SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
@@ -22387,10 +22420,87 @@
22420 for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
22421 if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
22422 }
22423 }
22424 #endif
22425
22426 /*
22427 ** Find (an approximate) sum of two LogEst values. This computation is
22428 ** not a simple "+" operator because LogEst is stored as a logarithmic
22429 ** value.
22430 **
22431 */
22432 SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){
22433 static const unsigned char x[] = {
22434 10, 10, /* 0,1 */
22435 9, 9, /* 2,3 */
22436 8, 8, /* 4,5 */
22437 7, 7, 7, /* 6,7,8 */
22438 6, 6, 6, /* 9,10,11 */
22439 5, 5, 5, /* 12-14 */
22440 4, 4, 4, 4, /* 15-18 */
22441 3, 3, 3, 3, 3, 3, /* 19-24 */
22442 2, 2, 2, 2, 2, 2, 2, /* 25-31 */
22443 };
22444 if( a>=b ){
22445 if( a>b+49 ) return a;
22446 if( a>b+31 ) return a+1;
22447 return a+x[a-b];
22448 }else{
22449 if( b>a+49 ) return b;
22450 if( b>a+31 ) return b+1;
22451 return b+x[b-a];
22452 }
22453 }
22454
22455 /*
22456 ** Convert an integer into a LogEst. In other words, compute a
22457 ** good approximatation for 10*log2(x).
22458 */
22459 SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){
22460 static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
22461 LogEst y = 40;
22462 if( x<8 ){
22463 if( x<2 ) return 0;
22464 while( x<8 ){ y -= 10; x <<= 1; }
22465 }else{
22466 while( x>255 ){ y += 40; x >>= 4; }
22467 while( x>15 ){ y += 10; x >>= 1; }
22468 }
22469 return a[x&7] + y - 10;
22470 }
22471
22472 #ifndef SQLITE_OMIT_VIRTUALTABLE
22473 /*
22474 ** Convert a double into a LogEst
22475 ** In other words, compute an approximation for 10*log2(x).
22476 */
22477 SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){
22478 u64 a;
22479 LogEst e;
22480 assert( sizeof(x)==8 && sizeof(a)==8 );
22481 if( x<=1 ) return 0;
22482 if( x<=2000000000 ) return sqlite3LogEst((u64)x);
22483 memcpy(&a, &x, 8);
22484 e = (a>>52) - 1022;
22485 return e*10;
22486 }
22487 #endif /* SQLITE_OMIT_VIRTUALTABLE */
22488
22489 /*
22490 ** Convert a LogEst into an integer.
22491 */
22492 SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
22493 u64 n;
22494 if( x<10 ) return 1;
22495 n = x%10;
22496 x /= 10;
22497 if( n>=5 ) n -= 2;
22498 else if( n>=1 ) n -= 1;
22499 if( x>=3 ) return (n+8)<<(x-3);
22500 return (n+8)>>(3-x);
22501 }
22502
22503 /************** End of util.c ************************************************/
22504 /************** Begin file hash.c ********************************************/
22505 /*
22506 ** 2001 September 22
@@ -31382,11 +31492,11 @@
31492 #endif
31493
31494 #define osGetVersionExA ((BOOL(WINAPI*)( \
31495 LPOSVERSIONINFOA))aSyscall[34].pCurrent)
31496
31497 #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
31498 { "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
31499 #else
31500 { "GetVersionExW", (SYSCALL)0, 0 },
31501 #endif
31502
@@ -48986,17 +49096,17 @@
49096 ** page contain a special header (the "file header") that describes the file.
49097 ** The format of the file header is as follows:
49098 **
49099 ** OFFSET SIZE DESCRIPTION
49100 ** 0 16 Header string: "SQLite format 3\000"
49101 ** 16 2 Page size in bytes. (1 means 65536)
49102 ** 18 1 File format write version
49103 ** 19 1 File format read version
49104 ** 20 1 Bytes of unused space at the end of each page
49105 ** 21 1 Max embedded payload fraction (must be 64)
49106 ** 22 1 Min embedded payload fraction (must be 32)
49107 ** 23 1 Min leaf payload fraction (must be 32)
49108 ** 24 4 File change counter
49109 ** 28 4 Reserved for future use
49110 ** 32 4 First freelist page
49111 ** 36 4 Number of freelist pages in the file
49112 ** 40 60 15 4-byte meta values passed to higher layers
@@ -49006,13 +49116,14 @@
49116 ** 48 4 Size of page cache
49117 ** 52 4 Largest root-page (auto/incr_vacuum)
49118 ** 56 4 1=UTF-8 2=UTF16le 3=UTF16be
49119 ** 60 4 User version
49120 ** 64 4 Incremental vacuum mode
49121 ** 68 4 Application-ID
49122 ** 72 20 unused
49123 ** 92 4 The version-valid-for number
49124 ** 96 4 SQLITE_VERSION_NUMBER
49125 **
49126 ** All of the integer values are big-endian (most significant byte first).
49127 **
49128 ** The file change counter is incremented when the database is changed
49129 ** This counter allows other processes to know when the file has changed
@@ -52378,11 +52489,10 @@
52489 pBt->max1bytePayload = (u8)pBt->maxLocal;
52490 }
52491 assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
52492 pBt->pPage1 = pPage1;
52493 pBt->nPage = nPage;
 
52494 return SQLITE_OK;
52495
52496 page1_init_failed:
52497 releasePage(pPage1);
52498 pBt->pPage1 = 0;
@@ -52538,11 +52648,11 @@
52648 ** is requested, this is a no-op.
52649 */
52650 if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
52651 goto trans_begun;
52652 }
52653 assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
52654
52655 /* Write transactions are not possible on a read-only database */
52656 if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
52657 rc = SQLITE_READONLY;
52658 goto trans_begun;
@@ -62977,10 +63087,11 @@
63087 }
63088 fclose(out);
63089 }
63090 }
63091 #endif
63092 p->iCurrentTime = 0;
63093 p->magic = VDBE_MAGIC_INIT;
63094 return p->rc & db->errMask;
63095 }
63096
63097 /*
@@ -76082,11 +76193,11 @@
76193 return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
76194 }
76195 #ifndef SQLITE_OMIT_CAST
76196 if( op==TK_CAST ){
76197 assert( !ExprHasProperty(pExpr, EP_IntValue) );
76198 return sqlite3AffinityType(pExpr->u.zToken, 0);
76199 }
76200 #endif
76201 if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER)
76202 && pExpr->pTab!=0
76203 ){
@@ -78502,11 +78613,11 @@
78613 case TK_CAST: {
78614 /* Expressions of the form: CAST(pLeft AS token) */
78615 int aff, to_op;
78616 inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
78617 assert( !ExprHasProperty(pExpr, EP_IntValue) );
78618 aff = sqlite3AffinityType(pExpr->u.zToken, 0);
78619 to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
78620 assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
78621 assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE );
78622 assert( to_op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC );
78623 assert( to_op==OP_ToInt || aff!=SQLITE_AFF_INTEGER );
@@ -79169,11 +79280,11 @@
79280 }
79281 #ifndef SQLITE_OMIT_CAST
79282 case TK_CAST: {
79283 /* Expressions of the form: CAST(pLeft AS token) */
79284 const char *zAff = "unk";
79285 switch( sqlite3AffinityType(pExpr->u.zToken, 0) ){
79286 case SQLITE_AFF_TEXT: zAff = "TEXT"; break;
79287 case SQLITE_AFF_NONE: zAff = "NONE"; break;
79288 case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break;
79289 case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break;
79290 case SQLITE_AFF_REAL: zAff = "REAL"; break;
@@ -81884,16 +81995,16 @@
81995 if( zRet==0 ){
81996 sqlite3_result_error_nomem(context);
81997 return;
81998 }
81999
82000 sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
82001 z = zRet + sqlite3Strlen30(zRet);
82002 for(i=0; i<(p->nCol-1); i++){
82003 u64 nDistinct = p->current.anDLt[i] + 1;
82004 u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
82005 sqlite3_snprintf(24, z, " %llu", iVal);
82006 z += sqlite3Strlen30(z);
82007 assert( p->current.anEq[i] );
82008 }
82009 assert( z[0]=='\0' && z>zRet );
82010
@@ -81930,11 +82041,11 @@
82041 sqlite3_result_error_nomem(context);
82042 }else{
82043 int i;
82044 char *z = zRet;
82045 for(i=0; i<p->nCol; i++){
82046 sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]);
82047 z += sqlite3Strlen30(z);
82048 }
82049 assert( z[0]=='\0' && z>zRet );
82050 z[-1] = '\0';
82051 sqlite3_result_text(context, zRet, -1, sqlite3_free);
@@ -82391,22 +82502,20 @@
82502 ** The first argument points to a nul-terminated string containing a
82503 ** list of space separated integers. Read the first nOut of these into
82504 ** the array aOut[].
82505 */
82506 static void decodeIntArray(
82507 char *zIntArray, /* String containing int array to decode */
82508 int nOut, /* Number of slots in aOut[] */
82509 tRowcnt *aOut, /* Store integers here */
82510 Index *pIndex /* Handle extra flags for this index, if not NULL */
82511 ){
82512 char *z = zIntArray;
82513 int c;
82514 int i;
82515 tRowcnt v;
82516
 
 
82517 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
82518 if( z==0 ) z = "";
82519 #else
82520 if( NEVER(z==0) ) z = "";
82521 #endif
@@ -82417,12 +82526,23 @@
82526 z++;
82527 }
82528 aOut[i] = v;
82529 if( *z==' ' ) z++;
82530 }
82531 #ifndef SQLITE_ENABLE_STAT3_OR_STAT4
82532 assert( pIndex!=0 );
82533 #else
82534 if( pIndex )
82535 #endif
82536 {
82537 if( strcmp(z, "unordered")==0 ){
82538 pIndex->bUnordered = 1;
82539 }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
82540 int v32 = 0;
82541 sqlite3GetInt32(z+3, &v32);
82542 pIndex->szIdxRow = sqlite3LogEst(v32);
82543 }
82544 }
82545 }
82546
82547 /*
82548 ** This callback is invoked once for each index when reading the
@@ -82457,16 +82577,17 @@
82577 pIndex = 0;
82578 }
82579 z = argv[2];
82580
82581 if( pIndex ){
82582 decodeIntArray((char*)z, pIndex->nColumn+1, pIndex->aiRowEst, pIndex);
 
82583 if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0];
 
82584 }else{
82585 Index fakeIdx;
82586 fakeIdx.szIdxRow = pTable->szTabRow;
82587 decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx);
82588 pTable->szTabRow = fakeIdx.szIdxRow;
82589 }
82590
82591 return 0;
82592 }
82593
@@ -83185,32 +83306,28 @@
83306 #endif /* SQLITE_OMIT_ATTACH */
83307
83308 /*
83309 ** Initialize a DbFixer structure. This routine must be called prior
83310 ** to passing the structure to one of the sqliteFixAAAA() routines below.
 
 
 
83311 */
83312 SQLITE_PRIVATE void sqlite3FixInit(
83313 DbFixer *pFix, /* The fixer to be initialized */
83314 Parse *pParse, /* Error messages will be written here */
83315 int iDb, /* This is the database that must be used */
83316 const char *zType, /* "view", "trigger", or "index" */
83317 const Token *pName /* Name of the view, trigger, or index */
83318 ){
83319 sqlite3 *db;
83320
 
83321 db = pParse->db;
83322 assert( db->nDb>iDb );
83323 pFix->pParse = pParse;
83324 pFix->zDb = db->aDb[iDb].zName;
83325 pFix->pSchema = db->aDb[iDb].pSchema;
83326 pFix->zType = zType;
83327 pFix->pName = pName;
83328 pFix->bVarOnly = (iDb==1);
83329 }
83330
83331 /*
83332 ** The following set of routines walk through the parse tree and assign
83333 ** a specific database to all table references where the database name
@@ -83234,19 +83351,21 @@
83351 struct SrcList_item *pItem;
83352
83353 if( NEVER(pList==0) ) return 0;
83354 zDb = pFix->zDb;
83355 for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
83356 if( pFix->bVarOnly==0 ){
83357 if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
83358 sqlite3ErrorMsg(pFix->pParse,
83359 "%s %T cannot reference objects in database %s",
83360 pFix->zType, pFix->pName, pItem->zDatabase);
83361 return 1;
83362 }
83363 sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
83364 pItem->zDatabase = 0;
83365 pItem->pSchema = pFix->pSchema;
83366 }
83367 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
83368 if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
83369 if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
83370 #endif
83371 }
@@ -83264,13 +83383,25 @@
83383 if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
83384 return 1;
83385 }
83386 if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
83387 return 1;
83388 }
83389 if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){
83390 return 1;
83391 }
83392 if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
83393 return 1;
83394 }
83395 if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){
83396 return 1;
83397 }
83398 if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
83399 return 1;
83400 }
83401 if( sqlite3FixExpr(pFix, pSelect->pOffset) ){
83402 return 1;
83403 }
83404 pSelect = pSelect->pPrior;
83405 }
83406 return 0;
83407 }
@@ -83277,10 +83408,18 @@
83408 SQLITE_PRIVATE int sqlite3FixExpr(
83409 DbFixer *pFix, /* Context of the fixation */
83410 Expr *pExpr /* The expression to be fixed to one database */
83411 ){
83412 while( pExpr ){
83413 if( pExpr->op==TK_VARIABLE ){
83414 if( pFix->pParse->db->init.busy ){
83415 pExpr->op = TK_NULL;
83416 }else{
83417 sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
83418 return 1;
83419 }
83420 }
83421 if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
83422 if( ExprHasProperty(pExpr, EP_xIsSelect) ){
83423 if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
83424 }else{
83425 if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
@@ -84460,11 +84599,11 @@
84599 }
84600 pTable->zName = zName;
84601 pTable->iPKey = -1;
84602 pTable->pSchema = db->aDb[iDb].pSchema;
84603 pTable->nRef = 1;
84604 pTable->nRowEst = 1048576;
84605 assert( pParse->pNewTable==0 );
84606 pParse->pNewTable = pTable;
84607
84608 /* If this is the magic sqlite_sequence table used by autoincrement,
84609 ** then record a pointer to this table in the main database structure
@@ -84607,10 +84746,11 @@
84746 /* If there is no type specified, columns have the default affinity
84747 ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will
84748 ** be called next to set pCol->affinity correctly.
84749 */
84750 pCol->affinity = SQLITE_AFF_NONE;
84751 pCol->szEst = 1;
84752 p->nCol++;
84753 }
84754
84755 /*
84756 ** This routine is called by the parser while in the middle of
@@ -84648,26 +84788,30 @@
84788 ** 'DOUB' | SQLITE_AFF_REAL
84789 **
84790 ** If none of the substrings in the above table are found,
84791 ** SQLITE_AFF_NUMERIC is returned.
84792 */
84793 SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
84794 u32 h = 0;
84795 char aff = SQLITE_AFF_NUMERIC;
84796 const char *zChar = 0;
84797
84798 if( zIn==0 ) return aff;
84799 while( zIn[0] ){
84800 h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
84801 zIn++;
84802 if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
84803 aff = SQLITE_AFF_TEXT;
84804 zChar = zIn;
84805 }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */
84806 aff = SQLITE_AFF_TEXT;
84807 }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */
84808 aff = SQLITE_AFF_TEXT;
84809 }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
84810 && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
84811 aff = SQLITE_AFF_NONE;
84812 if( zIn[0]=='(' ) zChar = zIn;
84813 #ifndef SQLITE_OMIT_FLOATING_POINT
84814 }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
84815 && aff==SQLITE_AFF_NUMERIC ){
84816 aff = SQLITE_AFF_REAL;
84817 }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */
@@ -84681,10 +84825,32 @@
84825 aff = SQLITE_AFF_INTEGER;
84826 break;
84827 }
84828 }
84829
84830 /* If pszEst is not NULL, store an estimate of the field size. The
84831 ** estimate is scaled so that the size of an integer is 1. */
84832 if( pszEst ){
84833 *pszEst = 1; /* default size is approx 4 bytes */
84834 if( aff<=SQLITE_AFF_NONE ){
84835 if( zChar ){
84836 while( zChar[0] ){
84837 if( sqlite3Isdigit(zChar[0]) ){
84838 int v;
84839 sqlite3GetInt32(zChar, &v);
84840 v = v/4 + 1;
84841 if( v>255 ) v = 255;
84842 *pszEst = v; /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */
84843 break;
84844 }
84845 zChar++;
84846 }
84847 }else{
84848 *pszEst = 5; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/
84849 }
84850 }
84851 }
84852 return aff;
84853 }
84854
84855 /*
84856 ** This routine is called by the parser while in the middle of
@@ -84702,11 +84868,11 @@
84868 p = pParse->pNewTable;
84869 if( p==0 || NEVER(p->nCol<1) ) return;
84870 pCol = &p->aCol[p->nCol-1];
84871 assert( pCol->zType==0 );
84872 pCol->zType = sqlite3NameFromToken(pParse->db, pType);
84873 pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
84874 }
84875
84876 /*
84877 ** The expression is the default value for the most recently added column
84878 ** of the table currently under construction.
@@ -85050,18 +85216,46 @@
85216 testcase( pCol->affinity==SQLITE_AFF_REAL );
85217
85218 zType = azType[pCol->affinity - SQLITE_AFF_TEXT];
85219 len = sqlite3Strlen30(zType);
85220 assert( pCol->affinity==SQLITE_AFF_NONE
85221 || pCol->affinity==sqlite3AffinityType(zType, 0) );
85222 memcpy(&zStmt[k], zType, len);
85223 k += len;
85224 assert( k<=n );
85225 }
85226 sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd);
85227 return zStmt;
85228 }
85229
85230 /*
85231 ** Estimate the total row width for a table.
85232 */
85233 static void estimateTableWidth(Table *pTab){
85234 unsigned wTable = 0;
85235 const Column *pTabCol;
85236 int i;
85237 for(i=pTab->nCol, pTabCol=pTab->aCol; i>0; i--, pTabCol++){
85238 wTable += pTabCol->szEst;
85239 }
85240 if( pTab->iPKey<0 ) wTable++;
85241 pTab->szTabRow = sqlite3LogEst(wTable*4);
85242 }
85243
85244 /*
85245 ** Estimate the average size of a row for an index.
85246 */
85247 static void estimateIndexWidth(Index *pIdx){
85248 unsigned wIndex = 1;
85249 int i;
85250 const Column *aCol = pIdx->pTable->aCol;
85251 for(i=0; i<pIdx->nColumn; i++){
85252 assert( pIdx->aiColumn[i]>=0 && pIdx->aiColumn[i]<pIdx->pTable->nCol );
85253 wIndex += aCol[pIdx->aiColumn[i]].szEst;
85254 }
85255 pIdx->szIdxRow = sqlite3LogEst(wIndex*4);
85256 }
85257
85258 /*
85259 ** This routine is called to report the final ")" that terminates
85260 ** a CREATE TABLE statement.
85261 **
@@ -85085,13 +85279,14 @@
85279 Parse *pParse, /* Parse context */
85280 Token *pCons, /* The ',' token after the last column defn. */
85281 Token *pEnd, /* The final ')' token in the CREATE TABLE */
85282 Select *pSelect /* Select from a "CREATE ... AS SELECT" */
85283 ){
85284 Table *p; /* The new table */
85285 sqlite3 *db = pParse->db; /* The database connection */
85286 int iDb; /* Database in which the table lives */
85287 Index *pIdx; /* An implied index of the table */
85288
85289 if( (pEnd==0 && pSelect==0) || db->mallocFailed ){
85290 return;
85291 }
85292 p = pParse->pNewTable;
@@ -85106,10 +85301,16 @@
85301 */
85302 if( p->pCheck ){
85303 sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
85304 }
85305 #endif /* !defined(SQLITE_OMIT_CHECK) */
85306
85307 /* Estimate the average row size for the table and for all implied indices */
85308 estimateTableWidth(p);
85309 for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
85310 estimateIndexWidth(pIdx);
85311 }
85312
85313 /* If the db->init.busy is 1 it means we are reading the SQL off the
85314 ** "sqlite_master" or "sqlite_temp_master" table on the disk.
85315 ** So do not write to the disk again. Extract the root page number
85316 ** for the table from the db->init.newTnum field. (The page number
@@ -85303,13 +85504,12 @@
85504 sqlite3SelectDelete(db, pSelect);
85505 return;
85506 }
85507 sqlite3TwoPartName(pParse, pName1, pName2, &pName);
85508 iDb = sqlite3SchemaToIndex(db, p->pSchema);
85509 sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
85510 if( sqlite3FixSelect(&sFix, pSelect) ){
 
85511 sqlite3SelectDelete(db, pSelect);
85512 return;
85513 }
85514
85515 /* Make a copy of the entire SELECT statement that defines the view.
@@ -86066,13 +86266,14 @@
86266 sqlite3 *db = pParse->db;
86267 Db *pDb; /* The specific table containing the indexed database */
86268 int iDb; /* Index of the database that is being written */
86269 Token *pName = 0; /* Unqualified name of the index to create */
86270 struct ExprList_item *pListItem; /* For looping over pList */
86271 const Column *pTabCol; /* A column in the table */
86272 int nCol; /* Number of columns */
86273 int nExtra = 0; /* Space allocated for zExtra[] */
86274 char *zExtra; /* Extra space after the Index object */
86275
86276 assert( pParse->nErr==0 ); /* Never called with prior errors */
86277 if( db->mallocFailed || IN_DECLARE_VTAB ){
86278 goto exit_create_index;
86279 }
@@ -86105,13 +86306,12 @@
86306 iDb = 1;
86307 }
86308 }
86309 #endif
86310
86311 sqlite3FixInit(&sFix, pParse, iDb, "index", pName);
86312 if( sqlite3FixSrcList(&sFix, pTblName) ){
 
86313 /* Because the parser constructs pTblName from a single identifier,
86314 ** sqlite3FixSrcList can never fail. */
86315 assert(0);
86316 }
86317 pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
@@ -86296,11 +86496,10 @@
86496 ** same column more than once cannot be an error because that would
86497 ** break backwards compatibility - it needs to be a warning.
86498 */
86499 for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
86500 const char *zColName = pListItem->zName;
 
86501 int requestedSortOrder;
86502 char *zColl; /* Collation sequence name */
86503
86504 for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
86505 if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
@@ -86333,10 +86532,11 @@
86532 requestedSortOrder = pListItem->sortOrder & sortOrderMask;
86533 pIndex->aSortOrder[i] = (u8)requestedSortOrder;
86534 if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0;
86535 }
86536 sqlite3DefaultRowEst(pIndex);
86537 if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
86538
86539 if( pTab==pParse->pNewTable ){
86540 /* This routine has been called to create an automatic index as a
86541 ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
86542 ** a PRIMARY KEY or UNIQUE clause following the column definitions.
@@ -88238,10 +88438,11 @@
88438 ** API function sqlite3_count_changes) to be set incorrectly. */
88439 if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab)
88440 && 0==sqlite3FkRequired(pParse, pTab, 0, 0)
88441 ){
88442 assert( !isView );
88443 sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
88444 sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt,
88445 pTab->zName, P4_STATIC);
88446 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
88447 assert( pIdx->pSchema==pTab->pSchema );
88448 sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
@@ -93487,10 +93688,11 @@
93688 (char*)pKey, P4_KEYINFO_HANDOFF);
93689 VdbeComment((v, "%s", pSrcIdx->zName));
93690 pKey = sqlite3IndexKeyinfo(pParse, pDestIdx);
93691 sqlite3VdbeAddOp4(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest,
93692 (char*)pKey, P4_KEYINFO_HANDOFF);
93693 sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
93694 VdbeComment((v, "%s", pDestIdx->zName));
93695 addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
93696 sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
93697 sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
93698 sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
@@ -94974,181 +95176,363 @@
95176 #define PragTyp_HEXKEY 35
95177 #define PragTyp_KEY 36
95178 #define PragTyp_REKEY 37
95179 #define PragTyp_LOCK_STATUS 38
95180 #define PragTyp_PARSER_TRACE 39
95181 #define PragFlag_NeedSchema 0x01
95182 static const struct sPragmaNames {
95183 const char *const zName; /* Name of pragma */
95184 u8 ePragTyp; /* PragTyp_XXX value */
95185 u8 mPragFlag; /* Zero or more PragFlag_XXX values */
95186 u32 iArg; /* Extra argument */
95187 } aPragmaNames[] = {
95188 #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
95189 { /* zName: */ "activate_extensions",
95190 /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
95191 /* ePragFlag: */ 0,
95192 /* iArg: */ 0 },
95193 #endif
95194 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95195 { /* zName: */ "application_id",
95196 /* ePragTyp: */ PragTyp_HEADER_VALUE,
95197 /* ePragFlag: */ 0,
95198 /* iArg: */ 0 },
95199 #endif
95200 #if !defined(SQLITE_OMIT_AUTOVACUUM)
95201 { /* zName: */ "auto_vacuum",
95202 /* ePragTyp: */ PragTyp_AUTO_VACUUM,
95203 /* ePragFlag: */ PragFlag_NeedSchema,
95204 /* iArg: */ 0 },
95205 #endif
95206 #if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
95207 { /* zName: */ "automatic_index",
95208 /* ePragTyp: */ PragTyp_FLAG,
95209 /* ePragFlag: */ 0,
95210 /* iArg: */ SQLITE_AutoIndex },
95211 #endif
95212 { /* zName: */ "busy_timeout",
95213 /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
95214 /* ePragFlag: */ 0,
95215 /* iArg: */ 0 },
95216 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95217 { /* zName: */ "cache_size",
95218 /* ePragTyp: */ PragTyp_CACHE_SIZE,
95219 /* ePragFlag: */ PragFlag_NeedSchema,
95220 /* iArg: */ 0 },
95221 #endif
95222 { /* zName: */ "cache_spill",
95223 /* ePragTyp: */ PragTyp_FLAG,
95224 /* ePragFlag: */ 0,
95225 /* iArg: */ SQLITE_CacheSpill },
95226 { /* zName: */ "case_sensitive_like",
95227 /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
95228 /* ePragFlag: */ 0,
95229 /* iArg: */ 0 },
95230 { /* zName: */ "checkpoint_fullfsync",
95231 /* ePragTyp: */ PragTyp_FLAG,
95232 /* ePragFlag: */ 0,
95233 /* iArg: */ SQLITE_CkptFullFSync },
95234 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95235 { /* zName: */ "collation_list",
95236 /* ePragTyp: */ PragTyp_COLLATION_LIST,
95237 /* ePragFlag: */ 0,
95238 /* iArg: */ 0 },
95239 #endif
95240 #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
95241 { /* zName: */ "compile_options",
95242 /* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
95243 /* ePragFlag: */ 0,
95244 /* iArg: */ 0 },
95245 #endif
95246 { /* zName: */ "count_changes",
95247 /* ePragTyp: */ PragTyp_FLAG,
95248 /* ePragFlag: */ 0,
95249 /* iArg: */ SQLITE_CountRows },
95250 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
95251 { /* zName: */ "data_store_directory",
95252 /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
95253 /* ePragFlag: */ 0,
95254 /* iArg: */ 0 },
95255 #endif
95256 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95257 { /* zName: */ "database_list",
95258 /* ePragTyp: */ PragTyp_DATABASE_LIST,
95259 /* ePragFlag: */ PragFlag_NeedSchema,
95260 /* iArg: */ 0 },
95261 #endif
95262 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
95263 { /* zName: */ "default_cache_size",
95264 /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
95265 /* ePragFlag: */ PragFlag_NeedSchema,
95266 /* iArg: */ 0 },
95267 #endif
95268 #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
95269 { /* zName: */ "defer_foreign_keys",
95270 /* ePragTyp: */ PragTyp_FLAG,
95271 /* ePragFlag: */ 0,
95272 /* iArg: */ SQLITE_DeferFKs },
95273 #endif
95274 { /* zName: */ "empty_result_callbacks",
95275 /* ePragTyp: */ PragTyp_FLAG,
95276 /* ePragFlag: */ 0,
95277 /* iArg: */ SQLITE_NullCallback },
95278 #if !defined(SQLITE_OMIT_UTF16)
95279 { /* zName: */ "encoding",
95280 /* ePragTyp: */ PragTyp_ENCODING,
95281 /* ePragFlag: */ 0,
95282 /* iArg: */ 0 },
95283 #endif
95284 #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
95285 { /* zName: */ "foreign_key_check",
95286 /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
95287 /* ePragFlag: */ PragFlag_NeedSchema,
95288 /* iArg: */ 0 },
95289 #endif
95290 #if !defined(SQLITE_OMIT_FOREIGN_KEY)
95291 { /* zName: */ "foreign_key_list",
95292 /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
95293 /* ePragFlag: */ PragFlag_NeedSchema,
95294 /* iArg: */ 0 },
95295 #endif
95296 #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
95297 { /* zName: */ "foreign_keys",
95298 /* ePragTyp: */ PragTyp_FLAG,
95299 /* ePragFlag: */ 0,
95300 /* iArg: */ SQLITE_ForeignKeys },
95301 #endif
95302 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95303 { /* zName: */ "freelist_count",
95304 /* ePragTyp: */ PragTyp_HEADER_VALUE,
95305 /* ePragFlag: */ 0,
95306 /* iArg: */ 0 },
95307 #endif
95308 { /* zName: */ "full_column_names",
95309 /* ePragTyp: */ PragTyp_FLAG,
95310 /* ePragFlag: */ 0,
95311 /* iArg: */ SQLITE_FullColNames },
95312 { /* zName: */ "fullfsync",
95313 /* ePragTyp: */ PragTyp_FLAG,
95314 /* ePragFlag: */ 0,
95315 /* iArg: */ SQLITE_FullFSync },
95316 #if defined(SQLITE_HAS_CODEC)
95317 { /* zName: */ "hexkey",
95318 /* ePragTyp: */ PragTyp_HEXKEY,
95319 /* ePragFlag: */ 0,
95320 /* iArg: */ 0 },
95321 { /* zName: */ "hexrekey",
95322 /* ePragTyp: */ PragTyp_HEXKEY,
95323 /* ePragFlag: */ 0,
95324 /* iArg: */ 0 },
95325 #endif
95326 #if !defined(SQLITE_OMIT_CHECK)
95327 { /* zName: */ "ignore_check_constraints",
95328 /* ePragTyp: */ PragTyp_FLAG,
95329 /* ePragFlag: */ 0,
95330 /* iArg: */ SQLITE_IgnoreChecks },
95331 #endif
95332 #if !defined(SQLITE_OMIT_AUTOVACUUM)
95333 { /* zName: */ "incremental_vacuum",
95334 /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
95335 /* ePragFlag: */ PragFlag_NeedSchema,
95336 /* iArg: */ 0 },
95337 #endif
95338 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95339 { /* zName: */ "index_info",
95340 /* ePragTyp: */ PragTyp_INDEX_INFO,
95341 /* ePragFlag: */ PragFlag_NeedSchema,
95342 /* iArg: */ 0 },
95343 { /* zName: */ "index_list",
95344 /* ePragTyp: */ PragTyp_INDEX_LIST,
95345 /* ePragFlag: */ PragFlag_NeedSchema,
95346 /* iArg: */ 0 },
95347 #endif
95348 #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
95349 { /* zName: */ "integrity_check",
95350 /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
95351 /* ePragFlag: */ PragFlag_NeedSchema,
95352 /* iArg: */ 0 },
95353 #endif
95354 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95355 { /* zName: */ "journal_mode",
95356 /* ePragTyp: */ PragTyp_JOURNAL_MODE,
95357 /* ePragFlag: */ PragFlag_NeedSchema,
95358 /* iArg: */ 0 },
95359 { /* zName: */ "journal_size_limit",
95360 /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
95361 /* ePragFlag: */ 0,
95362 /* iArg: */ 0 },
95363 #endif
95364 #if defined(SQLITE_HAS_CODEC)
95365 { /* zName: */ "key",
95366 /* ePragTyp: */ PragTyp_KEY,
95367 /* ePragFlag: */ 0,
95368 /* iArg: */ 0 },
95369 #endif
95370 { /* zName: */ "legacy_file_format",
95371 /* ePragTyp: */ PragTyp_FLAG,
95372 /* ePragFlag: */ 0,
95373 /* iArg: */ SQLITE_LegacyFileFmt },
95374 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
95375 { /* zName: */ "lock_proxy_file",
95376 /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
95377 /* ePragFlag: */ 0,
95378 /* iArg: */ 0 },
95379 #endif
95380 #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
95381 { /* zName: */ "lock_status",
95382 /* ePragTyp: */ PragTyp_LOCK_STATUS,
95383 /* ePragFlag: */ 0,
95384 /* iArg: */ 0 },
95385 #endif
95386 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95387 { /* zName: */ "locking_mode",
95388 /* ePragTyp: */ PragTyp_LOCKING_MODE,
95389 /* ePragFlag: */ 0,
95390 /* iArg: */ 0 },
95391 { /* zName: */ "max_page_count",
95392 /* ePragTyp: */ PragTyp_PAGE_COUNT,
95393 /* ePragFlag: */ PragFlag_NeedSchema,
95394 /* iArg: */ 0 },
95395 { /* zName: */ "mmap_size",
95396 /* ePragTyp: */ PragTyp_MMAP_SIZE,
95397 /* ePragFlag: */ 0,
95398 /* iArg: */ 0 },
95399 { /* zName: */ "page_count",
95400 /* ePragTyp: */ PragTyp_PAGE_COUNT,
95401 /* ePragFlag: */ PragFlag_NeedSchema,
95402 /* iArg: */ 0 },
95403 { /* zName: */ "page_size",
95404 /* ePragTyp: */ PragTyp_PAGE_SIZE,
95405 /* ePragFlag: */ 0,
95406 /* iArg: */ 0 },
95407 #endif
95408 #if defined(SQLITE_DEBUG)
95409 { /* zName: */ "parser_trace",
95410 /* ePragTyp: */ PragTyp_PARSER_TRACE,
95411 /* ePragFlag: */ 0,
95412 /* iArg: */ 0 },
95413 #endif
95414 { /* zName: */ "query_only",
95415 /* ePragTyp: */ PragTyp_FLAG,
95416 /* ePragFlag: */ 0,
95417 /* iArg: */ SQLITE_QueryOnly },
95418 #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
95419 { /* zName: */ "quick_check",
95420 /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
95421 /* ePragFlag: */ PragFlag_NeedSchema,
95422 /* iArg: */ 0 },
95423 #endif
95424 { /* zName: */ "read_uncommitted",
95425 /* ePragTyp: */ PragTyp_FLAG,
95426 /* ePragFlag: */ 0,
95427 /* iArg: */ SQLITE_ReadUncommitted },
95428 { /* zName: */ "recursive_triggers",
95429 /* ePragTyp: */ PragTyp_FLAG,
95430 /* ePragFlag: */ 0,
95431 /* iArg: */ SQLITE_RecTriggers },
95432 #if defined(SQLITE_HAS_CODEC)
95433 { /* zName: */ "rekey",
95434 /* ePragTyp: */ PragTyp_REKEY,
95435 /* ePragFlag: */ 0,
95436 /* iArg: */ 0 },
95437 #endif
95438 { /* zName: */ "reverse_unordered_selects",
95439 /* ePragTyp: */ PragTyp_FLAG,
95440 /* ePragFlag: */ 0,
95441 /* iArg: */ SQLITE_ReverseOrder },
95442 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95443 { /* zName: */ "schema_version",
95444 /* ePragTyp: */ PragTyp_HEADER_VALUE,
95445 /* ePragFlag: */ 0,
95446 /* iArg: */ 0 },
95447 #endif
95448 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95449 { /* zName: */ "secure_delete",
95450 /* ePragTyp: */ PragTyp_SECURE_DELETE,
95451 /* ePragFlag: */ 0,
95452 /* iArg: */ 0 },
95453 #endif
95454 { /* zName: */ "short_column_names",
95455 /* ePragTyp: */ PragTyp_FLAG,
95456 /* ePragFlag: */ 0,
95457 /* iArg: */ SQLITE_ShortColNames },
95458 { /* zName: */ "shrink_memory",
95459 /* ePragTyp: */ PragTyp_SHRINK_MEMORY,
95460 /* ePragFlag: */ 0,
95461 /* iArg: */ 0 },
95462 { /* zName: */ "soft_heap_limit",
95463 /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
95464 /* ePragFlag: */ 0,
95465 /* iArg: */ 0 },
95466 #if defined(SQLITE_DEBUG)
95467 { /* zName: */ "sql_trace",
95468 /* ePragTyp: */ PragTyp_FLAG,
95469 /* ePragFlag: */ 0,
95470 /* iArg: */ SQLITE_SqlTrace },
95471 #endif
95472 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95473 { /* zName: */ "synchronous",
95474 /* ePragTyp: */ PragTyp_SYNCHRONOUS,
95475 /* ePragFlag: */ PragFlag_NeedSchema,
95476 /* iArg: */ 0 },
95477 #endif
95478 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
95479 { /* zName: */ "table_info",
95480 /* ePragTyp: */ PragTyp_TABLE_INFO,
95481 /* ePragFlag: */ PragFlag_NeedSchema,
95482 /* iArg: */ 0 },
95483 #endif
95484 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
95485 { /* zName: */ "temp_store",
95486 /* ePragTyp: */ PragTyp_TEMP_STORE,
95487 /* ePragFlag: */ 0,
95488 /* iArg: */ 0 },
95489 { /* zName: */ "temp_store_directory",
95490 /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
95491 /* ePragFlag: */ 0,
95492 /* iArg: */ 0 },
95493 #endif
95494 #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
95495 { /* zName: */ "user_version",
95496 /* ePragTyp: */ PragTyp_HEADER_VALUE,
95497 /* ePragFlag: */ 0,
95498 /* iArg: */ 0 },
95499 #endif
95500 #if defined(SQLITE_DEBUG)
95501 { /* zName: */ "vdbe_addoptrace",
95502 /* ePragTyp: */ PragTyp_FLAG,
95503 /* ePragFlag: */ 0,
95504 /* iArg: */ SQLITE_VdbeAddopTrace },
95505 { /* zName: */ "vdbe_debug",
95506 /* ePragTyp: */ PragTyp_FLAG,
95507 /* ePragFlag: */ 0,
95508 /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
95509 { /* zName: */ "vdbe_listing",
95510 /* ePragTyp: */ PragTyp_FLAG,
95511 /* ePragFlag: */ 0,
95512 /* iArg: */ SQLITE_VdbeListing },
95513 { /* zName: */ "vdbe_trace",
95514 /* ePragTyp: */ PragTyp_FLAG,
95515 /* ePragFlag: */ 0,
95516 /* iArg: */ SQLITE_VdbeTrace },
95517 #endif
95518 #if !defined(SQLITE_OMIT_WAL)
95519 { /* zName: */ "wal_autocheckpoint",
95520 /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
95521 /* ePragFlag: */ 0,
95522 /* iArg: */ 0 },
95523 { /* zName: */ "wal_checkpoint",
95524 /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
95525 /* ePragFlag: */ PragFlag_NeedSchema,
95526 /* iArg: */ 0 },
95527 #endif
95528 { /* zName: */ "writable_schema",
95529 /* ePragTyp: */ PragTyp_FLAG,
95530 /* ePragFlag: */ 0,
95531 /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
95532 };
95533 /* Number of pragmas: 55 on by default, 67 total. */
95534 /* End of the automatically generated pragma table.
95535 ***************************************************************************/
95536
95537 /*
95538 ** Interpret the given string as a safety level. Return 0 for OFF,
@@ -95476,10 +95860,15 @@
95860 }else{
95861 lwr = mid + 1;
95862 }
95863 }
95864 if( lwr>upr ) goto pragma_out;
95865
95866 /* Make sure the database schema is loaded if the pragma requires that */
95867 if( (aPragmaNames[mid].mPragFlag & PragFlag_NeedSchema)!=0 ){
95868 if( sqlite3ReadSchema(pParse) ) goto pragma_out;
95869 }
95870
95871 /* Jump to the appropriate pragma handler */
95872 switch( aPragmaNames[mid].ePragTyp ){
95873
95874 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
@@ -95510,11 +95899,10 @@
95899 { OP_Integer, 0, 1, 0}, /* 6 */
95900 { OP_Noop, 0, 0, 0},
95901 { OP_ResultRow, 1, 1, 0},
95902 };
95903 int addr;
 
95904 sqlite3VdbeUsesBtree(v, iDb);
95905 if( !zRight ){
95906 sqlite3VdbeSetNumCols(v, 1);
95907 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC);
95908 pParse->nMem += 2;
@@ -95606,11 +95994,10 @@
95994 **
95995 ** Return the number of pages in the specified database.
95996 */
95997 case PragTyp_PAGE_COUNT: {
95998 int iReg;
 
95999 sqlite3CodeVerifySchema(pParse, iDb);
96000 iReg = ++pParse->nMem;
96001 if( sqlite3Tolower(zLeft[0])=='p' ){
96002 sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
96003 }else{
@@ -95679,18 +96066,10 @@
96066 */
96067 case PragTyp_JOURNAL_MODE: {
96068 int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
96069 int ii; /* Loop counter */
96070
 
 
 
 
 
 
 
 
96071 sqlite3VdbeSetNumCols(v, 1);
96072 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
96073
96074 if( zRight==0 ){
96075 /* If there is no "=MODE" part of the pragma, do a query for the
@@ -95752,55 +96131,44 @@
96131 */
96132 #ifndef SQLITE_OMIT_AUTOVACUUM
96133 case PragTyp_AUTO_VACUUM: {
96134 Btree *pBt = pDb->pBt;
96135 assert( pBt!=0 );
 
 
 
96136 if( !zRight ){
96137 returnSingleInt(pParse, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
 
 
 
 
 
 
96138 }else{
96139 int eAuto = getAutoVacuum(zRight);
96140 assert( eAuto>=0 && eAuto<=2 );
96141 db->nextAutovac = (u8)eAuto;
96142 /* Call SetAutoVacuum() to set initialize the internal auto and
96143 ** incr-vacuum flags. This is required in case this connection
96144 ** creates the database file. It is important that it is created
96145 ** as an auto-vacuum capable db.
96146 */
96147 rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
96148 if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
96149 /* When setting the auto_vacuum mode to either "full" or
96150 ** "incremental", write the value of meta[6] in the database
96151 ** file. Before writing to meta[6], check that meta[3] indicates
96152 ** that this really is an auto-vacuum capable database.
96153 */
96154 static const VdbeOpList setMeta6[] = {
96155 { OP_Transaction, 0, 1, 0}, /* 0 */
96156 { OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
96157 { OP_If, 1, 0, 0}, /* 2 */
96158 { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
96159 { OP_Integer, 0, 1, 0}, /* 4 */
96160 { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
96161 };
96162 int iAddr;
96163 iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6);
96164 sqlite3VdbeChangeP1(v, iAddr, iDb);
96165 sqlite3VdbeChangeP1(v, iAddr+1, iDb);
96166 sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
96167 sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
96168 sqlite3VdbeChangeP1(v, iAddr+5, iDb);
96169 sqlite3VdbeUsesBtree(v, iDb);
 
 
96170 }
96171 }
96172 break;
96173 }
96174 #endif
@@ -95811,13 +96179,10 @@
96179 ** Do N steps of incremental vacuuming on a database.
96180 */
96181 #ifndef SQLITE_OMIT_AUTOVACUUM
96182 case PragTyp_INCREMENTAL_VACUUM: {
96183 int iLimit, addr;
 
 
 
96184 if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
96185 iLimit = 0x7fffffff;
96186 }
96187 sqlite3BeginWriteOperation(pParse, 0, iDb);
96188 sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1);
@@ -95841,11 +96206,10 @@
96206 ** number of pages in the cache. If N is negative, then the
96207 ** number of pages is adjusted so that the cache uses -N kibibytes
96208 ** of memory.
96209 */
96210 case PragTyp_CACHE_SIZE: {
 
96211 assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
96212 if( !zRight ){
96213 returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
96214 }else{
96215 int size = sqlite3Atoi(zRight);
@@ -96062,11 +96426,10 @@
96426 ** the local value does not make changes to the disk file and the
96427 ** default value will be restored the next time the database is
96428 ** opened.
96429 */
96430 case PragTyp_SYNCHRONOUS: {
 
96431 if( !zRight ){
96432 returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
96433 }else{
96434 if( !db->autoCommit ){
96435 sqlite3ErrorMsg(pParse,
@@ -96124,11 +96487,10 @@
96487 ** notnull: True if 'NOT NULL' is part of column declaration
96488 ** dflt_value: The default value for the column, if any.
96489 */
96490 case PragTyp_TABLE_INFO: if( zRight ){
96491 Table *pTab;
 
96492 pTab = sqlite3FindTable(db, zRight, zDb);
96493 if( pTab ){
96494 int i, k;
96495 int nHidden = 0;
96496 Column *pCol;
@@ -96174,11 +96536,10 @@
96536 break;
96537
96538 case PragTyp_INDEX_INFO: if( zRight ){
96539 Index *pIdx;
96540 Table *pTab;
 
96541 pIdx = sqlite3FindIndex(db, zRight, zDb);
96542 if( pIdx ){
96543 int i;
96544 pTab = pIdx->pTable;
96545 sqlite3VdbeSetNumCols(v, 3);
@@ -96200,39 +96561,41 @@
96561 break;
96562
96563 case PragTyp_INDEX_LIST: if( zRight ){
96564 Index *pIdx;
96565 Table *pTab;
96566 int i;
96567 pTab = sqlite3FindTable(db, zRight, zDb);
96568 if( pTab ){
96569 v = sqlite3GetVdbe(pParse);
96570 sqlite3VdbeSetNumCols(v, 4);
96571 pParse->nMem = 4;
96572 sqlite3CodeVerifySchema(pParse, iDb);
96573 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
96574 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
96575 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
96576 sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "avgrowsize", SQLITE_STATIC);
96577 sqlite3VdbeAddOp2(v, OP_Integer, 0, 1);
96578 sqlite3VdbeAddOp2(v, OP_Null, 0, 2);
96579 sqlite3VdbeAddOp2(v, OP_Integer, 1, 3);
96580 sqlite3VdbeAddOp2(v, OP_Integer,
96581 (int)sqlite3LogEstToInt(pTab->szTabRow), 4);
96582 sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
96583 for(pIdx=pTab->pIndex, i=1; pIdx; pIdx=pIdx->pNext, i++){
96584 sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
96585 sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
96586 sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
96587 sqlite3VdbeAddOp2(v, OP_Integer,
96588 (int)sqlite3LogEstToInt(pIdx->szIdxRow), 4);
96589 sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
96590 }
96591 }
96592 }
96593 break;
96594
96595 case PragTyp_DATABASE_LIST: {
96596 int i;
 
96597 sqlite3VdbeSetNumCols(v, 3);
96598 pParse->nMem = 3;
96599 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
96600 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
96601 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", SQLITE_STATIC);
@@ -96267,11 +96630,10 @@
96630
96631 #ifndef SQLITE_OMIT_FOREIGN_KEY
96632 case PragTyp_FOREIGN_KEY_LIST: if( zRight ){
96633 FKey *pFK;
96634 Table *pTab;
 
96635 pTab = sqlite3FindTable(db, zRight, zDb);
96636 if( pTab ){
96637 v = sqlite3GetVdbe(pParse);
96638 pFK = pTab->pFKey;
96639 if( pFK ){
@@ -96329,11 +96691,10 @@
96691 int regRow; /* Registers to hold a row from pTab */
96692 int addrTop; /* Top of a loop checking foreign keys */
96693 int addrOk; /* Jump here if the key is OK */
96694 int *aiCols; /* child to parent column mapping */
96695
 
96696 regResult = pParse->nMem+1;
96697 pParse->nMem += 4;
96698 regKey = ++pParse->nMem;
96699 regRow = ++pParse->nMem;
96700 v = sqlite3GetVdbe(pParse);
@@ -96490,11 +96851,10 @@
96851 assert( iDb>=0 );
96852 assert( iDb==0 || pId2->z );
96853 if( pId2->z==0 ) iDb = -1;
96854
96855 /* Initialize the VDBE program */
 
96856 pParse->nMem = 6;
96857 sqlite3VdbeSetNumCols(v, 1);
96858 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", SQLITE_STATIC);
96859
96860 /* Set the maximum error count */
@@ -96814,11 +97174,10 @@
97174 eMode = SQLITE_CHECKPOINT_FULL;
97175 }else if( sqlite3StrICmp(zRight, "restart")==0 ){
97176 eMode = SQLITE_CHECKPOINT_RESTART;
97177 }
97178 }
 
97179 sqlite3VdbeSetNumCols(v, 3);
97180 pParse->nMem = 3;
97181 sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "busy", SQLITE_STATIC);
97182 sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "log", SQLITE_STATIC);
97183 sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "checkpointed", SQLITE_STATIC);
@@ -96934,16 +97293,16 @@
97293 if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight));
97294 break;
97295 }
97296 case PragTyp_HEXKEY: {
97297 if( zRight ){
97298 u8 iByte;
97299 int i;
97300 char zKey[40];
97301 for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zRight[i]); i++){
97302 iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
97303 if( (i&1)!=0 ) zKey[i/2] = iByte;
 
97304 }
97305 if( (zLeft[3] & 0xf)==0xb ){
97306 sqlite3_key_v2(db, zDb, zKey, i/2);
97307 }else{
97308 sqlite3_rekey_v2(db, zDb, zKey, i/2);
@@ -98913,10 +99272,13 @@
99272 }
99273
99274 /*
99275 ** Return a pointer to a string containing the 'declaration type' of the
99276 ** expression pExpr. The string may be treated as static by the caller.
99277 **
99278 ** Also try to estimate the size of the returned value and return that
99279 ** result in *pEstWidth.
99280 **
99281 ** The declaration type is the exact datatype definition extracted from the
99282 ** original CREATE TABLE statement if the expression is a column. The
99283 ** declaration type for a ROWID field is INTEGER. Exactly when an expression
99284 ** is considered a column can be complex in the presence of subqueries. The
@@ -98927,25 +99289,40 @@
99289 ** SELECT (SELECT col FROM tbl;
99290 ** SELECT (SELECT col FROM tbl);
99291 ** SELECT abc FROM (SELECT col AS abc FROM tbl);
99292 **
99293 ** The declaration type for any expression other than a column is NULL.
99294 **
99295 ** This routine has either 3 or 6 parameters depending on whether or not
99296 ** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
99297 */
99298 #ifdef SQLITE_ENABLE_COLUMN_METADATA
99299 # define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
99300 static const char *columnTypeImpl(
99301 NameContext *pNC,
99302 Expr *pExpr,
99303 const char **pzOrigDb,
99304 const char **pzOrigTab,
99305 const char **pzOrigCol,
99306 u8 *pEstWidth
99307 ){
99308 char const *zOrigDb = 0;
99309 char const *zOrigTab = 0;
99310 char const *zOrigCol = 0;
99311 #else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
99312 # define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
99313 static const char *columnTypeImpl(
99314 NameContext *pNC,
99315 Expr *pExpr,
99316 u8 *pEstWidth
 
 
99317 ){
99318 #endif /* !defined(SQLITE_ENABLE_COLUMN_METADATA) */
99319 char const *zType = 0;
 
 
 
99320 int j;
99321 u8 estWidth = 1;
99322
99323 if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
 
99324 switch( pExpr->op ){
99325 case TK_AGG_COLUMN:
99326 case TK_COLUMN: {
99327 /* The expression is a column. Locate the table the column is being
99328 ** extracted from in NameContext.pSrcList. This table may be real
@@ -99002,29 +99379,39 @@
99379 NameContext sNC;
99380 Expr *p = pS->pEList->a[iCol].pExpr;
99381 sNC.pSrcList = pS->pSrc;
99382 sNC.pNext = pNC;
99383 sNC.pParse = pNC->pParse;
99384 zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth);
99385 }
99386 }else if( ALWAYS(pTab->pSchema) ){
99387 /* A real table */
99388 assert( !pS );
99389 if( iCol<0 ) iCol = pTab->iPKey;
99390 assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
99391 #ifdef SQLITE_ENABLE_COLUMN_METADATA
99392 if( iCol<0 ){
99393 zType = "INTEGER";
99394 zOrigCol = "rowid";
99395 }else{
99396 zType = pTab->aCol[iCol].zType;
99397 zOrigCol = pTab->aCol[iCol].zName;
99398 estWidth = pTab->aCol[iCol].szEst;
99399 }
99400 zOrigTab = pTab->zName;
99401 if( pNC->pParse ){
99402 int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
99403 zOrigDb = pNC->pParse->db->aDb[iDb].zName;
99404 }
99405 #else
99406 if( iCol<0 ){
99407 zType = "INTEGER";
99408 }else{
99409 zType = pTab->aCol[iCol].zType;
99410 estWidth = pTab->aCol[iCol].szEst;
99411 }
99412 #endif
99413 }
99414 break;
99415 }
99416 #ifndef SQLITE_OMIT_SUBQUERY
99417 case TK_SELECT: {
@@ -99037,22 +99424,25 @@
99424 Expr *p = pS->pEList->a[0].pExpr;
99425 assert( ExprHasProperty(pExpr, EP_xIsSelect) );
99426 sNC.pSrcList = pS->pSrc;
99427 sNC.pNext = pNC;
99428 sNC.pParse = pNC->pParse;
99429 zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth);
99430 break;
99431 }
99432 #endif
99433 }
99434
99435 #ifdef SQLITE_ENABLE_COLUMN_METADATA
99436 if( pzOrigDb ){
99437 assert( pzOrigTab && pzOrigCol );
99438 *pzOrigDb = zOrigDb;
99439 *pzOrigTab = zOrigTab;
99440 *pzOrigCol = zOrigCol;
99441 }
99442 #endif
99443 if( pEstWidth ) *pEstWidth = estWidth;
99444 return zType;
99445 }
99446
99447 /*
99448 ** Generate code that will tell the VDBE the declaration types of columns
@@ -99074,25 +99464,25 @@
99464 const char *zType;
99465 #ifdef SQLITE_ENABLE_COLUMN_METADATA
99466 const char *zOrigDb = 0;
99467 const char *zOrigTab = 0;
99468 const char *zOrigCol = 0;
99469 zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0);
99470
99471 /* The vdbe must make its own copy of the column-type and other
99472 ** column specific strings, in case the schema is reset before this
99473 ** virtual machine is deleted.
99474 */
99475 sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, SQLITE_TRANSIENT);
99476 sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
99477 sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
99478 #else
99479 zType = columnType(&sNC, p, 0, 0, 0, 0);
99480 #endif
99481 sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
99482 }
99483 #endif /* !defined(SQLITE_OMIT_DECLTYPE) */
99484 }
99485
99486 /*
99487 ** Generate code that will tell the VDBE the names of columns
99488 ** in the result set. This information is used to provide the
@@ -99277,39 +99667,41 @@
99667 ** This routine requires that all identifiers in the SELECT
99668 ** statement be resolved.
99669 */
99670 static void selectAddColumnTypeAndCollation(
99671 Parse *pParse, /* Parsing contexts */
99672 Table *pTab, /* Add column type information to this table */
 
99673 Select *pSelect /* SELECT used to determine types and collations */
99674 ){
99675 sqlite3 *db = pParse->db;
99676 NameContext sNC;
99677 Column *pCol;
99678 CollSeq *pColl;
99679 int i;
99680 Expr *p;
99681 struct ExprList_item *a;
99682 u64 szAll = 0;
99683
99684 assert( pSelect!=0 );
99685 assert( (pSelect->selFlags & SF_Resolved)!=0 );
99686 assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed );
99687 if( db->mallocFailed ) return;
99688 memset(&sNC, 0, sizeof(sNC));
99689 sNC.pSrcList = pSelect->pSrc;
99690 a = pSelect->pEList->a;
99691 for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
99692 p = a[i].pExpr;
99693 pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst));
99694 szAll += pCol->szEst;
99695 pCol->affinity = sqlite3ExprAffinity(p);
99696 if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE;
99697 pColl = sqlite3ExprCollSeq(pParse, p);
99698 if( pColl ){
99699 pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
99700 }
99701 }
99702 pTab->szTabRow = sqlite3LogEst(szAll*4);
99703 }
99704
99705 /*
99706 ** Given a SELECT statement, generate a Table structure that describes
99707 ** the result set of that SELECT.
@@ -99333,13 +99725,13 @@
99725 /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
99726 ** is disabled */
99727 assert( db->lookaside.bEnabled==0 );
99728 pTab->nRef = 1;
99729 pTab->zName = 0;
99730 pTab->nRowEst = 1048576;
99731 selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
99732 selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
99733 pTab->iPKey = -1;
99734 if( db->mallocFailed ){
99735 sqlite3DeleteTable(db, pTab);
99736 return 0;
99737 }
@@ -101247,15 +101639,15 @@
101639 assert( pFrom->pTab==0 );
101640 sqlite3WalkSelect(pWalker, pSel);
101641 pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
101642 if( pTab==0 ) return WRC_Abort;
101643 pTab->nRef = 1;
101644 pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
101645 while( pSel->pPrior ){ pSel = pSel->pPrior; }
101646 selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
101647 pTab->iPKey = -1;
101648 pTab->nRowEst = 1048576;
101649 pTab->tabFlags |= TF_Ephemeral;
101650 #endif
101651 }else{
101652 /* An ordinary table or view name in the FROM clause */
101653 assert( pFrom->pTab==0 );
@@ -101535,11 +101927,11 @@
101927 if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
101928 /* A sub-query in the FROM clause of a SELECT */
101929 Select *pSel = pFrom->pSelect;
101930 assert( pSel );
101931 while( pSel->pPrior ) pSel = pSel->pPrior;
101932 selectAddColumnTypeAndCollation(pParse, pTab, pSel);
101933 }
101934 }
101935 }
101936 return WRC_Continue;
101937 }
@@ -102450,29 +102842,29 @@
102842 int iRoot = pTab->tnum; /* Root page of scanned b-tree */
102843
102844 sqlite3CodeVerifySchema(pParse, iDb);
102845 sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
102846
102847 /* Search for the index that has the lowest scan cost.
 
 
 
 
 
 
102848 **
102849 ** (2011-04-15) Do not do a full scan of an unordered index.
102850 **
102851 ** (2013-10-03) Do not count the entires in a partial index.
102852 **
102853 ** In practice the KeyInfo structure will not be used. It is only
102854 ** passed to keep OP_OpenRead happy.
102855 */
102856 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
102857 if( pIdx->bUnordered==0
102858 && pIdx->szIdxRow<pTab->szTabRow
102859 && pIdx->pPartIdxWhere==0
102860 && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
102861 ){
102862 pBest = pIdx;
102863 }
102864 }
102865 if( pBest ){
102866 iRoot = pBest->tnum;
102867 pKeyInfo = sqlite3IndexKeyinfo(pParse, pBest);
102868 }
102869
102870 /* Open a read-only cursor, execute the OP_Count, close the cursor. */
@@ -103046,12 +103438,12 @@
103438 }
103439
103440 /* Ensure the table name matches database name and that the table exists */
103441 if( db->mallocFailed ) goto trigger_cleanup;
103442 assert( pTableName->nSrc==1 );
103443 sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName);
103444 if( sqlite3FixSrcList(&sFix, pTableName) ){
103445 goto trigger_cleanup;
103446 }
103447 pTab = sqlite3SrcListLookup(pParse, pTableName);
103448 if( !pTab ){
103449 /* The table does not exist. */
@@ -103189,12 +103581,14 @@
103581 pStepList->pTrig = pTrig;
103582 pStepList = pStepList->pNext;
103583 }
103584 nameToken.z = pTrig->zName;
103585 nameToken.n = sqlite3Strlen30(nameToken.z);
103586 sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken);
103587 if( sqlite3FixTriggerStep(&sFix, pTrig->step_list)
103588 || sqlite3FixExpr(&sFix, pTrig->pWhen)
103589 ){
103590 goto triggerfinish_cleanup;
103591 }
103592
103593 /* if we are not initializing,
103594 ** build the sqlite_master entry
@@ -104781,18 +105175,38 @@
105175
105176 return vacuumFinalize(db, pStmt, pzErrMsg);
105177 }
105178
105179 /*
105180 ** The VACUUM command is used to clean up the database,
105181 ** collapse free space, etc. It is modelled after the VACUUM command
105182 ** in PostgreSQL. The VACUUM command works as follows:
105183 **
105184 ** (1) Create a new transient database file
105185 ** (2) Copy all content from the database being vacuumed into
105186 ** the new transient database file
105187 ** (3) Copy content from the transient database back into the
105188 ** original database.
105189 **
105190 ** The transient database requires temporary disk space approximately
105191 ** equal to the size of the original database. The copy operation of
105192 ** step (3) requires additional temporary disk space approximately equal
105193 ** to the size of the original database for the rollback journal.
105194 ** Hence, temporary disk space that is approximately 2x the size of the
105195 ** orginal database is required. Every page of the database is written
105196 ** approximately 3 times: Once for step (2) and twice for step (3).
105197 ** Two writes per page are required in step (3) because the original
105198 ** database content must be written into the rollback journal prior to
105199 ** overwriting the database with the vacuumed content.
105200 **
105201 ** Only 1x temporary space and only 1x writes would be required if
105202 ** the copy of step (3) were replace by deleting the original database
105203 ** and renaming the transient database as the original. But that will
105204 ** not work if other processes are attached to the original database.
105205 ** And a power loss in between deleting the original and renaming the
105206 ** transient would cause the database file to appear to be deleted
105207 ** following reboot.
105208 */
105209 SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
105210 Vdbe *v = sqlite3GetVdbe(pParse);
105211 if( v ){
105212 sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
@@ -106206,30 +106620,10 @@
106620 typedef struct WhereLoopBuilder WhereLoopBuilder;
106621 typedef struct WhereScan WhereScan;
106622 typedef struct WhereOrCost WhereOrCost;
106623 typedef struct WhereOrSet WhereOrSet;
106624
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106625 /*
106626 ** This object contains information needed to implement a single nested
106627 ** loop in WHERE clause.
106628 **
106629 ** Contrast this object with WhereLoop. This object describes the
@@ -106290,13 +106684,13 @@
106684 #ifdef SQLITE_DEBUG
106685 char cId; /* Symbolic ID of this loop for debugging use */
106686 #endif
106687 u8 iTab; /* Position in FROM clause of table for this loop */
106688 u8 iSortIdx; /* Sorting index number. 0==None */
106689 LogEst rSetup; /* One-time setup cost (ex: create transient index) */
106690 LogEst rRun; /* Cost of running each loop */
106691 LogEst nOut; /* Estimated number of output rows */
106692 union {
106693 struct { /* Information for internal btree tables */
106694 int nEq; /* Number of equality constraints */
106695 Index *pIndex; /* Index used, or NULL */
106696 } btree;
@@ -106322,12 +106716,12 @@
106716 ** subquery on one operand of an OR operator in the WHERE clause.
106717 ** See WhereOrSet for additional information
106718 */
106719 struct WhereOrCost {
106720 Bitmask prereq; /* Prerequisites */
106721 LogEst rRun; /* Cost of running this subquery */
106722 LogEst nOut; /* Number of outputs for this subquery */
106723 };
106724
106725 /* The WhereOrSet object holds a set of possible WhereOrCosts that
106726 ** correspond to the subquery(s) of OR-clause processing. Only the
106727 ** best N_OR_COST elements are retained.
@@ -106361,12 +106755,12 @@
106755 ** at the end is the choosen query plan.
106756 */
106757 struct WherePath {
106758 Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
106759 Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
106760 LogEst nRow; /* Estimated number of rows generated by this path */
106761 LogEst rCost; /* Total cost of this path */
106762 u8 isOrdered; /* True if this path satisfies ORDER BY */
106763 u8 isOrderedValid; /* True if the isOrdered field is valid */
106764 WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
106765 };
106766
@@ -106428,11 +106822,11 @@
106822 union {
106823 int leftColumn; /* Column number of X in "X <op> <expr>" */
106824 WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
106825 WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
106826 } u;
106827 LogEst truthProb; /* Probability of truth for this expression */
106828 u16 eOperator; /* A WO_xx value describing <op> */
106829 u8 wtFlags; /* TERM_xxx bit flags. See below */
106830 u8 nChild; /* Number of children that must disable us */
106831 WhereClause *pWC; /* The clause this term is part of */
106832 Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */
@@ -106576,11 +106970,11 @@
106970 SrcList *pTabList; /* List of tables in the join */
106971 ExprList *pOrderBy; /* The ORDER BY clause or NULL */
106972 ExprList *pResultSet; /* Result set. DISTINCT operates on these */
106973 WhereLoop *pLoops; /* List of all WhereLoop objects */
106974 Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
106975 LogEst nRowOut; /* Estimated number of output rows */
106976 u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
106977 u8 bOBSat; /* ORDER BY satisfied by indices */
106978 u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
106979 u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
106980 u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
@@ -106636,30 +107030,15 @@
107030 #define WHERE_IN_ABLE 0x00000800 /* Able to support an IN operator */
107031 #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */
107032 #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */
107033 #define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
107034
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107035 /*
107036 ** Return the estimated number of output rows from a WHERE clause
107037 */
107038 SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
107039 return sqlite3LogEstToInt(pWInfo->nRowOut);
107040 }
107041
107042 /*
107043 ** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this
107044 ** WHERE clause returns outputs for DISTINCT processing.
@@ -106717,12 +107096,12 @@
107096 ** so that pSet keeps the N_OR_COST best entries seen so far.
107097 */
107098 static int whereOrInsert(
107099 WhereOrSet *pSet, /* The WhereOrSet to be updated */
107100 Bitmask prereq, /* Prerequisites of the new entry */
107101 LogEst rRun, /* Run-cost of the new entry */
107102 LogEst nOut /* Number of outputs for the new entry */
107103 ){
107104 u16 i;
107105 WhereOrCost *p;
107106 for(i=pSet->n, p=pSet->a; i>0; i--, p++){
107107 if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){
@@ -106803,13 +107182,10 @@
107182 if( pWC->a!=pWC->aStatic ){
107183 sqlite3DbFree(db, pWC->a);
107184 }
107185 }
107186
 
 
 
107187 /*
107188 ** Add a single new WhereTerm entry to the WhereClause object pWC.
107189 ** The new WhereTerm object is constructed from Expr p and with wtFlags.
107190 ** The index in pWC->a[] of the new WhereTerm is returned on success.
107191 ** 0 is returned if the new WhereTerm could not be added due to a memory
@@ -106848,11 +107224,11 @@
107224 }
107225 pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
107226 }
107227 pTerm = &pWC->a[idx = pWC->nTerm++];
107228 if( p && ExprHasProperty(p, EP_Unlikely) ){
107229 pTerm->truthProb = sqlite3LogEst(p->iTable) - 99;
107230 }else{
107231 pTerm->truthProb = -1;
107232 }
107233 pTerm->pExpr = sqlite3ExprSkipCollate(p);
107234 pTerm->wtFlags = wtFlags;
@@ -108112,79 +108488,16 @@
108488 }
108489
108490 return 0;
108491 }
108492
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108493
108494 /*
108495 ** Estimate the logarithm of the input value to base 2.
108496 */
108497 static LogEst estLog(LogEst N){
108498 LogEst x = sqlite3LogEst(N);
108499 return x>33 ? x - 33 : 0;
108500 }
108501
108502 /*
108503 ** Two routines for printing the content of an sqlite3_index_info
@@ -108693,11 +109006,11 @@
109006 **
109007 ** ... FROM t1 WHERE a > ? AND a < ? ...
109008 **
109009 ** then nEq is set to 0.
109010 **
109011 ** When this function is called, *pnOut is set to the sqlite3LogEst() of the
109012 ** number of rows that the index scan is expected to visit without
109013 ** considering the range constraints. If nEq is 0, this is the number of
109014 ** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
109015 ** to account for the range contraints pLower and pUpper.
109016 **
@@ -108709,19 +109022,19 @@
109022 static int whereRangeScanEst(
109023 Parse *pParse, /* Parsing & code generating context */
109024 WhereLoopBuilder *pBuilder,
109025 WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
109026 WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */
109027 WhereLoop *pLoop /* Modify the .nOut and maybe .rRun fields */
109028 ){
109029 int rc = SQLITE_OK;
109030 int nOut = pLoop->nOut;
109031 int nEq = pLoop->u.btree.nEq;
109032 LogEst nNew;
109033
109034 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
109035 Index *p = pLoop->u.btree.pIndex;
 
109036
109037 if( p->nSample>0
109038 && nEq==pBuilder->nRecValid
109039 && nEq<p->nSampleCol
109040 && OptimizationEnabled(pParse->db, SQLITE_Stat3)
@@ -108798,18 +109111,18 @@
109111 }
109112
109113 pBuilder->pRec = pRec;
109114 if( rc==SQLITE_OK ){
109115 if( iUpper>iLower ){
109116 nNew = sqlite3LogEst(iUpper - iLower);
109117 }else{
109118 nNew = 10; assert( 10==sqlite3LogEst(2) );
109119 }
109120 if( nNew<nOut ){
109121 nOut = nNew;
109122 }
109123 pLoop->nOut = (LogEst)nOut;
109124 WHERETRACE(0x100, ("range scan regions: %u..%u est=%d\n",
109125 (u32)iLower, (u32)iUpper, nOut));
109126 return SQLITE_OK;
109127 }
109128 }
@@ -108820,20 +109133,20 @@
109133 assert( pLower || pUpper );
109134 /* TUNING: Each inequality constraint reduces the search space 4-fold.
109135 ** A BETWEEN operator, therefore, reduces the search space 16-fold */
109136 nNew = nOut;
109137 if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){
109138 nNew -= 20; assert( 20==sqlite3LogEst(4) );
109139 nOut--;
109140 }
109141 if( pUpper ){
109142 nNew -= 20; assert( 20==sqlite3LogEst(4) );
109143 nOut--;
109144 }
109145 if( nNew<10 ) nNew = 10;
109146 if( nNew<nOut ) nOut = nNew;
109147 pLoop->nOut = (LogEst)nOut;
109148 return rc;
109149 }
109150
109151 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
109152 /*
@@ -110473,11 +110786,11 @@
110786 */
110787 static int whereLoopAddBtreeIndex(
110788 WhereLoopBuilder *pBuilder, /* The WhereLoop factory */
110789 struct SrcList_item *pSrc, /* FROM clause term being analyzed */
110790 Index *pProbe, /* An index on pSrc */
110791 LogEst nInMul /* log(Number of iterations due to IN) */
110792 ){
110793 WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */
110794 Parse *pParse = pWInfo->pParse; /* Parsing context */
110795 sqlite3 *db = pParse->db; /* Database connection malloc context */
110796 WhereLoop *pNew; /* Template WhereLoop under construction */
@@ -110486,15 +110799,15 @@
110799 WhereScan scan; /* Iterator for WHERE terms */
110800 Bitmask saved_prereq; /* Original value of pNew->prereq */
110801 u16 saved_nLTerm; /* Original value of pNew->nLTerm */
110802 int saved_nEq; /* Original value of pNew->u.btree.nEq */
110803 u32 saved_wsFlags; /* Original value of pNew->wsFlags */
110804 LogEst saved_nOut; /* Original value of pNew->nOut */
110805 int iCol; /* Index of the column in the table */
110806 int rc = SQLITE_OK; /* Return code */
110807 LogEst nRowEst; /* Estimated index selectivity */
110808 LogEst rLogSize; /* Logarithm of table size */
110809 WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
110810
110811 pNew = pBuilder->pNew;
110812 if( db->mallocFailed ) return SQLITE_NOMEM;
110813
@@ -110510,11 +110823,11 @@
110823 if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
110824
110825 assert( pNew->u.btree.nEq<=pProbe->nColumn );
110826 if( pNew->u.btree.nEq < pProbe->nColumn ){
110827 iCol = pProbe->aiColumn[pNew->u.btree.nEq];
110828 nRowEst = sqlite3LogEst(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
110829 if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1;
110830 }else{
110831 iCol = -1;
110832 nRowEst = 0;
110833 }
@@ -110524,11 +110837,11 @@
110837 saved_nLTerm = pNew->nLTerm;
110838 saved_wsFlags = pNew->wsFlags;
110839 saved_prereq = pNew->prereq;
110840 saved_nOut = pNew->nOut;
110841 pNew->rSetup = 0;
110842 rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0]));
110843 for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
110844 int nIn = 0;
110845 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
110846 int nRecValid = pBuilder->nRecValid;
110847 #endif
@@ -110551,14 +110864,14 @@
110864 if( pTerm->eOperator & WO_IN ){
110865 Expr *pExpr = pTerm->pExpr;
110866 pNew->wsFlags |= WHERE_COLUMN_IN;
110867 if( ExprHasProperty(pExpr, EP_xIsSelect) ){
110868 /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
110869 nIn = 46; assert( 46==sqlite3LogEst(25) );
110870 }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
110871 /* "x IN (value, value, ...)" */
110872 nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
110873 }
110874 pNew->rRun += nIn;
110875 pNew->u.btree.nEq++;
110876 pNew->nOut = nRowEst + nInMul + nIn;
110877 }else if( pTerm->eOperator & (WO_EQ) ){
@@ -110576,11 +110889,11 @@
110889 pNew->nOut = nRowEst + nInMul;
110890 }else if( pTerm->eOperator & (WO_ISNULL) ){
110891 pNew->wsFlags |= WHERE_COLUMN_NULL;
110892 pNew->u.btree.nEq++;
110893 /* TUNING: IS NULL selects 2 rows */
110894 nIn = 10; assert( 10==sqlite3LogEst(2) );
110895 pNew->nOut = nRowEst + nInMul + nIn;
110896 }else if( pTerm->eOperator & (WO_GT|WO_GE) ){
110897 testcase( pTerm->eOperator & WO_GT );
110898 testcase( pTerm->eOperator & WO_GE );
110899 pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
@@ -110596,11 +110909,11 @@
110909 pNew->aLTerm[pNew->nLTerm-2] : 0;
110910 }
110911 if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
110912 /* Adjust nOut and rRun for STAT3 range values */
110913 assert( pNew->nOut==saved_nOut );
110914 whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew);
110915 }
110916 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
110917 if( nInMul==0
110918 && pProbe->nSample
110919 && pNew->u.btree.nEq<=pProbe->nSampleCol
@@ -110616,22 +110929,22 @@
110929 && !ExprHasProperty(pExpr, EP_xIsSelect) ){
110930 rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
110931 }
110932 assert( nOut==0 || rc==SQLITE_OK );
110933 if( nOut ){
110934 nOut = sqlite3LogEst(nOut);
110935 pNew->nOut = MIN(nOut, saved_nOut);
110936 }
110937 }
110938 #endif
110939 if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
110940 /* Each row involves a step of the index, then a binary search of
110941 ** the main table */
110942 pNew->rRun = sqlite3LogEstAdd(pNew->rRun,rLogSize>27 ? rLogSize-17 : 10);
110943 }
110944 /* Step cost for each output row */
110945 pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut);
110946 whereLoopOutputAdjust(pBuilder->pWC, pNew, pSrc->iCursor);
110947 rc = whereLoopInsert(pBuilder, pNew);
110948 if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
110949 && pNew->u.btree.nEq<(pProbe->nColumn + (pProbe->zName!=0))
110950 ){
@@ -110727,18 +111040,20 @@
111040 struct SrcList_item *pSrc; /* The FROM clause btree term to add */
111041 WhereLoop *pNew; /* Template WhereLoop object */
111042 int rc = SQLITE_OK; /* Return code */
111043 int iSortIdx = 1; /* Index number */
111044 int b; /* A boolean value */
111045 LogEst rSize; /* number of rows in the table */
111046 LogEst rLogSize; /* Logarithm of the number of rows in the table */
111047 WhereClause *pWC; /* The parsed WHERE clause */
111048 Table *pTab; /* Table being queried */
111049
111050 pNew = pBuilder->pNew;
111051 pWInfo = pBuilder->pWInfo;
111052 pTabList = pWInfo->pTabList;
111053 pSrc = pTabList->a + pNew->iTab;
111054 pTab = pSrc->pTab;
111055 pWC = pBuilder->pWC;
111056 assert( !IsVirtual(pSrc->pTab) );
111057
111058 if( pSrc->pIndex ){
111059 /* An INDEXED BY clause specifies a particular index to use */
@@ -110752,22 +111067,22 @@
111067 memset(&sPk, 0, sizeof(Index));
111068 sPk.nColumn = 1;
111069 sPk.aiColumn = &aiColumnPk;
111070 sPk.aiRowEst = aiRowEstPk;
111071 sPk.onError = OE_Replace;
111072 sPk.pTable = pTab;
111073 aiRowEstPk[0] = pTab->nRowEst;
111074 aiRowEstPk[1] = 1;
111075 pFirst = pSrc->pTab->pIndex;
111076 if( pSrc->notIndexed==0 ){
111077 /* The real indices of the table are only considered if the
111078 ** NOT INDEXED qualifier is omitted from the FROM clause */
111079 sPk.pNext = pFirst;
111080 }
111081 pProbe = &sPk;
111082 }
111083 rSize = sqlite3LogEst(pTab->nRowEst);
111084 rLogSize = estLog(rSize);
111085
111086 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
111087 /* Automatic indexes */
111088 if( !pBuilder->pOrSet
@@ -110788,17 +111103,17 @@
111103 pNew->nLTerm = 1;
111104 pNew->aLTerm[0] = pTerm;
111105 /* TUNING: One-time cost for computing the automatic index is
111106 ** approximately 7*N*log2(N) where N is the number of rows in
111107 ** the table being indexed. */
111108 pNew->rSetup = rLogSize + rSize + 28; assert( 28==sqlite3LogEst(7) );
111109 /* TUNING: Each index lookup yields 20 rows in the table. This
111110 ** is more than the usual guess of 10 rows, since we have no way
111111 ** of knowning how selective the index will ultimately be. It would
111112 ** not be unreasonable to make this value much larger. */
111113 pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
111114 pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
111115 pNew->wsFlags = WHERE_AUTO_INDEX;
111116 pNew->prereq = mExtra | pTerm->prereqRight;
111117 rc = whereLoopInsert(pBuilder, pNew);
111118 }
111119 }
@@ -110828,14 +111143,12 @@
111143
111144 /* Full table scan */
111145 pNew->iSortIdx = b ? iSortIdx : 0;
111146 /* TUNING: Cost of full table scan is 3*(N + log2(N)).
111147 ** + The extra 3 factor is to encourage the use of indexed lookups
111148 ** over full scans. FIXME */
111149 pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 16;
 
 
111150 whereLoopOutputAdjust(pWC, pNew, pSrc->iCursor);
111151 rc = whereLoopInsert(pBuilder, pNew);
111152 pNew->nOut = rSize;
111153 if( rc ) break;
111154 }else{
@@ -110844,26 +111157,25 @@
111157
111158 /* Full scan via index */
111159 if( b
111160 || ( m==0
111161 && pProbe->bUnordered==0
111162 && pProbe->szIdxRow<pTab->szTabRow
111163 && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0
111164 && sqlite3GlobalConfig.bUseCis
111165 && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan)
111166 )
111167 ){
111168 pNew->iSortIdx = b ? iSortIdx : 0;
111169 if( m==0 ){
111170 /* TUNING: Cost of a covering index scan is K*(N + log2(N)).
111171 ** + The extra factor K of between 1.1 and 3.0 that depends
111172 ** on the relative sizes of the table and the index. K
111173 ** is smaller for smaller indices, thus favoring them.
111174 */
111175 pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 1 +
111176 (15*pProbe->szIdxRow)/pTab->szTabRow;
 
 
111177 }else{
111178 assert( b!=0 );
111179 /* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N)
111180 ** which we will simplify to just N*log2(N) */
111181 pNew->rRun = rSize + rLogSize;
@@ -111037,13 +111349,13 @@
111349 pIdxInfo->needToFreeIdxStr = 0;
111350 pNew->u.vtab.idxStr = pIdxInfo->idxStr;
111351 pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0)
111352 && pIdxInfo->orderByConsumed);
111353 pNew->rSetup = 0;
111354 pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
111355 /* TUNING: Every virtual table query returns 25 rows */
111356 pNew->nOut = 46; assert( 46==sqlite3LogEst(25) );
111357 whereLoopInsert(pBuilder, pNew);
111358 if( pNew->u.vtab.needFree ){
111359 sqlite3_free(pNew->u.vtab.idxStr);
111360 pNew->u.vtab.needFree = 0;
111361 }
@@ -111076,10 +111388,12 @@
111388 pWC = pBuilder->pWC;
111389 if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
111390 pWCEnd = pWC->a + pWC->nTerm;
111391 pNew = pBuilder->pNew;
111392 memset(&sSum, 0, sizeof(sSum));
111393 pItem = pWInfo->pTabList->a + pNew->iTab;
111394 iCur = pItem->iCursor;
111395
111396 for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
111397 if( (pTerm->eOperator & WO_OR)!=0
111398 && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
111399 ){
@@ -111087,12 +111401,10 @@
111401 WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
111402 WhereTerm *pOrTerm;
111403 int once = 1;
111404 int i, j;
111405
 
 
111406 sSubBuild = *pBuilder;
111407 sSubBuild.pOrderBy = 0;
111408 sSubBuild.pOrSet = &sCur;
111409
111410 for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
@@ -111129,12 +111441,12 @@
111441 whereOrMove(&sPrev, &sSum);
111442 sSum.n = 0;
111443 for(i=0; i<sPrev.n; i++){
111444 for(j=0; j<sCur.n; j++){
111445 whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq,
111446 sqlite3LogEstAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
111447 sqlite3LogEstAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
111448 }
111449 }
111450 }
111451 }
111452 pNew->nLTerm = 1;
@@ -111468,23 +111780,23 @@
111780 ** costs if nRowEst==0.
111781 **
111782 ** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation
111783 ** error occurs.
111784 */
111785 static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
111786 int mxChoice; /* Maximum number of simultaneous paths tracked */
111787 int nLoop; /* Number of terms in the join */
111788 Parse *pParse; /* Parsing context */
111789 sqlite3 *db; /* The database connection */
111790 int iLoop; /* Loop counter over the terms of the join */
111791 int ii, jj; /* Loop counters */
111792 int mxI = 0; /* Index of next entry to replace */
111793 LogEst rCost; /* Cost of a path */
111794 LogEst nOut; /* Number of outputs */
111795 LogEst mxCost = 0; /* Maximum cost of a set of paths */
111796 LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
111797 LogEst rSortCost; /* Cost to do a sort */
111798 int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
111799 WherePath *aFrom; /* All nFrom paths at the previous level */
111800 WherePath *aTo; /* The nTo best paths at the current level */
111801 WherePath *pFrom; /* An element of aFrom[] that we are working on */
111802 WherePath *pTo; /* An element of aTo[] that we are working on */
@@ -111517,21 +111829,23 @@
111829 /* Seed the search with a single WherePath containing zero WhereLoops.
111830 **
111831 ** TUNING: Do not let the number of iterations go above 25. If the cost
111832 ** of computing an automatic index is not paid back within the first 25
111833 ** rows, then do not use the automatic index. */
111834 aFrom[0].nRow = MIN(pParse->nQueryLoop, 46); assert( 46==sqlite3LogEst(25) );
111835 nFrom = 1;
111836
111837 /* Precompute the cost of sorting the final result set, if the caller
111838 ** to sqlite3WhereBegin() was concerned about sorting */
111839 rSortCost = 0;
111840 if( pWInfo->pOrderBy==0 || nRowEst==0 ){
111841 aFrom[0].isOrderedValid = 1;
111842 }else{
111843 /* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the
111844 ** number of output rows. The 48 is the expected size of a row to sort.
111845 ** FIXME: compute a better estimate of the 48 multiplier based on the
111846 ** result set expressions. */
111847 rSortCost = nRowEst + estLog(nRowEst);
111848 WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost));
111849 }
111850
111851 /* Compute successively longer WherePaths using the previous generation
@@ -111547,12 +111861,12 @@
111861 u8 isOrdered = pFrom->isOrdered;
111862 if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
111863 if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
111864 /* At this point, pWLoop is a candidate to be the next loop.
111865 ** Compute its cost */
111866 rCost = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
111867 rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
111868 nOut = pFrom->nRow + pWLoop->nOut;
111869 maskNew = pFrom->maskLoop | pWLoop->maskSelf;
111870 if( !isOrderedValid ){
111871 switch( wherePathSatisfiesOrderBy(pWInfo,
111872 pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
@@ -111562,11 +111876,11 @@
111876 isOrderedValid = 1;
111877 break;
111878 case 0: /* No. pFrom+pWLoop will require a separate sort */
111879 isOrdered = 0;
111880 isOrderedValid = 1;
111881 rCost = sqlite3LogEstAdd(rCost, rSortCost);
111882 break;
111883 default: /* Cannot tell yet. Try again on the next iteration */
111884 break;
111885 }
111886 }else{
@@ -111769,11 +112083,11 @@
112083 pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
112084 pLoop->aLTerm[0] = pTerm;
112085 pLoop->nLTerm = 1;
112086 pLoop->u.btree.nEq = 1;
112087 /* TUNING: Cost of a rowid lookup is 10 */
112088 pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */
112089 }else{
112090 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
112091 assert( pLoop->aLTermSpace==pLoop->aLTerm );
112092 assert( ArraySize(pLoop->aLTermSpace)==4 );
112093 if( pIdx->onError==OE_None
@@ -111792,16 +112106,16 @@
112106 }
112107 pLoop->nLTerm = j;
112108 pLoop->u.btree.nEq = j;
112109 pLoop->u.btree.pIndex = pIdx;
112110 /* TUNING: Cost of a unique index lookup is 15 */
112111 pLoop->rRun = 39; /* 39==sqlite3LogEst(15) */
112112 break;
112113 }
112114 }
112115 if( pLoop->wsFlags ){
112116 pLoop->nOut = (LogEst)1;
112117 pWInfo->a[0].pWLoop = pLoop;
112118 pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
112119 pWInfo->a[0].iTabCur = iCur;
112120 pWInfo->nRowOut = 1;
112121 if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1;
@@ -112165,11 +112479,11 @@
112479 WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
112480 pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;
112481
112482 /* If the caller is an UPDATE or DELETE statement that is requesting
112483 ** to use a one-pass algorithm, determine if this is appropriate.
112484 ** The one-pass algorithm only works if the WHERE clause constrains
112485 ** the statement to update a single row.
112486 */
112487 assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
112488 if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
112489 && (pWInfo->a[0].pWLoop->wsFlags & WHERE_ONEROW)!=0 ){
@@ -121583,10 +121897,16 @@
121897 ** verifying the operation of the SQLite core.
121898 */
121899 int inTransaction; /* True after xBegin but before xCommit/xRollback */
121900 int mxSavepoint; /* Largest valid xSavepoint integer */
121901 #endif
121902
121903 #ifdef SQLITE_TEST
121904 /* True to disable the incremental doclist optimization. This is controled
121905 ** by special insert command 'test-no-incr-doclist'. */
121906 int bNoIncrDoclist;
121907 #endif
121908 };
121909
121910 /*
121911 ** When the core wants to read from the virtual table, it creates a
121912 ** virtual table cursor (an instance of the following structure) using
@@ -121608,11 +121928,12 @@
121928 int nDoclist; /* Size of buffer at aDoclist */
121929 u8 bDesc; /* True to sort in descending order */
121930 int eEvalmode; /* An FTS3_EVAL_XX constant */
121931 int nRowAvg; /* Average size of database rows, in pages */
121932 sqlite3_int64 nDoc; /* Documents in table */
121933 i64 iMinDocid; /* Minimum docid to return */
121934 i64 iMaxDocid; /* Maximum docid to return */
121935 int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
121936 u32 *aMatchinfo; /* Information about most recent match */
121937 int nMatchinfo; /* Number of elements in aMatchinfo[] */
121938 char *zMatchinfo; /* Matchinfo specification */
121939 };
@@ -121638,10 +121959,19 @@
121959 */
121960 #define FTS3_FULLSCAN_SEARCH 0 /* Linear scan of %_content table */
121961 #define FTS3_DOCID_SEARCH 1 /* Lookup by rowid on %_content table */
121962 #define FTS3_FULLTEXT_SEARCH 2 /* Full-text index search */
121963
121964 /*
121965 ** The lower 16-bits of the sqlite3_index_info.idxNum value set by
121966 ** the xBestIndex() method contains the Fts3Cursor.eSearch value described
121967 ** above. The upper 16-bits contain a combination of the following
121968 ** bits, used to describe extra constraints on full-text searches.
121969 */
121970 #define FTS3_HAVE_LANGID 0x00010000 /* languageid=? */
121971 #define FTS3_HAVE_DOCID_GE 0x00020000 /* docid>=? */
121972 #define FTS3_HAVE_DOCID_LE 0x00040000 /* docid<=? */
121973
121974 struct Fts3Doclist {
121975 char *aAll; /* Array containing doclist (or NULL) */
121976 int nAll; /* Size of a[] in bytes */
121977 char *pNextDocid; /* Pointer to next docid */
@@ -123058,27 +123388,31 @@
123388 */
123389 static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
123390 Fts3Table *p = (Fts3Table *)pVTab;
123391 int i; /* Iterator variable */
123392 int iCons = -1; /* Index of constraint to use */
123393
123394 int iLangidCons = -1; /* Index of langid=x constraint, if present */
123395 int iDocidGe = -1; /* Index of docid>=x constraint, if present */
123396 int iDocidLe = -1; /* Index of docid<=x constraint, if present */
123397 int iIdx;
123398
123399 /* By default use a full table scan. This is an expensive option,
123400 ** so search through the constraints to see if a more efficient
123401 ** strategy is possible.
123402 */
123403 pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
123404 pInfo->estimatedCost = 5000000;
123405 for(i=0; i<pInfo->nConstraint; i++){
123406 int bDocid; /* True if this constraint is on docid */
123407 struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i];
123408 if( pCons->usable==0 ) continue;
123409
123410 bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1);
123411
123412 /* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */
123413 if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){
 
 
 
123414 pInfo->idxNum = FTS3_DOCID_SEARCH;
123415 pInfo->estimatedCost = 1.0;
123416 iCons = i;
123417 }
123418
@@ -123103,18 +123437,42 @@
123437 if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
123438 && pCons->iColumn==p->nColumn + 2
123439 ){
123440 iLangidCons = i;
123441 }
123442
123443 if( bDocid ){
123444 switch( pCons->op ){
123445 case SQLITE_INDEX_CONSTRAINT_GE:
123446 case SQLITE_INDEX_CONSTRAINT_GT:
123447 iDocidGe = i;
123448 break;
123449
123450 case SQLITE_INDEX_CONSTRAINT_LE:
123451 case SQLITE_INDEX_CONSTRAINT_LT:
123452 iDocidLe = i;
123453 break;
123454 }
123455 }
123456 }
123457
123458 iIdx = 1;
123459 if( iCons>=0 ){
123460 pInfo->aConstraintUsage[iCons].argvIndex = iIdx++;
123461 pInfo->aConstraintUsage[iCons].omit = 1;
123462 }
123463 if( iLangidCons>=0 ){
123464 pInfo->idxNum |= FTS3_HAVE_LANGID;
123465 pInfo->aConstraintUsage[iLangidCons].argvIndex = iIdx++;
123466 }
123467 if( iDocidGe>=0 ){
123468 pInfo->idxNum |= FTS3_HAVE_DOCID_GE;
123469 pInfo->aConstraintUsage[iDocidGe].argvIndex = iIdx++;
123470 }
123471 if( iDocidLe>=0 ){
123472 pInfo->idxNum |= FTS3_HAVE_DOCID_LE;
123473 pInfo->aConstraintUsage[iDocidLe].argvIndex = iIdx++;
123474 }
123475
123476 /* Regardless of the strategy selected, FTS can deliver rows in rowid (or
123477 ** docid) order. Both ascending and descending are possible.
123478 */
@@ -124556,10 +124914,37 @@
124914 rc = fts3EvalNext((Fts3Cursor *)pCursor);
124915 }
124916 assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
124917 return rc;
124918 }
124919
124920 /*
124921 ** The following are copied from sqliteInt.h.
124922 **
124923 ** Constants for the largest and smallest possible 64-bit signed integers.
124924 ** These macros are designed to work correctly on both 32-bit and 64-bit
124925 ** compilers.
124926 */
124927 #ifndef SQLITE_AMALGAMATION
124928 # define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
124929 # define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
124930 #endif
124931
124932 /*
124933 ** If the numeric type of argument pVal is "integer", then return it
124934 ** converted to a 64-bit signed integer. Otherwise, return a copy of
124935 ** the second parameter, iDefault.
124936 */
124937 static sqlite3_int64 fts3DocidRange(sqlite3_value *pVal, i64 iDefault){
124938 if( pVal ){
124939 int eType = sqlite3_value_numeric_type(pVal);
124940 if( eType==SQLITE_INTEGER ){
124941 return sqlite3_value_int64(pVal);
124942 }
124943 }
124944 return iDefault;
124945 }
124946
124947 /*
124948 ** This is the xFilter interface for the virtual table. See
124949 ** the virtual table xFilter method documentation for additional
124950 ** information.
@@ -124582,44 +124967,62 @@
124967 int nVal, /* Number of elements in apVal */
124968 sqlite3_value **apVal /* Arguments for the indexing scheme */
124969 ){
124970 int rc;
124971 char *zSql; /* SQL statement used to access %_content */
124972 int eSearch;
124973 Fts3Table *p = (Fts3Table *)pCursor->pVtab;
124974 Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
124975
124976 sqlite3_value *pCons = 0; /* The MATCH or rowid constraint, if any */
124977 sqlite3_value *pLangid = 0; /* The "langid = ?" constraint, if any */
124978 sqlite3_value *pDocidGe = 0; /* The "docid >= ?" constraint, if any */
124979 sqlite3_value *pDocidLe = 0; /* The "docid <= ?" constraint, if any */
124980 int iIdx;
124981
124982 UNUSED_PARAMETER(idxStr);
124983 UNUSED_PARAMETER(nVal);
124984
124985 eSearch = (idxNum & 0x0000FFFF);
124986 assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
 
124987 assert( p->pSegments==0 );
124988
124989 /* Collect arguments into local variables */
124990 iIdx = 0;
124991 if( eSearch!=FTS3_FULLSCAN_SEARCH ) pCons = apVal[iIdx++];
124992 if( idxNum & FTS3_HAVE_LANGID ) pLangid = apVal[iIdx++];
124993 if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++];
124994 if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++];
124995 assert( iIdx==nVal );
124996
124997 /* In case the cursor has been used before, clear it now. */
124998 sqlite3_finalize(pCsr->pStmt);
124999 sqlite3_free(pCsr->aDoclist);
125000 sqlite3Fts3ExprFree(pCsr->pExpr);
125001 memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
125002
125003 /* Set the lower and upper bounds on docids to return */
125004 pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64);
125005 pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64);
125006
125007 if( idxStr ){
125008 pCsr->bDesc = (idxStr[0]=='D');
125009 }else{
125010 pCsr->bDesc = p->bDescIdx;
125011 }
125012 pCsr->eSearch = (i16)eSearch;
125013
125014 if( eSearch!=FTS3_DOCID_SEARCH && eSearch!=FTS3_FULLSCAN_SEARCH ){
125015 int iCol = eSearch-FTS3_FULLTEXT_SEARCH;
125016 const char *zQuery = (const char *)sqlite3_value_text(pCons);
125017
125018 if( zQuery==0 && sqlite3_value_type(pCons)!=SQLITE_NULL ){
125019 return SQLITE_NOMEM;
125020 }
125021
125022 pCsr->iLangid = 0;
125023 if( pLangid ) pCsr->iLangid = sqlite3_value_int(pLangid);
125024
125025 assert( p->base.zErrMsg==0 );
125026 rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
125027 p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr,
125028 &p->base.zErrMsg
@@ -124638,11 +125041,11 @@
125041 /* Compile a SELECT statement for this cursor. For a full-table-scan, the
125042 ** statement loops through all rows of the %_content table. For a
125043 ** full-text query or docid lookup, the statement retrieves a single
125044 ** row by docid.
125045 */
125046 if( eSearch==FTS3_FULLSCAN_SEARCH ){
125047 zSql = sqlite3_mprintf(
125048 "SELECT %s ORDER BY rowid %s",
125049 p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
125050 );
125051 if( zSql ){
@@ -124649,14 +125052,14 @@
125052 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
125053 sqlite3_free(zSql);
125054 }else{
125055 rc = SQLITE_NOMEM;
125056 }
125057 }else if( eSearch==FTS3_DOCID_SEARCH ){
125058 rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
125059 if( rc==SQLITE_OK ){
125060 rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons);
125061 }
125062 }
125063 if( rc!=SQLITE_OK ) return rc;
125064
125065 return fts3NextMethod(pCursor);
@@ -125543,10 +125946,16 @@
125946 }
125947
125948 return SQLITE_OK;
125949 }
125950
125951 /*
125952 ** Maximum number of tokens a phrase may have to be considered for the
125953 ** incremental doclists strategy.
125954 */
125955 #define MAX_INCR_PHRASE_TOKENS 4
125956
125957 /*
125958 ** This function is called for each Fts3Phrase in a full-text query
125959 ** expression to initialize the mechanism for returning rows. Once this
125960 ** function has been called successfully on an Fts3Phrase, it may be
125961 ** used with fts3EvalPhraseNext() to iterate through the matching docids.
@@ -125556,27 +125965,47 @@
125965 ** memory within this call.
125966 **
125967 ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
125968 */
125969 static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
 
 
125970 Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
125971 int rc = SQLITE_OK; /* Error code */
125972 int i;
125973
125974 /* Determine if doclists may be loaded from disk incrementally. This is
125975 ** possible if the bOptOk argument is true, the FTS doclists will be
125976 ** scanned in forward order, and the phrase consists of
125977 ** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first"
125978 ** tokens or prefix tokens that cannot use a prefix-index. */
125979 int bHaveIncr = 0;
125980 int bIncrOk = (bOptOk
125981 && pCsr->bDesc==pTab->bDescIdx
125982 && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
125983 && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
125984 #ifdef SQLITE_TEST
125985 && pTab->bNoIncrDoclist==0
125986 #endif
125987 );
125988 for(i=0; bIncrOk==1 && i<p->nToken; i++){
125989 Fts3PhraseToken *pToken = &p->aToken[i];
125990 if( pToken->bFirst || (pToken->pSegcsr!=0 && !pToken->pSegcsr->bLookup) ){
125991 bIncrOk = 0;
125992 }
125993 if( pToken->pSegcsr ) bHaveIncr = 1;
125994 }
125995
125996 if( bIncrOk && bHaveIncr ){
125997 /* Use the incremental approach. */
125998 int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
125999 for(i=0; rc==SQLITE_OK && i<p->nToken; i++){
126000 Fts3PhraseToken *pToken = &p->aToken[i];
126001 Fts3MultiSegReader *pSegcsr = pToken->pSegcsr;
126002 if( pSegcsr ){
126003 rc = sqlite3Fts3MsrIncrStart(pTab, pSegcsr, iCol, pToken->z, pToken->n);
126004 }
126005 }
126006 p->bIncr = 1;
 
126007 }else{
126008 /* Load the full doclist for the phrase into memory. */
126009 rc = fts3EvalPhraseLoad(pCsr, p);
126010 p->bIncr = 0;
126011 }
@@ -125680,10 +126109,220 @@
126109 }
126110 }
126111
126112 *ppIter = p;
126113 }
126114
126115 /*
126116 ** Advance the iterator pDL to the next entry in pDL->aAll/nAll. Set *pbEof
126117 ** to true if EOF is reached.
126118 */
126119 static void fts3EvalDlPhraseNext(
126120 Fts3Table *pTab,
126121 Fts3Doclist *pDL,
126122 u8 *pbEof
126123 ){
126124 char *pIter; /* Used to iterate through aAll */
126125 char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
126126
126127 if( pDL->pNextDocid ){
126128 pIter = pDL->pNextDocid;
126129 }else{
126130 pIter = pDL->aAll;
126131 }
126132
126133 if( pIter>=pEnd ){
126134 /* We have already reached the end of this doclist. EOF. */
126135 *pbEof = 1;
126136 }else{
126137 sqlite3_int64 iDelta;
126138 pIter += sqlite3Fts3GetVarint(pIter, &iDelta);
126139 if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
126140 pDL->iDocid += iDelta;
126141 }else{
126142 pDL->iDocid -= iDelta;
126143 }
126144 pDL->pList = pIter;
126145 fts3PoslistCopy(0, &pIter);
126146 pDL->nList = (int)(pIter - pDL->pList);
126147
126148 /* pIter now points just past the 0x00 that terminates the position-
126149 ** list for document pDL->iDocid. However, if this position-list was
126150 ** edited in place by fts3EvalNearTrim(), then pIter may not actually
126151 ** point to the start of the next docid value. The following line deals
126152 ** with this case by advancing pIter past the zero-padding added by
126153 ** fts3EvalNearTrim(). */
126154 while( pIter<pEnd && *pIter==0 ) pIter++;
126155
126156 pDL->pNextDocid = pIter;
126157 assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter );
126158 *pbEof = 0;
126159 }
126160 }
126161
126162 /*
126163 ** Helper type used by fts3EvalIncrPhraseNext() and incrPhraseTokenNext().
126164 */
126165 typedef struct TokenDoclist TokenDoclist;
126166 struct TokenDoclist {
126167 int bIgnore;
126168 sqlite3_int64 iDocid;
126169 char *pList;
126170 int nList;
126171 };
126172
126173 /*
126174 ** Token pToken is an incrementally loaded token that is part of a
126175 ** multi-token phrase. Advance it to the next matching document in the
126176 ** database and populate output variable *p with the details of the new
126177 ** entry. Or, if the iterator has reached EOF, set *pbEof to true.
126178 **
126179 ** If an error occurs, return an SQLite error code. Otherwise, return
126180 ** SQLITE_OK.
126181 */
126182 static int incrPhraseTokenNext(
126183 Fts3Table *pTab, /* Virtual table handle */
126184 Fts3Phrase *pPhrase, /* Phrase to advance token of */
126185 int iToken, /* Specific token to advance */
126186 TokenDoclist *p, /* OUT: Docid and doclist for new entry */
126187 u8 *pbEof /* OUT: True if iterator is at EOF */
126188 ){
126189 int rc = SQLITE_OK;
126190
126191 if( pPhrase->iDoclistToken==iToken ){
126192 assert( p->bIgnore==0 );
126193 assert( pPhrase->aToken[iToken].pSegcsr==0 );
126194 fts3EvalDlPhraseNext(pTab, &pPhrase->doclist, pbEof);
126195 p->pList = pPhrase->doclist.pList;
126196 p->nList = pPhrase->doclist.nList;
126197 p->iDocid = pPhrase->doclist.iDocid;
126198 }else{
126199 Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
126200 assert( pToken->pDeferred==0 );
126201 assert( pToken->pSegcsr || pPhrase->iDoclistToken>=0 );
126202 if( pToken->pSegcsr ){
126203 assert( p->bIgnore==0 );
126204 rc = sqlite3Fts3MsrIncrNext(
126205 pTab, pToken->pSegcsr, &p->iDocid, &p->pList, &p->nList
126206 );
126207 if( p->pList==0 ) *pbEof = 1;
126208 }else{
126209 p->bIgnore = 1;
126210 }
126211 }
126212
126213 return rc;
126214 }
126215
126216
126217 /*
126218 ** The phrase iterator passed as the second argument:
126219 **
126220 ** * features at least one token that uses an incremental doclist, and
126221 **
126222 ** * does not contain any deferred tokens.
126223 **
126224 ** Advance it to the next matching documnent in the database and populate
126225 ** the Fts3Doclist.pList and nList fields.
126226 **
126227 ** If there is no "next" entry and no error occurs, then *pbEof is set to
126228 ** 1 before returning. Otherwise, if no error occurs and the iterator is
126229 ** successfully advanced, *pbEof is set to 0.
126230 **
126231 ** If an error occurs, return an SQLite error code. Otherwise, return
126232 ** SQLITE_OK.
126233 */
126234 static int fts3EvalIncrPhraseNext(
126235 Fts3Cursor *pCsr, /* FTS Cursor handle */
126236 Fts3Phrase *p, /* Phrase object to advance to next docid */
126237 u8 *pbEof /* OUT: Set to 1 if EOF */
126238 ){
126239 int rc = SQLITE_OK;
126240 Fts3Doclist *pDL = &p->doclist;
126241 Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
126242 u8 bEof = 0;
126243
126244 /* This is only called if it is guaranteed that the phrase has at least
126245 ** one incremental token. In which case the bIncr flag is set. */
126246 assert( p->bIncr==1 );
126247
126248 if( p->nToken==1 && p->bIncr ){
126249 rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
126250 &pDL->iDocid, &pDL->pList, &pDL->nList
126251 );
126252 if( pDL->pList==0 ) bEof = 1;
126253 }else{
126254 int bDescDoclist = pCsr->bDesc;
126255 struct TokenDoclist a[MAX_INCR_PHRASE_TOKENS];
126256
126257 memset(a, 0, sizeof(a));
126258 assert( p->nToken<=MAX_INCR_PHRASE_TOKENS );
126259 assert( p->iDoclistToken<MAX_INCR_PHRASE_TOKENS );
126260
126261 while( bEof==0 ){
126262 int bMaxSet = 0;
126263 sqlite3_int64 iMax; /* Largest docid for all iterators */
126264 int i; /* Used to iterate through tokens */
126265
126266 /* Advance the iterator for each token in the phrase once. */
126267 for(i=0; rc==SQLITE_OK && i<p->nToken; i++){
126268 rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
126269 if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){
126270 iMax = a[i].iDocid;
126271 bMaxSet = 1;
126272 }
126273 }
126274 assert( rc!=SQLITE_OK || a[p->nToken-1].bIgnore==0 );
126275 assert( rc!=SQLITE_OK || bMaxSet );
126276
126277 /* Keep advancing iterators until they all point to the same document */
126278 for(i=0; i<p->nToken; i++){
126279 while( rc==SQLITE_OK && bEof==0
126280 && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0
126281 ){
126282 rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
126283 if( DOCID_CMP(a[i].iDocid, iMax)>0 ){
126284 iMax = a[i].iDocid;
126285 i = 0;
126286 }
126287 }
126288 }
126289
126290 /* Check if the current entries really are a phrase match */
126291 if( bEof==0 ){
126292 int nList = 0;
126293 int nByte = a[p->nToken-1].nList;
126294 char *aDoclist = sqlite3_malloc(nByte+1);
126295 if( !aDoclist ) return SQLITE_NOMEM;
126296 memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
126297
126298 for(i=0; i<(p->nToken-1); i++){
126299 if( a[i].bIgnore==0 ){
126300 char *pL = a[i].pList;
126301 char *pR = aDoclist;
126302 char *pOut = aDoclist;
126303 int nDist = p->nToken-1-i;
126304 int res = fts3PoslistPhraseMerge(&pOut, nDist, 0, 1, &pL, &pR);
126305 if( res==0 ) break;
126306 nList = (pOut - aDoclist);
126307 }
126308 }
126309 if( i==(p->nToken-1) ){
126310 pDL->iDocid = iMax;
126311 pDL->pList = aDoclist;
126312 pDL->nList = nList;
126313 pDL->bFreeList = 1;
126314 break;
126315 }
126316 sqlite3_free(aDoclist);
126317 }
126318 }
126319 }
126320
126321 *pbEof = bEof;
126322 return rc;
126323 }
126324
126325 /*
126326 ** Attempt to move the phrase iterator to point to the next matching docid.
126327 ** If an error occurs, return an SQLite error code. Otherwise, return
126328 ** SQLITE_OK.
@@ -125700,59 +126339,18 @@
126339 int rc = SQLITE_OK;
126340 Fts3Doclist *pDL = &p->doclist;
126341 Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
126342
126343 if( p->bIncr ){
126344 rc = fts3EvalIncrPhraseNext(pCsr, p, pbEof);
 
 
 
 
 
 
 
126345 }else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){
126346 sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll,
126347 &pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof
126348 );
126349 pDL->pList = pDL->pNextDocid;
126350 }else{
126351 fts3EvalDlPhraseNext(pTab, pDL, pbEof);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126352 }
126353
126354 return rc;
126355 }
126356
@@ -125773,11 +126371,10 @@
126371 ** code before returning.
126372 */
126373 static void fts3EvalStartReaders(
126374 Fts3Cursor *pCsr, /* FTS Cursor handle */
126375 Fts3Expr *pExpr, /* Expression to initialize phrases in */
 
126376 int *pRc /* IN/OUT: Error code */
126377 ){
126378 if( pExpr && SQLITE_OK==*pRc ){
126379 if( pExpr->eType==FTSQUERY_PHRASE ){
126380 int i;
@@ -125784,14 +126381,14 @@
126381 int nToken = pExpr->pPhrase->nToken;
126382 for(i=0; i<nToken; i++){
126383 if( pExpr->pPhrase->aToken[i].pDeferred==0 ) break;
126384 }
126385 pExpr->bDeferred = (i==nToken);
126386 *pRc = fts3EvalPhraseStart(pCsr, 1, pExpr->pPhrase);
126387 }else{
126388 fts3EvalStartReaders(pCsr, pExpr->pLeft, pRc);
126389 fts3EvalStartReaders(pCsr, pExpr->pRight, pRc);
126390 pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred);
126391 }
126392 }
126393 }
126394
@@ -126029,11 +126626,11 @@
126626 /* Set nLoad4 to the value of (4^nOther) for the next iteration of the
126627 ** for-loop. Except, limit the value to 2^24 to prevent it from
126628 ** overflowing the 32-bit integer it is stored in. */
126629 if( ii<12 ) nLoad4 = nLoad4*4;
126630
126631 if( ii==0 || (pTC->pPhrase->nToken>1 && ii!=nToken-1) ){
126632 /* Either this is the cheapest token in the entire query, or it is
126633 ** part of a multi-token phrase. Either way, the entire doclist will
126634 ** (eventually) be loaded into memory. It may as well be now. */
126635 Fts3PhraseToken *pToken = pTC->pToken;
126636 int nList = 0;
@@ -126109,11 +126706,11 @@
126706 sqlite3_free(aTC);
126707 }
126708 }
126709 #endif
126710
126711 fts3EvalStartReaders(pCsr, pCsr->pExpr, &rc);
126712 return rc;
126713 }
126714
126715 /*
126716 ** Invalidate the current position list for phrase pPhrase.
@@ -126592,10 +127189,20 @@
127189 pCsr->isRequireSeek = 1;
127190 pCsr->isMatchinfoNeeded = 1;
127191 pCsr->iPrevId = pExpr->iDocid;
127192 }while( pCsr->isEof==0 && fts3EvalTestDeferredAndNear(pCsr, &rc) );
127193 }
127194
127195 /* Check if the cursor is past the end of the docid range specified
127196 ** by Fts3Cursor.iMinDocid/iMaxDocid. If so, set the EOF flag. */
127197 if( rc==SQLITE_OK && (
127198 (pCsr->bDesc==0 && pCsr->iPrevId>pCsr->iMaxDocid)
127199 || (pCsr->bDesc!=0 && pCsr->iPrevId<pCsr->iMinDocid)
127200 )){
127201 pCsr->isEof = 1;
127202 }
127203
127204 return rc;
127205 }
127206
127207 /*
127208 ** Restart interation for expression pExpr so that the next call to
@@ -126615,16 +127222,20 @@
127222 Fts3Phrase *pPhrase = pExpr->pPhrase;
127223
127224 if( pPhrase ){
127225 fts3EvalInvalidatePoslist(pPhrase);
127226 if( pPhrase->bIncr ){
127227 int i;
127228 for(i=0; i<pPhrase->nToken; i++){
127229 Fts3PhraseToken *pToken = &pPhrase->aToken[i];
127230 assert( pToken->pDeferred==0 );
127231 if( pToken->pSegcsr ){
127232 sqlite3Fts3MsrIncrRestart(pToken->pSegcsr);
127233 }
127234 }
127235 *pRc = fts3EvalPhraseStart(pCsr, 0, pPhrase);
127236 }
 
127237 pPhrase->doclist.pNextDocid = 0;
127238 pPhrase->doclist.iDocid = 0;
127239 }
127240
127241 pExpr->iDocid = 0;
@@ -126869,19 +127480,27 @@
127480
127481 iDocid = pExpr->iDocid;
127482 pIter = pPhrase->doclist.pList;
127483 if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
127484 int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
127485 int iMul; /* +1 if csr dir matches index dir, else -1 */
127486 int bOr = 0;
127487 u8 bEof = 0;
127488 u8 bTreeEof = 0;
127489 Fts3Expr *p; /* Used to iterate from pExpr to root */
127490 Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
127491
127492 /* Check if this phrase descends from an OR expression node. If not,
127493 ** return NULL. Otherwise, the entry that corresponds to docid
127494 ** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the
127495 ** tree that the node is part of has been marked as EOF, but the node
127496 ** itself is not EOF, then it may point to an earlier entry. */
127497 pNear = pExpr;
127498 for(p=pExpr->pParent; p; p=p->pParent){
127499 if( p->eType==FTSQUERY_OR ) bOr = 1;
127500 if( p->eType==FTSQUERY_NEAR ) pNear = p;
127501 if( p->bEof ) bTreeEof = 1;
127502 }
127503 if( bOr==0 ) return SQLITE_OK;
127504
127505 /* This is the descendent of an OR node. In this case we cannot use
127506 ** an incremental phrase. Load the entire doclist for the phrase
@@ -126896,33 +127515,63 @@
127515 }
127516 pIter = pPhrase->doclist.pList;
127517 assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
127518 if( rc!=SQLITE_OK ) return rc;
127519 }
127520
127521 iMul = ((pCsr->bDesc==bDescDoclist) ? 1 : -1);
127522 while( bTreeEof==1
127523 && pNear->bEof==0
127524 && (DOCID_CMP(pNear->iDocid, pCsr->iPrevId) * iMul)<0
127525 ){
127526 int rc = SQLITE_OK;
127527 fts3EvalNextRow(pCsr, pExpr, &rc);
127528 if( rc!=SQLITE_OK ) return rc;
127529 iDocid = pExpr->iDocid;
127530 pIter = pPhrase->doclist.pList;
127531 }
127532
 
 
 
 
127533 bEof = (pPhrase->doclist.nAll==0);
127534 assert( bDescDoclist==0 || bDescDoclist==1 );
127535 assert( pCsr->bDesc==0 || pCsr->bDesc==1 );
127536
127537 if( bEof==0 ){
127538 if( pCsr->bDesc==bDescDoclist ){
127539 int dummy;
127540 if( pNear->bEof ){
127541 /* This expression is already at EOF. So position it to point to the
127542 ** last entry in the doclist at pPhrase->doclist.aAll[]. Variable
127543 ** iDocid is already set for this entry, so all that is required is
127544 ** to set pIter to point to the first byte of the last position-list
127545 ** in the doclist.
127546 **
127547 ** It would also be correct to set pIter and iDocid to zero. In
127548 ** this case, the first call to sqltie3Fts4DoclistPrev() below
127549 ** would also move the iterator to point to the last entry in the
127550 ** doclist. However, this is expensive, as to do so it has to
127551 ** iterate through the entire doclist from start to finish (since
127552 ** it does not know the docid for the last entry). */
127553 pIter = &pPhrase->doclist.aAll[pPhrase->doclist.nAll-1];
127554 fts3ReversePoslist(pPhrase->doclist.aAll, &pIter);
127555 }
127556 while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
127557 sqlite3Fts3DoclistPrev(
127558 bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
127559 &pIter, &iDocid, &dummy, &bEof
127560 );
127561 }
127562 }else{
127563 if( pNear->bEof ){
127564 pIter = 0;
127565 iDocid = 0;
127566 }
127567 while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
127568 sqlite3Fts3DoclistNext(
127569 bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
127570 &pIter, &iDocid, &bEof
127571 );
127572 }
127573 }
127574 }
127575
127576 if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
127577 }
@@ -135756,11 +136405,11 @@
136405 assert( p->bFts4==0 );
136406 sqlite3Fts3CreateStatTable(&rc, p);
136407 if( rc ) return rc;
136408 }
136409 rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0);
136410 if( rc ) return rc;
136411 sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE);
136412 sqlite3_bind_int(pStmt, 2, p->bAutoincrmerge);
136413 sqlite3_step(pStmt);
136414 rc = sqlite3_reset(pStmt);
136415 return rc;
@@ -136025,10 +136674,13 @@
136674 }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
136675 p->nNodeSize = atoi(&zVal[9]);
136676 rc = SQLITE_OK;
136677 }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
136678 p->nMaxPendingData = atoi(&zVal[11]);
136679 rc = SQLITE_OK;
136680 }else if( nVal>21 && 0==sqlite3_strnicmp(zVal, "test-no-incr-doclist=", 21) ){
136681 p->bNoIncrDoclist = atoi(&zVal[21]);
136682 rc = SQLITE_OK;
136683 #endif
136684 }else{
136685 rc = SQLITE_ERROR;
136686 }
136687
+1 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.8.1"
111111
#define SQLITE_VERSION_NUMBER 3008001
112
-#define SQLITE_SOURCE_ID "2013-09-16 12:57:19 daf6ba413cb3cb6065774ba07495eab4a28b49b0"
112
+#define SQLITE_SOURCE_ID "2013-10-11 13:27:26 03593817ab5abdd4bbaa5e47e2e4745eef025af9"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
118118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.1"
111 #define SQLITE_VERSION_NUMBER 3008001
112 #define SQLITE_SOURCE_ID "2013-09-16 12:57:19 daf6ba413cb3cb6065774ba07495eab4a28b49b0"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.1"
111 #define SQLITE_VERSION_NUMBER 3008001
112 #define SQLITE_SOURCE_ID "2013-10-11 13:27:26 03593817ab5abdd4bbaa5e47e2e4745eef025af9"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
+1 -1
--- src/stat.c
+++ src/stat.c
@@ -16,12 +16,12 @@
1616
*******************************************************************************
1717
**
1818
** This file contains code to implement the stat web page
1919
**
2020
*/
21
-#include <string.h>
2221
#include "config.h"
22
+#include <string.h>
2323
#include "stat.h"
2424
2525
/*
2626
** For a sufficiently large integer, provide an alternative
2727
** representation as MB or GB or TB.
2828
--- src/stat.c
+++ src/stat.c
@@ -16,12 +16,12 @@
16 *******************************************************************************
17 **
18 ** This file contains code to implement the stat web page
19 **
20 */
21 #include <string.h>
22 #include "config.h"
 
23 #include "stat.h"
24
25 /*
26 ** For a sufficiently large integer, provide an alternative
27 ** representation as MB or GB or TB.
28
--- src/stat.c
+++ src/stat.c
@@ -16,12 +16,12 @@
16 *******************************************************************************
17 **
18 ** This file contains code to implement the stat web page
19 **
20 */
 
21 #include "config.h"
22 #include <string.h>
23 #include "stat.h"
24
25 /*
26 ** For a sufficiently large integer, provide an alternative
27 ** representation as MB or GB or TB.
28
+8 -1
--- src/style.c
+++ src/style.c
@@ -175,11 +175,18 @@
175175
}
176176
for(i=0; i<nFormAction; i++){
177177
@ gebi("form%d(i+1)").action="%s(aFormAction[i])";
178178
}
179179
@ }
180
- if( db_get_boolean("auto-hyperlink-mouseover",0) ){
180
+ if( strglob("*Opera Mini/[1-9]*", P("HTTP_USER_AGENT")) ){
181
+ /* Special case for Opera Mini, which executes JS server-side */
182
+ @ var isOperaMini = Object.prototype.toString.call(window.operamini)
183
+ @ === "[object OperaMini]";
184
+ @ if( isOperaMini ){
185
+ @ setTimeout("setAllHrefs();",%d(nDelay));
186
+ @ }
187
+ }else if( db_get_boolean("auto-hyperlink-mouseover",0) ){
181188
/* Require mouse movement prior to activating hyperlinks */
182189
@ document.getElementsByTagName("body")[0].onmousemove=function(){
183190
@ setTimeout("setAllHrefs();",%d(nDelay));
184191
@ this.onmousemove = null;
185192
@ }
186193
--- src/style.c
+++ src/style.c
@@ -175,11 +175,18 @@
175 }
176 for(i=0; i<nFormAction; i++){
177 @ gebi("form%d(i+1)").action="%s(aFormAction[i])";
178 }
179 @ }
180 if( db_get_boolean("auto-hyperlink-mouseover",0) ){
 
 
 
 
 
 
 
181 /* Require mouse movement prior to activating hyperlinks */
182 @ document.getElementsByTagName("body")[0].onmousemove=function(){
183 @ setTimeout("setAllHrefs();",%d(nDelay));
184 @ this.onmousemove = null;
185 @ }
186
--- src/style.c
+++ src/style.c
@@ -175,11 +175,18 @@
175 }
176 for(i=0; i<nFormAction; i++){
177 @ gebi("form%d(i+1)").action="%s(aFormAction[i])";
178 }
179 @ }
180 if( strglob("*Opera Mini/[1-9]*", P("HTTP_USER_AGENT")) ){
181 /* Special case for Opera Mini, which executes JS server-side */
182 @ var isOperaMini = Object.prototype.toString.call(window.operamini)
183 @ === "[object OperaMini]";
184 @ if( isOperaMini ){
185 @ setTimeout("setAllHrefs();",%d(nDelay));
186 @ }
187 }else if( db_get_boolean("auto-hyperlink-mouseover",0) ){
188 /* Require mouse movement prior to activating hyperlinks */
189 @ document.getElementsByTagName("body")[0].onmousemove=function(){
190 @ setTimeout("setAllHrefs();",%d(nDelay));
191 @ this.onmousemove = null;
192 @ }
193
+6
--- src/sync.c
+++ src/sync.c
@@ -51,10 +51,12 @@
5151
}
5252
url_parse(0, URL_REMEMBER);
5353
if( g.urlProtocol==0 ) return 0;
5454
if( g.urlUser!=0 && g.urlPasswd==0 ){
5555
g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
56
+ g.urlFlags |= URL_PROMPT_PW;
57
+ url_prompt_for_password();
5658
}
5759
#if 0 /* Disabled for now */
5860
if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
5961
/* When doing an automatic pull, also automatically pull shuns from
6062
** the server if pull_shuns is enabled.
@@ -101,16 +103,20 @@
101103
*/
102104
if( find_option("verily",0,0)!=0 ){
103105
*pSyncFlags |= SYNC_RESYNC;
104106
}
105107
url_proxy_options();
108
+ clone_ssh_find_options();
106109
db_find_and_open_repository(0, 0);
107110
db_open_config(0);
108111
if( g.argc==2 ){
109112
if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
110113
}else if( g.argc==3 ){
111114
zUrl = g.argv[2];
115
+ }
116
+ if( urlFlags & URL_REMEMBER ){
117
+ clone_ssh_db_set_options();
112118
}
113119
url_parse(zUrl, urlFlags);
114120
if( g.urlProtocol==0 ){
115121
if( urlOptional ) fossil_exit(0);
116122
usage("URL");
117123
--- src/sync.c
+++ src/sync.c
@@ -51,10 +51,12 @@
51 }
52 url_parse(0, URL_REMEMBER);
53 if( g.urlProtocol==0 ) return 0;
54 if( g.urlUser!=0 && g.urlPasswd==0 ){
55 g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
 
 
56 }
57 #if 0 /* Disabled for now */
58 if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
59 /* When doing an automatic pull, also automatically pull shuns from
60 ** the server if pull_shuns is enabled.
@@ -101,16 +103,20 @@
101 */
102 if( find_option("verily",0,0)!=0 ){
103 *pSyncFlags |= SYNC_RESYNC;
104 }
105 url_proxy_options();
 
106 db_find_and_open_repository(0, 0);
107 db_open_config(0);
108 if( g.argc==2 ){
109 if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
110 }else if( g.argc==3 ){
111 zUrl = g.argv[2];
 
 
 
112 }
113 url_parse(zUrl, urlFlags);
114 if( g.urlProtocol==0 ){
115 if( urlOptional ) fossil_exit(0);
116 usage("URL");
117
--- src/sync.c
+++ src/sync.c
@@ -51,10 +51,12 @@
51 }
52 url_parse(0, URL_REMEMBER);
53 if( g.urlProtocol==0 ) return 0;
54 if( g.urlUser!=0 && g.urlPasswd==0 ){
55 g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
56 g.urlFlags |= URL_PROMPT_PW;
57 url_prompt_for_password();
58 }
59 #if 0 /* Disabled for now */
60 if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
61 /* When doing an automatic pull, also automatically pull shuns from
62 ** the server if pull_shuns is enabled.
@@ -101,16 +103,20 @@
103 */
104 if( find_option("verily",0,0)!=0 ){
105 *pSyncFlags |= SYNC_RESYNC;
106 }
107 url_proxy_options();
108 clone_ssh_find_options();
109 db_find_and_open_repository(0, 0);
110 db_open_config(0);
111 if( g.argc==2 ){
112 if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
113 }else if( g.argc==3 ){
114 zUrl = g.argv[2];
115 }
116 if( urlFlags & URL_REMEMBER ){
117 clone_ssh_db_set_options();
118 }
119 url_parse(zUrl, urlFlags);
120 if( g.urlProtocol==0 ){
121 if( urlOptional ) fossil_exit(0);
122 usage("URL");
123
+2 -2
--- src/tar.c
+++ src/tar.c
@@ -15,13 +15,13 @@
1515
**
1616
*******************************************************************************
1717
**
1818
** This file contains code used to generate tarballs.
1919
*/
20
+#include "config.h"
2021
#include <assert.h>
2122
#include <zlib.h>
22
-#include "config.h"
2323
#include "tar.h"
2424
2525
/*
2626
** State information for the tarball builder.
2727
*/
@@ -479,11 +479,11 @@
479479
if( zDir && zDir[0] ){
480480
blob_appendf(&filename, "%s/", zDir);
481481
}
482482
nPrefix = blob_size(&filename);
483483
484
- pManifest = manifest_get(rid, CFTYPE_MANIFEST);
484
+ pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
485485
if( pManifest ){
486486
mTime = (pManifest->rDate - 2440587.5)*86400.0;
487487
tar_begin(mTime);
488488
if( db_get_boolean("manifest", 0) ){
489489
blob_append(&filename, "manifest", -1);
490490
--- src/tar.c
+++ src/tar.c
@@ -15,13 +15,13 @@
15 **
16 *******************************************************************************
17 **
18 ** This file contains code used to generate tarballs.
19 */
 
20 #include <assert.h>
21 #include <zlib.h>
22 #include "config.h"
23 #include "tar.h"
24
25 /*
26 ** State information for the tarball builder.
27 */
@@ -479,11 +479,11 @@
479 if( zDir && zDir[0] ){
480 blob_appendf(&filename, "%s/", zDir);
481 }
482 nPrefix = blob_size(&filename);
483
484 pManifest = manifest_get(rid, CFTYPE_MANIFEST);
485 if( pManifest ){
486 mTime = (pManifest->rDate - 2440587.5)*86400.0;
487 tar_begin(mTime);
488 if( db_get_boolean("manifest", 0) ){
489 blob_append(&filename, "manifest", -1);
490
--- src/tar.c
+++ src/tar.c
@@ -15,13 +15,13 @@
15 **
16 *******************************************************************************
17 **
18 ** This file contains code used to generate tarballs.
19 */
20 #include "config.h"
21 #include <assert.h>
22 #include <zlib.h>
 
23 #include "tar.h"
24
25 /*
26 ** State information for the tarball builder.
27 */
@@ -479,11 +479,11 @@
479 if( zDir && zDir[0] ){
480 blob_appendf(&filename, "%s/", zDir);
481 }
482 nPrefix = blob_size(&filename);
483
484 pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
485 if( pManifest ){
486 mTime = (pManifest->rDate - 2440587.5)*86400.0;
487 tar_begin(mTime);
488 if( db_get_boolean("manifest", 0) ){
489 blob_append(&filename, "manifest", -1);
490
+1 -1
--- src/th.c
+++ src/th.c
@@ -2,10 +2,11 @@
22
/*
33
** The implementation of the TH core. This file contains the parser, and
44
** the implementation of the interface in th.h.
55
*/
66
7
+#include "config.h"
78
#include "th.h"
89
#include <string.h>
910
#include <assert.h>
1011
1112
typedef struct Th_Command Th_Command;
@@ -2354,11 +2355,10 @@
23542355
}
23552356
23562357
#ifndef LONGDOUBLE_TYPE
23572358
# define LONGDOUBLE_TYPE long double
23582359
#endif
2359
-typedef char u8;
23602360
23612361
23622362
/*
23632363
** Return TRUE if z is a pure numeric string. Return FALSE if the
23642364
** string contains any character which is not part of a number. If
23652365
--- src/th.c
+++ src/th.c
@@ -2,10 +2,11 @@
2 /*
3 ** The implementation of the TH core. This file contains the parser, and
4 ** the implementation of the interface in th.h.
5 */
6
 
7 #include "th.h"
8 #include <string.h>
9 #include <assert.h>
10
11 typedef struct Th_Command Th_Command;
@@ -2354,11 +2355,10 @@
2354 }
2355
2356 #ifndef LONGDOUBLE_TYPE
2357 # define LONGDOUBLE_TYPE long double
2358 #endif
2359 typedef char u8;
2360
2361
2362 /*
2363 ** Return TRUE if z is a pure numeric string. Return FALSE if the
2364 ** string contains any character which is not part of a number. If
2365
--- src/th.c
+++ src/th.c
@@ -2,10 +2,11 @@
2 /*
3 ** The implementation of the TH core. This file contains the parser, and
4 ** the implementation of the interface in th.h.
5 */
6
7 #include "config.h"
8 #include "th.h"
9 #include <string.h>
10 #include <assert.h>
11
12 typedef struct Th_Command Th_Command;
@@ -2354,11 +2355,10 @@
2355 }
2356
2357 #ifndef LONGDOUBLE_TYPE
2358 # define LONGDOUBLE_TYPE long double
2359 #endif
 
2360
2361
2362 /*
2363 ** Return TRUE if z is a pure numeric string. Return FALSE if the
2364 ** string contains any character which is not part of a number. If
2365
+4
--- src/th.h
+++ src/th.h
@@ -155,11 +155,15 @@
155155
*/
156156
int th_register_language(Th_Interp *interp); /* th_lang.c */
157157
int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */
158158
int th_register_vfs(Th_Interp *interp); /* th_vfs.c */
159159
int th_register_testvfs(Th_Interp *interp); /* th_testvfs.c */
160
+
161
+#ifdef FOSSIL_ENABLE_TCL
160162
int th_register_tcl(Th_Interp *interp, void *pContext); /* th_tcl.c */
163
+int unloadTcl(Th_Interp *interp, void *pContext); /* th_tcl.c */
164
+#endif
161165
162166
/*
163167
** General purpose hash table from th_lang.c.
164168
*/
165169
typedef struct Th_Hash Th_Hash;
166170
--- src/th.h
+++ src/th.h
@@ -155,11 +155,15 @@
155 */
156 int th_register_language(Th_Interp *interp); /* th_lang.c */
157 int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */
158 int th_register_vfs(Th_Interp *interp); /* th_vfs.c */
159 int th_register_testvfs(Th_Interp *interp); /* th_testvfs.c */
 
 
160 int th_register_tcl(Th_Interp *interp, void *pContext); /* th_tcl.c */
 
 
161
162 /*
163 ** General purpose hash table from th_lang.c.
164 */
165 typedef struct Th_Hash Th_Hash;
166
--- src/th.h
+++ src/th.h
@@ -155,11 +155,15 @@
155 */
156 int th_register_language(Th_Interp *interp); /* th_lang.c */
157 int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */
158 int th_register_vfs(Th_Interp *interp); /* th_vfs.c */
159 int th_register_testvfs(Th_Interp *interp); /* th_testvfs.c */
160
161 #ifdef FOSSIL_ENABLE_TCL
162 int th_register_tcl(Th_Interp *interp, void *pContext); /* th_tcl.c */
163 int unloadTcl(Th_Interp *interp, void *pContext); /* th_tcl.c */
164 #endif
165
166 /*
167 ** General purpose hash table from th_lang.c.
168 */
169 typedef struct Th_Hash Th_Hash;
170
--- src/th_main.c
+++ src/th_main.c
@@ -298,10 +298,11 @@
298298
** Return true if the fossil binary has the given compile-time feature
299299
** enabled. The set of features includes:
300300
**
301301
** "ssl" = FOSSIL_ENABLE_SSL
302302
** "tcl" = FOSSIL_ENABLE_TCL
303
+** "useTclStubs" = USE_TCL_STUBS
303304
** "tclStubs" = FOSSIL_ENABLE_TCL_STUBS
304305
** "tclPrivateStubs" = FOSSIL_ENABLE_TCL_PRIVATE_STUBS
305306
** "json" = FOSSIL_ENABLE_JSON
306307
** "markdown" = FOSSIL_ENABLE_MARKDOWN
307308
**
@@ -329,10 +330,15 @@
329330
#endif
330331
#if defined(FOSSIL_ENABLE_TCL)
331332
else if( 0 == fossil_strnicmp( zArg, "tcl\0", 4 ) ){
332333
rc = 1;
333334
}
335
+#endif
336
+#if defined(USE_TCL_STUBS)
337
+ else if( 0 == fossil_strnicmp( zArg, "useTclStubs\0", 12 ) ){
338
+ rc = 1;
339
+ }
334340
#endif
335341
#if defined(FOSSIL_ENABLE_TCL_STUBS)
336342
else if( 0 == fossil_strnicmp( zArg, "tclStubs\0", 9 ) ){
337343
rc = 1;
338344
}
339345
--- src/th_main.c
+++ src/th_main.c
@@ -298,10 +298,11 @@
298 ** Return true if the fossil binary has the given compile-time feature
299 ** enabled. The set of features includes:
300 **
301 ** "ssl" = FOSSIL_ENABLE_SSL
302 ** "tcl" = FOSSIL_ENABLE_TCL
 
303 ** "tclStubs" = FOSSIL_ENABLE_TCL_STUBS
304 ** "tclPrivateStubs" = FOSSIL_ENABLE_TCL_PRIVATE_STUBS
305 ** "json" = FOSSIL_ENABLE_JSON
306 ** "markdown" = FOSSIL_ENABLE_MARKDOWN
307 **
@@ -329,10 +330,15 @@
329 #endif
330 #if defined(FOSSIL_ENABLE_TCL)
331 else if( 0 == fossil_strnicmp( zArg, "tcl\0", 4 ) ){
332 rc = 1;
333 }
 
 
 
 
 
334 #endif
335 #if defined(FOSSIL_ENABLE_TCL_STUBS)
336 else if( 0 == fossil_strnicmp( zArg, "tclStubs\0", 9 ) ){
337 rc = 1;
338 }
339
--- src/th_main.c
+++ src/th_main.c
@@ -298,10 +298,11 @@
298 ** Return true if the fossil binary has the given compile-time feature
299 ** enabled. The set of features includes:
300 **
301 ** "ssl" = FOSSIL_ENABLE_SSL
302 ** "tcl" = FOSSIL_ENABLE_TCL
303 ** "useTclStubs" = USE_TCL_STUBS
304 ** "tclStubs" = FOSSIL_ENABLE_TCL_STUBS
305 ** "tclPrivateStubs" = FOSSIL_ENABLE_TCL_PRIVATE_STUBS
306 ** "json" = FOSSIL_ENABLE_JSON
307 ** "markdown" = FOSSIL_ENABLE_MARKDOWN
308 **
@@ -329,10 +330,15 @@
330 #endif
331 #if defined(FOSSIL_ENABLE_TCL)
332 else if( 0 == fossil_strnicmp( zArg, "tcl\0", 4 ) ){
333 rc = 1;
334 }
335 #endif
336 #if defined(USE_TCL_STUBS)
337 else if( 0 == fossil_strnicmp( zArg, "useTclStubs\0", 12 ) ){
338 rc = 1;
339 }
340 #endif
341 #if defined(FOSSIL_ENABLE_TCL_STUBS)
342 else if( 0 == fossil_strnicmp( zArg, "tclStubs\0", 9 ) ){
343 rc = 1;
344 }
345
+177 -87
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -23,48 +23,14 @@
2323
#ifdef FOSSIL_ENABLE_TCL
2424
2525
#include "th.h"
2626
#include "tcl.h"
2727
28
-/*
29
-** Has the decision about whether or not to use Tcl_EvalObjv already been made
30
-** via the Makefile?
31
- */
32
-#if !defined(USE_TCL_EVALOBJV)
33
-/*
34
-** Are we being compiled against Tcl 8.6b1 or b2? This check is [mostly]
35
-** wrong for at the following reason:
36
-**
37
-** 1. Technically, this check is completely useless when the stubs mechanism
38
-** is in use. In that case, a runtime version check would be required and
39
-** that has not been implemented.
40
-**
41
-** However, if a particular user compiles and runs against Tcl 8.6b1 or b2,
42
-** this will cause a fallback to using the "conservative" method of directly
43
-** invoking a Tcl command. In that case, potential crashes will be avoided if
44
-** the user just so happened to compile or run against Tcl 8.6b1 or b2.
45
- */
46
-#if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION == 6) && \
47
- (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE) && (TCL_RELEASE_SERIAL < 3)
48
-/*
49
-** Workaround NRE-specific issue in Tcl_EvalObjCmd (SF bug #3399564) by using
50
-** Tcl_EvalObjv instead of invoking the objProc directly.
51
- */
52
-# define USE_TCL_EVALOBJV (1)
53
-#else
54
-/*
55
-** We should be able to safely use Tcl_GetCommandInfoFromToken, when the need
56
-** arises, to invoke a specific Tcl command "directly" with some arguments.
57
- */
58
-# define USE_TCL_EVALOBJV (0)
59
-#endif /* (TCL_MAJOR_VERSION > 8) ... */
60
-#endif /* !defined(USE_TCL_EVALOBJV) */
61
-
6228
/*
6329
** These macros are designed to reduce the redundant code required to marshal
6430
** arguments from TH1 to Tcl.
65
- */
31
+*/
6632
#define USE_ARGV_TO_OBJV() \
6733
int objc; \
6834
Tcl_Obj **objv; \
6935
int i;
7036
@@ -83,18 +49,25 @@
8349
ckfree((char *)objv);
8450
8551
/*
8652
** Fetch the Tcl interpreter from the specified void pointer, cast to a Tcl
8753
** context.
88
- */
54
+*/
8955
#define GET_CTX_TCL_INTERP(ctx) \
9056
((struct TclContext *)(ctx))->interp
9157
58
+/*
59
+** Fetch the (logically boolean) value from the specified void pointer that
60
+** indicates whether or not we can/should use direct objProc calls.
61
+*/
62
+#define GET_CTX_TCL_USEOBJPROC(ctx) \
63
+ ((struct TclContext *)(ctx))->useObjProc
64
+
9265
/*
9366
** Define the Tcl shared library name, some exported function names, and some
9467
** cross-platform macros for use with the Tcl stubs mechanism, when enabled.
95
- */
68
+*/
9669
#if defined(USE_TCL_STUBS)
9770
# if defined(_WIN32)
9871
# define WIN32_LEAN_AND_MEAN
9972
# include <windows.h>
10073
# ifndef TCL_LIBRARY_NAME
@@ -144,33 +117,37 @@
144117
# define TCL_CREATEINTERP_NAME "_Tcl_CreateInterp"
145118
# endif
146119
# ifndef TCL_DELETEINTERP_NAME
147120
# define TCL_DELETEINTERP_NAME "_Tcl_DeleteInterp"
148121
# endif
122
+# ifndef TCL_FINALIZE_NAME
123
+# define TCL_FINALIZE_NAME "_Tcl_Finalize"
124
+# endif
149125
#endif /* defined(USE_TCL_STUBS) */
150126
151127
/*
152128
** The function types for Tcl_FindExecutable and Tcl_CreateInterp are needed
153129
** when the Tcl library is being loaded dynamically by a stubs-enabled
154130
** application (i.e. the inverse of using a stubs-enabled package). These are
155131
** the only Tcl API functions that MUST be called prior to being able to call
156132
** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). For complete
157133
** cleanup if the Tcl stubs initialization fails somehow, the Tcl_DeleteInterp
158
-** function type is also required.
159
- */
134
+** and Tcl_Finalize function types are also required.
135
+*/
160136
typedef void (tcl_FindExecutableProc) (const char * argv0);
161137
typedef Tcl_Interp *(tcl_CreateInterpProc) (void);
162138
typedef void (tcl_DeleteInterpProc) (Tcl_Interp *interp);
139
+typedef void (tcl_FinalizeProc) (void);
163140
164141
/*
165142
** The function types for the "hook" functions to be called before and after a
166143
** TH1 command makes a call to evaluate a Tcl script. If the "pre" function
167144
** returns anything but TH_OK, then evaluation of the Tcl script is skipped and
168145
** that value is used as the return code. If the "post" function returns
169146
** anything other than its rc argument, that will become the new return code
170147
** for the command.
171
- */
148
+*/
172149
typedef int (tcl_NotifyProc) (
173150
void *pContext, /* The context for this notification. */
174151
Th_Interp *interp, /* The TH1 interpreter being used. */
175152
void *ctx, /* The original TH1 command context. */
176153
int argc, /* Number of arguments for the TH1 command. */
@@ -181,27 +158,27 @@
181158
182159
/*
183160
** Are we using our own private implementation of the Tcl stubs mechanism? If
184161
** this is enabled, it prevents the user from having to link against the Tcl
185162
** stubs library for the target platform, which may not be readily available.
186
- */
163
+*/
187164
#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
188165
/*
189166
** HACK: Using some preprocessor magic and a private static variable, redirect
190167
** the Tcl API calls [found within this file] to the function pointers
191168
** that will be contained in our private Tcl stubs table. This takes
192169
** advantage of the fact that the Tcl headers always define the Tcl API
193170
** functions in terms of the "tclStubsPtr" variable.
194
- */
171
+*/
195172
#define tclStubsPtr privateTclStubsPtr
196173
static const TclStubs *tclStubsPtr = NULL;
197174
198175
/*
199176
** Create a Tcl interpreter structure that mirrors just enough fields to get
200177
** it up and running successfully with our private implementation of the Tcl
201178
** stubs mechanism.
202
- */
179
+*/
203180
struct PrivateTclInterp {
204181
char *result;
205182
Tcl_FreeProc *freeProc;
206183
int errorLine;
207184
const struct TclStubs *stubTable;
@@ -209,11 +186,11 @@
209186
210187
/*
211188
** Fossil can now be compiled without linking to the actual Tcl stubs library.
212189
** In that case, this function will be used to perform those steps that would
213190
** normally be performed within the Tcl stubs library.
214
- */
191
+*/
215192
static int initTclStubs(
216193
Th_Interp *interp,
217194
Tcl_Interp *tclInterp
218195
){
219196
tclStubsPtr = ((struct PrivateTclInterp *)tclInterp)->stubTable;
@@ -231,24 +208,56 @@
231208
return TH_ERROR;
232209
}
233210
return TH_OK;
234211
}
235212
#endif /* defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS) */
213
+
214
+/*
215
+** Is the loaded version of Tcl one where querying and/or calling the objProc
216
+** for a command does not work for some reason? The following special cases
217
+** are currently handled by this function:
218
+**
219
+** 1. All versions of Tcl 8.4 have a bug that causes a crash when calling into
220
+** the Tcl_GetCommandFromObj function via stubs (i.e. the stubs table entry
221
+** is NULL).
222
+**
223
+** 2. Various beta builds of Tcl 8.6, namely 1 and 2, have an NRE-specific bug
224
+** in Tcl_EvalObjCmd (SF bug #3399564) that cause a panic when calling into
225
+** the objProc directly.
226
+**
227
+** For both of the above cases, the Tcl_EvalObjv function must be used instead
228
+** of the more direct route of querying and calling the objProc directly.
229
+*/
230
+static int canUseObjProc(){
231
+ int major = -1, minor = -1, patchLevel = -1, type = -1;
232
+
233
+ Tcl_GetVersion(&major, &minor, &patchLevel, &type);
234
+ if( major<0 || minor<0 || patchLevel<0 || type<0 ){
235
+ return 0; /* NOTE: Invalid version info, assume bad. */
236
+ }
237
+ if( major==8 && minor==4 ){
238
+ return 0; /* NOTE: Disabled on Tcl 8.4, missing public API. */
239
+ }
240
+ if( major==8 && minor==6 && type==TCL_BETA_RELEASE && patchLevel<3 ){
241
+ return 0; /* NOTE: Disabled on Tcl 8.6b1/b2, SF bug #3399564. */
242
+ }
243
+ return 1; /* NOTE: For all other cases, assume good. */
244
+}
236245
237246
/*
238247
** Creates and initializes a Tcl interpreter for use with the specified TH1
239248
** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
240249
** by the caller. This must be declared here because quite a few functions in
241250
** this file need to use it before it can be defined.
242
- */
251
+*/
243252
static int createTclInterp(Th_Interp *interp, void *pContext);
244253
245254
/*
246255
** Returns the Tcl interpreter result as a string with the associated length.
247256
** If the Tcl interpreter or the Tcl result are NULL, the length will be 0.
248257
** If the length pointer is NULL, the length will not be stored.
249
- */
258
+*/
250259
static char *getTclResult(
251260
Tcl_Interp *pInterp,
252261
int *pN
253262
){
254263
Tcl_Obj *resultPtr;
@@ -274,11 +283,13 @@
274283
char **argv; /* Full copy of the original arguments. */
275284
void *library; /* The Tcl library module handle. */
276285
tcl_FindExecutableProc *xFindExecutable; /* Tcl_FindExecutable() pointer. */
277286
tcl_CreateInterpProc *xCreateInterp; /* Tcl_CreateInterp() pointer. */
278287
tcl_DeleteInterpProc *xDeleteInterp; /* Tcl_DeleteInterp() pointer. */
288
+ tcl_FinalizeProc *xFinalize; /* Tcl_Finalize() pointer. */
279289
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
290
+ int useObjProc; /* Non-zero if an objProc can be called directly. */
280291
char *setup; /* The optional Tcl setup script. */
281292
tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */
282293
void *pPreContext; /* Optional, provided to xPreEval(). */
283294
tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */
284295
void *pPostContext; /* Optional, provided to xPostEval(). */
@@ -443,20 +454,13 @@
443454
int argc,
444455
const char **argv,
445456
int *argl
446457
){
447458
Tcl_Interp *tclInterp;
448
-#if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
449
- Tcl_Command command;
450
- Tcl_CmdInfo cmdInfo;
451
-#endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */
452459
int rc = TH_OK;
453460
int nResult;
454461
const char *zResult;
455
-#if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
456
- Tcl_Obj *objPtr;
457
-#endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */
458462
USE_ARGV_TO_OBJV();
459463
460464
if( createTclInterp(interp, ctx)!=TH_OK ){
461465
return TH_ERROR;
462466
}
@@ -472,35 +476,40 @@
472476
if( rc!=TH_OK ){
473477
return rc;
474478
}
475479
Tcl_Preserve((ClientData)tclInterp);
476480
#if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
477
- objPtr = Tcl_NewStringObj(argv[1], argl[1]);
478
- Tcl_IncrRefCount(objPtr);
479
- command = Tcl_GetCommandFromObj(tclInterp, objPtr);
480
- if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){
481
- Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
482
- Tcl_DecrRefCount(objPtr);
483
- Tcl_Release((ClientData)tclInterp);
484
- return TH_ERROR;
485
- }
486
- if( !cmdInfo.objProc ){
487
- Th_ErrorMessage(interp, "cannot invoke Tcl command:", argv[1], argl[1]);
488
- Tcl_DecrRefCount(objPtr);
489
- Tcl_Release((ClientData)tclInterp);
490
- return TH_ERROR;
491
- }
492
- Tcl_DecrRefCount(objPtr);
493
-#endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */
494
- COPY_ARGV_TO_OBJV();
495
-#if defined(USE_TCL_EVALOBJV) && USE_TCL_EVALOBJV
496
- rc = Tcl_EvalObjv(tclInterp, objc, objv, 0);
497
-#else
498
- Tcl_ResetResult(tclInterp);
499
- rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv);
500
-#endif /* defined(USE_TCL_EVALOBJV) && USE_TCL_EVALOBJV */
501
- FREE_ARGV_TO_OBJV();
481
+ if( GET_CTX_TCL_USEOBJPROC(ctx) ){
482
+ Tcl_Command command;
483
+ Tcl_CmdInfo cmdInfo;
484
+ Tcl_Obj *objPtr = Tcl_NewStringObj(argv[1], argl[1]);
485
+ Tcl_IncrRefCount(objPtr);
486
+ command = Tcl_GetCommandFromObj(tclInterp, objPtr);
487
+ if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){
488
+ Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
489
+ Tcl_DecrRefCount(objPtr);
490
+ Tcl_Release((ClientData)tclInterp);
491
+ return TH_ERROR;
492
+ }
493
+ if( !cmdInfo.objProc ){
494
+ Th_ErrorMessage(interp, "cannot invoke Tcl command:", argv[1], argl[1]);
495
+ Tcl_DecrRefCount(objPtr);
496
+ Tcl_Release((ClientData)tclInterp);
497
+ return TH_ERROR;
498
+ }
499
+ Tcl_DecrRefCount(objPtr);
500
+ COPY_ARGV_TO_OBJV();
501
+ Tcl_ResetResult(tclInterp);
502
+ rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv);
503
+ FREE_ARGV_TO_OBJV();
504
+ }else
505
+#endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */
506
+ {
507
+ COPY_ARGV_TO_OBJV();
508
+ rc = Tcl_EvalObjv(tclInterp, objc, objv, 0);
509
+ FREE_ARGV_TO_OBJV();
510
+ }
502511
zResult = getTclResult(tclInterp, &nResult);
503512
Th_SetResult(interp, zResult, nResult);
504513
Tcl_Release((ClientData)tclInterp);
505514
rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc);
506515
return rc;
@@ -586,11 +595,11 @@
586595
};
587596
588597
/*
589598
** Called if the Tcl interpreter is deleted. Removes the Tcl integration
590599
** commands from the TH1 interpreter.
591
- */
600
+*/
592601
static void Th1DeleteProc(
593602
ClientData clientData,
594603
Tcl_Interp *interp
595604
){
596605
int i;
@@ -607,23 +616,25 @@
607616
** When Tcl stubs support is enabled, attempts to dynamically load the Tcl
608617
** shared library and fetch the function pointers necessary to create an
609618
** interpreter and initialize the stubs mechanism; otherwise, simply setup
610619
** the function pointers provided by the caller with the statically linked
611620
** functions.
612
- */
621
+*/
613622
static int loadTcl(
614623
Th_Interp *interp,
615624
void **pLibrary,
616625
tcl_FindExecutableProc **pxFindExecutable,
617626
tcl_CreateInterpProc **pxCreateInterp,
618
- tcl_DeleteInterpProc **pxDeleteInterp
627
+ tcl_DeleteInterpProc **pxDeleteInterp,
628
+ tcl_FinalizeProc **pxFinalize
619629
){
620630
#if defined(USE_TCL_STUBS)
621631
char fileName[] = TCL_LIBRARY_NAME;
622632
#endif /* defined(USE_TCL_STUBS) */
623633
624
- if( !pLibrary || !pxFindExecutable || !pxCreateInterp || !pxDeleteInterp ){
634
+ if( !pLibrary || !pxFindExecutable || !pxCreateInterp ||
635
+ !pxDeleteInterp || !pxFinalize ){
625636
Th_ErrorMessage(interp,
626637
"invalid Tcl loader argument(s)", (const char *)"", 0);
627638
return TH_ERROR;
628639
}
629640
#if defined(USE_TCL_STUBS)
@@ -631,10 +642,11 @@
631642
void *library = dlopen(fileName, RTLD_NOW | RTLD_GLOBAL);
632643
if( library ){
633644
tcl_FindExecutableProc *xFindExecutable;
634645
tcl_CreateInterpProc *xCreateInterp;
635646
tcl_DeleteInterpProc *xDeleteInterp;
647
+ tcl_FinalizeProc *xFinalize;
636648
const char *procName = TCL_FINDEXECUTABLE_NAME;
637649
xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName + 1);
638650
if( !xFindExecutable ){
639651
xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName);
640652
}
@@ -663,35 +675,49 @@
663675
if( !xDeleteInterp ){
664676
Th_ErrorMessage(interp,
665677
"could not locate Tcl_DeleteInterp", (const char *)"", 0);
666678
dlclose(library);
667679
return TH_ERROR;
680
+ }
681
+ procName = TCL_FINALIZE_NAME;
682
+ xFinalize = (tcl_FinalizeProc *)dlsym(library, procName + 1);
683
+ if( !xFinalize ){
684
+ xFinalize = (tcl_FinalizeProc *)dlsym(library, procName);
685
+ }
686
+ if( !xFinalize ){
687
+ Th_ErrorMessage(interp,
688
+ "could not locate Tcl_Finalize", (const char *)"", 0);
689
+ dlclose(library);
690
+ return TH_ERROR;
668691
}
669692
*pLibrary = library;
670693
*pxFindExecutable = xFindExecutable;
671694
*pxCreateInterp = xCreateInterp;
672695
*pxDeleteInterp = xDeleteInterp;
696
+ *pxFinalize = xFinalize;
673697
return TH_OK;
674698
}
675699
} while( --fileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */
676
- fileName[TCL_MINOR_OFFSET]++;
700
+ fileName[TCL_MINOR_OFFSET] = 'x';
677701
Th_ErrorMessage(interp,
678
- "could not load Tcl shared library \"", fileName, -1);
702
+ "could not load any supported Tcl 8.6, 8.5, or 8.4 shared library \"",
703
+ fileName, -1);
679704
return TH_ERROR;
680705
#else
681706
*pLibrary = 0;
682707
*pxFindExecutable = Tcl_FindExecutable;
683708
*pxCreateInterp = Tcl_CreateInterp;
684709
*pxDeleteInterp = Tcl_DeleteInterp;
710
+ *pxFinalize = Tcl_Finalize;
685711
return TH_OK;
686712
#endif /* defined(USE_TCL_STUBS) */
687713
}
688714
689715
/*
690716
** Sets the "argv0", "argc", and "argv" script variables in the Tcl interpreter
691717
** based on the supplied command line arguments.
692
- */
718
+*/
693719
static int setTclArguments(
694720
Tcl_Interp *pInterp,
695721
int argc,
696722
char **argv
697723
){
@@ -745,11 +771,11 @@
745771
746772
/*
747773
** Creates and initializes a Tcl interpreter for use with the specified TH1
748774
** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
749775
** by the caller.
750
- */
776
+*/
751777
static int createTclInterp(
752778
Th_Interp *interp,
753779
void *pContext
754780
){
755781
struct TclContext *tclContext = (struct TclContext *)pContext;
@@ -766,11 +792,12 @@
766792
}
767793
if ( tclContext->interp ){
768794
return TH_OK;
769795
}
770796
if( loadTcl(interp, &tclContext->library, &tclContext->xFindExecutable,
771
- &tclContext->xCreateInterp, &tclContext->xDeleteInterp)!=TH_OK ){
797
+ &tclContext->xCreateInterp, &tclContext->xDeleteInterp,
798
+ &tclContext->xFinalize)!=TH_OK ){
772799
return TH_ERROR;
773800
}
774801
argc = tclContext->argc;
775802
argv = tclContext->argv;
776803
if( argc>0 && argv ){
@@ -820,10 +847,15 @@
820847
"Tcl error setting arguments:", Tcl_GetStringResult(tclInterp), -1);
821848
Tcl_DeleteInterp(tclInterp);
822849
tclContext->interp = tclInterp = 0;
823850
return TH_ERROR;
824851
}
852
+ /*
853
+ ** Determine if an objProc can be called directly for a Tcl command invoked
854
+ ** via the tclInvoke TH1 command.
855
+ */
856
+ tclContext->useObjProc = canUseObjProc();
825857
/* Add the TH1 integration commands to Tcl. */
826858
Tcl_CallWhenDeleted(tclInterp, Th1DeleteProc, interp);
827859
Tcl_CreateObjCommand(tclInterp, "th1Eval", Th1EvalObjCmd, interp, NULL);
828860
Tcl_CreateObjCommand(tclInterp, "th1Expr", Th1ExprObjCmd, interp, NULL);
829861
/* If necessary, evaluate the custom Tcl setup script. */
@@ -835,10 +867,68 @@
835867
tclContext->interp = tclInterp = 0;
836868
return TH_ERROR;
837869
}
838870
return TH_OK;
839871
}
872
+
873
+/*
874
+** Finalizes and unloads the previously loaded Tcl library, if applicable.
875
+*/
876
+int unloadTcl(
877
+ Th_Interp *interp,
878
+ void *pContext
879
+){
880
+ struct TclContext *tclContext = (struct TclContext *)pContext;
881
+ Tcl_Interp *tclInterp;
882
+ tcl_FinalizeProc *xFinalize;
883
+#if defined(USE_TCL_STUBS)
884
+ void *library;
885
+#endif /* defined(USE_TCL_STUBS) */
886
+
887
+ if ( !tclContext ){
888
+ Th_ErrorMessage(interp,
889
+ "invalid Tcl context", (const char *)"", 0);
890
+ return TH_ERROR;
891
+ }
892
+ /*
893
+ ** Grab the Tcl_Finalize function pointer prior to deleting the Tcl
894
+ ** interpreter because the memory backing the Tcl stubs table will
895
+ ** be going away.
896
+ */
897
+ xFinalize = tclContext->xFinalize;
898
+ /*
899
+ ** If the Tcl interpreter has been created, formally delete it now.
900
+ */
901
+ tclInterp = tclContext->interp;
902
+ if ( tclInterp ){
903
+ Tcl_DeleteInterp(tclInterp);
904
+ tclContext->interp = tclInterp = 0;
905
+ }
906
+ /*
907
+ ** If the Tcl library is not finalized prior to unloading it, a deadlock
908
+ ** can occur in some circumstances (i.e. the [clock] thread is running).
909
+ */
910
+ if( xFinalize ) xFinalize();
911
+#if defined(USE_TCL_STUBS)
912
+ /*
913
+ ** If Tcl is compiled on Windows using the latest MinGW, Fossil can crash
914
+ ** when exiting while a stubs-enabled Tcl is still loaded. This is due to
915
+ ** a bug in MinGW, see:
916
+ **
917
+ ** http://comments.gmane.org/gmane.comp.gnu.mingw.user/41724
918
+ **
919
+ ** The workaround is to manually unload the loaded Tcl library prior to
920
+ ** exiting the process.
921
+ */
922
+ library = tclContext->library;
923
+ if( library ){
924
+ dlclose(library);
925
+ tclContext->library = library = 0;
926
+ }
927
+#endif /* defined(USE_TCL_STUBS) */
928
+ return TH_OK;
929
+}
840930
841931
/*
842932
** Register the Tcl language commands with interpreter interp.
843933
** Usually this is called soon after interpreter creation.
844934
*/
845935
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -23,48 +23,14 @@
23 #ifdef FOSSIL_ENABLE_TCL
24
25 #include "th.h"
26 #include "tcl.h"
27
28 /*
29 ** Has the decision about whether or not to use Tcl_EvalObjv already been made
30 ** via the Makefile?
31 */
32 #if !defined(USE_TCL_EVALOBJV)
33 /*
34 ** Are we being compiled against Tcl 8.6b1 or b2? This check is [mostly]
35 ** wrong for at the following reason:
36 **
37 ** 1. Technically, this check is completely useless when the stubs mechanism
38 ** is in use. In that case, a runtime version check would be required and
39 ** that has not been implemented.
40 **
41 ** However, if a particular user compiles and runs against Tcl 8.6b1 or b2,
42 ** this will cause a fallback to using the "conservative" method of directly
43 ** invoking a Tcl command. In that case, potential crashes will be avoided if
44 ** the user just so happened to compile or run against Tcl 8.6b1 or b2.
45 */
46 #if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION == 6) && \
47 (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE) && (TCL_RELEASE_SERIAL < 3)
48 /*
49 ** Workaround NRE-specific issue in Tcl_EvalObjCmd (SF bug #3399564) by using
50 ** Tcl_EvalObjv instead of invoking the objProc directly.
51 */
52 # define USE_TCL_EVALOBJV (1)
53 #else
54 /*
55 ** We should be able to safely use Tcl_GetCommandInfoFromToken, when the need
56 ** arises, to invoke a specific Tcl command "directly" with some arguments.
57 */
58 # define USE_TCL_EVALOBJV (0)
59 #endif /* (TCL_MAJOR_VERSION > 8) ... */
60 #endif /* !defined(USE_TCL_EVALOBJV) */
61
62 /*
63 ** These macros are designed to reduce the redundant code required to marshal
64 ** arguments from TH1 to Tcl.
65 */
66 #define USE_ARGV_TO_OBJV() \
67 int objc; \
68 Tcl_Obj **objv; \
69 int i;
70
@@ -83,18 +49,25 @@
83 ckfree((char *)objv);
84
85 /*
86 ** Fetch the Tcl interpreter from the specified void pointer, cast to a Tcl
87 ** context.
88 */
89 #define GET_CTX_TCL_INTERP(ctx) \
90 ((struct TclContext *)(ctx))->interp
91
 
 
 
 
 
 
 
92 /*
93 ** Define the Tcl shared library name, some exported function names, and some
94 ** cross-platform macros for use with the Tcl stubs mechanism, when enabled.
95 */
96 #if defined(USE_TCL_STUBS)
97 # if defined(_WIN32)
98 # define WIN32_LEAN_AND_MEAN
99 # include <windows.h>
100 # ifndef TCL_LIBRARY_NAME
@@ -144,33 +117,37 @@
144 # define TCL_CREATEINTERP_NAME "_Tcl_CreateInterp"
145 # endif
146 # ifndef TCL_DELETEINTERP_NAME
147 # define TCL_DELETEINTERP_NAME "_Tcl_DeleteInterp"
148 # endif
 
 
 
149 #endif /* defined(USE_TCL_STUBS) */
150
151 /*
152 ** The function types for Tcl_FindExecutable and Tcl_CreateInterp are needed
153 ** when the Tcl library is being loaded dynamically by a stubs-enabled
154 ** application (i.e. the inverse of using a stubs-enabled package). These are
155 ** the only Tcl API functions that MUST be called prior to being able to call
156 ** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). For complete
157 ** cleanup if the Tcl stubs initialization fails somehow, the Tcl_DeleteInterp
158 ** function type is also required.
159 */
160 typedef void (tcl_FindExecutableProc) (const char * argv0);
161 typedef Tcl_Interp *(tcl_CreateInterpProc) (void);
162 typedef void (tcl_DeleteInterpProc) (Tcl_Interp *interp);
 
163
164 /*
165 ** The function types for the "hook" functions to be called before and after a
166 ** TH1 command makes a call to evaluate a Tcl script. If the "pre" function
167 ** returns anything but TH_OK, then evaluation of the Tcl script is skipped and
168 ** that value is used as the return code. If the "post" function returns
169 ** anything other than its rc argument, that will become the new return code
170 ** for the command.
171 */
172 typedef int (tcl_NotifyProc) (
173 void *pContext, /* The context for this notification. */
174 Th_Interp *interp, /* The TH1 interpreter being used. */
175 void *ctx, /* The original TH1 command context. */
176 int argc, /* Number of arguments for the TH1 command. */
@@ -181,27 +158,27 @@
181
182 /*
183 ** Are we using our own private implementation of the Tcl stubs mechanism? If
184 ** this is enabled, it prevents the user from having to link against the Tcl
185 ** stubs library for the target platform, which may not be readily available.
186 */
187 #if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
188 /*
189 ** HACK: Using some preprocessor magic and a private static variable, redirect
190 ** the Tcl API calls [found within this file] to the function pointers
191 ** that will be contained in our private Tcl stubs table. This takes
192 ** advantage of the fact that the Tcl headers always define the Tcl API
193 ** functions in terms of the "tclStubsPtr" variable.
194 */
195 #define tclStubsPtr privateTclStubsPtr
196 static const TclStubs *tclStubsPtr = NULL;
197
198 /*
199 ** Create a Tcl interpreter structure that mirrors just enough fields to get
200 ** it up and running successfully with our private implementation of the Tcl
201 ** stubs mechanism.
202 */
203 struct PrivateTclInterp {
204 char *result;
205 Tcl_FreeProc *freeProc;
206 int errorLine;
207 const struct TclStubs *stubTable;
@@ -209,11 +186,11 @@
209
210 /*
211 ** Fossil can now be compiled without linking to the actual Tcl stubs library.
212 ** In that case, this function will be used to perform those steps that would
213 ** normally be performed within the Tcl stubs library.
214 */
215 static int initTclStubs(
216 Th_Interp *interp,
217 Tcl_Interp *tclInterp
218 ){
219 tclStubsPtr = ((struct PrivateTclInterp *)tclInterp)->stubTable;
@@ -231,24 +208,56 @@
231 return TH_ERROR;
232 }
233 return TH_OK;
234 }
235 #endif /* defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS) */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
237 /*
238 ** Creates and initializes a Tcl interpreter for use with the specified TH1
239 ** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
240 ** by the caller. This must be declared here because quite a few functions in
241 ** this file need to use it before it can be defined.
242 */
243 static int createTclInterp(Th_Interp *interp, void *pContext);
244
245 /*
246 ** Returns the Tcl interpreter result as a string with the associated length.
247 ** If the Tcl interpreter or the Tcl result are NULL, the length will be 0.
248 ** If the length pointer is NULL, the length will not be stored.
249 */
250 static char *getTclResult(
251 Tcl_Interp *pInterp,
252 int *pN
253 ){
254 Tcl_Obj *resultPtr;
@@ -274,11 +283,13 @@
274 char **argv; /* Full copy of the original arguments. */
275 void *library; /* The Tcl library module handle. */
276 tcl_FindExecutableProc *xFindExecutable; /* Tcl_FindExecutable() pointer. */
277 tcl_CreateInterpProc *xCreateInterp; /* Tcl_CreateInterp() pointer. */
278 tcl_DeleteInterpProc *xDeleteInterp; /* Tcl_DeleteInterp() pointer. */
 
279 Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
 
280 char *setup; /* The optional Tcl setup script. */
281 tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */
282 void *pPreContext; /* Optional, provided to xPreEval(). */
283 tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */
284 void *pPostContext; /* Optional, provided to xPostEval(). */
@@ -443,20 +454,13 @@
443 int argc,
444 const char **argv,
445 int *argl
446 ){
447 Tcl_Interp *tclInterp;
448 #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
449 Tcl_Command command;
450 Tcl_CmdInfo cmdInfo;
451 #endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */
452 int rc = TH_OK;
453 int nResult;
454 const char *zResult;
455 #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
456 Tcl_Obj *objPtr;
457 #endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */
458 USE_ARGV_TO_OBJV();
459
460 if( createTclInterp(interp, ctx)!=TH_OK ){
461 return TH_ERROR;
462 }
@@ -472,35 +476,40 @@
472 if( rc!=TH_OK ){
473 return rc;
474 }
475 Tcl_Preserve((ClientData)tclInterp);
476 #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
477 objPtr = Tcl_NewStringObj(argv[1], argl[1]);
478 Tcl_IncrRefCount(objPtr);
479 command = Tcl_GetCommandFromObj(tclInterp, objPtr);
480 if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){
481 Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
482 Tcl_DecrRefCount(objPtr);
483 Tcl_Release((ClientData)tclInterp);
484 return TH_ERROR;
485 }
486 if( !cmdInfo.objProc ){
487 Th_ErrorMessage(interp, "cannot invoke Tcl command:", argv[1], argl[1]);
488 Tcl_DecrRefCount(objPtr);
489 Tcl_Release((ClientData)tclInterp);
490 return TH_ERROR;
491 }
492 Tcl_DecrRefCount(objPtr);
493 #endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */
494 COPY_ARGV_TO_OBJV();
495 #if defined(USE_TCL_EVALOBJV) && USE_TCL_EVALOBJV
496 rc = Tcl_EvalObjv(tclInterp, objc, objv, 0);
497 #else
498 Tcl_ResetResult(tclInterp);
499 rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv);
500 #endif /* defined(USE_TCL_EVALOBJV) && USE_TCL_EVALOBJV */
501 FREE_ARGV_TO_OBJV();
 
 
 
 
 
502 zResult = getTclResult(tclInterp, &nResult);
503 Th_SetResult(interp, zResult, nResult);
504 Tcl_Release((ClientData)tclInterp);
505 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc);
506 return rc;
@@ -586,11 +595,11 @@
586 };
587
588 /*
589 ** Called if the Tcl interpreter is deleted. Removes the Tcl integration
590 ** commands from the TH1 interpreter.
591 */
592 static void Th1DeleteProc(
593 ClientData clientData,
594 Tcl_Interp *interp
595 ){
596 int i;
@@ -607,23 +616,25 @@
607 ** When Tcl stubs support is enabled, attempts to dynamically load the Tcl
608 ** shared library and fetch the function pointers necessary to create an
609 ** interpreter and initialize the stubs mechanism; otherwise, simply setup
610 ** the function pointers provided by the caller with the statically linked
611 ** functions.
612 */
613 static int loadTcl(
614 Th_Interp *interp,
615 void **pLibrary,
616 tcl_FindExecutableProc **pxFindExecutable,
617 tcl_CreateInterpProc **pxCreateInterp,
618 tcl_DeleteInterpProc **pxDeleteInterp
 
619 ){
620 #if defined(USE_TCL_STUBS)
621 char fileName[] = TCL_LIBRARY_NAME;
622 #endif /* defined(USE_TCL_STUBS) */
623
624 if( !pLibrary || !pxFindExecutable || !pxCreateInterp || !pxDeleteInterp ){
 
625 Th_ErrorMessage(interp,
626 "invalid Tcl loader argument(s)", (const char *)"", 0);
627 return TH_ERROR;
628 }
629 #if defined(USE_TCL_STUBS)
@@ -631,10 +642,11 @@
631 void *library = dlopen(fileName, RTLD_NOW | RTLD_GLOBAL);
632 if( library ){
633 tcl_FindExecutableProc *xFindExecutable;
634 tcl_CreateInterpProc *xCreateInterp;
635 tcl_DeleteInterpProc *xDeleteInterp;
 
636 const char *procName = TCL_FINDEXECUTABLE_NAME;
637 xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName + 1);
638 if( !xFindExecutable ){
639 xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName);
640 }
@@ -663,35 +675,49 @@
663 if( !xDeleteInterp ){
664 Th_ErrorMessage(interp,
665 "could not locate Tcl_DeleteInterp", (const char *)"", 0);
666 dlclose(library);
667 return TH_ERROR;
 
 
 
 
 
 
 
 
 
 
 
668 }
669 *pLibrary = library;
670 *pxFindExecutable = xFindExecutable;
671 *pxCreateInterp = xCreateInterp;
672 *pxDeleteInterp = xDeleteInterp;
 
673 return TH_OK;
674 }
675 } while( --fileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */
676 fileName[TCL_MINOR_OFFSET]++;
677 Th_ErrorMessage(interp,
678 "could not load Tcl shared library \"", fileName, -1);
 
679 return TH_ERROR;
680 #else
681 *pLibrary = 0;
682 *pxFindExecutable = Tcl_FindExecutable;
683 *pxCreateInterp = Tcl_CreateInterp;
684 *pxDeleteInterp = Tcl_DeleteInterp;
 
685 return TH_OK;
686 #endif /* defined(USE_TCL_STUBS) */
687 }
688
689 /*
690 ** Sets the "argv0", "argc", and "argv" script variables in the Tcl interpreter
691 ** based on the supplied command line arguments.
692 */
693 static int setTclArguments(
694 Tcl_Interp *pInterp,
695 int argc,
696 char **argv
697 ){
@@ -745,11 +771,11 @@
745
746 /*
747 ** Creates and initializes a Tcl interpreter for use with the specified TH1
748 ** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
749 ** by the caller.
750 */
751 static int createTclInterp(
752 Th_Interp *interp,
753 void *pContext
754 ){
755 struct TclContext *tclContext = (struct TclContext *)pContext;
@@ -766,11 +792,12 @@
766 }
767 if ( tclContext->interp ){
768 return TH_OK;
769 }
770 if( loadTcl(interp, &tclContext->library, &tclContext->xFindExecutable,
771 &tclContext->xCreateInterp, &tclContext->xDeleteInterp)!=TH_OK ){
 
772 return TH_ERROR;
773 }
774 argc = tclContext->argc;
775 argv = tclContext->argv;
776 if( argc>0 && argv ){
@@ -820,10 +847,15 @@
820 "Tcl error setting arguments:", Tcl_GetStringResult(tclInterp), -1);
821 Tcl_DeleteInterp(tclInterp);
822 tclContext->interp = tclInterp = 0;
823 return TH_ERROR;
824 }
 
 
 
 
 
825 /* Add the TH1 integration commands to Tcl. */
826 Tcl_CallWhenDeleted(tclInterp, Th1DeleteProc, interp);
827 Tcl_CreateObjCommand(tclInterp, "th1Eval", Th1EvalObjCmd, interp, NULL);
828 Tcl_CreateObjCommand(tclInterp, "th1Expr", Th1ExprObjCmd, interp, NULL);
829 /* If necessary, evaluate the custom Tcl setup script. */
@@ -835,10 +867,68 @@
835 tclContext->interp = tclInterp = 0;
836 return TH_ERROR;
837 }
838 return TH_OK;
839 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
840
841 /*
842 ** Register the Tcl language commands with interpreter interp.
843 ** Usually this is called soon after interpreter creation.
844 */
845
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -23,48 +23,14 @@
23 #ifdef FOSSIL_ENABLE_TCL
24
25 #include "th.h"
26 #include "tcl.h"
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28 /*
29 ** These macros are designed to reduce the redundant code required to marshal
30 ** arguments from TH1 to Tcl.
31 */
32 #define USE_ARGV_TO_OBJV() \
33 int objc; \
34 Tcl_Obj **objv; \
35 int i;
36
@@ -83,18 +49,25 @@
49 ckfree((char *)objv);
50
51 /*
52 ** Fetch the Tcl interpreter from the specified void pointer, cast to a Tcl
53 ** context.
54 */
55 #define GET_CTX_TCL_INTERP(ctx) \
56 ((struct TclContext *)(ctx))->interp
57
58 /*
59 ** Fetch the (logically boolean) value from the specified void pointer that
60 ** indicates whether or not we can/should use direct objProc calls.
61 */
62 #define GET_CTX_TCL_USEOBJPROC(ctx) \
63 ((struct TclContext *)(ctx))->useObjProc
64
65 /*
66 ** Define the Tcl shared library name, some exported function names, and some
67 ** cross-platform macros for use with the Tcl stubs mechanism, when enabled.
68 */
69 #if defined(USE_TCL_STUBS)
70 # if defined(_WIN32)
71 # define WIN32_LEAN_AND_MEAN
72 # include <windows.h>
73 # ifndef TCL_LIBRARY_NAME
@@ -144,33 +117,37 @@
117 # define TCL_CREATEINTERP_NAME "_Tcl_CreateInterp"
118 # endif
119 # ifndef TCL_DELETEINTERP_NAME
120 # define TCL_DELETEINTERP_NAME "_Tcl_DeleteInterp"
121 # endif
122 # ifndef TCL_FINALIZE_NAME
123 # define TCL_FINALIZE_NAME "_Tcl_Finalize"
124 # endif
125 #endif /* defined(USE_TCL_STUBS) */
126
127 /*
128 ** The function types for Tcl_FindExecutable and Tcl_CreateInterp are needed
129 ** when the Tcl library is being loaded dynamically by a stubs-enabled
130 ** application (i.e. the inverse of using a stubs-enabled package). These are
131 ** the only Tcl API functions that MUST be called prior to being able to call
132 ** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). For complete
133 ** cleanup if the Tcl stubs initialization fails somehow, the Tcl_DeleteInterp
134 ** and Tcl_Finalize function types are also required.
135 */
136 typedef void (tcl_FindExecutableProc) (const char * argv0);
137 typedef Tcl_Interp *(tcl_CreateInterpProc) (void);
138 typedef void (tcl_DeleteInterpProc) (Tcl_Interp *interp);
139 typedef void (tcl_FinalizeProc) (void);
140
141 /*
142 ** The function types for the "hook" functions to be called before and after a
143 ** TH1 command makes a call to evaluate a Tcl script. If the "pre" function
144 ** returns anything but TH_OK, then evaluation of the Tcl script is skipped and
145 ** that value is used as the return code. If the "post" function returns
146 ** anything other than its rc argument, that will become the new return code
147 ** for the command.
148 */
149 typedef int (tcl_NotifyProc) (
150 void *pContext, /* The context for this notification. */
151 Th_Interp *interp, /* The TH1 interpreter being used. */
152 void *ctx, /* The original TH1 command context. */
153 int argc, /* Number of arguments for the TH1 command. */
@@ -181,27 +158,27 @@
158
159 /*
160 ** Are we using our own private implementation of the Tcl stubs mechanism? If
161 ** this is enabled, it prevents the user from having to link against the Tcl
162 ** stubs library for the target platform, which may not be readily available.
163 */
164 #if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
165 /*
166 ** HACK: Using some preprocessor magic and a private static variable, redirect
167 ** the Tcl API calls [found within this file] to the function pointers
168 ** that will be contained in our private Tcl stubs table. This takes
169 ** advantage of the fact that the Tcl headers always define the Tcl API
170 ** functions in terms of the "tclStubsPtr" variable.
171 */
172 #define tclStubsPtr privateTclStubsPtr
173 static const TclStubs *tclStubsPtr = NULL;
174
175 /*
176 ** Create a Tcl interpreter structure that mirrors just enough fields to get
177 ** it up and running successfully with our private implementation of the Tcl
178 ** stubs mechanism.
179 */
180 struct PrivateTclInterp {
181 char *result;
182 Tcl_FreeProc *freeProc;
183 int errorLine;
184 const struct TclStubs *stubTable;
@@ -209,11 +186,11 @@
186
187 /*
188 ** Fossil can now be compiled without linking to the actual Tcl stubs library.
189 ** In that case, this function will be used to perform those steps that would
190 ** normally be performed within the Tcl stubs library.
191 */
192 static int initTclStubs(
193 Th_Interp *interp,
194 Tcl_Interp *tclInterp
195 ){
196 tclStubsPtr = ((struct PrivateTclInterp *)tclInterp)->stubTable;
@@ -231,24 +208,56 @@
208 return TH_ERROR;
209 }
210 return TH_OK;
211 }
212 #endif /* defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS) */
213
214 /*
215 ** Is the loaded version of Tcl one where querying and/or calling the objProc
216 ** for a command does not work for some reason? The following special cases
217 ** are currently handled by this function:
218 **
219 ** 1. All versions of Tcl 8.4 have a bug that causes a crash when calling into
220 ** the Tcl_GetCommandFromObj function via stubs (i.e. the stubs table entry
221 ** is NULL).
222 **
223 ** 2. Various beta builds of Tcl 8.6, namely 1 and 2, have an NRE-specific bug
224 ** in Tcl_EvalObjCmd (SF bug #3399564) that cause a panic when calling into
225 ** the objProc directly.
226 **
227 ** For both of the above cases, the Tcl_EvalObjv function must be used instead
228 ** of the more direct route of querying and calling the objProc directly.
229 */
230 static int canUseObjProc(){
231 int major = -1, minor = -1, patchLevel = -1, type = -1;
232
233 Tcl_GetVersion(&major, &minor, &patchLevel, &type);
234 if( major<0 || minor<0 || patchLevel<0 || type<0 ){
235 return 0; /* NOTE: Invalid version info, assume bad. */
236 }
237 if( major==8 && minor==4 ){
238 return 0; /* NOTE: Disabled on Tcl 8.4, missing public API. */
239 }
240 if( major==8 && minor==6 && type==TCL_BETA_RELEASE && patchLevel<3 ){
241 return 0; /* NOTE: Disabled on Tcl 8.6b1/b2, SF bug #3399564. */
242 }
243 return 1; /* NOTE: For all other cases, assume good. */
244 }
245
246 /*
247 ** Creates and initializes a Tcl interpreter for use with the specified TH1
248 ** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
249 ** by the caller. This must be declared here because quite a few functions in
250 ** this file need to use it before it can be defined.
251 */
252 static int createTclInterp(Th_Interp *interp, void *pContext);
253
254 /*
255 ** Returns the Tcl interpreter result as a string with the associated length.
256 ** If the Tcl interpreter or the Tcl result are NULL, the length will be 0.
257 ** If the length pointer is NULL, the length will not be stored.
258 */
259 static char *getTclResult(
260 Tcl_Interp *pInterp,
261 int *pN
262 ){
263 Tcl_Obj *resultPtr;
@@ -274,11 +283,13 @@
283 char **argv; /* Full copy of the original arguments. */
284 void *library; /* The Tcl library module handle. */
285 tcl_FindExecutableProc *xFindExecutable; /* Tcl_FindExecutable() pointer. */
286 tcl_CreateInterpProc *xCreateInterp; /* Tcl_CreateInterp() pointer. */
287 tcl_DeleteInterpProc *xDeleteInterp; /* Tcl_DeleteInterp() pointer. */
288 tcl_FinalizeProc *xFinalize; /* Tcl_Finalize() pointer. */
289 Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
290 int useObjProc; /* Non-zero if an objProc can be called directly. */
291 char *setup; /* The optional Tcl setup script. */
292 tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */
293 void *pPreContext; /* Optional, provided to xPreEval(). */
294 tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */
295 void *pPostContext; /* Optional, provided to xPostEval(). */
@@ -443,20 +454,13 @@
454 int argc,
455 const char **argv,
456 int *argl
457 ){
458 Tcl_Interp *tclInterp;
 
 
 
 
459 int rc = TH_OK;
460 int nResult;
461 const char *zResult;
 
 
 
462 USE_ARGV_TO_OBJV();
463
464 if( createTclInterp(interp, ctx)!=TH_OK ){
465 return TH_ERROR;
466 }
@@ -472,35 +476,40 @@
476 if( rc!=TH_OK ){
477 return rc;
478 }
479 Tcl_Preserve((ClientData)tclInterp);
480 #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
481 if( GET_CTX_TCL_USEOBJPROC(ctx) ){
482 Tcl_Command command;
483 Tcl_CmdInfo cmdInfo;
484 Tcl_Obj *objPtr = Tcl_NewStringObj(argv[1], argl[1]);
485 Tcl_IncrRefCount(objPtr);
486 command = Tcl_GetCommandFromObj(tclInterp, objPtr);
487 if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){
488 Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
489 Tcl_DecrRefCount(objPtr);
490 Tcl_Release((ClientData)tclInterp);
491 return TH_ERROR;
492 }
493 if( !cmdInfo.objProc ){
494 Th_ErrorMessage(interp, "cannot invoke Tcl command:", argv[1], argl[1]);
495 Tcl_DecrRefCount(objPtr);
496 Tcl_Release((ClientData)tclInterp);
497 return TH_ERROR;
498 }
499 Tcl_DecrRefCount(objPtr);
500 COPY_ARGV_TO_OBJV();
501 Tcl_ResetResult(tclInterp);
502 rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv);
503 FREE_ARGV_TO_OBJV();
504 }else
505 #endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */
506 {
507 COPY_ARGV_TO_OBJV();
508 rc = Tcl_EvalObjv(tclInterp, objc, objv, 0);
509 FREE_ARGV_TO_OBJV();
510 }
511 zResult = getTclResult(tclInterp, &nResult);
512 Th_SetResult(interp, zResult, nResult);
513 Tcl_Release((ClientData)tclInterp);
514 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc);
515 return rc;
@@ -586,11 +595,11 @@
595 };
596
597 /*
598 ** Called if the Tcl interpreter is deleted. Removes the Tcl integration
599 ** commands from the TH1 interpreter.
600 */
601 static void Th1DeleteProc(
602 ClientData clientData,
603 Tcl_Interp *interp
604 ){
605 int i;
@@ -607,23 +616,25 @@
616 ** When Tcl stubs support is enabled, attempts to dynamically load the Tcl
617 ** shared library and fetch the function pointers necessary to create an
618 ** interpreter and initialize the stubs mechanism; otherwise, simply setup
619 ** the function pointers provided by the caller with the statically linked
620 ** functions.
621 */
622 static int loadTcl(
623 Th_Interp *interp,
624 void **pLibrary,
625 tcl_FindExecutableProc **pxFindExecutable,
626 tcl_CreateInterpProc **pxCreateInterp,
627 tcl_DeleteInterpProc **pxDeleteInterp,
628 tcl_FinalizeProc **pxFinalize
629 ){
630 #if defined(USE_TCL_STUBS)
631 char fileName[] = TCL_LIBRARY_NAME;
632 #endif /* defined(USE_TCL_STUBS) */
633
634 if( !pLibrary || !pxFindExecutable || !pxCreateInterp ||
635 !pxDeleteInterp || !pxFinalize ){
636 Th_ErrorMessage(interp,
637 "invalid Tcl loader argument(s)", (const char *)"", 0);
638 return TH_ERROR;
639 }
640 #if defined(USE_TCL_STUBS)
@@ -631,10 +642,11 @@
642 void *library = dlopen(fileName, RTLD_NOW | RTLD_GLOBAL);
643 if( library ){
644 tcl_FindExecutableProc *xFindExecutable;
645 tcl_CreateInterpProc *xCreateInterp;
646 tcl_DeleteInterpProc *xDeleteInterp;
647 tcl_FinalizeProc *xFinalize;
648 const char *procName = TCL_FINDEXECUTABLE_NAME;
649 xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName + 1);
650 if( !xFindExecutable ){
651 xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName);
652 }
@@ -663,35 +675,49 @@
675 if( !xDeleteInterp ){
676 Th_ErrorMessage(interp,
677 "could not locate Tcl_DeleteInterp", (const char *)"", 0);
678 dlclose(library);
679 return TH_ERROR;
680 }
681 procName = TCL_FINALIZE_NAME;
682 xFinalize = (tcl_FinalizeProc *)dlsym(library, procName + 1);
683 if( !xFinalize ){
684 xFinalize = (tcl_FinalizeProc *)dlsym(library, procName);
685 }
686 if( !xFinalize ){
687 Th_ErrorMessage(interp,
688 "could not locate Tcl_Finalize", (const char *)"", 0);
689 dlclose(library);
690 return TH_ERROR;
691 }
692 *pLibrary = library;
693 *pxFindExecutable = xFindExecutable;
694 *pxCreateInterp = xCreateInterp;
695 *pxDeleteInterp = xDeleteInterp;
696 *pxFinalize = xFinalize;
697 return TH_OK;
698 }
699 } while( --fileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */
700 fileName[TCL_MINOR_OFFSET] = 'x';
701 Th_ErrorMessage(interp,
702 "could not load any supported Tcl 8.6, 8.5, or 8.4 shared library \"",
703 fileName, -1);
704 return TH_ERROR;
705 #else
706 *pLibrary = 0;
707 *pxFindExecutable = Tcl_FindExecutable;
708 *pxCreateInterp = Tcl_CreateInterp;
709 *pxDeleteInterp = Tcl_DeleteInterp;
710 *pxFinalize = Tcl_Finalize;
711 return TH_OK;
712 #endif /* defined(USE_TCL_STUBS) */
713 }
714
715 /*
716 ** Sets the "argv0", "argc", and "argv" script variables in the Tcl interpreter
717 ** based on the supplied command line arguments.
718 */
719 static int setTclArguments(
720 Tcl_Interp *pInterp,
721 int argc,
722 char **argv
723 ){
@@ -745,11 +771,11 @@
771
772 /*
773 ** Creates and initializes a Tcl interpreter for use with the specified TH1
774 ** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
775 ** by the caller.
776 */
777 static int createTclInterp(
778 Th_Interp *interp,
779 void *pContext
780 ){
781 struct TclContext *tclContext = (struct TclContext *)pContext;
@@ -766,11 +792,12 @@
792 }
793 if ( tclContext->interp ){
794 return TH_OK;
795 }
796 if( loadTcl(interp, &tclContext->library, &tclContext->xFindExecutable,
797 &tclContext->xCreateInterp, &tclContext->xDeleteInterp,
798 &tclContext->xFinalize)!=TH_OK ){
799 return TH_ERROR;
800 }
801 argc = tclContext->argc;
802 argv = tclContext->argv;
803 if( argc>0 && argv ){
@@ -820,10 +847,15 @@
847 "Tcl error setting arguments:", Tcl_GetStringResult(tclInterp), -1);
848 Tcl_DeleteInterp(tclInterp);
849 tclContext->interp = tclInterp = 0;
850 return TH_ERROR;
851 }
852 /*
853 ** Determine if an objProc can be called directly for a Tcl command invoked
854 ** via the tclInvoke TH1 command.
855 */
856 tclContext->useObjProc = canUseObjProc();
857 /* Add the TH1 integration commands to Tcl. */
858 Tcl_CallWhenDeleted(tclInterp, Th1DeleteProc, interp);
859 Tcl_CreateObjCommand(tclInterp, "th1Eval", Th1EvalObjCmd, interp, NULL);
860 Tcl_CreateObjCommand(tclInterp, "th1Expr", Th1ExprObjCmd, interp, NULL);
861 /* If necessary, evaluate the custom Tcl setup script. */
@@ -835,10 +867,68 @@
867 tclContext->interp = tclInterp = 0;
868 return TH_ERROR;
869 }
870 return TH_OK;
871 }
872
873 /*
874 ** Finalizes and unloads the previously loaded Tcl library, if applicable.
875 */
876 int unloadTcl(
877 Th_Interp *interp,
878 void *pContext
879 ){
880 struct TclContext *tclContext = (struct TclContext *)pContext;
881 Tcl_Interp *tclInterp;
882 tcl_FinalizeProc *xFinalize;
883 #if defined(USE_TCL_STUBS)
884 void *library;
885 #endif /* defined(USE_TCL_STUBS) */
886
887 if ( !tclContext ){
888 Th_ErrorMessage(interp,
889 "invalid Tcl context", (const char *)"", 0);
890 return TH_ERROR;
891 }
892 /*
893 ** Grab the Tcl_Finalize function pointer prior to deleting the Tcl
894 ** interpreter because the memory backing the Tcl stubs table will
895 ** be going away.
896 */
897 xFinalize = tclContext->xFinalize;
898 /*
899 ** If the Tcl interpreter has been created, formally delete it now.
900 */
901 tclInterp = tclContext->interp;
902 if ( tclInterp ){
903 Tcl_DeleteInterp(tclInterp);
904 tclContext->interp = tclInterp = 0;
905 }
906 /*
907 ** If the Tcl library is not finalized prior to unloading it, a deadlock
908 ** can occur in some circumstances (i.e. the [clock] thread is running).
909 */
910 if( xFinalize ) xFinalize();
911 #if defined(USE_TCL_STUBS)
912 /*
913 ** If Tcl is compiled on Windows using the latest MinGW, Fossil can crash
914 ** when exiting while a stubs-enabled Tcl is still loaded. This is due to
915 ** a bug in MinGW, see:
916 **
917 ** http://comments.gmane.org/gmane.comp.gnu.mingw.user/41724
918 **
919 ** The workaround is to manually unload the loaded Tcl library prior to
920 ** exiting the process.
921 */
922 library = tclContext->library;
923 if( library ){
924 dlclose(library);
925 tclContext->library = library = 0;
926 }
927 #endif /* defined(USE_TCL_STUBS) */
928 return TH_OK;
929 }
930
931 /*
932 ** Register the Tcl language commands with interpreter interp.
933 ** Usually this is called soon after interpreter creation.
934 */
935
+194 -24
--- src/timeline.c
+++ src/timeline.c
@@ -16,13 +16,13 @@
1616
*******************************************************************************
1717
**
1818
** This file contains code to implement the timeline web page
1919
**
2020
*/
21
+#include "config.h"
2122
#include <string.h>
2223
#include <time.h>
23
-#include "config.h"
2424
#include "timeline.h"
2525
2626
/*
2727
** Shorten a UUID so that is the minimum length needed to contain
2828
** at least one digit in the range 'a'..'f'. The minimum length is 10.
@@ -369,14 +369,18 @@
369369
zUuid, isLeaf);
370370
db_reset(&qbranch);
371371
@ <div id="m%d(gidx)"></div>
372372
}
373373
@</td>
374
+ @ <td class="timelineTableCell"
375
+ if( zTagList && zTagList[0] ){
376
+ @ class="%h(zTagList)"
377
+ }
374378
if( zBgClr && zBgClr[0] ){
375
- @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
379
+ @ style="background-color: %h(zBgClr);">
376380
}else{
377
- @ <td class="timelineTableCell">
381
+ @ >
378382
}
379383
if( pGraph && zType[0]!='c' ){
380384
@ &bull;
381385
}
382386
if( modPending ){
@@ -1159,12 +1163,12 @@
11591163
p = p->u.pTo;
11601164
}
11611165
blob_append(&sql, ")", -1);
11621166
path_reset();
11631167
blob_append(&desc, "All nodes on the path from ", -1);
1164
- blob_appendf(&desc, "%z%h</a>", href("%R/info/%h", zFrom), zFrom);
1165
- blob_append(&desc, " and ", -1);
1168
+ blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom);
1169
+ blob_append(&desc, " to ", -1);
11661170
blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
11671171
tmFlags |= TIMELINE_DISJOINT;
11681172
db_multi_exec("%s", blob_str(&sql));
11691173
}else if( (p_rid || d_rid) && g.perm.Read ){
11701174
/* If p= or d= is present, ignore all other parameters other than n= */
@@ -1850,10 +1854,154 @@
18501854
@ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
18511855
}
18521856
db_finalize(&q);
18531857
style_footer();
18541858
}
1859
+
1860
+
1861
+/*
1862
+** Used by stats_report_xxxxx() to remember which type of events
1863
+** to show. Populated by stats_report_init_view() and holds the
1864
+** return value of that function.
1865
+*/
1866
+static int statsReportType = 0;
1867
+
1868
+/*
1869
+** Set by stats_report_init_view() to one of the y=XXXX values
1870
+** accepted by /timeline?y=XXXX.
1871
+*/
1872
+static char const * statsReportTimelineYFlag = NULL;
1873
+
1874
+/*
1875
+** Creates a TEMP VIEW named v_reports which is a wrapper around the
1876
+** EVENT table filtered on event.type. It looks for the request
1877
+** parameter 'type' (reminder: we "should" use 'y' for consistency
1878
+** with /timeline, but /reports uses 'y' for the year) and expects it
1879
+** to contain one of the conventional values from event.type or the
1880
+** value "all", which is treated as equivalent to "*". By default (if
1881
+** no 'y' is specified), "*" is assumed (that is also the default for
1882
+** invalid/unknown filter values). That 'y' filter is the one used for
1883
+** the event list. Note that a filter of "*" or "all" is equivalent to
1884
+** querying against the full event table. The view, however, adds an
1885
+** abstraction level to simplify the implementation code for the
1886
+** various /reports pages.
1887
+**
1888
+** Returns one of: 'c', 'w', 'g', 't', 'e', representing the type of
1889
+** filter it applies, or '*' if no filter is applied (i.e. if "all" is
1890
+** used).
1891
+*/
1892
+static int stats_report_init_view(){
1893
+ char const * zType = PD("type","*"); /* analog to /timeline?y=... */
1894
+ char const * zRealType = NULL; /* normalized form of zType */
1895
+ int rc = 0; /* result code */
1896
+ assert( !statsReportType && "Must not be called more than once." );
1897
+ switch( (zType && *zType) ? *zType : 0 ){
1898
+ case 'c':
1899
+ case 'C':
1900
+ zRealType = "ci";
1901
+ rc = *zRealType;
1902
+ break;
1903
+ case 'e':
1904
+ case 'E':
1905
+ zRealType = "e";
1906
+ rc = *zRealType;
1907
+ break;
1908
+ case 'g':
1909
+ case 'G':
1910
+ zRealType = "g";
1911
+ rc = *zRealType;
1912
+ break;
1913
+ case 't':
1914
+ case 'T':
1915
+ zRealType = "t";
1916
+ rc = *zRealType;
1917
+ break;
1918
+ case 'w':
1919
+ case 'W':
1920
+ zRealType = "w";
1921
+ rc = *zRealType;
1922
+ break;
1923
+ default:
1924
+ rc = '*';
1925
+ break;
1926
+ }
1927
+ assert(0 != rc);
1928
+ if(zRealType){
1929
+ statsReportTimelineYFlag = zRealType;
1930
+ db_multi_exec("CREATE TEMP VIEW v_reports AS "
1931
+ "SELECT * FROM event WHERE type GLOB %Q",
1932
+ zRealType);
1933
+ }else{
1934
+ statsReportTimelineYFlag = "a";
1935
+ db_multi_exec("CREATE TEMP VIEW v_reports AS "
1936
+ "SELECT * FROM event");
1937
+ }
1938
+ return statsReportType = rc;
1939
+}
1940
+
1941
+/*
1942
+** Returns a string suitable (for a given value of suitable) for
1943
+** use in a label with the header of the /reports pages, dependent
1944
+** on the 'type' flag. See stats_report_init_view().
1945
+** The returned bytes are static.
1946
+*/
1947
+static char const * stats_report_label_for_type(){
1948
+ assert( statsReportType && "Must call stats_report_init_view() first." );
1949
+ switch( statsReportType ){
1950
+ case 'c':
1951
+ return "checkins";
1952
+ case 'w':
1953
+ return "wiki changes";
1954
+ case 't':
1955
+ return "ticket changes";
1956
+ case 'g':
1957
+ return "tag changes";
1958
+ default:
1959
+ return "all types";
1960
+ }
1961
+}
1962
+
1963
+/*
1964
+** A helper for the /reports family of pages which prints out a menu
1965
+** of links for the various type=XXX flags. zCurrentViewName must be
1966
+** the name/value of the 'view' parameter which is in effect at
1967
+** the time this is called. e.g. if called from the 'byuser' view
1968
+** then zCurrentViewName must be "byuser".
1969
+*/
1970
+static void stats_report_event_types_menu(char const * zCurrentViewName){
1971
+ char * zTop = mprintf("%s/reports?view=%s", g.zTop, zCurrentViewName);
1972
+ cgi_printf("<div>");
1973
+ cgi_printf("<span>Event types:</span> ");
1974
+ if('*' == statsReportType){
1975
+ cgi_printf(" <strong>all</strong>", zTop);
1976
+ }else{
1977
+ cgi_printf(" <a href='%s'>all</a>", zTop);
1978
+ }
1979
+ if('c' == statsReportType){
1980
+ cgi_printf(" <strong>checkins</strong>", zTop);
1981
+ }else{
1982
+ cgi_printf(" <a href='%s&type=ci'>checkins</a>", zTop);
1983
+ }
1984
+ if( 't' == statsReportType ){
1985
+ cgi_printf(" <strong>tickets</strong>", zTop);
1986
+ }else{
1987
+ cgi_printf(" <a href='%s&type=t'>tickets</a>", zTop);
1988
+ }
1989
+ if( 'g' == statsReportType ){
1990
+ cgi_printf(" <strong>tags</strong>", zTop);
1991
+ }else{
1992
+ cgi_printf(" <a href='%s&type=g'>tags</a>", zTop);
1993
+ }
1994
+ if( 'w' == statsReportType ){
1995
+ cgi_printf(" <strong>wiki</strong>", zTop);
1996
+ }else{
1997
+ cgi_printf(" <a href='%s&type=w'>wiki</a>", zTop);
1998
+ }
1999
+ fossil_free(zTop);
2000
+ cgi_printf("</div>");
2001
+}
2002
+
18552003
18562004
/*
18572005
** Helper for stats_report_by_month_year(), which generates a list of
18582006
** week numbers. zTimeframe should be either a timeframe in the form YYYY
18592007
** or YYYY-MM.
@@ -1864,22 +2012,22 @@
18642012
memcpy(yearPart, zTimeframe, 4);
18652013
db_prepare(&stWeek,
18662014
"SELECT DISTINCT strftime('%%W',mtime) AS wk, "
18672015
"count(*) AS n, "
18682016
"substr(date(mtime),1,%d) AS ym "
1869
- "FROM event "
2017
+ "FROM v_reports "
18702018
"WHERE ym=%Q AND mtime < current_timestamp "
18712019
"GROUP BY wk ORDER BY wk",
18722020
strlen(zTimeframe),
18732021
zTimeframe);
18742022
while( SQLITE_ROW == db_step(&stWeek) ){
18752023
const char * zWeek = db_column_text(&stWeek,0);
18762024
const int nCount = db_column_int(&stWeek,1);
18772025
cgi_printf("<a href='%s/timeline?"
1878
- "yw=%t-%t&n=%d'>%s</a>",
2026
+ "yw=%t-%t&n=%d&y=%s'>%s</a>",
18792027
g.zTop, yearPart, zWeek,
1880
- nCount, zWeek);
2028
+ nCount, statsReportTimelineYFlag, zWeek);
18812029
}
18822030
db_finalize(&stWeek);
18832031
}
18842032
18852033
/*
@@ -1908,16 +2056,19 @@
19082056
Blob header = empty_blob; /* Page header text */
19092057
int nMaxEvents = 1; /* for calculating length of graph
19102058
bars. */
19112059
int iterations = 0; /* number of weeks/months we iterate
19122060
over */
1913
- blob_appendf(&header, "Timeline Events by year%s",
2061
+ stats_report_init_view();
2062
+ stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear" );
2063
+ blob_appendf(&header, "Timeline Events (%s) by year%s",
2064
+ stats_report_label_for_type(),
19142065
(includeMonth ? "/month" : ""));
19152066
blob_appendf(&sql,
19162067
"SELECT substr(date(mtime),1,%d) AS timeframe, "
19172068
"count(*) AS eventCount "
1918
- "FROM event ",
2069
+ "FROM v_reports ",
19192070
includeMonth ? 7 : 4);
19202071
if(zUserName&&*zUserName){
19212072
blob_appendf(&sql, " WHERE user=%Q ", zUserName);
19222073
blob_appendf(&header," for user %q", zUserName);
19232074
}
@@ -1981,21 +2132,23 @@
19812132
nEventsPerYear += nCount;
19822133
@<tr class='row%d(rowClass)'>
19832134
@ <td>
19842135
if(includeMonth){
19852136
cgi_printf("<a href='%s/timeline?"
1986
- "ym=%t&n=%d",
1987
- g.zTop, zTimeframe, nCount );
2137
+ "ym=%t&n=%d&y=%s",
2138
+ g.zTop, zTimeframe, nCount,
2139
+ statsReportTimelineYFlag );
19882140
/* Reminder: n=nCount is not actually correct for bymonth unless
19892141
that was the only user who caused events.
19902142
*/
19912143
if( zUserName && *zUserName ){
19922144
cgi_printf("&u=%t", zUserName);
19932145
}
19942146
cgi_printf("' target='_new'>%s</a>",zTimeframe);
19952147
}else {
1996
- cgi_printf("<a href='?view=byweek&y=%s", zTimeframe);
2148
+ cgi_printf("<a href='?view=byweek&y=%s&type=%c",
2149
+ zTimeframe, (char)statsReportType);
19972150
if(zUserName && *zUserName){
19982151
cgi_printf("&u=%t", zUserName);
19992152
}
20002153
cgi_printf("'>%s</a>", zTimeframe);
20012154
}
@@ -2053,19 +2206,22 @@
20532206
int rowClass = 0; /* counter for alternating
20542207
row colors */
20552208
Blob sql = empty_blob; /* SQL */
20562209
int nMaxEvents = 1; /* max number of events for
20572210
all rows. */
2211
+ stats_report_init_view();
2212
+ stats_report_event_types_menu("byuser");
20582213
blob_append(&sql,
20592214
"SELECT user, "
20602215
"COUNT(*) AS eventCount "
2061
- "FROM event "
2216
+ "FROM v_reports "
20622217
"GROUP BY user ORDER BY eventCount DESC",
20632218
-1);
20642219
db_prepare(&query, blob_str(&sql));
20652220
blob_reset(&sql);
2066
- @ <h1>Timeline Events by User</h1>
2221
+ @ <h1>Timeline Events
2222
+ @ (%s(stats_report_label_for_type())) by User</h1>
20672223
@ <table class='statistics-report-table-events' border='0'
20682224
@ cellpadding='2' cellspacing='0' id='statsTable'>
20692225
@ <thead><tr>
20702226
@ <th>User</th>
20712227
@ <th>Events</th>
@@ -2087,11 +2243,11 @@
20872243
if(!nCount) continue /* arguable! Possible? */;
20882244
rowClass = ++nRowNumber % 2;
20892245
nEventTotal += nCount;
20902246
@<tr class='row%d(rowClass)'>
20912247
@ <td>
2092
- @ <a href="?view=bymonth&user=%h(zUser)">%h(zUser)</a>
2248
+ @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a>
20932249
@ </td><td>%d(nCount)</td>
20942250
@ <td>
20952251
@ <div class='statistics-report-graph-line'
20962252
@ style='height:16px;width:%d(nSize)%%;'>
20972253
@ </div></td>
@@ -2120,15 +2276,16 @@
21202276
char * zDefaultYear = NULL;
21212277
Blob sql = empty_blob;
21222278
int nMaxEvents = 1; /* max number of events for
21232279
all rows. */
21242280
int iterations = 0; /* # of active time periods. */
2125
-
2281
+ stats_report_init_view();
2282
+ stats_report_event_types_menu("byweek");
21262283
cgi_printf("Select year: ");
21272284
blob_append(&sql,
21282285
"SELECT DISTINCT substr(date(mtime),1,4) AS y "
2129
- "FROM event WHERE 1 ", -1);
2286
+ "FROM v_reports WHERE 1 ", -1);
21302287
if(zUserName&&*zUserName){
21312288
blob_appendf(&sql,"AND user=%Q ", zUserName);
21322289
}
21332290
blob_append(&sql,"GROUP BY y ORDER BY y", -1);
21342291
db_prepare(&qYears, blob_str(&sql));
@@ -2136,11 +2293,12 @@
21362293
while( SQLITE_ROW == db_step(&qYears) ){
21372294
const char * zT = db_column_text(&qYears, 0);
21382295
if( i++ ){
21392296
cgi_printf(" ");
21402297
}
2141
- cgi_printf("<a href='?view=byweek&y=%s", zT);
2298
+ cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT,
2299
+ (char)statsReportType);
21422300
if(zUserName && *zUserName){
21432301
cgi_printf("&user=%t",zUserName);
21442302
}
21452303
cgi_printf("'>%s</a>",zT);
21462304
}
@@ -2154,16 +2312,17 @@
21542312
if(4 == nYear){
21552313
Stmt stWeek = empty_Stmt;
21562314
int rowCount = 0;
21572315
int total = 0;
21582316
Blob header = empty_blob;
2159
- blob_appendf(&header, "Timeline events for the calendar weeks "
2160
- "of %h", zYear);
2317
+ blob_appendf(&header, "Timeline events (%s) for the calendar weeks "
2318
+ "of %h", stats_report_label_for_type(),
2319
+ zYear);
21612320
blob_appendf(&sql,
21622321
"SELECT DISTINCT strftime('%%%%W',mtime) AS wk, "
21632322
"count(*) AS n "
2164
- "FROM event "
2323
+ "FROM v_reports "
21652324
"WHERE %Q=substr(date(mtime),1,4) "
21662325
"AND mtime < current_timestamp ",
21672326
zYear);
21682327
if(zUserName&&*zUserName){
21692328
blob_appendf(&sql, " AND user=%Q ", zUserName);
@@ -2197,12 +2356,13 @@
21972356
const int nSize = nCount
21982357
? (int)(100 * nCount / nMaxEvents)
21992358
: 0;
22002359
total += nCount;
22012360
cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2202
- cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d",
2203
- g.zTop, zYear, zWeek, nCount);
2361
+ cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s",
2362
+ g.zTop, zYear, zWeek, nCount,
2363
+ statsReportTimelineYFlag);
22042364
if(zUserName && *zUserName){
22052365
cgi_printf("&u=%t",zUserName);
22062366
}
22072367
cgi_printf("'>%s</a></td>",zWeek);
22082368
@@ -2235,10 +2395,20 @@
22352395
**
22362396
** Query Parameters:
22372397
**
22382398
** view=REPORT_NAME Valid values: bymonth, byyear, byuser
22392399
** user=NAME Restricts statistics to the given user
2400
+** type=TYPE Restricts the report to a specific event type:
2401
+** ci (checkin), w (wiki), t (ticket), g (tag)
2402
+** Defaulting to all event types.
2403
+**
2404
+** The view-specific query parameters include:
2405
+**
2406
+** view=byweek:
2407
+**
2408
+** y=YYYY The year to report (default is the server's
2409
+** current year).
22402410
*/
22412411
void stats_report_page(){
22422412
HQuery url; /* URL for various branch links */
22432413
const char * zView = P("view"); /* Which view/report to show. */
22442414
const char *zUserName = P("user");
22452415
--- src/timeline.c
+++ src/timeline.c
@@ -16,13 +16,13 @@
16 *******************************************************************************
17 **
18 ** This file contains code to implement the timeline web page
19 **
20 */
 
21 #include <string.h>
22 #include <time.h>
23 #include "config.h"
24 #include "timeline.h"
25
26 /*
27 ** Shorten a UUID so that is the minimum length needed to contain
28 ** at least one digit in the range 'a'..'f'. The minimum length is 10.
@@ -369,14 +369,18 @@
369 zUuid, isLeaf);
370 db_reset(&qbranch);
371 @ <div id="m%d(gidx)"></div>
372 }
373 @</td>
 
 
 
 
374 if( zBgClr && zBgClr[0] ){
375 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
376 }else{
377 @ <td class="timelineTableCell">
378 }
379 if( pGraph && zType[0]!='c' ){
380 @ &bull;
381 }
382 if( modPending ){
@@ -1159,12 +1163,12 @@
1159 p = p->u.pTo;
1160 }
1161 blob_append(&sql, ")", -1);
1162 path_reset();
1163 blob_append(&desc, "All nodes on the path from ", -1);
1164 blob_appendf(&desc, "%z%h</a>", href("%R/info/%h", zFrom), zFrom);
1165 blob_append(&desc, " and ", -1);
1166 blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
1167 tmFlags |= TIMELINE_DISJOINT;
1168 db_multi_exec("%s", blob_str(&sql));
1169 }else if( (p_rid || d_rid) && g.perm.Read ){
1170 /* If p= or d= is present, ignore all other parameters other than n= */
@@ -1850,10 +1854,154 @@
1850 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1851 }
1852 db_finalize(&q);
1853 style_footer();
1854 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1855
1856 /*
1857 ** Helper for stats_report_by_month_year(), which generates a list of
1858 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
1859 ** or YYYY-MM.
@@ -1864,22 +2012,22 @@
1864 memcpy(yearPart, zTimeframe, 4);
1865 db_prepare(&stWeek,
1866 "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
1867 "count(*) AS n, "
1868 "substr(date(mtime),1,%d) AS ym "
1869 "FROM event "
1870 "WHERE ym=%Q AND mtime < current_timestamp "
1871 "GROUP BY wk ORDER BY wk",
1872 strlen(zTimeframe),
1873 zTimeframe);
1874 while( SQLITE_ROW == db_step(&stWeek) ){
1875 const char * zWeek = db_column_text(&stWeek,0);
1876 const int nCount = db_column_int(&stWeek,1);
1877 cgi_printf("<a href='%s/timeline?"
1878 "yw=%t-%t&n=%d'>%s</a>",
1879 g.zTop, yearPart, zWeek,
1880 nCount, zWeek);
1881 }
1882 db_finalize(&stWeek);
1883 }
1884
1885 /*
@@ -1908,16 +2056,19 @@
1908 Blob header = empty_blob; /* Page header text */
1909 int nMaxEvents = 1; /* for calculating length of graph
1910 bars. */
1911 int iterations = 0; /* number of weeks/months we iterate
1912 over */
1913 blob_appendf(&header, "Timeline Events by year%s",
 
 
 
1914 (includeMonth ? "/month" : ""));
1915 blob_appendf(&sql,
1916 "SELECT substr(date(mtime),1,%d) AS timeframe, "
1917 "count(*) AS eventCount "
1918 "FROM event ",
1919 includeMonth ? 7 : 4);
1920 if(zUserName&&*zUserName){
1921 blob_appendf(&sql, " WHERE user=%Q ", zUserName);
1922 blob_appendf(&header," for user %q", zUserName);
1923 }
@@ -1981,21 +2132,23 @@
1981 nEventsPerYear += nCount;
1982 @<tr class='row%d(rowClass)'>
1983 @ <td>
1984 if(includeMonth){
1985 cgi_printf("<a href='%s/timeline?"
1986 "ym=%t&n=%d",
1987 g.zTop, zTimeframe, nCount );
 
1988 /* Reminder: n=nCount is not actually correct for bymonth unless
1989 that was the only user who caused events.
1990 */
1991 if( zUserName && *zUserName ){
1992 cgi_printf("&u=%t", zUserName);
1993 }
1994 cgi_printf("' target='_new'>%s</a>",zTimeframe);
1995 }else {
1996 cgi_printf("<a href='?view=byweek&y=%s", zTimeframe);
 
1997 if(zUserName && *zUserName){
1998 cgi_printf("&u=%t", zUserName);
1999 }
2000 cgi_printf("'>%s</a>", zTimeframe);
2001 }
@@ -2053,19 +2206,22 @@
2053 int rowClass = 0; /* counter for alternating
2054 row colors */
2055 Blob sql = empty_blob; /* SQL */
2056 int nMaxEvents = 1; /* max number of events for
2057 all rows. */
 
 
2058 blob_append(&sql,
2059 "SELECT user, "
2060 "COUNT(*) AS eventCount "
2061 "FROM event "
2062 "GROUP BY user ORDER BY eventCount DESC",
2063 -1);
2064 db_prepare(&query, blob_str(&sql));
2065 blob_reset(&sql);
2066 @ <h1>Timeline Events by User</h1>
 
2067 @ <table class='statistics-report-table-events' border='0'
2068 @ cellpadding='2' cellspacing='0' id='statsTable'>
2069 @ <thead><tr>
2070 @ <th>User</th>
2071 @ <th>Events</th>
@@ -2087,11 +2243,11 @@
2087 if(!nCount) continue /* arguable! Possible? */;
2088 rowClass = ++nRowNumber % 2;
2089 nEventTotal += nCount;
2090 @<tr class='row%d(rowClass)'>
2091 @ <td>
2092 @ <a href="?view=bymonth&user=%h(zUser)">%h(zUser)</a>
2093 @ </td><td>%d(nCount)</td>
2094 @ <td>
2095 @ <div class='statistics-report-graph-line'
2096 @ style='height:16px;width:%d(nSize)%%;'>
2097 @ </div></td>
@@ -2120,15 +2276,16 @@
2120 char * zDefaultYear = NULL;
2121 Blob sql = empty_blob;
2122 int nMaxEvents = 1; /* max number of events for
2123 all rows. */
2124 int iterations = 0; /* # of active time periods. */
2125
 
2126 cgi_printf("Select year: ");
2127 blob_append(&sql,
2128 "SELECT DISTINCT substr(date(mtime),1,4) AS y "
2129 "FROM event WHERE 1 ", -1);
2130 if(zUserName&&*zUserName){
2131 blob_appendf(&sql,"AND user=%Q ", zUserName);
2132 }
2133 blob_append(&sql,"GROUP BY y ORDER BY y", -1);
2134 db_prepare(&qYears, blob_str(&sql));
@@ -2136,11 +2293,12 @@
2136 while( SQLITE_ROW == db_step(&qYears) ){
2137 const char * zT = db_column_text(&qYears, 0);
2138 if( i++ ){
2139 cgi_printf(" ");
2140 }
2141 cgi_printf("<a href='?view=byweek&y=%s", zT);
 
2142 if(zUserName && *zUserName){
2143 cgi_printf("&user=%t",zUserName);
2144 }
2145 cgi_printf("'>%s</a>",zT);
2146 }
@@ -2154,16 +2312,17 @@
2154 if(4 == nYear){
2155 Stmt stWeek = empty_Stmt;
2156 int rowCount = 0;
2157 int total = 0;
2158 Blob header = empty_blob;
2159 blob_appendf(&header, "Timeline events for the calendar weeks "
2160 "of %h", zYear);
 
2161 blob_appendf(&sql,
2162 "SELECT DISTINCT strftime('%%%%W',mtime) AS wk, "
2163 "count(*) AS n "
2164 "FROM event "
2165 "WHERE %Q=substr(date(mtime),1,4) "
2166 "AND mtime < current_timestamp ",
2167 zYear);
2168 if(zUserName&&*zUserName){
2169 blob_appendf(&sql, " AND user=%Q ", zUserName);
@@ -2197,12 +2356,13 @@
2197 const int nSize = nCount
2198 ? (int)(100 * nCount / nMaxEvents)
2199 : 0;
2200 total += nCount;
2201 cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2202 cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d",
2203 g.zTop, zYear, zWeek, nCount);
 
2204 if(zUserName && *zUserName){
2205 cgi_printf("&u=%t",zUserName);
2206 }
2207 cgi_printf("'>%s</a></td>",zWeek);
2208
@@ -2235,10 +2395,20 @@
2235 **
2236 ** Query Parameters:
2237 **
2238 ** view=REPORT_NAME Valid values: bymonth, byyear, byuser
2239 ** user=NAME Restricts statistics to the given user
 
 
 
 
 
 
 
 
 
 
2240 */
2241 void stats_report_page(){
2242 HQuery url; /* URL for various branch links */
2243 const char * zView = P("view"); /* Which view/report to show. */
2244 const char *zUserName = P("user");
2245
--- src/timeline.c
+++ src/timeline.c
@@ -16,13 +16,13 @@
16 *******************************************************************************
17 **
18 ** This file contains code to implement the timeline web page
19 **
20 */
21 #include "config.h"
22 #include <string.h>
23 #include <time.h>
 
24 #include "timeline.h"
25
26 /*
27 ** Shorten a UUID so that is the minimum length needed to contain
28 ** at least one digit in the range 'a'..'f'. The minimum length is 10.
@@ -369,14 +369,18 @@
369 zUuid, isLeaf);
370 db_reset(&qbranch);
371 @ <div id="m%d(gidx)"></div>
372 }
373 @</td>
374 @ <td class="timelineTableCell"
375 if( zTagList && zTagList[0] ){
376 @ class="%h(zTagList)"
377 }
378 if( zBgClr && zBgClr[0] ){
379 @ style="background-color: %h(zBgClr);">
380 }else{
381 @ >
382 }
383 if( pGraph && zType[0]!='c' ){
384 @ &bull;
385 }
386 if( modPending ){
@@ -1159,12 +1163,12 @@
1163 p = p->u.pTo;
1164 }
1165 blob_append(&sql, ")", -1);
1166 path_reset();
1167 blob_append(&desc, "All nodes on the path from ", -1);
1168 blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom);
1169 blob_append(&desc, " to ", -1);
1170 blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
1171 tmFlags |= TIMELINE_DISJOINT;
1172 db_multi_exec("%s", blob_str(&sql));
1173 }else if( (p_rid || d_rid) && g.perm.Read ){
1174 /* If p= or d= is present, ignore all other parameters other than n= */
@@ -1850,10 +1854,154 @@
1854 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1855 }
1856 db_finalize(&q);
1857 style_footer();
1858 }
1859
1860
1861 /*
1862 ** Used by stats_report_xxxxx() to remember which type of events
1863 ** to show. Populated by stats_report_init_view() and holds the
1864 ** return value of that function.
1865 */
1866 static int statsReportType = 0;
1867
1868 /*
1869 ** Set by stats_report_init_view() to one of the y=XXXX values
1870 ** accepted by /timeline?y=XXXX.
1871 */
1872 static char const * statsReportTimelineYFlag = NULL;
1873
1874 /*
1875 ** Creates a TEMP VIEW named v_reports which is a wrapper around the
1876 ** EVENT table filtered on event.type. It looks for the request
1877 ** parameter 'type' (reminder: we "should" use 'y' for consistency
1878 ** with /timeline, but /reports uses 'y' for the year) and expects it
1879 ** to contain one of the conventional values from event.type or the
1880 ** value "all", which is treated as equivalent to "*". By default (if
1881 ** no 'y' is specified), "*" is assumed (that is also the default for
1882 ** invalid/unknown filter values). That 'y' filter is the one used for
1883 ** the event list. Note that a filter of "*" or "all" is equivalent to
1884 ** querying against the full event table. The view, however, adds an
1885 ** abstraction level to simplify the implementation code for the
1886 ** various /reports pages.
1887 **
1888 ** Returns one of: 'c', 'w', 'g', 't', 'e', representing the type of
1889 ** filter it applies, or '*' if no filter is applied (i.e. if "all" is
1890 ** used).
1891 */
1892 static int stats_report_init_view(){
1893 char const * zType = PD("type","*"); /* analog to /timeline?y=... */
1894 char const * zRealType = NULL; /* normalized form of zType */
1895 int rc = 0; /* result code */
1896 assert( !statsReportType && "Must not be called more than once." );
1897 switch( (zType && *zType) ? *zType : 0 ){
1898 case 'c':
1899 case 'C':
1900 zRealType = "ci";
1901 rc = *zRealType;
1902 break;
1903 case 'e':
1904 case 'E':
1905 zRealType = "e";
1906 rc = *zRealType;
1907 break;
1908 case 'g':
1909 case 'G':
1910 zRealType = "g";
1911 rc = *zRealType;
1912 break;
1913 case 't':
1914 case 'T':
1915 zRealType = "t";
1916 rc = *zRealType;
1917 break;
1918 case 'w':
1919 case 'W':
1920 zRealType = "w";
1921 rc = *zRealType;
1922 break;
1923 default:
1924 rc = '*';
1925 break;
1926 }
1927 assert(0 != rc);
1928 if(zRealType){
1929 statsReportTimelineYFlag = zRealType;
1930 db_multi_exec("CREATE TEMP VIEW v_reports AS "
1931 "SELECT * FROM event WHERE type GLOB %Q",
1932 zRealType);
1933 }else{
1934 statsReportTimelineYFlag = "a";
1935 db_multi_exec("CREATE TEMP VIEW v_reports AS "
1936 "SELECT * FROM event");
1937 }
1938 return statsReportType = rc;
1939 }
1940
1941 /*
1942 ** Returns a string suitable (for a given value of suitable) for
1943 ** use in a label with the header of the /reports pages, dependent
1944 ** on the 'type' flag. See stats_report_init_view().
1945 ** The returned bytes are static.
1946 */
1947 static char const * stats_report_label_for_type(){
1948 assert( statsReportType && "Must call stats_report_init_view() first." );
1949 switch( statsReportType ){
1950 case 'c':
1951 return "checkins";
1952 case 'w':
1953 return "wiki changes";
1954 case 't':
1955 return "ticket changes";
1956 case 'g':
1957 return "tag changes";
1958 default:
1959 return "all types";
1960 }
1961 }
1962
1963 /*
1964 ** A helper for the /reports family of pages which prints out a menu
1965 ** of links for the various type=XXX flags. zCurrentViewName must be
1966 ** the name/value of the 'view' parameter which is in effect at
1967 ** the time this is called. e.g. if called from the 'byuser' view
1968 ** then zCurrentViewName must be "byuser".
1969 */
1970 static void stats_report_event_types_menu(char const * zCurrentViewName){
1971 char * zTop = mprintf("%s/reports?view=%s", g.zTop, zCurrentViewName);
1972 cgi_printf("<div>");
1973 cgi_printf("<span>Event types:</span> ");
1974 if('*' == statsReportType){
1975 cgi_printf(" <strong>all</strong>", zTop);
1976 }else{
1977 cgi_printf(" <a href='%s'>all</a>", zTop);
1978 }
1979 if('c' == statsReportType){
1980 cgi_printf(" <strong>checkins</strong>", zTop);
1981 }else{
1982 cgi_printf(" <a href='%s&type=ci'>checkins</a>", zTop);
1983 }
1984 if( 't' == statsReportType ){
1985 cgi_printf(" <strong>tickets</strong>", zTop);
1986 }else{
1987 cgi_printf(" <a href='%s&type=t'>tickets</a>", zTop);
1988 }
1989 if( 'g' == statsReportType ){
1990 cgi_printf(" <strong>tags</strong>", zTop);
1991 }else{
1992 cgi_printf(" <a href='%s&type=g'>tags</a>", zTop);
1993 }
1994 if( 'w' == statsReportType ){
1995 cgi_printf(" <strong>wiki</strong>", zTop);
1996 }else{
1997 cgi_printf(" <a href='%s&type=w'>wiki</a>", zTop);
1998 }
1999 fossil_free(zTop);
2000 cgi_printf("</div>");
2001 }
2002
2003
2004 /*
2005 ** Helper for stats_report_by_month_year(), which generates a list of
2006 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
2007 ** or YYYY-MM.
@@ -1864,22 +2012,22 @@
2012 memcpy(yearPart, zTimeframe, 4);
2013 db_prepare(&stWeek,
2014 "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
2015 "count(*) AS n, "
2016 "substr(date(mtime),1,%d) AS ym "
2017 "FROM v_reports "
2018 "WHERE ym=%Q AND mtime < current_timestamp "
2019 "GROUP BY wk ORDER BY wk",
2020 strlen(zTimeframe),
2021 zTimeframe);
2022 while( SQLITE_ROW == db_step(&stWeek) ){
2023 const char * zWeek = db_column_text(&stWeek,0);
2024 const int nCount = db_column_int(&stWeek,1);
2025 cgi_printf("<a href='%s/timeline?"
2026 "yw=%t-%t&n=%d&y=%s'>%s</a>",
2027 g.zTop, yearPart, zWeek,
2028 nCount, statsReportTimelineYFlag, zWeek);
2029 }
2030 db_finalize(&stWeek);
2031 }
2032
2033 /*
@@ -1908,16 +2056,19 @@
2056 Blob header = empty_blob; /* Page header text */
2057 int nMaxEvents = 1; /* for calculating length of graph
2058 bars. */
2059 int iterations = 0; /* number of weeks/months we iterate
2060 over */
2061 stats_report_init_view();
2062 stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear" );
2063 blob_appendf(&header, "Timeline Events (%s) by year%s",
2064 stats_report_label_for_type(),
2065 (includeMonth ? "/month" : ""));
2066 blob_appendf(&sql,
2067 "SELECT substr(date(mtime),1,%d) AS timeframe, "
2068 "count(*) AS eventCount "
2069 "FROM v_reports ",
2070 includeMonth ? 7 : 4);
2071 if(zUserName&&*zUserName){
2072 blob_appendf(&sql, " WHERE user=%Q ", zUserName);
2073 blob_appendf(&header," for user %q", zUserName);
2074 }
@@ -1981,21 +2132,23 @@
2132 nEventsPerYear += nCount;
2133 @<tr class='row%d(rowClass)'>
2134 @ <td>
2135 if(includeMonth){
2136 cgi_printf("<a href='%s/timeline?"
2137 "ym=%t&n=%d&y=%s",
2138 g.zTop, zTimeframe, nCount,
2139 statsReportTimelineYFlag );
2140 /* Reminder: n=nCount is not actually correct for bymonth unless
2141 that was the only user who caused events.
2142 */
2143 if( zUserName && *zUserName ){
2144 cgi_printf("&u=%t", zUserName);
2145 }
2146 cgi_printf("' target='_new'>%s</a>",zTimeframe);
2147 }else {
2148 cgi_printf("<a href='?view=byweek&y=%s&type=%c",
2149 zTimeframe, (char)statsReportType);
2150 if(zUserName && *zUserName){
2151 cgi_printf("&u=%t", zUserName);
2152 }
2153 cgi_printf("'>%s</a>", zTimeframe);
2154 }
@@ -2053,19 +2206,22 @@
2206 int rowClass = 0; /* counter for alternating
2207 row colors */
2208 Blob sql = empty_blob; /* SQL */
2209 int nMaxEvents = 1; /* max number of events for
2210 all rows. */
2211 stats_report_init_view();
2212 stats_report_event_types_menu("byuser");
2213 blob_append(&sql,
2214 "SELECT user, "
2215 "COUNT(*) AS eventCount "
2216 "FROM v_reports "
2217 "GROUP BY user ORDER BY eventCount DESC",
2218 -1);
2219 db_prepare(&query, blob_str(&sql));
2220 blob_reset(&sql);
2221 @ <h1>Timeline Events
2222 @ (%s(stats_report_label_for_type())) by User</h1>
2223 @ <table class='statistics-report-table-events' border='0'
2224 @ cellpadding='2' cellspacing='0' id='statsTable'>
2225 @ <thead><tr>
2226 @ <th>User</th>
2227 @ <th>Events</th>
@@ -2087,11 +2243,11 @@
2243 if(!nCount) continue /* arguable! Possible? */;
2244 rowClass = ++nRowNumber % 2;
2245 nEventTotal += nCount;
2246 @<tr class='row%d(rowClass)'>
2247 @ <td>
2248 @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a>
2249 @ </td><td>%d(nCount)</td>
2250 @ <td>
2251 @ <div class='statistics-report-graph-line'
2252 @ style='height:16px;width:%d(nSize)%%;'>
2253 @ </div></td>
@@ -2120,15 +2276,16 @@
2276 char * zDefaultYear = NULL;
2277 Blob sql = empty_blob;
2278 int nMaxEvents = 1; /* max number of events for
2279 all rows. */
2280 int iterations = 0; /* # of active time periods. */
2281 stats_report_init_view();
2282 stats_report_event_types_menu("byweek");
2283 cgi_printf("Select year: ");
2284 blob_append(&sql,
2285 "SELECT DISTINCT substr(date(mtime),1,4) AS y "
2286 "FROM v_reports WHERE 1 ", -1);
2287 if(zUserName&&*zUserName){
2288 blob_appendf(&sql,"AND user=%Q ", zUserName);
2289 }
2290 blob_append(&sql,"GROUP BY y ORDER BY y", -1);
2291 db_prepare(&qYears, blob_str(&sql));
@@ -2136,11 +2293,12 @@
2293 while( SQLITE_ROW == db_step(&qYears) ){
2294 const char * zT = db_column_text(&qYears, 0);
2295 if( i++ ){
2296 cgi_printf(" ");
2297 }
2298 cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT,
2299 (char)statsReportType);
2300 if(zUserName && *zUserName){
2301 cgi_printf("&user=%t",zUserName);
2302 }
2303 cgi_printf("'>%s</a>",zT);
2304 }
@@ -2154,16 +2312,17 @@
2312 if(4 == nYear){
2313 Stmt stWeek = empty_Stmt;
2314 int rowCount = 0;
2315 int total = 0;
2316 Blob header = empty_blob;
2317 blob_appendf(&header, "Timeline events (%s) for the calendar weeks "
2318 "of %h", stats_report_label_for_type(),
2319 zYear);
2320 blob_appendf(&sql,
2321 "SELECT DISTINCT strftime('%%%%W',mtime) AS wk, "
2322 "count(*) AS n "
2323 "FROM v_reports "
2324 "WHERE %Q=substr(date(mtime),1,4) "
2325 "AND mtime < current_timestamp ",
2326 zYear);
2327 if(zUserName&&*zUserName){
2328 blob_appendf(&sql, " AND user=%Q ", zUserName);
@@ -2197,12 +2356,13 @@
2356 const int nSize = nCount
2357 ? (int)(100 * nCount / nMaxEvents)
2358 : 0;
2359 total += nCount;
2360 cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2361 cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s",
2362 g.zTop, zYear, zWeek, nCount,
2363 statsReportTimelineYFlag);
2364 if(zUserName && *zUserName){
2365 cgi_printf("&u=%t",zUserName);
2366 }
2367 cgi_printf("'>%s</a></td>",zWeek);
2368
@@ -2235,10 +2395,20 @@
2395 **
2396 ** Query Parameters:
2397 **
2398 ** view=REPORT_NAME Valid values: bymonth, byyear, byuser
2399 ** user=NAME Restricts statistics to the given user
2400 ** type=TYPE Restricts the report to a specific event type:
2401 ** ci (checkin), w (wiki), t (ticket), g (tag)
2402 ** Defaulting to all event types.
2403 **
2404 ** The view-specific query parameters include:
2405 **
2406 ** view=byweek:
2407 **
2408 ** y=YYYY The year to report (default is the server's
2409 ** current year).
2410 */
2411 void stats_report_page(){
2412 HQuery url; /* URL for various branch links */
2413 const char * zView = P("view"); /* Which view/report to show. */
2414 const char *zUserName = P("user");
2415
+194 -24
--- src/timeline.c
+++ src/timeline.c
@@ -16,13 +16,13 @@
1616
*******************************************************************************
1717
**
1818
** This file contains code to implement the timeline web page
1919
**
2020
*/
21
+#include "config.h"
2122
#include <string.h>
2223
#include <time.h>
23
-#include "config.h"
2424
#include "timeline.h"
2525
2626
/*
2727
** Shorten a UUID so that is the minimum length needed to contain
2828
** at least one digit in the range 'a'..'f'. The minimum length is 10.
@@ -369,14 +369,18 @@
369369
zUuid, isLeaf);
370370
db_reset(&qbranch);
371371
@ <div id="m%d(gidx)"></div>
372372
}
373373
@</td>
374
+ @ <td class="timelineTableCell"
375
+ if( zTagList && zTagList[0] ){
376
+ @ class="%h(zTagList)"
377
+ }
374378
if( zBgClr && zBgClr[0] ){
375
- @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
379
+ @ style="background-color: %h(zBgClr);">
376380
}else{
377
- @ <td class="timelineTableCell">
381
+ @ >
378382
}
379383
if( pGraph && zType[0]!='c' ){
380384
@ &bull;
381385
}
382386
if( modPending ){
@@ -1159,12 +1163,12 @@
11591163
p = p->u.pTo;
11601164
}
11611165
blob_append(&sql, ")", -1);
11621166
path_reset();
11631167
blob_append(&desc, "All nodes on the path from ", -1);
1164
- blob_appendf(&desc, "%z%h</a>", href("%R/info/%h", zFrom), zFrom);
1165
- blob_append(&desc, " and ", -1);
1168
+ blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom);
1169
+ blob_append(&desc, " to ", -1);
11661170
blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
11671171
tmFlags |= TIMELINE_DISJOINT;
11681172
db_multi_exec("%s", blob_str(&sql));
11691173
}else if( (p_rid || d_rid) && g.perm.Read ){
11701174
/* If p= or d= is present, ignore all other parameters other than n= */
@@ -1850,10 +1854,154 @@
18501854
@ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
18511855
}
18521856
db_finalize(&q);
18531857
style_footer();
18541858
}
1859
+
1860
+
1861
+/*
1862
+** Used by stats_report_xxxxx() to remember which type of events
1863
+** to show. Populated by stats_report_init_view() and holds the
1864
+** return value of that function.
1865
+*/
1866
+static int statsReportType = 0;
1867
+
1868
+/*
1869
+** Set by stats_report_init_view() to one of the y=XXXX values
1870
+** accepted by /timeline?y=XXXX.
1871
+*/
1872
+static char const * statsReportTimelineYFlag = NULL;
1873
+
1874
+/*
1875
+** Creates a TEMP VIEW named v_reports which is a wrapper around the
1876
+** EVENT table filtered on event.type. It looks for the request
1877
+** parameter 'type' (reminder: we "should" use 'y' for consistency
1878
+** with /timeline, but /reports uses 'y' for the year) and expects it
1879
+** to contain one of the conventional values from event.type or the
1880
+** value "all", which is treated as equivalent to "*". By default (if
1881
+** no 'y' is specified), "*" is assumed (that is also the default for
1882
+** invalid/unknown filter values). That 'y' filter is the one used for
1883
+** the event list. Note that a filter of "*" or "all" is equivalent to
1884
+** querying against the full event table. The view, however, adds an
1885
+** abstraction level to simplify the implementation code for the
1886
+** various /reports pages.
1887
+**
1888
+** Returns one of: 'c', 'w', 'g', 't', 'e', representing the type of
1889
+** filter it applies, or '*' if no filter is applied (i.e. if "all" is
1890
+** used).
1891
+*/
1892
+static int stats_report_init_view(){
1893
+ char const * zType = PD("type","*"); /* analog to /timeline?y=... */
1894
+ char const * zRealType = NULL; /* normalized form of zType */
1895
+ int rc = 0; /* result code */
1896
+ assert( !statsReportType && "Must not be called more than once." );
1897
+ switch( (zType && *zType) ? *zType : 0 ){
1898
+ case 'c':
1899
+ case 'C':
1900
+ zRealType = "ci";
1901
+ rc = *zRealType;
1902
+ break;
1903
+ case 'e':
1904
+ case 'E':
1905
+ zRealType = "e";
1906
+ rc = *zRealType;
1907
+ break;
1908
+ case 'g':
1909
+ case 'G':
1910
+ zRealType = "g";
1911
+ rc = *zRealType;
1912
+ break;
1913
+ case 't':
1914
+ case 'T':
1915
+ zRealType = "t";
1916
+ rc = *zRealType;
1917
+ break;
1918
+ case 'w':
1919
+ case 'W':
1920
+ zRealType = "w";
1921
+ rc = *zRealType;
1922
+ break;
1923
+ default:
1924
+ rc = '*';
1925
+ break;
1926
+ }
1927
+ assert(0 != rc);
1928
+ if(zRealType){
1929
+ statsReportTimelineYFlag = zRealType;
1930
+ db_multi_exec("CREATE TEMP VIEW v_reports AS "
1931
+ "SELECT * FROM event WHERE type GLOB %Q",
1932
+ zRealType);
1933
+ }else{
1934
+ statsReportTimelineYFlag = "a";
1935
+ db_multi_exec("CREATE TEMP VIEW v_reports AS "
1936
+ "SELECT * FROM event");
1937
+ }
1938
+ return statsReportType = rc;
1939
+}
1940
+
1941
+/*
1942
+** Returns a string suitable (for a given value of suitable) for
1943
+** use in a label with the header of the /reports pages, dependent
1944
+** on the 'type' flag. See stats_report_init_view().
1945
+** The returned bytes are static.
1946
+*/
1947
+static char const * stats_report_label_for_type(){
1948
+ assert( statsReportType && "Must call stats_report_init_view() first." );
1949
+ switch( statsReportType ){
1950
+ case 'c':
1951
+ return "checkins";
1952
+ case 'w':
1953
+ return "wiki changes";
1954
+ case 't':
1955
+ return "ticket changes";
1956
+ case 'g':
1957
+ return "tag changes";
1958
+ default:
1959
+ return "all types";
1960
+ }
1961
+}
1962
+
1963
+/*
1964
+** A helper for the /reports family of pages which prints out a menu
1965
+** of links for the various type=XXX flags. zCurrentViewName must be
1966
+** the name/value of the 'view' parameter which is in effect at
1967
+** the time this is called. e.g. if called from the 'byuser' view
1968
+** then zCurrentViewName must be "byuser".
1969
+*/
1970
+static void stats_report_event_types_menu(char const * zCurrentViewName){
1971
+ char * zTop = mprintf("%s/reports?view=%s", g.zTop, zCurrentViewName);
1972
+ cgi_printf("<div>");
1973
+ cgi_printf("<span>Event types:</span> ");
1974
+ if('*' == statsReportType){
1975
+ cgi_printf(" <strong>all</strong>", zTop);
1976
+ }else{
1977
+ cgi_printf(" <a href='%s'>all</a>", zTop);
1978
+ }
1979
+ if('c' == statsReportType){
1980
+ cgi_printf(" <strong>checkins</strong>", zTop);
1981
+ }else{
1982
+ cgi_printf(" <a href='%s&type=ci'>checkins</a>", zTop);
1983
+ }
1984
+ if( 't' == statsReportType ){
1985
+ cgi_printf(" <strong>tickets</strong>", zTop);
1986
+ }else{
1987
+ cgi_printf(" <a href='%s&type=t'>tickets</a>", zTop);
1988
+ }
1989
+ if( 'g' == statsReportType ){
1990
+ cgi_printf(" <strong>tags</strong>", zTop);
1991
+ }else{
1992
+ cgi_printf(" <a href='%s&type=g'>tags</a>", zTop);
1993
+ }
1994
+ if( 'w' == statsReportType ){
1995
+ cgi_printf(" <strong>wiki</strong>", zTop);
1996
+ }else{
1997
+ cgi_printf(" <a href='%s&type=w'>wiki</a>", zTop);
1998
+ }
1999
+ fossil_free(zTop);
2000
+ cgi_printf("</div>");
2001
+}
2002
+
18552003
18562004
/*
18572005
** Helper for stats_report_by_month_year(), which generates a list of
18582006
** week numbers. zTimeframe should be either a timeframe in the form YYYY
18592007
** or YYYY-MM.
@@ -1864,22 +2012,22 @@
18642012
memcpy(yearPart, zTimeframe, 4);
18652013
db_prepare(&stWeek,
18662014
"SELECT DISTINCT strftime('%%W',mtime) AS wk, "
18672015
"count(*) AS n, "
18682016
"substr(date(mtime),1,%d) AS ym "
1869
- "FROM event "
2017
+ "FROM v_reports "
18702018
"WHERE ym=%Q AND mtime < current_timestamp "
18712019
"GROUP BY wk ORDER BY wk",
18722020
strlen(zTimeframe),
18732021
zTimeframe);
18742022
while( SQLITE_ROW == db_step(&stWeek) ){
18752023
const char * zWeek = db_column_text(&stWeek,0);
18762024
const int nCount = db_column_int(&stWeek,1);
18772025
cgi_printf("<a href='%s/timeline?"
1878
- "yw=%t-%t&n=%d'>%s</a>",
2026
+ "yw=%t-%t&n=%d&y=%s'>%s</a>",
18792027
g.zTop, yearPart, zWeek,
1880
- nCount, zWeek);
2028
+ nCount, statsReportTimelineYFlag, zWeek);
18812029
}
18822030
db_finalize(&stWeek);
18832031
}
18842032
18852033
/*
@@ -1908,16 +2056,19 @@
19082056
Blob header = empty_blob; /* Page header text */
19092057
int nMaxEvents = 1; /* for calculating length of graph
19102058
bars. */
19112059
int iterations = 0; /* number of weeks/months we iterate
19122060
over */
1913
- blob_appendf(&header, "Timeline Events by year%s",
2061
+ stats_report_init_view();
2062
+ stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear" );
2063
+ blob_appendf(&header, "Timeline Events (%s) by year%s",
2064
+ stats_report_label_for_type(),
19142065
(includeMonth ? "/month" : ""));
19152066
blob_appendf(&sql,
19162067
"SELECT substr(date(mtime),1,%d) AS timeframe, "
19172068
"count(*) AS eventCount "
1918
- "FROM event ",
2069
+ "FROM v_reports ",
19192070
includeMonth ? 7 : 4);
19202071
if(zUserName&&*zUserName){
19212072
blob_appendf(&sql, " WHERE user=%Q ", zUserName);
19222073
blob_appendf(&header," for user %q", zUserName);
19232074
}
@@ -1981,21 +2132,23 @@
19812132
nEventsPerYear += nCount;
19822133
@<tr class='row%d(rowClass)'>
19832134
@ <td>
19842135
if(includeMonth){
19852136
cgi_printf("<a href='%s/timeline?"
1986
- "ym=%t&n=%d",
1987
- g.zTop, zTimeframe, nCount );
2137
+ "ym=%t&n=%d&y=%s",
2138
+ g.zTop, zTimeframe, nCount,
2139
+ statsReportTimelineYFlag );
19882140
/* Reminder: n=nCount is not actually correct for bymonth unless
19892141
that was the only user who caused events.
19902142
*/
19912143
if( zUserName && *zUserName ){
19922144
cgi_printf("&u=%t", zUserName);
19932145
}
19942146
cgi_printf("' target='_new'>%s</a>",zTimeframe);
19952147
}else {
1996
- cgi_printf("<a href='?view=byweek&y=%s", zTimeframe);
2148
+ cgi_printf("<a href='?view=byweek&y=%s&type=%c",
2149
+ zTimeframe, (char)statsReportType);
19972150
if(zUserName && *zUserName){
19982151
cgi_printf("&u=%t", zUserName);
19992152
}
20002153
cgi_printf("'>%s</a>", zTimeframe);
20012154
}
@@ -2053,19 +2206,22 @@
20532206
int rowClass = 0; /* counter for alternating
20542207
row colors */
20552208
Blob sql = empty_blob; /* SQL */
20562209
int nMaxEvents = 1; /* max number of events for
20572210
all rows. */
2211
+ stats_report_init_view();
2212
+ stats_report_event_types_menu("byuser");
20582213
blob_append(&sql,
20592214
"SELECT user, "
20602215
"COUNT(*) AS eventCount "
2061
- "FROM event "
2216
+ "FROM v_reports "
20622217
"GROUP BY user ORDER BY eventCount DESC",
20632218
-1);
20642219
db_prepare(&query, blob_str(&sql));
20652220
blob_reset(&sql);
2066
- @ <h1>Timeline Events by User</h1>
2221
+ @ <h1>Timeline Events
2222
+ @ (%s(stats_report_label_for_type())) by User</h1>
20672223
@ <table class='statistics-report-table-events' border='0'
20682224
@ cellpadding='2' cellspacing='0' id='statsTable'>
20692225
@ <thead><tr>
20702226
@ <th>User</th>
20712227
@ <th>Events</th>
@@ -2087,11 +2243,11 @@
20872243
if(!nCount) continue /* arguable! Possible? */;
20882244
rowClass = ++nRowNumber % 2;
20892245
nEventTotal += nCount;
20902246
@<tr class='row%d(rowClass)'>
20912247
@ <td>
2092
- @ <a href="?view=bymonth&user=%h(zUser)">%h(zUser)</a>
2248
+ @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a>
20932249
@ </td><td>%d(nCount)</td>
20942250
@ <td>
20952251
@ <div class='statistics-report-graph-line'
20962252
@ style='height:16px;width:%d(nSize)%%;'>
20972253
@ </div></td>
@@ -2120,15 +2276,16 @@
21202276
char * zDefaultYear = NULL;
21212277
Blob sql = empty_blob;
21222278
int nMaxEvents = 1; /* max number of events for
21232279
all rows. */
21242280
int iterations = 0; /* # of active time periods. */
2125
-
2281
+ stats_report_init_view();
2282
+ stats_report_event_types_menu("byweek");
21262283
cgi_printf("Select year: ");
21272284
blob_append(&sql,
21282285
"SELECT DISTINCT substr(date(mtime),1,4) AS y "
2129
- "FROM event WHERE 1 ", -1);
2286
+ "FROM v_reports WHERE 1 ", -1);
21302287
if(zUserName&&*zUserName){
21312288
blob_appendf(&sql,"AND user=%Q ", zUserName);
21322289
}
21332290
blob_append(&sql,"GROUP BY y ORDER BY y", -1);
21342291
db_prepare(&qYears, blob_str(&sql));
@@ -2136,11 +2293,12 @@
21362293
while( SQLITE_ROW == db_step(&qYears) ){
21372294
const char * zT = db_column_text(&qYears, 0);
21382295
if( i++ ){
21392296
cgi_printf(" ");
21402297
}
2141
- cgi_printf("<a href='?view=byweek&y=%s", zT);
2298
+ cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT,
2299
+ (char)statsReportType);
21422300
if(zUserName && *zUserName){
21432301
cgi_printf("&user=%t",zUserName);
21442302
}
21452303
cgi_printf("'>%s</a>",zT);
21462304
}
@@ -2154,16 +2312,17 @@
21542312
if(4 == nYear){
21552313
Stmt stWeek = empty_Stmt;
21562314
int rowCount = 0;
21572315
int total = 0;
21582316
Blob header = empty_blob;
2159
- blob_appendf(&header, "Timeline events for the calendar weeks "
2160
- "of %h", zYear);
2317
+ blob_appendf(&header, "Timeline events (%s) for the calendar weeks "
2318
+ "of %h", stats_report_label_for_type(),
2319
+ zYear);
21612320
blob_appendf(&sql,
21622321
"SELECT DISTINCT strftime('%%%%W',mtime) AS wk, "
21632322
"count(*) AS n "
2164
- "FROM event "
2323
+ "FROM v_reports "
21652324
"WHERE %Q=substr(date(mtime),1,4) "
21662325
"AND mtime < current_timestamp ",
21672326
zYear);
21682327
if(zUserName&&*zUserName){
21692328
blob_appendf(&sql, " AND user=%Q ", zUserName);
@@ -2197,12 +2356,13 @@
21972356
const int nSize = nCount
21982357
? (int)(100 * nCount / nMaxEvents)
21992358
: 0;
22002359
total += nCount;
22012360
cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2202
- cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d",
2203
- g.zTop, zYear, zWeek, nCount);
2361
+ cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s",
2362
+ g.zTop, zYear, zWeek, nCount,
2363
+ statsReportTimelineYFlag);
22042364
if(zUserName && *zUserName){
22052365
cgi_printf("&u=%t",zUserName);
22062366
}
22072367
cgi_printf("'>%s</a></td>",zWeek);
22082368
@@ -2235,10 +2395,20 @@
22352395
**
22362396
** Query Parameters:
22372397
**
22382398
** view=REPORT_NAME Valid values: bymonth, byyear, byuser
22392399
** user=NAME Restricts statistics to the given user
2400
+** type=TYPE Restricts the report to a specific event type:
2401
+** ci (checkin), w (wiki), t (ticket), g (tag)
2402
+** Defaulting to all event types.
2403
+**
2404
+** The view-specific query parameters include:
2405
+**
2406
+** view=byweek:
2407
+**
2408
+** y=YYYY The year to report (default is the server's
2409
+** current year).
22402410
*/
22412411
void stats_report_page(){
22422412
HQuery url; /* URL for various branch links */
22432413
const char * zView = P("view"); /* Which view/report to show. */
22442414
const char *zUserName = P("user");
22452415
--- src/timeline.c
+++ src/timeline.c
@@ -16,13 +16,13 @@
16 *******************************************************************************
17 **
18 ** This file contains code to implement the timeline web page
19 **
20 */
 
21 #include <string.h>
22 #include <time.h>
23 #include "config.h"
24 #include "timeline.h"
25
26 /*
27 ** Shorten a UUID so that is the minimum length needed to contain
28 ** at least one digit in the range 'a'..'f'. The minimum length is 10.
@@ -369,14 +369,18 @@
369 zUuid, isLeaf);
370 db_reset(&qbranch);
371 @ <div id="m%d(gidx)"></div>
372 }
373 @</td>
 
 
 
 
374 if( zBgClr && zBgClr[0] ){
375 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
376 }else{
377 @ <td class="timelineTableCell">
378 }
379 if( pGraph && zType[0]!='c' ){
380 @ &bull;
381 }
382 if( modPending ){
@@ -1159,12 +1163,12 @@
1159 p = p->u.pTo;
1160 }
1161 blob_append(&sql, ")", -1);
1162 path_reset();
1163 blob_append(&desc, "All nodes on the path from ", -1);
1164 blob_appendf(&desc, "%z%h</a>", href("%R/info/%h", zFrom), zFrom);
1165 blob_append(&desc, " and ", -1);
1166 blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
1167 tmFlags |= TIMELINE_DISJOINT;
1168 db_multi_exec("%s", blob_str(&sql));
1169 }else if( (p_rid || d_rid) && g.perm.Read ){
1170 /* If p= or d= is present, ignore all other parameters other than n= */
@@ -1850,10 +1854,154 @@
1850 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1851 }
1852 db_finalize(&q);
1853 style_footer();
1854 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1855
1856 /*
1857 ** Helper for stats_report_by_month_year(), which generates a list of
1858 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
1859 ** or YYYY-MM.
@@ -1864,22 +2012,22 @@
1864 memcpy(yearPart, zTimeframe, 4);
1865 db_prepare(&stWeek,
1866 "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
1867 "count(*) AS n, "
1868 "substr(date(mtime),1,%d) AS ym "
1869 "FROM event "
1870 "WHERE ym=%Q AND mtime < current_timestamp "
1871 "GROUP BY wk ORDER BY wk",
1872 strlen(zTimeframe),
1873 zTimeframe);
1874 while( SQLITE_ROW == db_step(&stWeek) ){
1875 const char * zWeek = db_column_text(&stWeek,0);
1876 const int nCount = db_column_int(&stWeek,1);
1877 cgi_printf("<a href='%s/timeline?"
1878 "yw=%t-%t&n=%d'>%s</a>",
1879 g.zTop, yearPart, zWeek,
1880 nCount, zWeek);
1881 }
1882 db_finalize(&stWeek);
1883 }
1884
1885 /*
@@ -1908,16 +2056,19 @@
1908 Blob header = empty_blob; /* Page header text */
1909 int nMaxEvents = 1; /* for calculating length of graph
1910 bars. */
1911 int iterations = 0; /* number of weeks/months we iterate
1912 over */
1913 blob_appendf(&header, "Timeline Events by year%s",
 
 
 
1914 (includeMonth ? "/month" : ""));
1915 blob_appendf(&sql,
1916 "SELECT substr(date(mtime),1,%d) AS timeframe, "
1917 "count(*) AS eventCount "
1918 "FROM event ",
1919 includeMonth ? 7 : 4);
1920 if(zUserName&&*zUserName){
1921 blob_appendf(&sql, " WHERE user=%Q ", zUserName);
1922 blob_appendf(&header," for user %q", zUserName);
1923 }
@@ -1981,21 +2132,23 @@
1981 nEventsPerYear += nCount;
1982 @<tr class='row%d(rowClass)'>
1983 @ <td>
1984 if(includeMonth){
1985 cgi_printf("<a href='%s/timeline?"
1986 "ym=%t&n=%d",
1987 g.zTop, zTimeframe, nCount );
 
1988 /* Reminder: n=nCount is not actually correct for bymonth unless
1989 that was the only user who caused events.
1990 */
1991 if( zUserName && *zUserName ){
1992 cgi_printf("&u=%t", zUserName);
1993 }
1994 cgi_printf("' target='_new'>%s</a>",zTimeframe);
1995 }else {
1996 cgi_printf("<a href='?view=byweek&y=%s", zTimeframe);
 
1997 if(zUserName && *zUserName){
1998 cgi_printf("&u=%t", zUserName);
1999 }
2000 cgi_printf("'>%s</a>", zTimeframe);
2001 }
@@ -2053,19 +2206,22 @@
2053 int rowClass = 0; /* counter for alternating
2054 row colors */
2055 Blob sql = empty_blob; /* SQL */
2056 int nMaxEvents = 1; /* max number of events for
2057 all rows. */
 
 
2058 blob_append(&sql,
2059 "SELECT user, "
2060 "COUNT(*) AS eventCount "
2061 "FROM event "
2062 "GROUP BY user ORDER BY eventCount DESC",
2063 -1);
2064 db_prepare(&query, blob_str(&sql));
2065 blob_reset(&sql);
2066 @ <h1>Timeline Events by User</h1>
 
2067 @ <table class='statistics-report-table-events' border='0'
2068 @ cellpadding='2' cellspacing='0' id='statsTable'>
2069 @ <thead><tr>
2070 @ <th>User</th>
2071 @ <th>Events</th>
@@ -2087,11 +2243,11 @@
2087 if(!nCount) continue /* arguable! Possible? */;
2088 rowClass = ++nRowNumber % 2;
2089 nEventTotal += nCount;
2090 @<tr class='row%d(rowClass)'>
2091 @ <td>
2092 @ <a href="?view=bymonth&user=%h(zUser)">%h(zUser)</a>
2093 @ </td><td>%d(nCount)</td>
2094 @ <td>
2095 @ <div class='statistics-report-graph-line'
2096 @ style='height:16px;width:%d(nSize)%%;'>
2097 @ </div></td>
@@ -2120,15 +2276,16 @@
2120 char * zDefaultYear = NULL;
2121 Blob sql = empty_blob;
2122 int nMaxEvents = 1; /* max number of events for
2123 all rows. */
2124 int iterations = 0; /* # of active time periods. */
2125
 
2126 cgi_printf("Select year: ");
2127 blob_append(&sql,
2128 "SELECT DISTINCT substr(date(mtime),1,4) AS y "
2129 "FROM event WHERE 1 ", -1);
2130 if(zUserName&&*zUserName){
2131 blob_appendf(&sql,"AND user=%Q ", zUserName);
2132 }
2133 blob_append(&sql,"GROUP BY y ORDER BY y", -1);
2134 db_prepare(&qYears, blob_str(&sql));
@@ -2136,11 +2293,12 @@
2136 while( SQLITE_ROW == db_step(&qYears) ){
2137 const char * zT = db_column_text(&qYears, 0);
2138 if( i++ ){
2139 cgi_printf(" ");
2140 }
2141 cgi_printf("<a href='?view=byweek&y=%s", zT);
 
2142 if(zUserName && *zUserName){
2143 cgi_printf("&user=%t",zUserName);
2144 }
2145 cgi_printf("'>%s</a>",zT);
2146 }
@@ -2154,16 +2312,17 @@
2154 if(4 == nYear){
2155 Stmt stWeek = empty_Stmt;
2156 int rowCount = 0;
2157 int total = 0;
2158 Blob header = empty_blob;
2159 blob_appendf(&header, "Timeline events for the calendar weeks "
2160 "of %h", zYear);
 
2161 blob_appendf(&sql,
2162 "SELECT DISTINCT strftime('%%%%W',mtime) AS wk, "
2163 "count(*) AS n "
2164 "FROM event "
2165 "WHERE %Q=substr(date(mtime),1,4) "
2166 "AND mtime < current_timestamp ",
2167 zYear);
2168 if(zUserName&&*zUserName){
2169 blob_appendf(&sql, " AND user=%Q ", zUserName);
@@ -2197,12 +2356,13 @@
2197 const int nSize = nCount
2198 ? (int)(100 * nCount / nMaxEvents)
2199 : 0;
2200 total += nCount;
2201 cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2202 cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d",
2203 g.zTop, zYear, zWeek, nCount);
 
2204 if(zUserName && *zUserName){
2205 cgi_printf("&u=%t",zUserName);
2206 }
2207 cgi_printf("'>%s</a></td>",zWeek);
2208
@@ -2235,10 +2395,20 @@
2235 **
2236 ** Query Parameters:
2237 **
2238 ** view=REPORT_NAME Valid values: bymonth, byyear, byuser
2239 ** user=NAME Restricts statistics to the given user
 
 
 
 
 
 
 
 
 
 
2240 */
2241 void stats_report_page(){
2242 HQuery url; /* URL for various branch links */
2243 const char * zView = P("view"); /* Which view/report to show. */
2244 const char *zUserName = P("user");
2245
--- src/timeline.c
+++ src/timeline.c
@@ -16,13 +16,13 @@
16 *******************************************************************************
17 **
18 ** This file contains code to implement the timeline web page
19 **
20 */
21 #include "config.h"
22 #include <string.h>
23 #include <time.h>
 
24 #include "timeline.h"
25
26 /*
27 ** Shorten a UUID so that is the minimum length needed to contain
28 ** at least one digit in the range 'a'..'f'. The minimum length is 10.
@@ -369,14 +369,18 @@
369 zUuid, isLeaf);
370 db_reset(&qbranch);
371 @ <div id="m%d(gidx)"></div>
372 }
373 @</td>
374 @ <td class="timelineTableCell"
375 if( zTagList && zTagList[0] ){
376 @ class="%h(zTagList)"
377 }
378 if( zBgClr && zBgClr[0] ){
379 @ style="background-color: %h(zBgClr);">
380 }else{
381 @ >
382 }
383 if( pGraph && zType[0]!='c' ){
384 @ &bull;
385 }
386 if( modPending ){
@@ -1159,12 +1163,12 @@
1163 p = p->u.pTo;
1164 }
1165 blob_append(&sql, ")", -1);
1166 path_reset();
1167 blob_append(&desc, "All nodes on the path from ", -1);
1168 blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom);
1169 blob_append(&desc, " to ", -1);
1170 blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
1171 tmFlags |= TIMELINE_DISJOINT;
1172 db_multi_exec("%s", blob_str(&sql));
1173 }else if( (p_rid || d_rid) && g.perm.Read ){
1174 /* If p= or d= is present, ignore all other parameters other than n= */
@@ -1850,10 +1854,154 @@
1854 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1855 }
1856 db_finalize(&q);
1857 style_footer();
1858 }
1859
1860
1861 /*
1862 ** Used by stats_report_xxxxx() to remember which type of events
1863 ** to show. Populated by stats_report_init_view() and holds the
1864 ** return value of that function.
1865 */
1866 static int statsReportType = 0;
1867
1868 /*
1869 ** Set by stats_report_init_view() to one of the y=XXXX values
1870 ** accepted by /timeline?y=XXXX.
1871 */
1872 static char const * statsReportTimelineYFlag = NULL;
1873
1874 /*
1875 ** Creates a TEMP VIEW named v_reports which is a wrapper around the
1876 ** EVENT table filtered on event.type. It looks for the request
1877 ** parameter 'type' (reminder: we "should" use 'y' for consistency
1878 ** with /timeline, but /reports uses 'y' for the year) and expects it
1879 ** to contain one of the conventional values from event.type or the
1880 ** value "all", which is treated as equivalent to "*". By default (if
1881 ** no 'y' is specified), "*" is assumed (that is also the default for
1882 ** invalid/unknown filter values). That 'y' filter is the one used for
1883 ** the event list. Note that a filter of "*" or "all" is equivalent to
1884 ** querying against the full event table. The view, however, adds an
1885 ** abstraction level to simplify the implementation code for the
1886 ** various /reports pages.
1887 **
1888 ** Returns one of: 'c', 'w', 'g', 't', 'e', representing the type of
1889 ** filter it applies, or '*' if no filter is applied (i.e. if "all" is
1890 ** used).
1891 */
1892 static int stats_report_init_view(){
1893 char const * zType = PD("type","*"); /* analog to /timeline?y=... */
1894 char const * zRealType = NULL; /* normalized form of zType */
1895 int rc = 0; /* result code */
1896 assert( !statsReportType && "Must not be called more than once." );
1897 switch( (zType && *zType) ? *zType : 0 ){
1898 case 'c':
1899 case 'C':
1900 zRealType = "ci";
1901 rc = *zRealType;
1902 break;
1903 case 'e':
1904 case 'E':
1905 zRealType = "e";
1906 rc = *zRealType;
1907 break;
1908 case 'g':
1909 case 'G':
1910 zRealType = "g";
1911 rc = *zRealType;
1912 break;
1913 case 't':
1914 case 'T':
1915 zRealType = "t";
1916 rc = *zRealType;
1917 break;
1918 case 'w':
1919 case 'W':
1920 zRealType = "w";
1921 rc = *zRealType;
1922 break;
1923 default:
1924 rc = '*';
1925 break;
1926 }
1927 assert(0 != rc);
1928 if(zRealType){
1929 statsReportTimelineYFlag = zRealType;
1930 db_multi_exec("CREATE TEMP VIEW v_reports AS "
1931 "SELECT * FROM event WHERE type GLOB %Q",
1932 zRealType);
1933 }else{
1934 statsReportTimelineYFlag = "a";
1935 db_multi_exec("CREATE TEMP VIEW v_reports AS "
1936 "SELECT * FROM event");
1937 }
1938 return statsReportType = rc;
1939 }
1940
1941 /*
1942 ** Returns a string suitable (for a given value of suitable) for
1943 ** use in a label with the header of the /reports pages, dependent
1944 ** on the 'type' flag. See stats_report_init_view().
1945 ** The returned bytes are static.
1946 */
1947 static char const * stats_report_label_for_type(){
1948 assert( statsReportType && "Must call stats_report_init_view() first." );
1949 switch( statsReportType ){
1950 case 'c':
1951 return "checkins";
1952 case 'w':
1953 return "wiki changes";
1954 case 't':
1955 return "ticket changes";
1956 case 'g':
1957 return "tag changes";
1958 default:
1959 return "all types";
1960 }
1961 }
1962
1963 /*
1964 ** A helper for the /reports family of pages which prints out a menu
1965 ** of links for the various type=XXX flags. zCurrentViewName must be
1966 ** the name/value of the 'view' parameter which is in effect at
1967 ** the time this is called. e.g. if called from the 'byuser' view
1968 ** then zCurrentViewName must be "byuser".
1969 */
1970 static void stats_report_event_types_menu(char const * zCurrentViewName){
1971 char * zTop = mprintf("%s/reports?view=%s", g.zTop, zCurrentViewName);
1972 cgi_printf("<div>");
1973 cgi_printf("<span>Event types:</span> ");
1974 if('*' == statsReportType){
1975 cgi_printf(" <strong>all</strong>", zTop);
1976 }else{
1977 cgi_printf(" <a href='%s'>all</a>", zTop);
1978 }
1979 if('c' == statsReportType){
1980 cgi_printf(" <strong>checkins</strong>", zTop);
1981 }else{
1982 cgi_printf(" <a href='%s&type=ci'>checkins</a>", zTop);
1983 }
1984 if( 't' == statsReportType ){
1985 cgi_printf(" <strong>tickets</strong>", zTop);
1986 }else{
1987 cgi_printf(" <a href='%s&type=t'>tickets</a>", zTop);
1988 }
1989 if( 'g' == statsReportType ){
1990 cgi_printf(" <strong>tags</strong>", zTop);
1991 }else{
1992 cgi_printf(" <a href='%s&type=g'>tags</a>", zTop);
1993 }
1994 if( 'w' == statsReportType ){
1995 cgi_printf(" <strong>wiki</strong>", zTop);
1996 }else{
1997 cgi_printf(" <a href='%s&type=w'>wiki</a>", zTop);
1998 }
1999 fossil_free(zTop);
2000 cgi_printf("</div>");
2001 }
2002
2003
2004 /*
2005 ** Helper for stats_report_by_month_year(), which generates a list of
2006 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
2007 ** or YYYY-MM.
@@ -1864,22 +2012,22 @@
2012 memcpy(yearPart, zTimeframe, 4);
2013 db_prepare(&stWeek,
2014 "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
2015 "count(*) AS n, "
2016 "substr(date(mtime),1,%d) AS ym "
2017 "FROM v_reports "
2018 "WHERE ym=%Q AND mtime < current_timestamp "
2019 "GROUP BY wk ORDER BY wk",
2020 strlen(zTimeframe),
2021 zTimeframe);
2022 while( SQLITE_ROW == db_step(&stWeek) ){
2023 const char * zWeek = db_column_text(&stWeek,0);
2024 const int nCount = db_column_int(&stWeek,1);
2025 cgi_printf("<a href='%s/timeline?"
2026 "yw=%t-%t&n=%d&y=%s'>%s</a>",
2027 g.zTop, yearPart, zWeek,
2028 nCount, statsReportTimelineYFlag, zWeek);
2029 }
2030 db_finalize(&stWeek);
2031 }
2032
2033 /*
@@ -1908,16 +2056,19 @@
2056 Blob header = empty_blob; /* Page header text */
2057 int nMaxEvents = 1; /* for calculating length of graph
2058 bars. */
2059 int iterations = 0; /* number of weeks/months we iterate
2060 over */
2061 stats_report_init_view();
2062 stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear" );
2063 blob_appendf(&header, "Timeline Events (%s) by year%s",
2064 stats_report_label_for_type(),
2065 (includeMonth ? "/month" : ""));
2066 blob_appendf(&sql,
2067 "SELECT substr(date(mtime),1,%d) AS timeframe, "
2068 "count(*) AS eventCount "
2069 "FROM v_reports ",
2070 includeMonth ? 7 : 4);
2071 if(zUserName&&*zUserName){
2072 blob_appendf(&sql, " WHERE user=%Q ", zUserName);
2073 blob_appendf(&header," for user %q", zUserName);
2074 }
@@ -1981,21 +2132,23 @@
2132 nEventsPerYear += nCount;
2133 @<tr class='row%d(rowClass)'>
2134 @ <td>
2135 if(includeMonth){
2136 cgi_printf("<a href='%s/timeline?"
2137 "ym=%t&n=%d&y=%s",
2138 g.zTop, zTimeframe, nCount,
2139 statsReportTimelineYFlag );
2140 /* Reminder: n=nCount is not actually correct for bymonth unless
2141 that was the only user who caused events.
2142 */
2143 if( zUserName && *zUserName ){
2144 cgi_printf("&u=%t", zUserName);
2145 }
2146 cgi_printf("' target='_new'>%s</a>",zTimeframe);
2147 }else {
2148 cgi_printf("<a href='?view=byweek&y=%s&type=%c",
2149 zTimeframe, (char)statsReportType);
2150 if(zUserName && *zUserName){
2151 cgi_printf("&u=%t", zUserName);
2152 }
2153 cgi_printf("'>%s</a>", zTimeframe);
2154 }
@@ -2053,19 +2206,22 @@
2206 int rowClass = 0; /* counter for alternating
2207 row colors */
2208 Blob sql = empty_blob; /* SQL */
2209 int nMaxEvents = 1; /* max number of events for
2210 all rows. */
2211 stats_report_init_view();
2212 stats_report_event_types_menu("byuser");
2213 blob_append(&sql,
2214 "SELECT user, "
2215 "COUNT(*) AS eventCount "
2216 "FROM v_reports "
2217 "GROUP BY user ORDER BY eventCount DESC",
2218 -1);
2219 db_prepare(&query, blob_str(&sql));
2220 blob_reset(&sql);
2221 @ <h1>Timeline Events
2222 @ (%s(stats_report_label_for_type())) by User</h1>
2223 @ <table class='statistics-report-table-events' border='0'
2224 @ cellpadding='2' cellspacing='0' id='statsTable'>
2225 @ <thead><tr>
2226 @ <th>User</th>
2227 @ <th>Events</th>
@@ -2087,11 +2243,11 @@
2243 if(!nCount) continue /* arguable! Possible? */;
2244 rowClass = ++nRowNumber % 2;
2245 nEventTotal += nCount;
2246 @<tr class='row%d(rowClass)'>
2247 @ <td>
2248 @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a>
2249 @ </td><td>%d(nCount)</td>
2250 @ <td>
2251 @ <div class='statistics-report-graph-line'
2252 @ style='height:16px;width:%d(nSize)%%;'>
2253 @ </div></td>
@@ -2120,15 +2276,16 @@
2276 char * zDefaultYear = NULL;
2277 Blob sql = empty_blob;
2278 int nMaxEvents = 1; /* max number of events for
2279 all rows. */
2280 int iterations = 0; /* # of active time periods. */
2281 stats_report_init_view();
2282 stats_report_event_types_menu("byweek");
2283 cgi_printf("Select year: ");
2284 blob_append(&sql,
2285 "SELECT DISTINCT substr(date(mtime),1,4) AS y "
2286 "FROM v_reports WHERE 1 ", -1);
2287 if(zUserName&&*zUserName){
2288 blob_appendf(&sql,"AND user=%Q ", zUserName);
2289 }
2290 blob_append(&sql,"GROUP BY y ORDER BY y", -1);
2291 db_prepare(&qYears, blob_str(&sql));
@@ -2136,11 +2293,12 @@
2293 while( SQLITE_ROW == db_step(&qYears) ){
2294 const char * zT = db_column_text(&qYears, 0);
2295 if( i++ ){
2296 cgi_printf(" ");
2297 }
2298 cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT,
2299 (char)statsReportType);
2300 if(zUserName && *zUserName){
2301 cgi_printf("&user=%t",zUserName);
2302 }
2303 cgi_printf("'>%s</a>",zT);
2304 }
@@ -2154,16 +2312,17 @@
2312 if(4 == nYear){
2313 Stmt stWeek = empty_Stmt;
2314 int rowCount = 0;
2315 int total = 0;
2316 Blob header = empty_blob;
2317 blob_appendf(&header, "Timeline events (%s) for the calendar weeks "
2318 "of %h", stats_report_label_for_type(),
2319 zYear);
2320 blob_appendf(&sql,
2321 "SELECT DISTINCT strftime('%%%%W',mtime) AS wk, "
2322 "count(*) AS n "
2323 "FROM v_reports "
2324 "WHERE %Q=substr(date(mtime),1,4) "
2325 "AND mtime < current_timestamp ",
2326 zYear);
2327 if(zUserName&&*zUserName){
2328 blob_appendf(&sql, " AND user=%Q ", zUserName);
@@ -2197,12 +2356,13 @@
2356 const int nSize = nCount
2357 ? (int)(100 * nCount / nMaxEvents)
2358 : 0;
2359 total += nCount;
2360 cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
2361 cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s",
2362 g.zTop, zYear, zWeek, nCount,
2363 statsReportTimelineYFlag);
2364 if(zUserName && *zUserName){
2365 cgi_printf("&u=%t",zUserName);
2366 }
2367 cgi_printf("'>%s</a></td>",zWeek);
2368
@@ -2235,10 +2395,20 @@
2395 **
2396 ** Query Parameters:
2397 **
2398 ** view=REPORT_NAME Valid values: bymonth, byyear, byuser
2399 ** user=NAME Restricts statistics to the given user
2400 ** type=TYPE Restricts the report to a specific event type:
2401 ** ci (checkin), w (wiki), t (ticket), g (tag)
2402 ** Defaulting to all event types.
2403 **
2404 ** The view-specific query parameters include:
2405 **
2406 ** view=byweek:
2407 **
2408 ** y=YYYY The year to report (default is the server's
2409 ** current year).
2410 */
2411 void stats_report_page(){
2412 HQuery url; /* URL for various branch links */
2413 const char * zView = P("view"); /* Which view/report to show. */
2414 const char *zUserName = P("user");
2415
+3 -3
--- src/tkt.c
+++ src/tkt.c
@@ -296,11 +296,11 @@
296296
db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid);
297297
tktid = 0;
298298
db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid);
299299
while( db_step(&q)==SQLITE_ROW ){
300300
int rid = db_column_int(&q, 0);
301
- pTicket = manifest_get(rid, CFTYPE_TICKET);
301
+ pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
302302
if( pTicket ){
303303
tktid = ticket_insert(pTicket, rid, tktid);
304304
manifest_ticket_event(rid, pTicket, createFlag, tagid);
305305
manifest_destroy(pTicket);
306306
}
@@ -938,11 +938,11 @@
938938
@ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
939939
@ (rid %d(rid)) by
940940
hyperlink_to_user(zUser,zDate," on");
941941
hyperlink_to_date(zDate, ".</p>");
942942
}else{
943
- pTicket = manifest_get(rid, CFTYPE_TICKET);
943
+ pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
944944
if( pTicket ){
945945
@
946946
@ <li><p>Ticket change
947947
@ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
948948
@ (rid %d(rid)) by
@@ -1238,11 +1238,11 @@
12381238
}else{
12391239
fossil_print("Add attachment %s\n", zFile);
12401240
}
12411241
fossil_print(" by %s on %s\n", zUser, zDate);
12421242
}else{
1243
- pTicket = manifest_get(rid, CFTYPE_TICKET);
1243
+ pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
12441244
if( pTicket ){
12451245
int i;
12461246
12471247
fossil_print("Ticket Change by %s on %s:\n",
12481248
pTicket->zUser, zDate);
12491249
--- src/tkt.c
+++ src/tkt.c
@@ -296,11 +296,11 @@
296 db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid);
297 tktid = 0;
298 db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid);
299 while( db_step(&q)==SQLITE_ROW ){
300 int rid = db_column_int(&q, 0);
301 pTicket = manifest_get(rid, CFTYPE_TICKET);
302 if( pTicket ){
303 tktid = ticket_insert(pTicket, rid, tktid);
304 manifest_ticket_event(rid, pTicket, createFlag, tagid);
305 manifest_destroy(pTicket);
306 }
@@ -938,11 +938,11 @@
938 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
939 @ (rid %d(rid)) by
940 hyperlink_to_user(zUser,zDate," on");
941 hyperlink_to_date(zDate, ".</p>");
942 }else{
943 pTicket = manifest_get(rid, CFTYPE_TICKET);
944 if( pTicket ){
945 @
946 @ <li><p>Ticket change
947 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
948 @ (rid %d(rid)) by
@@ -1238,11 +1238,11 @@
1238 }else{
1239 fossil_print("Add attachment %s\n", zFile);
1240 }
1241 fossil_print(" by %s on %s\n", zUser, zDate);
1242 }else{
1243 pTicket = manifest_get(rid, CFTYPE_TICKET);
1244 if( pTicket ){
1245 int i;
1246
1247 fossil_print("Ticket Change by %s on %s:\n",
1248 pTicket->zUser, zDate);
1249
--- src/tkt.c
+++ src/tkt.c
@@ -296,11 +296,11 @@
296 db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid);
297 tktid = 0;
298 db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid);
299 while( db_step(&q)==SQLITE_ROW ){
300 int rid = db_column_int(&q, 0);
301 pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
302 if( pTicket ){
303 tktid = ticket_insert(pTicket, rid, tktid);
304 manifest_ticket_event(rid, pTicket, createFlag, tagid);
305 manifest_destroy(pTicket);
306 }
@@ -938,11 +938,11 @@
938 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
939 @ (rid %d(rid)) by
940 hyperlink_to_user(zUser,zDate," on");
941 hyperlink_to_date(zDate, ".</p>");
942 }else{
943 pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
944 if( pTicket ){
945 @
946 @ <li><p>Ticket change
947 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
948 @ (rid %d(rid)) by
@@ -1238,11 +1238,11 @@
1238 }else{
1239 fossil_print("Add attachment %s\n", zFile);
1240 }
1241 fossil_print(" by %s on %s\n", zUser, zDate);
1242 }else{
1243 pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
1244 if( pTicket ){
1245 int i;
1246
1247 fossil_print("Ticket Change by %s on %s:\n",
1248 pTicket->zUser, zDate);
1249
+3 -3
--- src/tkt.c
+++ src/tkt.c
@@ -296,11 +296,11 @@
296296
db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid);
297297
tktid = 0;
298298
db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid);
299299
while( db_step(&q)==SQLITE_ROW ){
300300
int rid = db_column_int(&q, 0);
301
- pTicket = manifest_get(rid, CFTYPE_TICKET);
301
+ pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
302302
if( pTicket ){
303303
tktid = ticket_insert(pTicket, rid, tktid);
304304
manifest_ticket_event(rid, pTicket, createFlag, tagid);
305305
manifest_destroy(pTicket);
306306
}
@@ -938,11 +938,11 @@
938938
@ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
939939
@ (rid %d(rid)) by
940940
hyperlink_to_user(zUser,zDate," on");
941941
hyperlink_to_date(zDate, ".</p>");
942942
}else{
943
- pTicket = manifest_get(rid, CFTYPE_TICKET);
943
+ pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
944944
if( pTicket ){
945945
@
946946
@ <li><p>Ticket change
947947
@ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
948948
@ (rid %d(rid)) by
@@ -1238,11 +1238,11 @@
12381238
}else{
12391239
fossil_print("Add attachment %s\n", zFile);
12401240
}
12411241
fossil_print(" by %s on %s\n", zUser, zDate);
12421242
}else{
1243
- pTicket = manifest_get(rid, CFTYPE_TICKET);
1243
+ pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
12441244
if( pTicket ){
12451245
int i;
12461246
12471247
fossil_print("Ticket Change by %s on %s:\n",
12481248
pTicket->zUser, zDate);
12491249
--- src/tkt.c
+++ src/tkt.c
@@ -296,11 +296,11 @@
296 db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid);
297 tktid = 0;
298 db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid);
299 while( db_step(&q)==SQLITE_ROW ){
300 int rid = db_column_int(&q, 0);
301 pTicket = manifest_get(rid, CFTYPE_TICKET);
302 if( pTicket ){
303 tktid = ticket_insert(pTicket, rid, tktid);
304 manifest_ticket_event(rid, pTicket, createFlag, tagid);
305 manifest_destroy(pTicket);
306 }
@@ -938,11 +938,11 @@
938 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
939 @ (rid %d(rid)) by
940 hyperlink_to_user(zUser,zDate," on");
941 hyperlink_to_date(zDate, ".</p>");
942 }else{
943 pTicket = manifest_get(rid, CFTYPE_TICKET);
944 if( pTicket ){
945 @
946 @ <li><p>Ticket change
947 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
948 @ (rid %d(rid)) by
@@ -1238,11 +1238,11 @@
1238 }else{
1239 fossil_print("Add attachment %s\n", zFile);
1240 }
1241 fossil_print(" by %s on %s\n", zUser, zDate);
1242 }else{
1243 pTicket = manifest_get(rid, CFTYPE_TICKET);
1244 if( pTicket ){
1245 int i;
1246
1247 fossil_print("Ticket Change by %s on %s:\n",
1248 pTicket->zUser, zDate);
1249
--- src/tkt.c
+++ src/tkt.c
@@ -296,11 +296,11 @@
296 db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid);
297 tktid = 0;
298 db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid);
299 while( db_step(&q)==SQLITE_ROW ){
300 int rid = db_column_int(&q, 0);
301 pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
302 if( pTicket ){
303 tktid = ticket_insert(pTicket, rid, tktid);
304 manifest_ticket_event(rid, pTicket, createFlag, tagid);
305 manifest_destroy(pTicket);
306 }
@@ -938,11 +938,11 @@
938 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
939 @ (rid %d(rid)) by
940 hyperlink_to_user(zUser,zDate," on");
941 hyperlink_to_date(zDate, ".</p>");
942 }else{
943 pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
944 if( pTicket ){
945 @
946 @ <li><p>Ticket change
947 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
948 @ (rid %d(rid)) by
@@ -1238,11 +1238,11 @@
1238 }else{
1239 fossil_print("Add attachment %s\n", zFile);
1240 }
1241 fossil_print(" by %s on %s\n", zUser, zDate);
1242 }else{
1243 pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
1244 if( pTicket ){
1245 int i;
1246
1247 fossil_print("Ticket Change by %s on %s:\n",
1248 pTicket->zUser, zDate);
1249
+1 -1
--- src/update.c
+++ src/update.c
@@ -635,11 +635,11 @@
635635
}
636636
if( !is_a_version(rid) ){
637637
if( errCode>0 ) return errCode;
638638
fossil_fatal("no such checkin: %s", revision);
639639
}
640
- pManifest = manifest_get(rid, CFTYPE_MANIFEST);
640
+ pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
641641
642642
if( pManifest ){
643643
pFile = manifest_file_find(pManifest, file);
644644
if( pFile ){
645645
int rc;
646646
--- src/update.c
+++ src/update.c
@@ -635,11 +635,11 @@
635 }
636 if( !is_a_version(rid) ){
637 if( errCode>0 ) return errCode;
638 fossil_fatal("no such checkin: %s", revision);
639 }
640 pManifest = manifest_get(rid, CFTYPE_MANIFEST);
641
642 if( pManifest ){
643 pFile = manifest_file_find(pManifest, file);
644 if( pFile ){
645 int rc;
646
--- src/update.c
+++ src/update.c
@@ -635,11 +635,11 @@
635 }
636 if( !is_a_version(rid) ){
637 if( errCode>0 ) return errCode;
638 fossil_fatal("no such checkin: %s", revision);
639 }
640 pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
641
642 if( pManifest ){
643 pFile = manifest_file_find(pManifest, file);
644 if( pFile ){
645 int rc;
646
+2 -20
--- src/url.c
+++ src/url.c
@@ -100,11 +100,10 @@
100100
}else if( zUrl[0]=='s' ){
101101
g.urlIsSsh = 1;
102102
g.urlProtocol = "ssh";
103103
g.urlDfltPort = 22;
104104
g.urlFossil = "fossil";
105
- g.urlShell = 0;
106105
iStart = 6;
107106
}else{
108107
g.urlIsHttps = 0;
109108
g.urlProtocol = "http";
110109
g.urlDfltPort = 80;
@@ -173,16 +172,10 @@
173172
g.urlFossil = zValue;
174173
dehttpize(g.urlFossil);
175174
zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
176175
cQuerySep = '&';
177176
}
178
- if( fossil_strcmp(zName,"shell")==0 ){
179
- g.urlShell = zValue;
180
- dehttpize(g.urlShell);
181
- zExe = mprintf("%cshell=%T", cQuerySep, g.urlFossil);
182
- cQuerySep = '&';
183
- }
184177
}
185178
186179
dehttpize(g.urlPath);
187180
if( g.urlDfltPort==g.urlPort ){
188181
g.urlCanonical = mprintf(
@@ -444,26 +437,16 @@
444437
if( g.urlIsSsh || g.urlIsFile ) return;
445438
if( isatty(fileno(stdin))
446439
&& (g.urlFlags & URL_PROMPT_PW)!=0
447440
&& (g.urlFlags & URL_PROMPTED)==0
448441
){
449
- char *zPrompt = mprintf("\rpassword for %s: ", g.urlUser);
450
- Blob x;
451
- fossil_force_newline();
452
- prompt_for_password(zPrompt, &x, 0);
453
- free(zPrompt);
454
- g.urlPasswd = mprintf("%b", &x);
455
- blob_reset(&x);
456442
g.urlFlags |= URL_PROMPTED;
443
+ g.urlPasswd = prompt_for_user_password(g.urlUser);
457444
if( g.urlPasswd[0]
458445
&& (g.urlFlags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
459446
){
460
- char c;
461
- prompt_user("remember password (Y/n)? ", &x);
462
- c = blob_str(&x)[0];
463
- blob_reset(&x);
464
- if( c!='n' && c!='N' ){
447
+ if( save_password_prompt() ){
465448
g.urlFlags |= URL_REMEMBER_PW;
466449
if( g.urlFlags & URL_REMEMBER ){
467450
db_set("last-sync-pw", obscure(g.urlPasswd), 0);
468451
}
469452
}
@@ -490,10 +473,9 @@
490473
*/
491474
void url_get_password_if_needed(void){
492475
if( (g.urlUser && g.urlUser[0])
493476
&& (g.urlPasswd==0 || g.urlPasswd[0]==0)
494477
&& isatty(fileno(stdin))
495
- && g.urlIsSsh==0
496478
){
497479
url_prompt_for_password();
498480
}
499481
}
500482
--- src/url.c
+++ src/url.c
@@ -100,11 +100,10 @@
100 }else if( zUrl[0]=='s' ){
101 g.urlIsSsh = 1;
102 g.urlProtocol = "ssh";
103 g.urlDfltPort = 22;
104 g.urlFossil = "fossil";
105 g.urlShell = 0;
106 iStart = 6;
107 }else{
108 g.urlIsHttps = 0;
109 g.urlProtocol = "http";
110 g.urlDfltPort = 80;
@@ -173,16 +172,10 @@
173 g.urlFossil = zValue;
174 dehttpize(g.urlFossil);
175 zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
176 cQuerySep = '&';
177 }
178 if( fossil_strcmp(zName,"shell")==0 ){
179 g.urlShell = zValue;
180 dehttpize(g.urlShell);
181 zExe = mprintf("%cshell=%T", cQuerySep, g.urlFossil);
182 cQuerySep = '&';
183 }
184 }
185
186 dehttpize(g.urlPath);
187 if( g.urlDfltPort==g.urlPort ){
188 g.urlCanonical = mprintf(
@@ -444,26 +437,16 @@
444 if( g.urlIsSsh || g.urlIsFile ) return;
445 if( isatty(fileno(stdin))
446 && (g.urlFlags & URL_PROMPT_PW)!=0
447 && (g.urlFlags & URL_PROMPTED)==0
448 ){
449 char *zPrompt = mprintf("\rpassword for %s: ", g.urlUser);
450 Blob x;
451 fossil_force_newline();
452 prompt_for_password(zPrompt, &x, 0);
453 free(zPrompt);
454 g.urlPasswd = mprintf("%b", &x);
455 blob_reset(&x);
456 g.urlFlags |= URL_PROMPTED;
 
457 if( g.urlPasswd[0]
458 && (g.urlFlags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
459 ){
460 char c;
461 prompt_user("remember password (Y/n)? ", &x);
462 c = blob_str(&x)[0];
463 blob_reset(&x);
464 if( c!='n' && c!='N' ){
465 g.urlFlags |= URL_REMEMBER_PW;
466 if( g.urlFlags & URL_REMEMBER ){
467 db_set("last-sync-pw", obscure(g.urlPasswd), 0);
468 }
469 }
@@ -490,10 +473,9 @@
490 */
491 void url_get_password_if_needed(void){
492 if( (g.urlUser && g.urlUser[0])
493 && (g.urlPasswd==0 || g.urlPasswd[0]==0)
494 && isatty(fileno(stdin))
495 && g.urlIsSsh==0
496 ){
497 url_prompt_for_password();
498 }
499 }
500
--- src/url.c
+++ src/url.c
@@ -100,11 +100,10 @@
100 }else if( zUrl[0]=='s' ){
101 g.urlIsSsh = 1;
102 g.urlProtocol = "ssh";
103 g.urlDfltPort = 22;
104 g.urlFossil = "fossil";
 
105 iStart = 6;
106 }else{
107 g.urlIsHttps = 0;
108 g.urlProtocol = "http";
109 g.urlDfltPort = 80;
@@ -173,16 +172,10 @@
172 g.urlFossil = zValue;
173 dehttpize(g.urlFossil);
174 zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
175 cQuerySep = '&';
176 }
 
 
 
 
 
 
177 }
178
179 dehttpize(g.urlPath);
180 if( g.urlDfltPort==g.urlPort ){
181 g.urlCanonical = mprintf(
@@ -444,26 +437,16 @@
437 if( g.urlIsSsh || g.urlIsFile ) return;
438 if( isatty(fileno(stdin))
439 && (g.urlFlags & URL_PROMPT_PW)!=0
440 && (g.urlFlags & URL_PROMPTED)==0
441 ){
 
 
 
 
 
 
 
442 g.urlFlags |= URL_PROMPTED;
443 g.urlPasswd = prompt_for_user_password(g.urlUser);
444 if( g.urlPasswd[0]
445 && (g.urlFlags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
446 ){
447 if( save_password_prompt() ){
 
 
 
 
448 g.urlFlags |= URL_REMEMBER_PW;
449 if( g.urlFlags & URL_REMEMBER ){
450 db_set("last-sync-pw", obscure(g.urlPasswd), 0);
451 }
452 }
@@ -490,10 +473,9 @@
473 */
474 void url_get_password_if_needed(void){
475 if( (g.urlUser && g.urlUser[0])
476 && (g.urlPasswd==0 || g.urlPasswd[0]==0)
477 && isatty(fileno(stdin))
 
478 ){
479 url_prompt_for_password();
480 }
481 }
482
+28 -1
--- src/user.c
+++ src/user.c
@@ -34,11 +34,11 @@
3434
if( z[i]=='\r' || z[i]=='\n' ){
3535
while( i>0 && fossil_isspace(z[i-1]) ){ i--; }
3636
z[i] = 0;
3737
break;
3838
}
39
- if( z[i]<' ' ) z[i] = ' ';
39
+ if( z[i]>0 && z[i]<' ' ) z[i] = ' ';
4040
}
4141
blob_append(pBlob, z, -1);
4242
}
4343
4444
#if defined(_WIN32) || defined(__BIONIC__)
@@ -128,10 +128,37 @@
128128
break;
129129
}
130130
}
131131
blob_reset(&secondTry);
132132
}
133
+
134
+/*
135
+** Prompt to save Fossil user password
136
+*/
137
+int save_password_prompt(){
138
+ Blob x;
139
+ char c;
140
+ prompt_user("remember password (Y/n)? ", &x);
141
+ c = blob_str(&x)[0];
142
+ blob_reset(&x);
143
+ return ( c!='n' && c!='N' );
144
+}
145
+
146
+/*
147
+** Prompt for Fossil user password
148
+*/
149
+char *prompt_for_user_password(const char *zUser){
150
+ char *zPrompt = mprintf("\rpassword for %s: ", zUser);
151
+ char *zPw;
152
+ Blob x;
153
+ fossil_force_newline();
154
+ prompt_for_password(zPrompt, &x, 0);
155
+ free(zPrompt);
156
+ zPw = mprintf("%b", &x);
157
+ blob_reset(&x);
158
+ return zPw;
159
+}
133160
134161
/*
135162
** Prompt the user to enter a single line of text.
136163
*/
137164
void prompt_user(const char *zPrompt, Blob *pIn){
138165
--- src/user.c
+++ src/user.c
@@ -34,11 +34,11 @@
34 if( z[i]=='\r' || z[i]=='\n' ){
35 while( i>0 && fossil_isspace(z[i-1]) ){ i--; }
36 z[i] = 0;
37 break;
38 }
39 if( z[i]<' ' ) z[i] = ' ';
40 }
41 blob_append(pBlob, z, -1);
42 }
43
44 #if defined(_WIN32) || defined(__BIONIC__)
@@ -128,10 +128,37 @@
128 break;
129 }
130 }
131 blob_reset(&secondTry);
132 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
134 /*
135 ** Prompt the user to enter a single line of text.
136 */
137 void prompt_user(const char *zPrompt, Blob *pIn){
138
--- src/user.c
+++ src/user.c
@@ -34,11 +34,11 @@
34 if( z[i]=='\r' || z[i]=='\n' ){
35 while( i>0 && fossil_isspace(z[i-1]) ){ i--; }
36 z[i] = 0;
37 break;
38 }
39 if( z[i]>0 && z[i]<' ' ) z[i] = ' ';
40 }
41 blob_append(pBlob, z, -1);
42 }
43
44 #if defined(_WIN32) || defined(__BIONIC__)
@@ -128,10 +128,37 @@
128 break;
129 }
130 }
131 blob_reset(&secondTry);
132 }
133
134 /*
135 ** Prompt to save Fossil user password
136 */
137 int save_password_prompt(){
138 Blob x;
139 char c;
140 prompt_user("remember password (Y/n)? ", &x);
141 c = blob_str(&x)[0];
142 blob_reset(&x);
143 return ( c!='n' && c!='N' );
144 }
145
146 /*
147 ** Prompt for Fossil user password
148 */
149 char *prompt_for_user_password(const char *zUser){
150 char *zPrompt = mprintf("\rpassword for %s: ", zUser);
151 char *zPw;
152 Blob x;
153 fossil_force_newline();
154 prompt_for_password(zPrompt, &x, 0);
155 free(zPrompt);
156 zPw = mprintf("%b", &x);
157 blob_reset(&x);
158 return zPw;
159 }
160
161 /*
162 ** Prompt the user to enter a single line of text.
163 */
164 void prompt_user(const char *zPrompt, Blob *pIn){
165
+1 -8
--- src/utf8.c
+++ src/utf8.c
@@ -23,18 +23,11 @@
2323
#include "utf8.h"
2424
#include <sqlite3.h>
2525
#ifdef _WIN32
2626
# include <windows.h>
2727
#endif
28
-#ifdef __CYGWIN__
29
-# include <sys/cygwin.h>
30
-# define CP_UTF8 65001
31
- __declspec(dllimport) extern __stdcall int WideCharToMultiByte(int, int,
32
- const char *, int, const char *, int, const char *, const char *);
33
- __declspec(dllimport) extern __stdcall int MultiByteToWideChar(int, int,
34
- const char *, int, wchar_t*, int);
35
-#endif
28
+#include "cygsup.h"
3629
3730
#ifdef _WIN32
3831
/*
3932
** Translate MBCS to UTF-8. Return a pointer to the translated text.
4033
** Call fossil_mbcs_free() to deallocate any memory used to store the
4134
--- src/utf8.c
+++ src/utf8.c
@@ -23,18 +23,11 @@
23 #include "utf8.h"
24 #include <sqlite3.h>
25 #ifdef _WIN32
26 # include <windows.h>
27 #endif
28 #ifdef __CYGWIN__
29 # include <sys/cygwin.h>
30 # define CP_UTF8 65001
31 __declspec(dllimport) extern __stdcall int WideCharToMultiByte(int, int,
32 const char *, int, const char *, int, const char *, const char *);
33 __declspec(dllimport) extern __stdcall int MultiByteToWideChar(int, int,
34 const char *, int, wchar_t*, int);
35 #endif
36
37 #ifdef _WIN32
38 /*
39 ** Translate MBCS to UTF-8. Return a pointer to the translated text.
40 ** Call fossil_mbcs_free() to deallocate any memory used to store the
41
--- src/utf8.c
+++ src/utf8.c
@@ -23,18 +23,11 @@
23 #include "utf8.h"
24 #include <sqlite3.h>
25 #ifdef _WIN32
26 # include <windows.h>
27 #endif
28 #include "cygsup.h"
 
 
 
 
 
 
 
29
30 #ifdef _WIN32
31 /*
32 ** Translate MBCS to UTF-8. Return a pointer to the translated text.
33 ** Call fossil_mbcs_free() to deallocate any memory used to store the
34
+130 -10
--- src/vfile.c
+++ src/vfile.c
@@ -81,11 +81,11 @@
8181
if( db_exists("SELECT 1 FROM vfile WHERE vid=%d", vid) ){
8282
return;
8383
}
8484
8585
db_begin_transaction();
86
- p = manifest_get(vid, CFTYPE_MANIFEST);
86
+ p = manifest_get(vid, CFTYPE_MANIFEST, 0);
8787
if( p==0 ) {
8888
db_end_transaction(1);
8989
return;
9090
}
9191
db_prepare(&ins,
@@ -418,10 +418,11 @@
418418
/*
419419
** Values for the scanFlags parameter to vfile_scan().
420420
*/
421421
#define SCAN_ALL 0x001 /* Includes files that begin with "." */
422422
#define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
423
+#define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */
423424
#endif /* INTERFACE */
424425
425426
/*
426427
** Load into table SFILE the name of every ordinary file in
427428
** the directory pPath. Omit the first nPrefix characters of
@@ -428,15 +429,16 @@
428429
** of pPath when inserting into the SFILE table.
429430
**
430431
** Subdirectories are scanned recursively.
431432
** Omit files named in VFILE.
432433
**
433
-** Files whose names begin with "." are omitted unless allFlag is true.
434
+** Files whose names begin with "." are omitted unless the SCAN_ALL
435
+** flag is set.
434436
**
435
-** Any files or directories that match the glob pattern pIgnore are
436
-** excluded from the scan. Name matching occurs after the first
437
-** nPrefix characters are elided from the filename.
437
+** Any files or directories that match the glob patterns pIgnore*
438
+** are excluded from the scan. Name matching occurs after the
439
+** first nPrefix characters are elided from the filename.
438440
*/
439441
void vfile_scan(
440442
Blob *pPath, /* Directory to be scanned */
441443
int nPrefix, /* Number of bytes in directory name */
442444
unsigned scanFlags, /* Zero or more SCAN_xxx flags */
@@ -443,11 +445,10 @@
443445
Glob *pIgnore1, /* Do not add files that match this GLOB */
444446
Glob *pIgnore2 /* Omit files matching this GLOB too */
445447
){
446448
DIR *d;
447449
int origSize;
448
- const char *zDir;
449450
struct dirent *pEntry;
450451
int skipAll = 0;
451452
static Stmt ins;
452453
static int depth = 0;
453454
void *zNative;
@@ -468,12 +469,11 @@
468469
" pathname=:file %s)", filename_collation()
469470
);
470471
}
471472
depth++;
472473
473
- zDir = blob_str(pPath);
474
- zNative = fossil_utf8_to_filename(zDir);
474
+ zNative = fossil_utf8_to_filename(blob_str(pPath));
475475
d = opendir(zNative);
476476
if( d ){
477477
while( (pEntry=readdir(d))!=0 ){
478478
char *zPath;
479479
char *zUtf8;
@@ -509,10 +509,127 @@
509509
depth--;
510510
if( depth==0 ){
511511
db_finalize(&ins);
512512
}
513513
}
514
+
515
+/*
516
+** Scans the specified base directory for any directories within it, while
517
+** keeping a count of how many files they each contains, either directly or
518
+** indirectly.
519
+**
520
+** Subdirectories are scanned recursively.
521
+** Omit files named in VFILE.
522
+**
523
+** Directories whose names begin with "." are omitted unless the SCAN_ALL
524
+** flag is set.
525
+**
526
+** Any directories that match the glob patterns pIgnore* are excluded from
527
+** the scan. Name matching occurs after the first nPrefix characters are
528
+** elided from the filename.
529
+**
530
+** Returns the total number of files found.
531
+*/
532
+int vfile_dir_scan(
533
+ Blob *pPath, /* Base directory to be scanned */
534
+ int nPrefix, /* Number of bytes in base directory name */
535
+ unsigned scanFlags, /* Zero or more SCAN_xxx flags */
536
+ Glob *pIgnore1, /* Do not add directories that match this GLOB */
537
+ Glob *pIgnore2, /* Omit directories matching this GLOB too */
538
+ Glob *pIgnore3 /* Omit directories matching this GLOB too */
539
+){
540
+ int result = 0;
541
+ DIR *d;
542
+ int origSize;
543
+ struct dirent *pEntry;
544
+ int skipAll = 0;
545
+ static Stmt ins;
546
+ static Stmt upd;
547
+ static int depth = 0;
548
+ void *zNative;
549
+
550
+ origSize = blob_size(pPath);
551
+ if( pIgnore1 || pIgnore2 || pIgnore3 ){
552
+ blob_appendf(pPath, "/");
553
+ if( glob_match(pIgnore1, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1;
554
+ if( glob_match(pIgnore2, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1;
555
+ if( glob_match(pIgnore3, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1;
556
+ blob_resize(pPath, origSize);
557
+ }
558
+ if( skipAll ) return result;
559
+
560
+ if( depth==0 ){
561
+ db_multi_exec("DROP TABLE IF EXISTS dscan_temp;"
562
+ "CREATE TEMP TABLE dscan_temp("
563
+ " x TEXT PRIMARY KEY %s, y INTEGER)",
564
+ filename_collation());
565
+ db_prepare(&ins,
566
+ "INSERT OR IGNORE INTO dscan_temp(x, y) SELECT :file, :count"
567
+ " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
568
+ " pathname GLOB :file || '/*' %s)", filename_collation()
569
+ );
570
+ db_prepare(&upd,
571
+ "UPDATE OR IGNORE dscan_temp SET y = coalesce(y, 0) + 1"
572
+ " WHERE x=:file %s",
573
+ filename_collation()
574
+ );
575
+ }
576
+ depth++;
577
+
578
+ zNative = fossil_utf8_to_filename(blob_str(pPath));
579
+ d = opendir(zNative);
580
+ if( d ){
581
+ while( (pEntry=readdir(d))!=0 ){
582
+ char *zOrigPath;
583
+ char *zPath;
584
+ char *zUtf8;
585
+ if( pEntry->d_name[0]=='.' ){
586
+ if( (scanFlags & SCAN_ALL)==0 ) continue;
587
+ if( pEntry->d_name[1]==0 ) continue;
588
+ if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
589
+ }
590
+ zOrigPath = mprintf("%s", blob_str(pPath));
591
+ zUtf8 = fossil_filename_to_utf8(pEntry->d_name);
592
+ blob_appendf(pPath, "/%s", zUtf8);
593
+ zPath = blob_str(pPath);
594
+ if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
595
+ glob_match(pIgnore2, &zPath[nPrefix+1]) ||
596
+ glob_match(pIgnore3, &zPath[nPrefix+1]) ){
597
+ /* do nothing */
598
+ }else if( file_wd_isdir(zPath)==1 ){
599
+ if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){
600
+ char *zSavePath = mprintf("%s", zPath);
601
+ int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1,
602
+ pIgnore2, pIgnore3);
603
+ db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]);
604
+ db_bind_int(&ins, ":count", count);
605
+ db_step(&ins);
606
+ db_reset(&ins);
607
+ fossil_free(zSavePath);
608
+ result += count; /* found X normal files? */
609
+ }
610
+ }else if( file_wd_isfile_or_link(zPath) ){
611
+ db_bind_text(&upd, ":file", zOrigPath);
612
+ db_step(&upd);
613
+ db_reset(&upd);
614
+ result++; /* found 1 normal file */
615
+ }
616
+ fossil_filename_free(zUtf8);
617
+ blob_resize(pPath, origSize);
618
+ fossil_free(zOrigPath);
619
+ }
620
+ closedir(d);
621
+ }
622
+ fossil_filename_free(zNative);
623
+
624
+ depth--;
625
+ if( depth==0 ){
626
+ db_finalize(&upd);
627
+ db_finalize(&ins);
628
+ }
629
+ return result;
630
+}
514631
515632
/*
516633
** Compute an aggregate MD5 checksum over the disk image of every
517634
** file in vid. The file names are part of the checksum. The resulting
518635
** checksum is the same as is expected on the R-card of a manifest.
@@ -735,22 +852,25 @@
735852
** pManOut, should be identical.
736853
*/
737854
void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){
738855
int fid;
739856
Blob file;
857
+ Blob err;
740858
Manifest *pManifest;
741859
ManifestFile *pFile;
742860
char zBuf[100];
743861
744862
blob_zero(pOut);
863
+ blob_zero(&err);
745864
if( pManOut ){
746865
blob_zero(pManOut);
747866
}
748867
db_must_be_within_tree();
749
- pManifest = manifest_get(vid, CFTYPE_MANIFEST);
868
+ pManifest = manifest_get(vid, CFTYPE_MANIFEST, &err);
750869
if( pManifest==0 ){
751
- fossil_fatal("manifest file (%d) is malformed", vid);
870
+ fossil_fatal("manifest file (%d) is malformed:\n%s\n",
871
+ vid, blob_str(&err));
752872
}
753873
manifest_file_rewind(pManifest);
754874
while( (pFile = manifest_file_next(pManifest,0))!=0 ){
755875
if( pFile->zUuid==0 ) continue;
756876
fid = uuid_to_rid(pFile->zUuid, 0);
757877
--- src/vfile.c
+++ src/vfile.c
@@ -81,11 +81,11 @@
81 if( db_exists("SELECT 1 FROM vfile WHERE vid=%d", vid) ){
82 return;
83 }
84
85 db_begin_transaction();
86 p = manifest_get(vid, CFTYPE_MANIFEST);
87 if( p==0 ) {
88 db_end_transaction(1);
89 return;
90 }
91 db_prepare(&ins,
@@ -418,10 +418,11 @@
418 /*
419 ** Values for the scanFlags parameter to vfile_scan().
420 */
421 #define SCAN_ALL 0x001 /* Includes files that begin with "." */
422 #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
 
423 #endif /* INTERFACE */
424
425 /*
426 ** Load into table SFILE the name of every ordinary file in
427 ** the directory pPath. Omit the first nPrefix characters of
@@ -428,15 +429,16 @@
428 ** of pPath when inserting into the SFILE table.
429 **
430 ** Subdirectories are scanned recursively.
431 ** Omit files named in VFILE.
432 **
433 ** Files whose names begin with "." are omitted unless allFlag is true.
 
434 **
435 ** Any files or directories that match the glob pattern pIgnore are
436 ** excluded from the scan. Name matching occurs after the first
437 ** nPrefix characters are elided from the filename.
438 */
439 void vfile_scan(
440 Blob *pPath, /* Directory to be scanned */
441 int nPrefix, /* Number of bytes in directory name */
442 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
@@ -443,11 +445,10 @@
443 Glob *pIgnore1, /* Do not add files that match this GLOB */
444 Glob *pIgnore2 /* Omit files matching this GLOB too */
445 ){
446 DIR *d;
447 int origSize;
448 const char *zDir;
449 struct dirent *pEntry;
450 int skipAll = 0;
451 static Stmt ins;
452 static int depth = 0;
453 void *zNative;
@@ -468,12 +469,11 @@
468 " pathname=:file %s)", filename_collation()
469 );
470 }
471 depth++;
472
473 zDir = blob_str(pPath);
474 zNative = fossil_utf8_to_filename(zDir);
475 d = opendir(zNative);
476 if( d ){
477 while( (pEntry=readdir(d))!=0 ){
478 char *zPath;
479 char *zUtf8;
@@ -509,10 +509,127 @@
509 depth--;
510 if( depth==0 ){
511 db_finalize(&ins);
512 }
513 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
514
515 /*
516 ** Compute an aggregate MD5 checksum over the disk image of every
517 ** file in vid. The file names are part of the checksum. The resulting
518 ** checksum is the same as is expected on the R-card of a manifest.
@@ -735,22 +852,25 @@
735 ** pManOut, should be identical.
736 */
737 void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){
738 int fid;
739 Blob file;
 
740 Manifest *pManifest;
741 ManifestFile *pFile;
742 char zBuf[100];
743
744 blob_zero(pOut);
 
745 if( pManOut ){
746 blob_zero(pManOut);
747 }
748 db_must_be_within_tree();
749 pManifest = manifest_get(vid, CFTYPE_MANIFEST);
750 if( pManifest==0 ){
751 fossil_fatal("manifest file (%d) is malformed", vid);
 
752 }
753 manifest_file_rewind(pManifest);
754 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
755 if( pFile->zUuid==0 ) continue;
756 fid = uuid_to_rid(pFile->zUuid, 0);
757
--- src/vfile.c
+++ src/vfile.c
@@ -81,11 +81,11 @@
81 if( db_exists("SELECT 1 FROM vfile WHERE vid=%d", vid) ){
82 return;
83 }
84
85 db_begin_transaction();
86 p = manifest_get(vid, CFTYPE_MANIFEST, 0);
87 if( p==0 ) {
88 db_end_transaction(1);
89 return;
90 }
91 db_prepare(&ins,
@@ -418,10 +418,11 @@
418 /*
419 ** Values for the scanFlags parameter to vfile_scan().
420 */
421 #define SCAN_ALL 0x001 /* Includes files that begin with "." */
422 #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
423 #define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */
424 #endif /* INTERFACE */
425
426 /*
427 ** Load into table SFILE the name of every ordinary file in
428 ** the directory pPath. Omit the first nPrefix characters of
@@ -428,15 +429,16 @@
429 ** of pPath when inserting into the SFILE table.
430 **
431 ** Subdirectories are scanned recursively.
432 ** Omit files named in VFILE.
433 **
434 ** Files whose names begin with "." are omitted unless the SCAN_ALL
435 ** flag is set.
436 **
437 ** Any files or directories that match the glob patterns pIgnore*
438 ** are excluded from the scan. Name matching occurs after the
439 ** first nPrefix characters are elided from the filename.
440 */
441 void vfile_scan(
442 Blob *pPath, /* Directory to be scanned */
443 int nPrefix, /* Number of bytes in directory name */
444 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
@@ -443,11 +445,10 @@
445 Glob *pIgnore1, /* Do not add files that match this GLOB */
446 Glob *pIgnore2 /* Omit files matching this GLOB too */
447 ){
448 DIR *d;
449 int origSize;
 
450 struct dirent *pEntry;
451 int skipAll = 0;
452 static Stmt ins;
453 static int depth = 0;
454 void *zNative;
@@ -468,12 +469,11 @@
469 " pathname=:file %s)", filename_collation()
470 );
471 }
472 depth++;
473
474 zNative = fossil_utf8_to_filename(blob_str(pPath));
 
475 d = opendir(zNative);
476 if( d ){
477 while( (pEntry=readdir(d))!=0 ){
478 char *zPath;
479 char *zUtf8;
@@ -509,10 +509,127 @@
509 depth--;
510 if( depth==0 ){
511 db_finalize(&ins);
512 }
513 }
514
515 /*
516 ** Scans the specified base directory for any directories within it, while
517 ** keeping a count of how many files they each contains, either directly or
518 ** indirectly.
519 **
520 ** Subdirectories are scanned recursively.
521 ** Omit files named in VFILE.
522 **
523 ** Directories whose names begin with "." are omitted unless the SCAN_ALL
524 ** flag is set.
525 **
526 ** Any directories that match the glob patterns pIgnore* are excluded from
527 ** the scan. Name matching occurs after the first nPrefix characters are
528 ** elided from the filename.
529 **
530 ** Returns the total number of files found.
531 */
532 int vfile_dir_scan(
533 Blob *pPath, /* Base directory to be scanned */
534 int nPrefix, /* Number of bytes in base directory name */
535 unsigned scanFlags, /* Zero or more SCAN_xxx flags */
536 Glob *pIgnore1, /* Do not add directories that match this GLOB */
537 Glob *pIgnore2, /* Omit directories matching this GLOB too */
538 Glob *pIgnore3 /* Omit directories matching this GLOB too */
539 ){
540 int result = 0;
541 DIR *d;
542 int origSize;
543 struct dirent *pEntry;
544 int skipAll = 0;
545 static Stmt ins;
546 static Stmt upd;
547 static int depth = 0;
548 void *zNative;
549
550 origSize = blob_size(pPath);
551 if( pIgnore1 || pIgnore2 || pIgnore3 ){
552 blob_appendf(pPath, "/");
553 if( glob_match(pIgnore1, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1;
554 if( glob_match(pIgnore2, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1;
555 if( glob_match(pIgnore3, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1;
556 blob_resize(pPath, origSize);
557 }
558 if( skipAll ) return result;
559
560 if( depth==0 ){
561 db_multi_exec("DROP TABLE IF EXISTS dscan_temp;"
562 "CREATE TEMP TABLE dscan_temp("
563 " x TEXT PRIMARY KEY %s, y INTEGER)",
564 filename_collation());
565 db_prepare(&ins,
566 "INSERT OR IGNORE INTO dscan_temp(x, y) SELECT :file, :count"
567 " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
568 " pathname GLOB :file || '/*' %s)", filename_collation()
569 );
570 db_prepare(&upd,
571 "UPDATE OR IGNORE dscan_temp SET y = coalesce(y, 0) + 1"
572 " WHERE x=:file %s",
573 filename_collation()
574 );
575 }
576 depth++;
577
578 zNative = fossil_utf8_to_filename(blob_str(pPath));
579 d = opendir(zNative);
580 if( d ){
581 while( (pEntry=readdir(d))!=0 ){
582 char *zOrigPath;
583 char *zPath;
584 char *zUtf8;
585 if( pEntry->d_name[0]=='.' ){
586 if( (scanFlags & SCAN_ALL)==0 ) continue;
587 if( pEntry->d_name[1]==0 ) continue;
588 if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
589 }
590 zOrigPath = mprintf("%s", blob_str(pPath));
591 zUtf8 = fossil_filename_to_utf8(pEntry->d_name);
592 blob_appendf(pPath, "/%s", zUtf8);
593 zPath = blob_str(pPath);
594 if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
595 glob_match(pIgnore2, &zPath[nPrefix+1]) ||
596 glob_match(pIgnore3, &zPath[nPrefix+1]) ){
597 /* do nothing */
598 }else if( file_wd_isdir(zPath)==1 ){
599 if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){
600 char *zSavePath = mprintf("%s", zPath);
601 int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1,
602 pIgnore2, pIgnore3);
603 db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]);
604 db_bind_int(&ins, ":count", count);
605 db_step(&ins);
606 db_reset(&ins);
607 fossil_free(zSavePath);
608 result += count; /* found X normal files? */
609 }
610 }else if( file_wd_isfile_or_link(zPath) ){
611 db_bind_text(&upd, ":file", zOrigPath);
612 db_step(&upd);
613 db_reset(&upd);
614 result++; /* found 1 normal file */
615 }
616 fossil_filename_free(zUtf8);
617 blob_resize(pPath, origSize);
618 fossil_free(zOrigPath);
619 }
620 closedir(d);
621 }
622 fossil_filename_free(zNative);
623
624 depth--;
625 if( depth==0 ){
626 db_finalize(&upd);
627 db_finalize(&ins);
628 }
629 return result;
630 }
631
632 /*
633 ** Compute an aggregate MD5 checksum over the disk image of every
634 ** file in vid. The file names are part of the checksum. The resulting
635 ** checksum is the same as is expected on the R-card of a manifest.
@@ -735,22 +852,25 @@
852 ** pManOut, should be identical.
853 */
854 void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){
855 int fid;
856 Blob file;
857 Blob err;
858 Manifest *pManifest;
859 ManifestFile *pFile;
860 char zBuf[100];
861
862 blob_zero(pOut);
863 blob_zero(&err);
864 if( pManOut ){
865 blob_zero(pManOut);
866 }
867 db_must_be_within_tree();
868 pManifest = manifest_get(vid, CFTYPE_MANIFEST, &err);
869 if( pManifest==0 ){
870 fossil_fatal("manifest file (%d) is malformed:\n%s\n",
871 vid, blob_str(&err));
872 }
873 manifest_file_rewind(pManifest);
874 while( (pFile = manifest_file_next(pManifest,0))!=0 ){
875 if( pFile->zUuid==0 ) continue;
876 fid = uuid_to_rid(pFile->zUuid, 0);
877
+7 -7
--- src/wiki.c
+++ src/wiki.c
@@ -16,13 +16,13 @@
1616
**
1717
*******************************************************************************
1818
**
1919
** This file contains code to do formatting of wiki text.
2020
*/
21
+#include "config.h"
2122
#include <assert.h>
2223
#include <ctype.h>
23
-#include "config.h"
2424
#include "wiki.h"
2525
2626
/*
2727
** Return true if the input string is a well-formed wiki page name.
2828
**
@@ -228,11 +228,11 @@
228228
"SELECT rid FROM tagxref"
229229
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
230230
" ORDER BY mtime DESC", zTag
231231
);
232232
free(zTag);
233
- pWiki = manifest_get(rid, CFTYPE_WIKI);
233
+ pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
234234
if( pWiki ){
235235
zBody = pWiki->zWiki;
236236
zMimetype = pWiki->zMimetype;
237237
}
238238
}
@@ -392,11 +392,11 @@
392392
free(zTag);
393393
if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
394394
login_needed();
395395
return;
396396
}
397
- if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
397
+ if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
398398
zBody = pWiki->zWiki;
399399
zMimetype = pWiki->zMimetype;
400400
}
401401
}
402402
if( P("submit")!=0 && zBody!=0
@@ -633,11 +633,11 @@
633633
blob_appendf(&body, db_get("sandbox",""));
634634
appendRemark(&body, zMimetype);
635635
db_set("sandbox", blob_str(&body), 0);
636636
}else{
637637
login_verify_csrf_secret();
638
- pWiki = manifest_get(rid, CFTYPE_WIKI);
638
+ pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
639639
if( pWiki ){
640640
blob_append(&body, pWiki->zWiki, -1);
641641
manifest_destroy(pWiki);
642642
}
643643
blob_zero(&wiki);
@@ -783,15 +783,15 @@
783783
" WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)"
784784
" ORDER BY event.mtime DESC LIMIT 1",
785785
zPageName, rid1
786786
);
787787
}
788
- pW1 = manifest_get(rid1, CFTYPE_WIKI);
788
+ pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
789789
if( pW1==0 ) fossil_redirect_home();
790790
blob_init(&w1, pW1->zWiki, -1);
791791
blob_zero(&w2);
792
- if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
792
+ if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI, 0))!=0 ){
793793
blob_init(&w2, pW2->zWiki, -1);
794794
}
795795
blob_zero(&d);
796796
diffFlags = construct_diff_flags(1,0);
797797
text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
@@ -1065,11 +1065,11 @@
10651065
rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
10661066
" WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
10671067
" ORDER BY x.mtime DESC LIMIT 1",
10681068
zPageName
10691069
);
1070
- if( (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
1070
+ if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
10711071
zBody = pWiki->zWiki;
10721072
}
10731073
if( zBody==0 ){
10741074
fossil_fatal("wiki page [%s] not found",zPageName);
10751075
}
10761076
--- src/wiki.c
+++ src/wiki.c
@@ -16,13 +16,13 @@
16 **
17 *******************************************************************************
18 **
19 ** This file contains code to do formatting of wiki text.
20 */
 
21 #include <assert.h>
22 #include <ctype.h>
23 #include "config.h"
24 #include "wiki.h"
25
26 /*
27 ** Return true if the input string is a well-formed wiki page name.
28 **
@@ -228,11 +228,11 @@
228 "SELECT rid FROM tagxref"
229 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
230 " ORDER BY mtime DESC", zTag
231 );
232 free(zTag);
233 pWiki = manifest_get(rid, CFTYPE_WIKI);
234 if( pWiki ){
235 zBody = pWiki->zWiki;
236 zMimetype = pWiki->zMimetype;
237 }
238 }
@@ -392,11 +392,11 @@
392 free(zTag);
393 if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
394 login_needed();
395 return;
396 }
397 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
398 zBody = pWiki->zWiki;
399 zMimetype = pWiki->zMimetype;
400 }
401 }
402 if( P("submit")!=0 && zBody!=0
@@ -633,11 +633,11 @@
633 blob_appendf(&body, db_get("sandbox",""));
634 appendRemark(&body, zMimetype);
635 db_set("sandbox", blob_str(&body), 0);
636 }else{
637 login_verify_csrf_secret();
638 pWiki = manifest_get(rid, CFTYPE_WIKI);
639 if( pWiki ){
640 blob_append(&body, pWiki->zWiki, -1);
641 manifest_destroy(pWiki);
642 }
643 blob_zero(&wiki);
@@ -783,15 +783,15 @@
783 " WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)"
784 " ORDER BY event.mtime DESC LIMIT 1",
785 zPageName, rid1
786 );
787 }
788 pW1 = manifest_get(rid1, CFTYPE_WIKI);
789 if( pW1==0 ) fossil_redirect_home();
790 blob_init(&w1, pW1->zWiki, -1);
791 blob_zero(&w2);
792 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
793 blob_init(&w2, pW2->zWiki, -1);
794 }
795 blob_zero(&d);
796 diffFlags = construct_diff_flags(1,0);
797 text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
@@ -1065,11 +1065,11 @@
1065 rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
1066 " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
1067 " ORDER BY x.mtime DESC LIMIT 1",
1068 zPageName
1069 );
1070 if( (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
1071 zBody = pWiki->zWiki;
1072 }
1073 if( zBody==0 ){
1074 fossil_fatal("wiki page [%s] not found",zPageName);
1075 }
1076
--- src/wiki.c
+++ src/wiki.c
@@ -16,13 +16,13 @@
16 **
17 *******************************************************************************
18 **
19 ** This file contains code to do formatting of wiki text.
20 */
21 #include "config.h"
22 #include <assert.h>
23 #include <ctype.h>
 
24 #include "wiki.h"
25
26 /*
27 ** Return true if the input string is a well-formed wiki page name.
28 **
@@ -228,11 +228,11 @@
228 "SELECT rid FROM tagxref"
229 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
230 " ORDER BY mtime DESC", zTag
231 );
232 free(zTag);
233 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
234 if( pWiki ){
235 zBody = pWiki->zWiki;
236 zMimetype = pWiki->zMimetype;
237 }
238 }
@@ -392,11 +392,11 @@
392 free(zTag);
393 if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
394 login_needed();
395 return;
396 }
397 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
398 zBody = pWiki->zWiki;
399 zMimetype = pWiki->zMimetype;
400 }
401 }
402 if( P("submit")!=0 && zBody!=0
@@ -633,11 +633,11 @@
633 blob_appendf(&body, db_get("sandbox",""));
634 appendRemark(&body, zMimetype);
635 db_set("sandbox", blob_str(&body), 0);
636 }else{
637 login_verify_csrf_secret();
638 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
639 if( pWiki ){
640 blob_append(&body, pWiki->zWiki, -1);
641 manifest_destroy(pWiki);
642 }
643 blob_zero(&wiki);
@@ -783,15 +783,15 @@
783 " WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)"
784 " ORDER BY event.mtime DESC LIMIT 1",
785 zPageName, rid1
786 );
787 }
788 pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
789 if( pW1==0 ) fossil_redirect_home();
790 blob_init(&w1, pW1->zWiki, -1);
791 blob_zero(&w2);
792 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI, 0))!=0 ){
793 blob_init(&w2, pW2->zWiki, -1);
794 }
795 blob_zero(&d);
796 diffFlags = construct_diff_flags(1,0);
797 text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
@@ -1065,11 +1065,11 @@
1065 rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
1066 " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
1067 " ORDER BY x.mtime DESC LIMIT 1",
1068 zPageName
1069 );
1070 if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
1071 zBody = pWiki->zWiki;
1072 }
1073 if( zBody==0 ){
1074 fossil_fatal("wiki page [%s] not found",zPageName);
1075 }
1076
+7 -7
--- src/wiki.c
+++ src/wiki.c
@@ -16,13 +16,13 @@
1616
**
1717
*******************************************************************************
1818
**
1919
** This file contains code to do formatting of wiki text.
2020
*/
21
+#include "config.h"
2122
#include <assert.h>
2223
#include <ctype.h>
23
-#include "config.h"
2424
#include "wiki.h"
2525
2626
/*
2727
** Return true if the input string is a well-formed wiki page name.
2828
**
@@ -228,11 +228,11 @@
228228
"SELECT rid FROM tagxref"
229229
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
230230
" ORDER BY mtime DESC", zTag
231231
);
232232
free(zTag);
233
- pWiki = manifest_get(rid, CFTYPE_WIKI);
233
+ pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
234234
if( pWiki ){
235235
zBody = pWiki->zWiki;
236236
zMimetype = pWiki->zMimetype;
237237
}
238238
}
@@ -392,11 +392,11 @@
392392
free(zTag);
393393
if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
394394
login_needed();
395395
return;
396396
}
397
- if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
397
+ if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
398398
zBody = pWiki->zWiki;
399399
zMimetype = pWiki->zMimetype;
400400
}
401401
}
402402
if( P("submit")!=0 && zBody!=0
@@ -633,11 +633,11 @@
633633
blob_appendf(&body, db_get("sandbox",""));
634634
appendRemark(&body, zMimetype);
635635
db_set("sandbox", blob_str(&body), 0);
636636
}else{
637637
login_verify_csrf_secret();
638
- pWiki = manifest_get(rid, CFTYPE_WIKI);
638
+ pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
639639
if( pWiki ){
640640
blob_append(&body, pWiki->zWiki, -1);
641641
manifest_destroy(pWiki);
642642
}
643643
blob_zero(&wiki);
@@ -783,15 +783,15 @@
783783
" WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)"
784784
" ORDER BY event.mtime DESC LIMIT 1",
785785
zPageName, rid1
786786
);
787787
}
788
- pW1 = manifest_get(rid1, CFTYPE_WIKI);
788
+ pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
789789
if( pW1==0 ) fossil_redirect_home();
790790
blob_init(&w1, pW1->zWiki, -1);
791791
blob_zero(&w2);
792
- if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
792
+ if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI, 0))!=0 ){
793793
blob_init(&w2, pW2->zWiki, -1);
794794
}
795795
blob_zero(&d);
796796
diffFlags = construct_diff_flags(1,0);
797797
text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
@@ -1065,11 +1065,11 @@
10651065
rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
10661066
" WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
10671067
" ORDER BY x.mtime DESC LIMIT 1",
10681068
zPageName
10691069
);
1070
- if( (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
1070
+ if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
10711071
zBody = pWiki->zWiki;
10721072
}
10731073
if( zBody==0 ){
10741074
fossil_fatal("wiki page [%s] not found",zPageName);
10751075
}
10761076
--- src/wiki.c
+++ src/wiki.c
@@ -16,13 +16,13 @@
16 **
17 *******************************************************************************
18 **
19 ** This file contains code to do formatting of wiki text.
20 */
 
21 #include <assert.h>
22 #include <ctype.h>
23 #include "config.h"
24 #include "wiki.h"
25
26 /*
27 ** Return true if the input string is a well-formed wiki page name.
28 **
@@ -228,11 +228,11 @@
228 "SELECT rid FROM tagxref"
229 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
230 " ORDER BY mtime DESC", zTag
231 );
232 free(zTag);
233 pWiki = manifest_get(rid, CFTYPE_WIKI);
234 if( pWiki ){
235 zBody = pWiki->zWiki;
236 zMimetype = pWiki->zMimetype;
237 }
238 }
@@ -392,11 +392,11 @@
392 free(zTag);
393 if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
394 login_needed();
395 return;
396 }
397 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
398 zBody = pWiki->zWiki;
399 zMimetype = pWiki->zMimetype;
400 }
401 }
402 if( P("submit")!=0 && zBody!=0
@@ -633,11 +633,11 @@
633 blob_appendf(&body, db_get("sandbox",""));
634 appendRemark(&body, zMimetype);
635 db_set("sandbox", blob_str(&body), 0);
636 }else{
637 login_verify_csrf_secret();
638 pWiki = manifest_get(rid, CFTYPE_WIKI);
639 if( pWiki ){
640 blob_append(&body, pWiki->zWiki, -1);
641 manifest_destroy(pWiki);
642 }
643 blob_zero(&wiki);
@@ -783,15 +783,15 @@
783 " WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)"
784 " ORDER BY event.mtime DESC LIMIT 1",
785 zPageName, rid1
786 );
787 }
788 pW1 = manifest_get(rid1, CFTYPE_WIKI);
789 if( pW1==0 ) fossil_redirect_home();
790 blob_init(&w1, pW1->zWiki, -1);
791 blob_zero(&w2);
792 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
793 blob_init(&w2, pW2->zWiki, -1);
794 }
795 blob_zero(&d);
796 diffFlags = construct_diff_flags(1,0);
797 text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
@@ -1065,11 +1065,11 @@
1065 rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
1066 " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
1067 " ORDER BY x.mtime DESC LIMIT 1",
1068 zPageName
1069 );
1070 if( (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
1071 zBody = pWiki->zWiki;
1072 }
1073 if( zBody==0 ){
1074 fossil_fatal("wiki page [%s] not found",zPageName);
1075 }
1076
--- src/wiki.c
+++ src/wiki.c
@@ -16,13 +16,13 @@
16 **
17 *******************************************************************************
18 **
19 ** This file contains code to do formatting of wiki text.
20 */
21 #include "config.h"
22 #include <assert.h>
23 #include <ctype.h>
 
24 #include "wiki.h"
25
26 /*
27 ** Return true if the input string is a well-formed wiki page name.
28 **
@@ -228,11 +228,11 @@
228 "SELECT rid FROM tagxref"
229 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
230 " ORDER BY mtime DESC", zTag
231 );
232 free(zTag);
233 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
234 if( pWiki ){
235 zBody = pWiki->zWiki;
236 zMimetype = pWiki->zMimetype;
237 }
238 }
@@ -392,11 +392,11 @@
392 free(zTag);
393 if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
394 login_needed();
395 return;
396 }
397 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
398 zBody = pWiki->zWiki;
399 zMimetype = pWiki->zMimetype;
400 }
401 }
402 if( P("submit")!=0 && zBody!=0
@@ -633,11 +633,11 @@
633 blob_appendf(&body, db_get("sandbox",""));
634 appendRemark(&body, zMimetype);
635 db_set("sandbox", blob_str(&body), 0);
636 }else{
637 login_verify_csrf_secret();
638 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
639 if( pWiki ){
640 blob_append(&body, pWiki->zWiki, -1);
641 manifest_destroy(pWiki);
642 }
643 blob_zero(&wiki);
@@ -783,15 +783,15 @@
783 " WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)"
784 " ORDER BY event.mtime DESC LIMIT 1",
785 zPageName, rid1
786 );
787 }
788 pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
789 if( pW1==0 ) fossil_redirect_home();
790 blob_init(&w1, pW1->zWiki, -1);
791 blob_zero(&w2);
792 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI, 0))!=0 ){
793 blob_init(&w2, pW2->zWiki, -1);
794 }
795 blob_zero(&d);
796 diffFlags = construct_diff_flags(1,0);
797 text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
@@ -1065,11 +1065,11 @@
1065 rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
1066 " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
1067 " ORDER BY x.mtime DESC LIMIT 1",
1068 zPageName
1069 );
1070 if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
1071 zBody = pWiki->zWiki;
1072 }
1073 if( zBody==0 ){
1074 fossil_fatal("wiki page [%s] not found",zPageName);
1075 }
1076
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -15,12 +15,12 @@
1515
**
1616
*******************************************************************************
1717
**
1818
** This file contains code to do formatting of wiki text.
1919
*/
20
-#include <assert.h>
2120
#include "config.h"
21
+#include <assert.h>
2222
#include "wikiformat.h"
2323
2424
#if INTERFACE
2525
/*
2626
** Allowed wiki transformation operations
2727
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -15,12 +15,12 @@
15 **
16 *******************************************************************************
17 **
18 ** This file contains code to do formatting of wiki text.
19 */
20 #include <assert.h>
21 #include "config.h"
 
22 #include "wikiformat.h"
23
24 #if INTERFACE
25 /*
26 ** Allowed wiki transformation operations
27
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -15,12 +15,12 @@
15 **
16 *******************************************************************************
17 **
18 ** This file contains code to do formatting of wiki text.
19 */
 
20 #include "config.h"
21 #include <assert.h>
22 #include "wikiformat.h"
23
24 #if INTERFACE
25 /*
26 ** Allowed wiki transformation operations
27
+1 -1
--- src/wysiwyg.c
+++ src/wysiwyg.c
@@ -16,13 +16,13 @@
1616
*******************************************************************************
1717
**
1818
** This file contains code that generates WYSIWYG text editors on
1919
** web pages.
2020
*/
21
+#include "config.h"
2122
#include <assert.h>
2223
#include <ctype.h>
23
-#include "config.h"
2424
#include "wysiwyg.h"
2525
2626
2727
/*
2828
** Output code for a WYSIWYG editor. The caller must have already generated
2929
--- src/wysiwyg.c
+++ src/wysiwyg.c
@@ -16,13 +16,13 @@
16 *******************************************************************************
17 **
18 ** This file contains code that generates WYSIWYG text editors on
19 ** web pages.
20 */
 
21 #include <assert.h>
22 #include <ctype.h>
23 #include "config.h"
24 #include "wysiwyg.h"
25
26
27 /*
28 ** Output code for a WYSIWYG editor. The caller must have already generated
29
--- src/wysiwyg.c
+++ src/wysiwyg.c
@@ -16,13 +16,13 @@
16 *******************************************************************************
17 **
18 ** This file contains code that generates WYSIWYG text editors on
19 ** web pages.
20 */
21 #include "config.h"
22 #include <assert.h>
23 #include <ctype.h>
 
24 #include "wysiwyg.h"
25
26
27 /*
28 ** Output code for a WYSIWYG editor. The caller must have already generated
29
+18 -11
--- src/xfer.c
+++ src/xfer.c
@@ -1324,10 +1324,11 @@
13241324
{
13251325
cgi_reset_content();
13261326
@ error bad\scommand:\s%F(blob_str(&xfer.line))
13271327
}
13281328
blobarray_reset(xfer.aToken, xfer.nToken);
1329
+ blob_reset(&xfer.line);
13291330
}
13301331
if( isPush ){
13311332
if( run_script("xfer-push-script", 0) ){
13321333
cgi_reset_content();
13331334
@ error push\sscript\sfailed:\s%F(g.zErrMsg)
@@ -1351,10 +1352,11 @@
13511352
if( xfer.syncPrivate ) send_private(&xfer);
13521353
}
13531354
if( recvConfig ){
13541355
configure_finalize_receive();
13551356
}
1357
+ db_multi_exec("DROP TABLE onremote");
13561358
manifest_crosslink_end();
13571359
13581360
/* Send the server timestamp last, in case prior processing happened
13591361
** to use up a significant fraction of our time window.
13601362
*/
@@ -1521,11 +1523,10 @@
15211523
nCardSent++;
15221524
if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
15231525
if( (syncFlags & SYNC_RESYNC)!=0 ) xfer.resync = 0x7fffffff;
15241526
}
15251527
manifest_crosslink_begin();
1526
- transport_global_startup();
15271528
if( syncFlags & SYNC_VERBOSE ){
15281529
fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
15291530
}
15301531
15311532
while( go ){
@@ -1600,11 +1601,22 @@
16001601
*/
16011602
zRandomness = db_text(0, "SELECT hex(randomblob(20))");
16021603
blob_appendf(&send, "# %s\n", zRandomness);
16031604
free(zRandomness);
16041605
1606
+ if( syncFlags & SYNC_VERBOSE ){
1607
+ fossil_print("waiting for server...");
1608
+ }
1609
+ fflush(stdout);
16051610
/* Exchange messages with the server */
1611
+ if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1612
+ MAX_REDIRECTS) ){
1613
+ nErr++;
1614
+ break;
1615
+ }
1616
+
1617
+ /* Output current stats */
16061618
if( syncFlags & SYNC_VERBOSE ){
16071619
fossil_print(zValueFormat, "Sent:",
16081620
blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
16091621
xfer.nFileSent, xfer.nDeltaSent);
16101622
}else{
@@ -1616,19 +1628,11 @@
16161628
nCardRcvd = 0;
16171629
xfer.nFileSent = 0;
16181630
xfer.nDeltaSent = 0;
16191631
xfer.nGimmeSent = 0;
16201632
xfer.nIGotSent = 0;
1621
- if( syncFlags & SYNC_VERBOSE ){
1622
- fossil_print("waiting for server...");
1623
- }
1624
- fflush(stdout);
1625
- if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1626
- MAX_REDIRECTS) ){
1627
- nErr++;
1628
- break;
1629
- }
1633
+
16301634
lastPctDone = -1;
16311635
blob_reset(&send);
16321636
rArrivalTime = db_double(0.0, "SELECT julianday('now')");
16331637
16341638
/* Send the send-private pragma if we are trying to sync private data */
@@ -1871,11 +1875,14 @@
18711875
fossil_print("Error: %s\n", zMsg);
18721876
if( fossil_strcmp(zMsg, "login failed")==0 ){
18731877
if( nCycle<2 ){
18741878
g.urlPasswd = 0;
18751879
go = 1;
1876
- if( g.cgiOutput==0 ) url_prompt_for_password();
1880
+ if( g.cgiOutput==0 ){
1881
+ g.urlFlags |= URL_PROMPT_PW;
1882
+ url_prompt_for_password();
1883
+ }
18771884
}
18781885
}else{
18791886
blob_appendf(&xfer.err, "server says: %s\n", zMsg);
18801887
nErr++;
18811888
}
18821889
--- src/xfer.c
+++ src/xfer.c
@@ -1324,10 +1324,11 @@
1324 {
1325 cgi_reset_content();
1326 @ error bad\scommand:\s%F(blob_str(&xfer.line))
1327 }
1328 blobarray_reset(xfer.aToken, xfer.nToken);
 
1329 }
1330 if( isPush ){
1331 if( run_script("xfer-push-script", 0) ){
1332 cgi_reset_content();
1333 @ error push\sscript\sfailed:\s%F(g.zErrMsg)
@@ -1351,10 +1352,11 @@
1351 if( xfer.syncPrivate ) send_private(&xfer);
1352 }
1353 if( recvConfig ){
1354 configure_finalize_receive();
1355 }
 
1356 manifest_crosslink_end();
1357
1358 /* Send the server timestamp last, in case prior processing happened
1359 ** to use up a significant fraction of our time window.
1360 */
@@ -1521,11 +1523,10 @@
1521 nCardSent++;
1522 if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
1523 if( (syncFlags & SYNC_RESYNC)!=0 ) xfer.resync = 0x7fffffff;
1524 }
1525 manifest_crosslink_begin();
1526 transport_global_startup();
1527 if( syncFlags & SYNC_VERBOSE ){
1528 fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
1529 }
1530
1531 while( go ){
@@ -1600,11 +1601,22 @@
1600 */
1601 zRandomness = db_text(0, "SELECT hex(randomblob(20))");
1602 blob_appendf(&send, "# %s\n", zRandomness);
1603 free(zRandomness);
1604
 
 
 
 
1605 /* Exchange messages with the server */
 
 
 
 
 
 
 
1606 if( syncFlags & SYNC_VERBOSE ){
1607 fossil_print(zValueFormat, "Sent:",
1608 blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
1609 xfer.nFileSent, xfer.nDeltaSent);
1610 }else{
@@ -1616,19 +1628,11 @@
1616 nCardRcvd = 0;
1617 xfer.nFileSent = 0;
1618 xfer.nDeltaSent = 0;
1619 xfer.nGimmeSent = 0;
1620 xfer.nIGotSent = 0;
1621 if( syncFlags & SYNC_VERBOSE ){
1622 fossil_print("waiting for server...");
1623 }
1624 fflush(stdout);
1625 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1626 MAX_REDIRECTS) ){
1627 nErr++;
1628 break;
1629 }
1630 lastPctDone = -1;
1631 blob_reset(&send);
1632 rArrivalTime = db_double(0.0, "SELECT julianday('now')");
1633
1634 /* Send the send-private pragma if we are trying to sync private data */
@@ -1871,11 +1875,14 @@
1871 fossil_print("Error: %s\n", zMsg);
1872 if( fossil_strcmp(zMsg, "login failed")==0 ){
1873 if( nCycle<2 ){
1874 g.urlPasswd = 0;
1875 go = 1;
1876 if( g.cgiOutput==0 ) url_prompt_for_password();
 
 
 
1877 }
1878 }else{
1879 blob_appendf(&xfer.err, "server says: %s\n", zMsg);
1880 nErr++;
1881 }
1882
--- src/xfer.c
+++ src/xfer.c
@@ -1324,10 +1324,11 @@
1324 {
1325 cgi_reset_content();
1326 @ error bad\scommand:\s%F(blob_str(&xfer.line))
1327 }
1328 blobarray_reset(xfer.aToken, xfer.nToken);
1329 blob_reset(&xfer.line);
1330 }
1331 if( isPush ){
1332 if( run_script("xfer-push-script", 0) ){
1333 cgi_reset_content();
1334 @ error push\sscript\sfailed:\s%F(g.zErrMsg)
@@ -1351,10 +1352,11 @@
1352 if( xfer.syncPrivate ) send_private(&xfer);
1353 }
1354 if( recvConfig ){
1355 configure_finalize_receive();
1356 }
1357 db_multi_exec("DROP TABLE onremote");
1358 manifest_crosslink_end();
1359
1360 /* Send the server timestamp last, in case prior processing happened
1361 ** to use up a significant fraction of our time window.
1362 */
@@ -1521,11 +1523,10 @@
1523 nCardSent++;
1524 if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
1525 if( (syncFlags & SYNC_RESYNC)!=0 ) xfer.resync = 0x7fffffff;
1526 }
1527 manifest_crosslink_begin();
 
1528 if( syncFlags & SYNC_VERBOSE ){
1529 fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
1530 }
1531
1532 while( go ){
@@ -1600,11 +1601,22 @@
1601 */
1602 zRandomness = db_text(0, "SELECT hex(randomblob(20))");
1603 blob_appendf(&send, "# %s\n", zRandomness);
1604 free(zRandomness);
1605
1606 if( syncFlags & SYNC_VERBOSE ){
1607 fossil_print("waiting for server...");
1608 }
1609 fflush(stdout);
1610 /* Exchange messages with the server */
1611 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1612 MAX_REDIRECTS) ){
1613 nErr++;
1614 break;
1615 }
1616
1617 /* Output current stats */
1618 if( syncFlags & SYNC_VERBOSE ){
1619 fossil_print(zValueFormat, "Sent:",
1620 blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
1621 xfer.nFileSent, xfer.nDeltaSent);
1622 }else{
@@ -1616,19 +1628,11 @@
1628 nCardRcvd = 0;
1629 xfer.nFileSent = 0;
1630 xfer.nDeltaSent = 0;
1631 xfer.nGimmeSent = 0;
1632 xfer.nIGotSent = 0;
1633
 
 
 
 
 
 
 
 
1634 lastPctDone = -1;
1635 blob_reset(&send);
1636 rArrivalTime = db_double(0.0, "SELECT julianday('now')");
1637
1638 /* Send the send-private pragma if we are trying to sync private data */
@@ -1871,11 +1875,14 @@
1875 fossil_print("Error: %s\n", zMsg);
1876 if( fossil_strcmp(zMsg, "login failed")==0 ){
1877 if( nCycle<2 ){
1878 g.urlPasswd = 0;
1879 go = 1;
1880 if( g.cgiOutput==0 ){
1881 g.urlFlags |= URL_PROMPT_PW;
1882 url_prompt_for_password();
1883 }
1884 }
1885 }else{
1886 blob_appendf(&xfer.err, "server says: %s\n", zMsg);
1887 nErr++;
1888 }
1889
+18 -11
--- src/xfer.c
+++ src/xfer.c
@@ -1324,10 +1324,11 @@
13241324
{
13251325
cgi_reset_content();
13261326
@ error bad\scommand:\s%F(blob_str(&xfer.line))
13271327
}
13281328
blobarray_reset(xfer.aToken, xfer.nToken);
1329
+ blob_reset(&xfer.line);
13291330
}
13301331
if( isPush ){
13311332
if( run_script("xfer-push-script", 0) ){
13321333
cgi_reset_content();
13331334
@ error push\sscript\sfailed:\s%F(g.zErrMsg)
@@ -1351,10 +1352,11 @@
13511352
if( xfer.syncPrivate ) send_private(&xfer);
13521353
}
13531354
if( recvConfig ){
13541355
configure_finalize_receive();
13551356
}
1357
+ db_multi_exec("DROP TABLE onremote");
13561358
manifest_crosslink_end();
13571359
13581360
/* Send the server timestamp last, in case prior processing happened
13591361
** to use up a significant fraction of our time window.
13601362
*/
@@ -1521,11 +1523,10 @@
15211523
nCardSent++;
15221524
if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
15231525
if( (syncFlags & SYNC_RESYNC)!=0 ) xfer.resync = 0x7fffffff;
15241526
}
15251527
manifest_crosslink_begin();
1526
- transport_global_startup();
15271528
if( syncFlags & SYNC_VERBOSE ){
15281529
fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
15291530
}
15301531
15311532
while( go ){
@@ -1600,11 +1601,22 @@
16001601
*/
16011602
zRandomness = db_text(0, "SELECT hex(randomblob(20))");
16021603
blob_appendf(&send, "# %s\n", zRandomness);
16031604
free(zRandomness);
16041605
1606
+ if( syncFlags & SYNC_VERBOSE ){
1607
+ fossil_print("waiting for server...");
1608
+ }
1609
+ fflush(stdout);
16051610
/* Exchange messages with the server */
1611
+ if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1612
+ MAX_REDIRECTS) ){
1613
+ nErr++;
1614
+ break;
1615
+ }
1616
+
1617
+ /* Output current stats */
16061618
if( syncFlags & SYNC_VERBOSE ){
16071619
fossil_print(zValueFormat, "Sent:",
16081620
blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
16091621
xfer.nFileSent, xfer.nDeltaSent);
16101622
}else{
@@ -1616,19 +1628,11 @@
16161628
nCardRcvd = 0;
16171629
xfer.nFileSent = 0;
16181630
xfer.nDeltaSent = 0;
16191631
xfer.nGimmeSent = 0;
16201632
xfer.nIGotSent = 0;
1621
- if( syncFlags & SYNC_VERBOSE ){
1622
- fossil_print("waiting for server...");
1623
- }
1624
- fflush(stdout);
1625
- if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1626
- MAX_REDIRECTS) ){
1627
- nErr++;
1628
- break;
1629
- }
1633
+
16301634
lastPctDone = -1;
16311635
blob_reset(&send);
16321636
rArrivalTime = db_double(0.0, "SELECT julianday('now')");
16331637
16341638
/* Send the send-private pragma if we are trying to sync private data */
@@ -1871,11 +1875,14 @@
18711875
fossil_print("Error: %s\n", zMsg);
18721876
if( fossil_strcmp(zMsg, "login failed")==0 ){
18731877
if( nCycle<2 ){
18741878
g.urlPasswd = 0;
18751879
go = 1;
1876
- if( g.cgiOutput==0 ) url_prompt_for_password();
1880
+ if( g.cgiOutput==0 ){
1881
+ g.urlFlags |= URL_PROMPT_PW;
1882
+ url_prompt_for_password();
1883
+ }
18771884
}
18781885
}else{
18791886
blob_appendf(&xfer.err, "server says: %s\n", zMsg);
18801887
nErr++;
18811888
}
18821889
--- src/xfer.c
+++ src/xfer.c
@@ -1324,10 +1324,11 @@
1324 {
1325 cgi_reset_content();
1326 @ error bad\scommand:\s%F(blob_str(&xfer.line))
1327 }
1328 blobarray_reset(xfer.aToken, xfer.nToken);
 
1329 }
1330 if( isPush ){
1331 if( run_script("xfer-push-script", 0) ){
1332 cgi_reset_content();
1333 @ error push\sscript\sfailed:\s%F(g.zErrMsg)
@@ -1351,10 +1352,11 @@
1351 if( xfer.syncPrivate ) send_private(&xfer);
1352 }
1353 if( recvConfig ){
1354 configure_finalize_receive();
1355 }
 
1356 manifest_crosslink_end();
1357
1358 /* Send the server timestamp last, in case prior processing happened
1359 ** to use up a significant fraction of our time window.
1360 */
@@ -1521,11 +1523,10 @@
1521 nCardSent++;
1522 if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
1523 if( (syncFlags & SYNC_RESYNC)!=0 ) xfer.resync = 0x7fffffff;
1524 }
1525 manifest_crosslink_begin();
1526 transport_global_startup();
1527 if( syncFlags & SYNC_VERBOSE ){
1528 fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
1529 }
1530
1531 while( go ){
@@ -1600,11 +1601,22 @@
1600 */
1601 zRandomness = db_text(0, "SELECT hex(randomblob(20))");
1602 blob_appendf(&send, "# %s\n", zRandomness);
1603 free(zRandomness);
1604
 
 
 
 
1605 /* Exchange messages with the server */
 
 
 
 
 
 
 
1606 if( syncFlags & SYNC_VERBOSE ){
1607 fossil_print(zValueFormat, "Sent:",
1608 blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
1609 xfer.nFileSent, xfer.nDeltaSent);
1610 }else{
@@ -1616,19 +1628,11 @@
1616 nCardRcvd = 0;
1617 xfer.nFileSent = 0;
1618 xfer.nDeltaSent = 0;
1619 xfer.nGimmeSent = 0;
1620 xfer.nIGotSent = 0;
1621 if( syncFlags & SYNC_VERBOSE ){
1622 fossil_print("waiting for server...");
1623 }
1624 fflush(stdout);
1625 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1626 MAX_REDIRECTS) ){
1627 nErr++;
1628 break;
1629 }
1630 lastPctDone = -1;
1631 blob_reset(&send);
1632 rArrivalTime = db_double(0.0, "SELECT julianday('now')");
1633
1634 /* Send the send-private pragma if we are trying to sync private data */
@@ -1871,11 +1875,14 @@
1871 fossil_print("Error: %s\n", zMsg);
1872 if( fossil_strcmp(zMsg, "login failed")==0 ){
1873 if( nCycle<2 ){
1874 g.urlPasswd = 0;
1875 go = 1;
1876 if( g.cgiOutput==0 ) url_prompt_for_password();
 
 
 
1877 }
1878 }else{
1879 blob_appendf(&xfer.err, "server says: %s\n", zMsg);
1880 nErr++;
1881 }
1882
--- src/xfer.c
+++ src/xfer.c
@@ -1324,10 +1324,11 @@
1324 {
1325 cgi_reset_content();
1326 @ error bad\scommand:\s%F(blob_str(&xfer.line))
1327 }
1328 blobarray_reset(xfer.aToken, xfer.nToken);
1329 blob_reset(&xfer.line);
1330 }
1331 if( isPush ){
1332 if( run_script("xfer-push-script", 0) ){
1333 cgi_reset_content();
1334 @ error push\sscript\sfailed:\s%F(g.zErrMsg)
@@ -1351,10 +1352,11 @@
1352 if( xfer.syncPrivate ) send_private(&xfer);
1353 }
1354 if( recvConfig ){
1355 configure_finalize_receive();
1356 }
1357 db_multi_exec("DROP TABLE onremote");
1358 manifest_crosslink_end();
1359
1360 /* Send the server timestamp last, in case prior processing happened
1361 ** to use up a significant fraction of our time window.
1362 */
@@ -1521,11 +1523,10 @@
1523 nCardSent++;
1524 if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
1525 if( (syncFlags & SYNC_RESYNC)!=0 ) xfer.resync = 0x7fffffff;
1526 }
1527 manifest_crosslink_begin();
 
1528 if( syncFlags & SYNC_VERBOSE ){
1529 fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
1530 }
1531
1532 while( go ){
@@ -1600,11 +1601,22 @@
1601 */
1602 zRandomness = db_text(0, "SELECT hex(randomblob(20))");
1603 blob_appendf(&send, "# %s\n", zRandomness);
1604 free(zRandomness);
1605
1606 if( syncFlags & SYNC_VERBOSE ){
1607 fossil_print("waiting for server...");
1608 }
1609 fflush(stdout);
1610 /* Exchange messages with the server */
1611 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
1612 MAX_REDIRECTS) ){
1613 nErr++;
1614 break;
1615 }
1616
1617 /* Output current stats */
1618 if( syncFlags & SYNC_VERBOSE ){
1619 fossil_print(zValueFormat, "Sent:",
1620 blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
1621 xfer.nFileSent, xfer.nDeltaSent);
1622 }else{
@@ -1616,19 +1628,11 @@
1628 nCardRcvd = 0;
1629 xfer.nFileSent = 0;
1630 xfer.nDeltaSent = 0;
1631 xfer.nGimmeSent = 0;
1632 xfer.nIGotSent = 0;
1633
 
 
 
 
 
 
 
 
1634 lastPctDone = -1;
1635 blob_reset(&send);
1636 rArrivalTime = db_double(0.0, "SELECT julianday('now')");
1637
1638 /* Send the send-private pragma if we are trying to sync private data */
@@ -1871,11 +1875,14 @@
1875 fossil_print("Error: %s\n", zMsg);
1876 if( fossil_strcmp(zMsg, "login failed")==0 ){
1877 if( nCycle<2 ){
1878 g.urlPasswd = 0;
1879 go = 1;
1880 if( g.cgiOutput==0 ){
1881 g.urlFlags |= URL_PROMPT_PW;
1882 url_prompt_for_password();
1883 }
1884 }
1885 }else{
1886 blob_appendf(&xfer.err, "server says: %s\n", zMsg);
1887 nErr++;
1888 }
1889
+2 -2
--- src/zip.c
+++ src/zip.c
@@ -15,13 +15,13 @@
1515
**
1616
*******************************************************************************
1717
**
1818
** This file contains code used to generate ZIP archives.
1919
*/
20
+#include "config.h"
2021
#include <assert.h>
2122
#include <zlib.h>
22
-#include "config.h"
2323
#include "zip.h"
2424
2525
/*
2626
** Write a 16- or 32-bit integer as little-endian into the given buffer.
2727
*/
@@ -337,11 +337,11 @@
337337
if( zDir && zDir[0] ){
338338
blob_appendf(&filename, "%s/", zDir);
339339
}
340340
nPrefix = blob_size(&filename);
341341
342
- pManifest = manifest_get(rid, CFTYPE_MANIFEST);
342
+ pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
343343
if( pManifest ){
344344
char *zName;
345345
zip_set_timedate(pManifest->rDate);
346346
if( db_get_boolean("manifest", 0) ){
347347
blob_append(&filename, "manifest", -1);
348348
--- src/zip.c
+++ src/zip.c
@@ -15,13 +15,13 @@
15 **
16 *******************************************************************************
17 **
18 ** This file contains code used to generate ZIP archives.
19 */
 
20 #include <assert.h>
21 #include <zlib.h>
22 #include "config.h"
23 #include "zip.h"
24
25 /*
26 ** Write a 16- or 32-bit integer as little-endian into the given buffer.
27 */
@@ -337,11 +337,11 @@
337 if( zDir && zDir[0] ){
338 blob_appendf(&filename, "%s/", zDir);
339 }
340 nPrefix = blob_size(&filename);
341
342 pManifest = manifest_get(rid, CFTYPE_MANIFEST);
343 if( pManifest ){
344 char *zName;
345 zip_set_timedate(pManifest->rDate);
346 if( db_get_boolean("manifest", 0) ){
347 blob_append(&filename, "manifest", -1);
348
--- src/zip.c
+++ src/zip.c
@@ -15,13 +15,13 @@
15 **
16 *******************************************************************************
17 **
18 ** This file contains code used to generate ZIP archives.
19 */
20 #include "config.h"
21 #include <assert.h>
22 #include <zlib.h>
 
23 #include "zip.h"
24
25 /*
26 ** Write a 16- or 32-bit integer as little-endian into the given buffer.
27 */
@@ -337,11 +337,11 @@
337 if( zDir && zDir[0] ){
338 blob_appendf(&filename, "%s/", zDir);
339 }
340 nPrefix = blob_size(&filename);
341
342 pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
343 if( pManifest ){
344 char *zName;
345 zip_set_timedate(pManifest->rDate);
346 if( db_get_boolean("manifest", 0) ){
347 blob_append(&filename, "manifest", -1);
348
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -114,11 +114,12 @@
114114
[file nativename [file join $dir th1-tcl8.txt]]
115115
116116
test th1-tcl-8 {$RESULT eq {<hr><p class="thmainError">ERROR:\
117117
cannot invoke Tcl command: tailcall</p>} || $RESULT eq {<hr><p\
118118
class="thmainError">ERROR: tailcall can only be called from a proc or\
119
-lambda</p>}}
119
+lambda</p>} || $RESULT eq {<hr><p class="thmainError">ERROR: This test\
120
+requires Tcl 8.6 or higher.</p>}}
120121
121122
###############################################################################
122123
123124
fossil test-th-render --th-open-config \
124125
[file nativename [file join $dir th1-tcl9.txt]]
125126
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -114,11 +114,12 @@
114 [file nativename [file join $dir th1-tcl8.txt]]
115
116 test th1-tcl-8 {$RESULT eq {<hr><p class="thmainError">ERROR:\
117 cannot invoke Tcl command: tailcall</p>} || $RESULT eq {<hr><p\
118 class="thmainError">ERROR: tailcall can only be called from a proc or\
119 lambda</p>}}
 
120
121 ###############################################################################
122
123 fossil test-th-render --th-open-config \
124 [file nativename [file join $dir th1-tcl9.txt]]
125
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -114,11 +114,12 @@
114 [file nativename [file join $dir th1-tcl8.txt]]
115
116 test th1-tcl-8 {$RESULT eq {<hr><p class="thmainError">ERROR:\
117 cannot invoke Tcl command: tailcall</p>} || $RESULT eq {<hr><p\
118 class="thmainError">ERROR: tailcall can only be called from a proc or\
119 lambda</p>} || $RESULT eq {<hr><p class="thmainError">ERROR: This test\
120 requires Tcl 8.6 or higher.</p>}}
121
122 ###############################################################################
123
124 fossil test-th-render --th-open-config \
125 [file nativename [file join $dir th1-tcl9.txt]]
126
--- test/th1-tcl8.txt
+++ test/th1-tcl8.txt
@@ -7,8 +7,8 @@
77
proc doOut {msg} {puts $msg; puts \n}
88
99
if {[tclInvoke set tcl_version] >= 8.6} {
1010
doOut [tclInvoke tailcall set x 1]
1111
} else {
12
- doOut "This test requires Tcl 8.6 or higher."
12
+ error "This test requires Tcl 8.6 or higher."
1313
}
1414
</th1>
1515
--- test/th1-tcl8.txt
+++ test/th1-tcl8.txt
@@ -7,8 +7,8 @@
7 proc doOut {msg} {puts $msg; puts \n}
8
9 if {[tclInvoke set tcl_version] >= 8.6} {
10 doOut [tclInvoke tailcall set x 1]
11 } else {
12 doOut "This test requires Tcl 8.6 or higher."
13 }
14 </th1>
15
--- test/th1-tcl8.txt
+++ test/th1-tcl8.txt
@@ -7,8 +7,8 @@
7 proc doOut {msg} {puts $msg; puts \n}
8
9 if {[tclInvoke set tcl_version] >= 8.6} {
10 doOut [tclInvoke tailcall set x 1]
11 } else {
12 error "This test requires Tcl 8.6 or higher."
13 }
14 </th1>
15
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -68,13 +68,13 @@
6868
FOSSIL_TCL_SOURCE = 1
6969
7070
#### Check if the workaround for the MinGW command line handling needs to
7171
# be enabled by default.
7272
#
73
-ifndef BROKEN_MINGW_CMDLINE
73
+ifndef MINGW_IS_32BIT_ONLY
7474
ifeq (,$(findstring w64-mingw32,$(PREFIX)))
75
-BROKEN_MINGW_CMDLINE = 1
75
+MINGW_IS_32BIT_ONLY = 1
7676
endif
7777
endif
7878
7979
#### The directories where the zlib include and library files are located.
8080
#
@@ -162,11 +162,11 @@
162162
RCC += -I$(TCLINCDIR)
163163
endif
164164
endif
165165
166166
# With MinGW command line handling workaround
167
-ifdef BROKEN_MINGW_CMDLINE
167
+ifdef MINGW_IS_32BIT_ONLY
168168
TCC += -DBROKEN_MINGW_CMDLINE=1
169169
RCC += -DBROKEN_MINGW_CMDLINE=1
170170
endif
171171
172172
# With HTTPS support
@@ -203,11 +203,11 @@
203203
# executable that will run in a chroot jail.
204204
#
205205
LIB = -static
206206
207207
# MinGW: If available, use the Unicode capable runtime startup code.
208
-ifndef BROKEN_MINGW_CMDLINE
208
+ifndef MINGW_IS_32BIT_ONLY
209209
LIB += -municode
210210
endif
211211
212212
# OpenSSL: Add the necessary libraries required, if enabled.
213213
ifdef FOSSIL_ENABLE_SSL
@@ -1685,11 +1685,11 @@
16851685
$(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
16861686
16871687
$(OBJDIR)/zip.h: $(OBJDIR)/headers
16881688
16891689
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1690
- $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_WIN32_NO_ANSI -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1690
+ $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_WIN32_NO_ANSI -D_HAVE_SQLITE_CONFIG_H -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
16911691
16921692
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
16931693
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
16941694
16951695
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
16961696
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -68,13 +68,13 @@
68 FOSSIL_TCL_SOURCE = 1
69
70 #### Check if the workaround for the MinGW command line handling needs to
71 # be enabled by default.
72 #
73 ifndef BROKEN_MINGW_CMDLINE
74 ifeq (,$(findstring w64-mingw32,$(PREFIX)))
75 BROKEN_MINGW_CMDLINE = 1
76 endif
77 endif
78
79 #### The directories where the zlib include and library files are located.
80 #
@@ -162,11 +162,11 @@
162 RCC += -I$(TCLINCDIR)
163 endif
164 endif
165
166 # With MinGW command line handling workaround
167 ifdef BROKEN_MINGW_CMDLINE
168 TCC += -DBROKEN_MINGW_CMDLINE=1
169 RCC += -DBROKEN_MINGW_CMDLINE=1
170 endif
171
172 # With HTTPS support
@@ -203,11 +203,11 @@
203 # executable that will run in a chroot jail.
204 #
205 LIB = -static
206
207 # MinGW: If available, use the Unicode capable runtime startup code.
208 ifndef BROKEN_MINGW_CMDLINE
209 LIB += -municode
210 endif
211
212 # OpenSSL: Add the necessary libraries required, if enabled.
213 ifdef FOSSIL_ENABLE_SSL
@@ -1685,11 +1685,11 @@
1685 $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
1686
1687 $(OBJDIR)/zip.h: $(OBJDIR)/headers
1688
1689 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1690 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_WIN32_NO_ANSI -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1691
1692 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1693 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1694
1695 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1696
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -68,13 +68,13 @@
68 FOSSIL_TCL_SOURCE = 1
69
70 #### Check if the workaround for the MinGW command line handling needs to
71 # be enabled by default.
72 #
73 ifndef MINGW_IS_32BIT_ONLY
74 ifeq (,$(findstring w64-mingw32,$(PREFIX)))
75 MINGW_IS_32BIT_ONLY = 1
76 endif
77 endif
78
79 #### The directories where the zlib include and library files are located.
80 #
@@ -162,11 +162,11 @@
162 RCC += -I$(TCLINCDIR)
163 endif
164 endif
165
166 # With MinGW command line handling workaround
167 ifdef MINGW_IS_32BIT_ONLY
168 TCC += -DBROKEN_MINGW_CMDLINE=1
169 RCC += -DBROKEN_MINGW_CMDLINE=1
170 endif
171
172 # With HTTPS support
@@ -203,11 +203,11 @@
203 # executable that will run in a chroot jail.
204 #
205 LIB = -static
206
207 # MinGW: If available, use the Unicode capable runtime startup code.
208 ifndef MINGW_IS_32BIT_ONLY
209 LIB += -municode
210 endif
211
212 # OpenSSL: Add the necessary libraries required, if enabled.
213 ifdef FOSSIL_ENABLE_SSL
@@ -1685,11 +1685,11 @@
1685 $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
1686
1687 $(OBJDIR)/zip.h: $(OBJDIR)/headers
1688
1689 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1690 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_WIN32_NO_ANSI -D_HAVE_SQLITE_CONFIG_H -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1691
1692 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1693 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1694
1695 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1696
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -68,13 +68,13 @@
6868
FOSSIL_TCL_SOURCE = 1
6969
7070
#### Check if the workaround for the MinGW command line handling needs to
7171
# be enabled by default.
7272
#
73
-ifndef BROKEN_MINGW_CMDLINE
73
+ifndef MINGW_IS_32BIT_ONLY
7474
ifeq (,$(findstring w64-mingw32,$(PREFIX)))
75
-BROKEN_MINGW_CMDLINE = 1
75
+MINGW_IS_32BIT_ONLY = 1
7676
endif
7777
endif
7878
7979
#### The directories where the zlib include and library files are located.
8080
#
@@ -162,11 +162,11 @@
162162
RCC += -I$(TCLINCDIR)
163163
endif
164164
endif
165165
166166
# With MinGW command line handling workaround
167
-ifdef BROKEN_MINGW_CMDLINE
167
+ifdef MINGW_IS_32BIT_ONLY
168168
TCC += -DBROKEN_MINGW_CMDLINE=1
169169
RCC += -DBROKEN_MINGW_CMDLINE=1
170170
endif
171171
172172
# With HTTPS support
@@ -203,11 +203,11 @@
203203
# executable that will run in a chroot jail.
204204
#
205205
LIB = -static
206206
207207
# MinGW: If available, use the Unicode capable runtime startup code.
208
-ifndef BROKEN_MINGW_CMDLINE
208
+ifndef MINGW_IS_32BIT_ONLY
209209
LIB += -municode
210210
endif
211211
212212
# OpenSSL: Add the necessary libraries required, if enabled.
213213
ifdef FOSSIL_ENABLE_SSL
@@ -1685,11 +1685,11 @@
16851685
$(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
16861686
16871687
$(OBJDIR)/zip.h: $(OBJDIR)/headers
16881688
16891689
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1690
- $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_WIN32_NO_ANSI -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1690
+ $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_WIN32_NO_ANSI -D_HAVE_SQLITE_CONFIG_H -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
16911691
16921692
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
16931693
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
16941694
16951695
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
16961696
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -68,13 +68,13 @@
68 FOSSIL_TCL_SOURCE = 1
69
70 #### Check if the workaround for the MinGW command line handling needs to
71 # be enabled by default.
72 #
73 ifndef BROKEN_MINGW_CMDLINE
74 ifeq (,$(findstring w64-mingw32,$(PREFIX)))
75 BROKEN_MINGW_CMDLINE = 1
76 endif
77 endif
78
79 #### The directories where the zlib include and library files are located.
80 #
@@ -162,11 +162,11 @@
162 RCC += -I$(TCLINCDIR)
163 endif
164 endif
165
166 # With MinGW command line handling workaround
167 ifdef BROKEN_MINGW_CMDLINE
168 TCC += -DBROKEN_MINGW_CMDLINE=1
169 RCC += -DBROKEN_MINGW_CMDLINE=1
170 endif
171
172 # With HTTPS support
@@ -203,11 +203,11 @@
203 # executable that will run in a chroot jail.
204 #
205 LIB = -static
206
207 # MinGW: If available, use the Unicode capable runtime startup code.
208 ifndef BROKEN_MINGW_CMDLINE
209 LIB += -municode
210 endif
211
212 # OpenSSL: Add the necessary libraries required, if enabled.
213 ifdef FOSSIL_ENABLE_SSL
@@ -1685,11 +1685,11 @@
1685 $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
1686
1687 $(OBJDIR)/zip.h: $(OBJDIR)/headers
1688
1689 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1690 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_WIN32_NO_ANSI -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1691
1692 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1693 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1694
1695 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1696
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -68,13 +68,13 @@
68 FOSSIL_TCL_SOURCE = 1
69
70 #### Check if the workaround for the MinGW command line handling needs to
71 # be enabled by default.
72 #
73 ifndef MINGW_IS_32BIT_ONLY
74 ifeq (,$(findstring w64-mingw32,$(PREFIX)))
75 MINGW_IS_32BIT_ONLY = 1
76 endif
77 endif
78
79 #### The directories where the zlib include and library files are located.
80 #
@@ -162,11 +162,11 @@
162 RCC += -I$(TCLINCDIR)
163 endif
164 endif
165
166 # With MinGW command line handling workaround
167 ifdef MINGW_IS_32BIT_ONLY
168 TCC += -DBROKEN_MINGW_CMDLINE=1
169 RCC += -DBROKEN_MINGW_CMDLINE=1
170 endif
171
172 # With HTTPS support
@@ -203,11 +203,11 @@
203 # executable that will run in a chroot jail.
204 #
205 LIB = -static
206
207 # MinGW: If available, use the Unicode capable runtime startup code.
208 ifndef MINGW_IS_32BIT_ONLY
209 LIB += -municode
210 endif
211
212 # OpenSSL: Add the necessary libraries required, if enabled.
213 ifdef FOSSIL_ENABLE_SSL
@@ -1685,11 +1685,11 @@
1685 $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
1686
1687 $(OBJDIR)/zip.h: $(OBJDIR)/headers
1688
1689 $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c
1690 $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT3 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_WIN32_NO_ANSI -D_HAVE_SQLITE_CONFIG_H -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
1691
1692 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
1693 $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
1694
1695 $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
1696
--- win/fossil.rc
+++ win/fossil.rc
@@ -103,10 +103,15 @@
103103
#if defined(FOSSIL_ENABLE_SSL)
104104
VALUE "SslEnabled", "Yes, " OPENSSL_VERSION_TEXT "\0"
105105
#endif /* defined(FOSSIL_ENABLE_SSL) */
106106
#if defined(FOSSIL_ENABLE_TCL)
107107
VALUE "TclEnabled", "Yes, Tcl " TCL_PATCH_LEVEL "\0"
108
+#if defined(USE_TCL_STUBS)
109
+ VALUE "UseTclStubsEnabled", "Yes\0"
110
+#else
111
+ VALUE "UseTclStubsEnabled", "No\0"
112
+#endif /* defined(USE_TCL_STUBS) */
108113
#if defined(FOSSIL_ENABLE_TCL_STUBS)
109114
VALUE "TclStubsEnabled", "Yes\0"
110115
#else
111116
VALUE "TclStubsEnabled", "No\0"
112117
#endif /* defined(FOSSIL_ENABLE_TCL_STUBS) */
113118
--- win/fossil.rc
+++ win/fossil.rc
@@ -103,10 +103,15 @@
103 #if defined(FOSSIL_ENABLE_SSL)
104 VALUE "SslEnabled", "Yes, " OPENSSL_VERSION_TEXT "\0"
105 #endif /* defined(FOSSIL_ENABLE_SSL) */
106 #if defined(FOSSIL_ENABLE_TCL)
107 VALUE "TclEnabled", "Yes, Tcl " TCL_PATCH_LEVEL "\0"
 
 
 
 
 
108 #if defined(FOSSIL_ENABLE_TCL_STUBS)
109 VALUE "TclStubsEnabled", "Yes\0"
110 #else
111 VALUE "TclStubsEnabled", "No\0"
112 #endif /* defined(FOSSIL_ENABLE_TCL_STUBS) */
113
--- win/fossil.rc
+++ win/fossil.rc
@@ -103,10 +103,15 @@
103 #if defined(FOSSIL_ENABLE_SSL)
104 VALUE "SslEnabled", "Yes, " OPENSSL_VERSION_TEXT "\0"
105 #endif /* defined(FOSSIL_ENABLE_SSL) */
106 #if defined(FOSSIL_ENABLE_TCL)
107 VALUE "TclEnabled", "Yes, Tcl " TCL_PATCH_LEVEL "\0"
108 #if defined(USE_TCL_STUBS)
109 VALUE "UseTclStubsEnabled", "Yes\0"
110 #else
111 VALUE "UseTclStubsEnabled", "No\0"
112 #endif /* defined(USE_TCL_STUBS) */
113 #if defined(FOSSIL_ENABLE_TCL_STUBS)
114 VALUE "TclStubsEnabled", "Yes\0"
115 #else
116 VALUE "TclStubsEnabled", "No\0"
117 #endif /* defined(FOSSIL_ENABLE_TCL_STUBS) */
118
--- www/adding_code.wiki
+++ www/adding_code.wiki
@@ -10,11 +10,11 @@
1010
Fossil is written in C-89. There are specific [./style.wiki | style guidelines]
1111
that are required for any new code that will be accepted into the Fossil core.
1212
But, of course, if you are writing an extension just for yourself, you can
1313
use any programming style you want.
1414
15
-The source code for Fossil is not feed directly into the C compiler, however.
15
+The source code for Fossil is not sent directly into the C compiler.
1616
There are three separate code [./makefile.wiki#preprocessing|preprocessors]
1717
that run over the code first.
1818
1919
1. The <b>mkindex</b> preprocessor scans all regular source files looking
2020
for special comments that contain "help" text and which identify routines
2121
--- www/adding_code.wiki
+++ www/adding_code.wiki
@@ -10,11 +10,11 @@
10 Fossil is written in C-89. There are specific [./style.wiki | style guidelines]
11 that are required for any new code that will be accepted into the Fossil core.
12 But, of course, if you are writing an extension just for yourself, you can
13 use any programming style you want.
14
15 The source code for Fossil is not feed directly into the C compiler, however.
16 There are three separate code [./makefile.wiki#preprocessing|preprocessors]
17 that run over the code first.
18
19 1. The <b>mkindex</b> preprocessor scans all regular source files looking
20 for special comments that contain "help" text and which identify routines
21
--- www/adding_code.wiki
+++ www/adding_code.wiki
@@ -10,11 +10,11 @@
10 Fossil is written in C-89. There are specific [./style.wiki | style guidelines]
11 that are required for any new code that will be accepted into the Fossil core.
12 But, of course, if you are writing an extension just for yourself, you can
13 use any programming style you want.
14
15 The source code for Fossil is not sent directly into the C compiler.
16 There are three separate code [./makefile.wiki#preprocessing|preprocessors]
17 that run over the code first.
18
19 1. The <b>mkindex</b> preprocessor scans all regular source files looking
20 for special comments that contain "help" text and which identify routines
21
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,6 +1,10 @@
11
<title>Change Log</title>
2
+
3
+<h2>Changes For Version 1.28 (as yet unreleased)</h2>
4
+ * Enhance [/help?cmd=/reports | /reports] to support event type filtering.
5
+
26
37
<h2>Changes For Version 1.27 (2013-09-11)</h2>
48
* Enhance the [/help?cmd=changes | fossil changes],
59
[/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
610
[/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
711
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,6 +1,10 @@
1 <title>Change Log</title>
 
 
 
 
2
3 <h2>Changes For Version 1.27 (2013-09-11)</h2>
4 * Enhance the [/help?cmd=changes | fossil changes],
5 [/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
6 [/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
7
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,6 +1,10 @@
1 <title>Change Log</title>
2
3 <h2>Changes For Version 1.28 (as yet unreleased)</h2>
4 * Enhance [/help?cmd=/reports | /reports] to support event type filtering.
5
6
7 <h2>Changes For Version 1.27 (2013-09-11)</h2>
8 * Enhance the [/help?cmd=changes | fossil changes],
9 [/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
10 [/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
11
--- www/selfhost.wiki
+++ www/selfhost.wiki
@@ -38,11 +38,11 @@
3838
Server (3) runs as a CGI script on a shared hosting account at
3939
<a href="http://www.he.net/">Hurricane Electric</a> in Fremont, CA.
4040
This server demonstrates the ability of
4141
Fossil to run on an economical shared-host web account with no
4242
privileges beyond port 80 HTTP access and CGI. It is not necessary
43
-to have a dedicated computer with administrator to run Fossil.
43
+to have a dedicated computer with administrator privileges to run Fossil.
4444
As far as we are aware,
4545
Fossil is the only full-featured configuration management system
4646
that can run in
4747
such a restricted environment. The CGI script that runs on the
4848
Hurricane Electric server is the same as the CGI script shown above,
4949
--- www/selfhost.wiki
+++ www/selfhost.wiki
@@ -38,11 +38,11 @@
38 Server (3) runs as a CGI script on a shared hosting account at
39 <a href="http://www.he.net/">Hurricane Electric</a> in Fremont, CA.
40 This server demonstrates the ability of
41 Fossil to run on an economical shared-host web account with no
42 privileges beyond port 80 HTTP access and CGI. It is not necessary
43 to have a dedicated computer with administrator to run Fossil.
44 As far as we are aware,
45 Fossil is the only full-featured configuration management system
46 that can run in
47 such a restricted environment. The CGI script that runs on the
48 Hurricane Electric server is the same as the CGI script shown above,
49
--- www/selfhost.wiki
+++ www/selfhost.wiki
@@ -38,11 +38,11 @@
38 Server (3) runs as a CGI script on a shared hosting account at
39 <a href="http://www.he.net/">Hurricane Electric</a> in Fremont, CA.
40 This server demonstrates the ability of
41 Fossil to run on an economical shared-host web account with no
42 privileges beyond port 80 HTTP access and CGI. It is not necessary
43 to have a dedicated computer with administrator privileges to run Fossil.
44 As far as we are aware,
45 Fossil is the only full-featured configuration management system
46 that can run in
47 such a restricted environment. The CGI script that runs on the
48 Hurricane Electric server is the same as the CGI script shown above,
49
+31 -4
--- www/server.wiki
+++ www/server.wiki
@@ -102,11 +102,23 @@
102102
[http://www.stunnel.org/ | Stunnel version 4] is an inetd-like process that
103103
accepts and decodes SSL-encrypted connections. Fossil can be run directly from
104104
stunnel in a mannar similar to inetd and xinetd. This can be used to provide
105105
a secure link to a Fossil project. The configuration needed to get stunnel4
106106
to invoke Fossil is very similar to the inetd and xinetd examples shown above.
107
-See the stunnel4 documentation for details.
107
+The relevant parts of an stunnel configuration might look something
108
+like the following:
109
+<blockquote><pre><nowiki>
110
+[https]
111
+accept = www.ubercool-project.org:443
112
+TIMEOUTclose = 0
113
+exec = /usr/bin/fossil
114
+execargs = /usr/bin/fossil http /home/fossil/ubercool.fossil --https
115
+</nowiki></pre></blockquote>
116
+See the stunnel4 documentation for further details bout the /etc/stunnel/stunnel.conf
117
+configuration file. Note that the [/help/http|fossil http] command should include
118
+the --https option to let Fossil know to use "https" instead of "http" as the scheme
119
+on generated hyperlinks.
108120
<p>
109121
Using inetd or xinetd or stunnel is a more complex setup
110122
than the "standalone" server, but it has the
111123
advantage of only using system resources when an actual connection is
112124
attempted. If no-one ever connects to that port, a Fossil server will
@@ -129,25 +141,40 @@
129141
<blockquote><pre>
130142
#!/usr/bin/fossil
131143
repository: /home/fossil/repo.fossil
132144
</pre></blockquote>
133145
</p>
146
+
134147
<p>
135148
As always, adjust your paths appropriately.
136149
It may be necessary to set permissions properly, or to modify an ".htaccess"
137150
file or make other server-specific changes. Consult the documentation
138
-for your particular web server.
151
+for your particular web server. In particular, the following permissions are
152
+<em>normally</em> required (but, again, may be different for a particular
153
+configuration):
154
+
155
+<ul>
156
+<li>The Fossil binary must be readable/executable, and ALL directories leading up to it
157
+must be readable by the process which executes the CGI.</li>
158
+<li>ALL directories leading to the CGI script must also be readable and the CGI
159
+script itself must be executable for the user under which it will run (which often differs
160
+from the one running the web server - consult your site's documentation or administrator).</li>
161
+<li>The repository file AND the directory containing it must be writable by the same account
162
+which executes the Fossil binary (again, this might differ from the WWW user). The directory
163
+needs to be writable so that sqlite can write its journal files.</li>
164
+</ul>
139165
</p>
166
+
140167
<p>
141168
Once the script is set up correctly, and assuming your server is also set
142169
correctly, you should be able to access your repository with a URL like:
143170
<b>http://mydomain.org/cgi-bin/repo</b> (assuming the "repo" script is
144171
accessible under "cgi-bin", which would be a typical deployment on Apache
145172
for instance).
146173
</p>
147174
<p>
148
-To server multiple repositories from a directory using CGI, use the "directory:"
175
+To serve multiple repositories from a directory using CGI, use the "directory:"
149176
tag in the CGI script rather than "repository:". You might also want to add
150177
a "notfound:" tag to tell where to redirect if the particular repository requested
151178
by the URL is not found:
152179
<blockquote><pre>
153180
#!/usr/bin/fossil
@@ -155,11 +182,11 @@
155182
notfound: http://url-to-go-to-if-repo-not-found/
156183
</pre></blockquote>
157184
</p>
158185
<p>
159186
Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b>
160
-will serve up the repository "/home/fossil/repos/XYX.fossil" (if it exists).
187
+will serve up the repository "/home/fossil/repos/XYZ.fossil" (if it exists).
161188
</p>
162189
</blockquote>
163190
164191
<a name="scgi"></a>
165192
<h2>Fossil as SCGI</h2><blockquote>
166193
--- www/server.wiki
+++ www/server.wiki
@@ -102,11 +102,23 @@
102 [http://www.stunnel.org/ | Stunnel version 4] is an inetd-like process that
103 accepts and decodes SSL-encrypted connections. Fossil can be run directly from
104 stunnel in a mannar similar to inetd and xinetd. This can be used to provide
105 a secure link to a Fossil project. The configuration needed to get stunnel4
106 to invoke Fossil is very similar to the inetd and xinetd examples shown above.
107 See the stunnel4 documentation for details.
 
 
 
 
 
 
 
 
 
 
 
 
108 <p>
109 Using inetd or xinetd or stunnel is a more complex setup
110 than the "standalone" server, but it has the
111 advantage of only using system resources when an actual connection is
112 attempted. If no-one ever connects to that port, a Fossil server will
@@ -129,25 +141,40 @@
129 <blockquote><pre>
130 #!/usr/bin/fossil
131 repository: /home/fossil/repo.fossil
132 </pre></blockquote>
133 </p>
 
134 <p>
135 As always, adjust your paths appropriately.
136 It may be necessary to set permissions properly, or to modify an ".htaccess"
137 file or make other server-specific changes. Consult the documentation
138 for your particular web server.
 
 
 
 
 
 
 
 
 
 
 
 
 
139 </p>
 
140 <p>
141 Once the script is set up correctly, and assuming your server is also set
142 correctly, you should be able to access your repository with a URL like:
143 <b>http://mydomain.org/cgi-bin/repo</b> (assuming the "repo" script is
144 accessible under "cgi-bin", which would be a typical deployment on Apache
145 for instance).
146 </p>
147 <p>
148 To server multiple repositories from a directory using CGI, use the "directory:"
149 tag in the CGI script rather than "repository:". You might also want to add
150 a "notfound:" tag to tell where to redirect if the particular repository requested
151 by the URL is not found:
152 <blockquote><pre>
153 #!/usr/bin/fossil
@@ -155,11 +182,11 @@
155 notfound: http://url-to-go-to-if-repo-not-found/
156 </pre></blockquote>
157 </p>
158 <p>
159 Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b>
160 will serve up the repository "/home/fossil/repos/XYX.fossil" (if it exists).
161 </p>
162 </blockquote>
163
164 <a name="scgi"></a>
165 <h2>Fossil as SCGI</h2><blockquote>
166
--- www/server.wiki
+++ www/server.wiki
@@ -102,11 +102,23 @@
102 [http://www.stunnel.org/ | Stunnel version 4] is an inetd-like process that
103 accepts and decodes SSL-encrypted connections. Fossil can be run directly from
104 stunnel in a mannar similar to inetd and xinetd. This can be used to provide
105 a secure link to a Fossil project. The configuration needed to get stunnel4
106 to invoke Fossil is very similar to the inetd and xinetd examples shown above.
107 The relevant parts of an stunnel configuration might look something
108 like the following:
109 <blockquote><pre><nowiki>
110 [https]
111 accept = www.ubercool-project.org:443
112 TIMEOUTclose = 0
113 exec = /usr/bin/fossil
114 execargs = /usr/bin/fossil http /home/fossil/ubercool.fossil --https
115 </nowiki></pre></blockquote>
116 See the stunnel4 documentation for further details bout the /etc/stunnel/stunnel.conf
117 configuration file. Note that the [/help/http|fossil http] command should include
118 the --https option to let Fossil know to use "https" instead of "http" as the scheme
119 on generated hyperlinks.
120 <p>
121 Using inetd or xinetd or stunnel is a more complex setup
122 than the "standalone" server, but it has the
123 advantage of only using system resources when an actual connection is
124 attempted. If no-one ever connects to that port, a Fossil server will
@@ -129,25 +141,40 @@
141 <blockquote><pre>
142 #!/usr/bin/fossil
143 repository: /home/fossil/repo.fossil
144 </pre></blockquote>
145 </p>
146
147 <p>
148 As always, adjust your paths appropriately.
149 It may be necessary to set permissions properly, or to modify an ".htaccess"
150 file or make other server-specific changes. Consult the documentation
151 for your particular web server. In particular, the following permissions are
152 <em>normally</em> required (but, again, may be different for a particular
153 configuration):
154
155 <ul>
156 <li>The Fossil binary must be readable/executable, and ALL directories leading up to it
157 must be readable by the process which executes the CGI.</li>
158 <li>ALL directories leading to the CGI script must also be readable and the CGI
159 script itself must be executable for the user under which it will run (which often differs
160 from the one running the web server - consult your site's documentation or administrator).</li>
161 <li>The repository file AND the directory containing it must be writable by the same account
162 which executes the Fossil binary (again, this might differ from the WWW user). The directory
163 needs to be writable so that sqlite can write its journal files.</li>
164 </ul>
165 </p>
166
167 <p>
168 Once the script is set up correctly, and assuming your server is also set
169 correctly, you should be able to access your repository with a URL like:
170 <b>http://mydomain.org/cgi-bin/repo</b> (assuming the "repo" script is
171 accessible under "cgi-bin", which would be a typical deployment on Apache
172 for instance).
173 </p>
174 <p>
175 To serve multiple repositories from a directory using CGI, use the "directory:"
176 tag in the CGI script rather than "repository:". You might also want to add
177 a "notfound:" tag to tell where to redirect if the particular repository requested
178 by the URL is not found:
179 <blockquote><pre>
180 #!/usr/bin/fossil
@@ -155,11 +182,11 @@
182 notfound: http://url-to-go-to-if-repo-not-found/
183 </pre></blockquote>
184 </p>
185 <p>
186 Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b>
187 will serve up the repository "/home/fossil/repos/XYZ.fossil" (if it exists).
188 </p>
189 </blockquote>
190
191 <a name="scgi"></a>
192 <h2>Fossil as SCGI</h2><blockquote>
193

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button