• R/O
  • HTTP
  • SSH
  • HTTPS

提交

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

あれとこれのコンバータ


Commit MetaInfo

修订版8cc2bc46a39929ea8f3767b37f7aa4fc940860aa (tree)
时间2011-11-27 20:20:03
作者masakih <masakih@user...>
Commitermasakih

Log Message

append external source files and fix it.

更改概述

差异

--- a/BathyScapheDataConverter.xcodeproj/project.pbxproj
+++ b/BathyScapheDataConverter.xcodeproj/project.pbxproj
@@ -13,6 +13,24 @@
1313 F43ADAEF14821535004E2386 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F43ADAED14821535004E2386 /* Credits.rtf */; };
1414 F43ADAF214821535004E2386 /* BSDCAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADAF114821535004E2386 /* BSDCAppDelegate.m */; };
1515 F43ADAF514821535004E2386 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F43ADAF314821535004E2386 /* MainMenu.xib */; };
16+ F43ADB111482157E004E2386 /* BathyScapheCore.xcdatamodel in Sources */ = {isa = PBXBuildFile; fileRef = F43ADAFC1482157E004E2386 /* BathyScapheCore.xcdatamodel */; };
17+ F43ADB121482157E004E2386 /* BSBoardHistoryObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADAFE1482157E004E2386 /* BSBoardHistoryObject.m */; };
18+ F43ADB131482157E004E2386 /* BSBoardInformationObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB001482157E004E2386 /* BSBoardInformationObject.m */; };
19+ F43ADB141482157E004E2386 /* BSBoardThreadItemsObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB021482157E004E2386 /* BSBoardThreadItemsObject.m */; };
20+ F43ADB151482157E004E2386 /* BSCoreDataManager_DataAccessor.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB031482157E004E2386 /* BSCoreDataManager_DataAccessor.m */; };
21+ F43ADB161482157E004E2386 /* BSCoreDataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB051482157E004E2386 /* BSCoreDataManager.m */; };
22+ F43ADB171482157E004E2386 /* BSDatabaseTranslator.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB071482157E004E2386 /* BSDatabaseTranslator.m */; };
23+ F43ADB181482157E004E2386 /* BSFavoriteObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB091482157E004E2386 /* BSFavoriteObject.m */; };
24+ F43ADB191482157E004E2386 /* BSThreadInformationObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB0B1482157E004E2386 /* BSThreadInformationObject.m */; };
25+ F43ADB1A1482157E004E2386 /* BSThreadItemObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB0D1482157E004E2386 /* BSThreadItemObject.m */; };
26+ F43ADB1B1482157E004E2386 /* BSThreadListItemObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB0F1482157E004E2386 /* BSThreadListItemObject.m */; };
27+ F43ADB1C1482157E004E2386 /* EntityDescription.txt in Resources */ = {isa = PBXBuildFile; fileRef = F43ADB101482157E004E2386 /* EntityDescription.txt */; };
28+ F43ADB26148215B5004E2386 /* DatabaseManager-DatabaseAccess.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB1E148215B5004E2386 /* DatabaseManager-DatabaseAccess.m */; };
29+ F43ADB27148215B5004E2386 /* DatabaseManager-Notifications.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB1F148215B5004E2386 /* DatabaseManager-Notifications.m */; };
30+ F43ADB28148215B5004E2386 /* DatabaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB21148215B5004E2386 /* DatabaseManager.m */; };
31+ F43ADB29148215B5004E2386 /* DatabaseUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB23148215B5004E2386 /* DatabaseUpdater.m */; };
32+ F43ADB2A148215B5004E2386 /* SQLiteDB.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB25148215B5004E2386 /* SQLiteDB.m */; };
33+ F43ADB2D148215D7004E2386 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = F43ADB2B148215D7004E2386 /* sqlite3.c */; };
1634 /* End PBXBuildFile section */
1735
1836 /* Begin PBXFileReference section */
@@ -21,14 +39,45 @@
2139 F43ADAE114821535004E2386 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
2240 F43ADAE214821535004E2386 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
2341 F43ADAE314821535004E2386 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
24- F43ADAE614821535004E2386 /* BathyScapheDataConverter-Info.plist */ = {isa = PBXFileReference; path = "BathyScapheDataConverter-Info.plist"; sourceTree = "<group>"; };
42+ F43ADAE614821535004E2386 /* BathyScapheDataConverter-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BathyScapheDataConverter-Info.plist"; sourceTree = "<group>"; };
2543 F43ADAE814821535004E2386 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
2644 F43ADAEA14821535004E2386 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
27- F43ADAEC14821535004E2386 /* BathyScapheDataConverter-Prefix.pch */ = {isa = PBXFileReference; path = "BathyScapheDataConverter-Prefix.pch"; sourceTree = "<group>"; };
45+ F43ADAEC14821535004E2386 /* BathyScapheDataConverter-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BathyScapheDataConverter-Prefix.pch"; sourceTree = "<group>"; };
2846 F43ADAEE14821535004E2386 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = "<group>"; };
29- F43ADAF014821535004E2386 /* BSDCAppDelegate.h */ = {isa = PBXFileReference; path = BSDCAppDelegate.h; sourceTree = "<group>"; };
47+ F43ADAF014821535004E2386 /* BSDCAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSDCAppDelegate.h; sourceTree = "<group>"; };
3048 F43ADAF114821535004E2386 /* BSDCAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSDCAppDelegate.m; sourceTree = "<group>"; };
3149 F43ADAF414821535004E2386 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
50+ F43ADAFC1482157E004E2386 /* BathyScapheCore.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = BathyScapheCore.xcdatamodel; sourceTree = "<group>"; };
51+ F43ADAFD1482157E004E2386 /* BSBoardHistoryObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSBoardHistoryObject.h; sourceTree = "<group>"; };
52+ F43ADAFE1482157E004E2386 /* BSBoardHistoryObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSBoardHistoryObject.m; sourceTree = "<group>"; };
53+ F43ADAFF1482157E004E2386 /* BSBoardInformationObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSBoardInformationObject.h; sourceTree = "<group>"; };
54+ F43ADB001482157E004E2386 /* BSBoardInformationObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSBoardInformationObject.m; sourceTree = "<group>"; };
55+ F43ADB011482157E004E2386 /* BSBoardThreadItemsObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSBoardThreadItemsObject.h; sourceTree = "<group>"; };
56+ F43ADB021482157E004E2386 /* BSBoardThreadItemsObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSBoardThreadItemsObject.m; sourceTree = "<group>"; };
57+ F43ADB031482157E004E2386 /* BSCoreDataManager_DataAccessor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSCoreDataManager_DataAccessor.m; sourceTree = "<group>"; };
58+ F43ADB041482157E004E2386 /* BSCoreDataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSCoreDataManager.h; sourceTree = "<group>"; };
59+ F43ADB051482157E004E2386 /* BSCoreDataManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSCoreDataManager.m; sourceTree = "<group>"; };
60+ F43ADB061482157E004E2386 /* BSDatabaseTranslator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSDatabaseTranslator.h; sourceTree = "<group>"; };
61+ F43ADB071482157E004E2386 /* BSDatabaseTranslator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSDatabaseTranslator.m; sourceTree = "<group>"; };
62+ F43ADB081482157E004E2386 /* BSFavoriteObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSFavoriteObject.h; sourceTree = "<group>"; };
63+ F43ADB091482157E004E2386 /* BSFavoriteObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSFavoriteObject.m; sourceTree = "<group>"; };
64+ F43ADB0A1482157E004E2386 /* BSThreadInformationObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSThreadInformationObject.h; sourceTree = "<group>"; };
65+ F43ADB0B1482157E004E2386 /* BSThreadInformationObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSThreadInformationObject.m; sourceTree = "<group>"; };
66+ F43ADB0C1482157E004E2386 /* BSThreadItemObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSThreadItemObject.h; sourceTree = "<group>"; };
67+ F43ADB0D1482157E004E2386 /* BSThreadItemObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSThreadItemObject.m; sourceTree = "<group>"; };
68+ F43ADB0E1482157E004E2386 /* BSThreadListItemObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSThreadListItemObject.h; sourceTree = "<group>"; };
69+ F43ADB0F1482157E004E2386 /* BSThreadListItemObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSThreadListItemObject.m; sourceTree = "<group>"; };
70+ F43ADB101482157E004E2386 /* EntityDescription.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = EntityDescription.txt; sourceTree = "<group>"; };
71+ F43ADB1E148215B5004E2386 /* DatabaseManager-DatabaseAccess.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "DatabaseManager-DatabaseAccess.m"; sourceTree = "<group>"; };
72+ F43ADB1F148215B5004E2386 /* DatabaseManager-Notifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "DatabaseManager-Notifications.m"; sourceTree = "<group>"; };
73+ F43ADB20148215B5004E2386 /* DatabaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseManager.h; sourceTree = "<group>"; };
74+ F43ADB21148215B5004E2386 /* DatabaseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DatabaseManager.m; sourceTree = "<group>"; };
75+ F43ADB22148215B5004E2386 /* DatabaseUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseUpdater.h; sourceTree = "<group>"; };
76+ F43ADB23148215B5004E2386 /* DatabaseUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DatabaseUpdater.m; sourceTree = "<group>"; };
77+ F43ADB24148215B5004E2386 /* SQLiteDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQLiteDB.h; sourceTree = "<group>"; };
78+ F43ADB25148215B5004E2386 /* SQLiteDB.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQLiteDB.m; sourceTree = "<group>"; };
79+ F43ADB2B148215D7004E2386 /* sqlite3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sqlite3.c; sourceTree = "<group>"; };
80+ F43ADB2C148215D7004E2386 /* sqlite3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqlite3.h; sourceTree = "<group>"; };
3281 /* End PBXFileReference section */
3382
3483 /* Begin PBXFrameworksBuildPhase section */
@@ -46,6 +95,8 @@
4695 F43ADACF14821535004E2386 = {
4796 isa = PBXGroup;
4897 children = (
98+ F43ADB1D14821585004E2386 /* BSSQLiteData */,
99+ F43ADAFB14821546004E2386 /* BSCoreData */,
49100 F43ADAE414821535004E2386 /* BathyScapheDataConverter */,
50101 F43ADADD14821535004E2386 /* Frameworks */,
51102 F43ADADB14821535004E2386 /* Products */,
@@ -102,6 +153,52 @@
102153 name = "Supporting Files";
103154 sourceTree = "<group>";
104155 };
156+ F43ADAFB14821546004E2386 /* BSCoreData */ = {
157+ isa = PBXGroup;
158+ children = (
159+ F43ADAFC1482157E004E2386 /* BathyScapheCore.xcdatamodel */,
160+ F43ADAFD1482157E004E2386 /* BSBoardHistoryObject.h */,
161+ F43ADAFE1482157E004E2386 /* BSBoardHistoryObject.m */,
162+ F43ADAFF1482157E004E2386 /* BSBoardInformationObject.h */,
163+ F43ADB001482157E004E2386 /* BSBoardInformationObject.m */,
164+ F43ADB011482157E004E2386 /* BSBoardThreadItemsObject.h */,
165+ F43ADB021482157E004E2386 /* BSBoardThreadItemsObject.m */,
166+ F43ADB031482157E004E2386 /* BSCoreDataManager_DataAccessor.m */,
167+ F43ADB041482157E004E2386 /* BSCoreDataManager.h */,
168+ F43ADB051482157E004E2386 /* BSCoreDataManager.m */,
169+ F43ADB061482157E004E2386 /* BSDatabaseTranslator.h */,
170+ F43ADB071482157E004E2386 /* BSDatabaseTranslator.m */,
171+ F43ADB081482157E004E2386 /* BSFavoriteObject.h */,
172+ F43ADB091482157E004E2386 /* BSFavoriteObject.m */,
173+ F43ADB0A1482157E004E2386 /* BSThreadInformationObject.h */,
174+ F43ADB0B1482157E004E2386 /* BSThreadInformationObject.m */,
175+ F43ADB0C1482157E004E2386 /* BSThreadItemObject.h */,
176+ F43ADB0D1482157E004E2386 /* BSThreadItemObject.m */,
177+ F43ADB0E1482157E004E2386 /* BSThreadListItemObject.h */,
178+ F43ADB0F1482157E004E2386 /* BSThreadListItemObject.m */,
179+ F43ADB101482157E004E2386 /* EntityDescription.txt */,
180+ );
181+ name = BSCoreData;
182+ path = BathyScapheDataConverter;
183+ sourceTree = "<group>";
184+ };
185+ F43ADB1D14821585004E2386 /* BSSQLiteData */ = {
186+ isa = PBXGroup;
187+ children = (
188+ F43ADB2B148215D7004E2386 /* sqlite3.c */,
189+ F43ADB2C148215D7004E2386 /* sqlite3.h */,
190+ F43ADB1E148215B5004E2386 /* DatabaseManager-DatabaseAccess.m */,
191+ F43ADB1F148215B5004E2386 /* DatabaseManager-Notifications.m */,
192+ F43ADB20148215B5004E2386 /* DatabaseManager.h */,
193+ F43ADB21148215B5004E2386 /* DatabaseManager.m */,
194+ F43ADB22148215B5004E2386 /* DatabaseUpdater.h */,
195+ F43ADB23148215B5004E2386 /* DatabaseUpdater.m */,
196+ F43ADB24148215B5004E2386 /* SQLiteDB.h */,
197+ F43ADB25148215B5004E2386 /* SQLiteDB.m */,
198+ );
199+ name = BSSQLiteData;
200+ sourceTree = "<group>";
201+ };
105202 /* End PBXGroup section */
106203
107204 /* Begin PBXNativeTarget section */
@@ -155,6 +252,7 @@
155252 F43ADAE914821535004E2386 /* InfoPlist.strings in Resources */,
156253 F43ADAEF14821535004E2386 /* Credits.rtf in Resources */,
157254 F43ADAF514821535004E2386 /* MainMenu.xib in Resources */,
255+ F43ADB1C1482157E004E2386 /* EntityDescription.txt in Resources */,
158256 );
159257 runOnlyForDeploymentPostprocessing = 0;
160258 };
@@ -167,6 +265,23 @@
167265 files = (
168266 F43ADAEB14821535004E2386 /* main.m in Sources */,
169267 F43ADAF214821535004E2386 /* BSDCAppDelegate.m in Sources */,
268+ F43ADB111482157E004E2386 /* BathyScapheCore.xcdatamodel in Sources */,
269+ F43ADB121482157E004E2386 /* BSBoardHistoryObject.m in Sources */,
270+ F43ADB131482157E004E2386 /* BSBoardInformationObject.m in Sources */,
271+ F43ADB141482157E004E2386 /* BSBoardThreadItemsObject.m in Sources */,
272+ F43ADB151482157E004E2386 /* BSCoreDataManager_DataAccessor.m in Sources */,
273+ F43ADB161482157E004E2386 /* BSCoreDataManager.m in Sources */,
274+ F43ADB171482157E004E2386 /* BSDatabaseTranslator.m in Sources */,
275+ F43ADB181482157E004E2386 /* BSFavoriteObject.m in Sources */,
276+ F43ADB191482157E004E2386 /* BSThreadInformationObject.m in Sources */,
277+ F43ADB1A1482157E004E2386 /* BSThreadItemObject.m in Sources */,
278+ F43ADB1B1482157E004E2386 /* BSThreadListItemObject.m in Sources */,
279+ F43ADB26148215B5004E2386 /* DatabaseManager-DatabaseAccess.m in Sources */,
280+ F43ADB27148215B5004E2386 /* DatabaseManager-Notifications.m in Sources */,
281+ F43ADB28148215B5004E2386 /* DatabaseManager.m in Sources */,
282+ F43ADB29148215B5004E2386 /* DatabaseUpdater.m in Sources */,
283+ F43ADB2A148215B5004E2386 /* SQLiteDB.m in Sources */,
284+ F43ADB2D148215D7004E2386 /* sqlite3.c in Sources */,
170285 );
171286 runOnlyForDeploymentPostprocessing = 0;
172287 };
--- /dev/null
+++ b/BathyScapheDataConverter/BSBoardHistoryObject.h
@@ -0,0 +1,24 @@
1+//
2+// BSBoardHistoryObject.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/14.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import <CoreData/CoreData.h>
10+
11+@class BSBoardInformationObject;
12+
13+@interface BSBoardHistoryObject : NSManagedObject
14+{
15+}
16+
17+@property (nonatomic, retain) NSString * boardURL;
18+@property (nonatomic, retain) NSString * boardName;
19+@property (nonatomic, retain) BSBoardInformationObject * board;
20+
21+@end
22+
23+
24+
--- /dev/null
+++ b/BathyScapheDataConverter/BSBoardHistoryObject.m
@@ -0,0 +1,19 @@
1+//
2+// BSBoardHistoryObject.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/14.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import "BSBoardHistoryObject.h"
10+
11+#import "BSBoardInformationObject.h"
12+
13+@implementation BSBoardHistoryObject
14+
15+@dynamic boardURL;
16+@dynamic boardName;
17+@dynamic board;
18+
19+@end
--- /dev/null
+++ b/BathyScapheDataConverter/BSBoardInformationObject.h
@@ -0,0 +1,39 @@
1+//
2+// BSBoardInformationObject.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import <CoreData/CoreData.h>
10+
11+@class BSBoardHistoryObject;
12+@class BSThreadInformationObject;
13+
14+@interface BSBoardInformationObject : NSManagedObject
15+{
16+}
17+
18+@property (nonatomic, retain) NSNumber * boardID;
19+@property (nonatomic, retain) NSString * boardName;
20+@property (nonatomic, retain) NSString * boardURL;
21+@property (nonatomic, retain) NSSet* histories;
22+@property (nonatomic, retain) NSSet* threads;
23+
24+@end
25+
26+
27+@interface BSBoardInformationObject (CoreDataGeneratedAccessors)
28+- (void)addHistoriesObject:(BSBoardHistoryObject *)value;
29+- (void)removeHistoriesObject:(BSBoardHistoryObject *)value;
30+- (void)addHistories:(NSSet *)value;
31+- (void)removeHistories:(NSSet *)value;
32+
33+- (void)addThreadsObject:(BSThreadInformationObject *)value;
34+- (void)removeThreadsObject:(BSThreadInformationObject *)value;
35+- (void)addThreads:(NSSet *)value;
36+- (void)removeThreads:(NSSet *)value;
37+
38+@end
39+
--- /dev/null
+++ b/BathyScapheDataConverter/BSBoardInformationObject.m
@@ -0,0 +1,22 @@
1+//
2+// BSBoardInformationObject.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import "BSBoardInformationObject.h"
10+
11+#import "BSBoardHistoryObject.h"
12+#import "BSThreadInformationObject.h"
13+
14+@implementation BSBoardInformationObject
15+
16+@dynamic boardID;
17+@dynamic boardName;
18+@dynamic boardURL;
19+@dynamic histories;
20+@dynamic threads;
21+
22+@end
--- /dev/null
+++ b/BathyScapheDataConverter/BSBoardThreadItemsObject.h
@@ -0,0 +1,31 @@
1+//
2+// BSBoardThreadItemsObject.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/17.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import <CoreData/CoreData.h>
10+
11+@class BSBoardInformationObject;
12+@class BSThreadItemObject;
13+
14+@interface BSBoardThreadItemsObject : NSManagedObject
15+{
16+}
17+
18+@property (nonatomic, retain) NSSet* items;
19+@property (nonatomic, retain) BSBoardInformationObject * board;
20+
21+@end
22+
23+
24+@interface BSBoardThreadItemsObject (CoreDataGeneratedAccessors)
25+- (void)addItemsObject:(BSThreadItemObject *)value;
26+- (void)removeItemsObject:(BSThreadItemObject *)value;
27+- (void)addItems:(NSSet *)value;
28+- (void)removeItems:(NSSet *)value;
29+
30+@end
31+
--- /dev/null
+++ b/BathyScapheDataConverter/BSBoardThreadItemsObject.m
@@ -0,0 +1,19 @@
1+//
2+// BSBoardThreadItemsObject.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/17.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import "BSBoardThreadItemsObject.h"
10+
11+#import "BSBoardInformationObject.h"
12+#import "BSThreadItemObject.h"
13+
14+@implementation BSBoardThreadItemsObject
15+
16+@dynamic items;
17+@dynamic board;
18+
19+@end
--- /dev/null
+++ b/BathyScapheDataConverter/BSCoreDataManager.h
@@ -0,0 +1,151 @@
1+//
2+// BSCoreDataManager.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import <Cocoa/Cocoa.h>
10+
11+
12+@class ThreadTextDownloader;
13+@class BSBoardInformationObject;
14+@class BSThreadInformationObject;
15+
16+@interface BSCoreDataManager : NSObject
17+{
18+ NSPersistentStoreCoordinator *persistentStoreCoordinator;
19+ NSManagedObjectModel *managedObjectModel;
20+ NSManagedObjectContext *managedObjectContext;
21+
22+ BOOL oneTimeEditor;
23+}
24+
25+@property (readonly) NSManagedObjectContext *managedObjectContext;
26+
27++ (BSCoreDataManager *)defaultManager;
28++ (BSCoreDataManager *)oneTimeEditor;
29+
30+- (void)refresh;
31+- (void)doVacuum; // ???
32+
33+// raise BSCoreDataManagerFailExuteFetchException, if fail to execute.
34+- (NSArray *)fetchDataForEntityName:(NSString *)entityName predicate:(NSPredicate *)predicate;
35+- (NSArray *)fetchDataForEntityName:(NSString *)entityName predicateFormat:(NSString *)predicateFormat, ...;
36+- (NSArray *)fetchDataForEntityName:(NSString *)entityName sortDescriptors:(NSArray *)sortDescriptors predicate:(NSPredicate *)predicate;
37+- (NSArray *)fetchDataForEntityName:(NSString *)entityName sortDescriptors:(NSArray *)sortDescriptors predicateFormat:(NSString *)predicateFormat, ...;
38+
39+
40+- (IBAction)saveAction:(id)sender;
41+
42+@end
43+
44+@interface BSCoreDataManager (BSCoreDataModelAccess)
45+// Board info Accessor
46+- (BSBoardInformationObject *)findBSBoardInformationObjectForHints:(NSDictionary *)hints;
47+
48+- (BSBoardInformationObject *)resisterBoardInformationWithName:(NSString *)name URLString:(NSString *)urlString;
49+
50+- (void)setName:(NSString *)name toBoard:(BSBoardInformationObject *)board;
51+- (void)setName:(NSString *)name toBoardID:(NSNumber *)boardID;
52+- (void)setURLString:(NSString *)urlString toBoard:(BSBoardInformationObject *)board;
53+- (void)setURLString:(NSString *)urlString toBoardID:(NSNumber *)baordID;
54+
55+- (NSNumber *)boardIDFromBoardURL:(NSString *)urlString;
56+- (NSString *)urlStringFromBoardID:(NSNumber *)boardID;
57+- (NSNumber *)boardIDFromBoardName:(NSString *)boardName;
58+- (NSString *)urlStringFromBoardName:(NSString *)boardName;
59+- (NSString *)boardNameFromBoardID:(NSNumber *)boardID;
60+- (NSString *)boardNameFromBoardURL:(NSString *)urlString;
61+
62+// for BoardManager-BoardListRepiar
63+- (BOOL)removeBoardInformationWithURL:(NSString *)urlString;
64+
65+
66+// Thread Info Accessor
67+- (NSArray *)threadInfoWithBoardID:(NSNumber *)boardID;
68+- (NSArray *)cachedThreadInfoWithBoardID:(NSNumber *)boardID;
69+- (BSThreadInformationObject *)threadInfoWithIdentifier:(NSString *)threadID boardInfo:(BSBoardInformationObject *)board;
70+- (BSThreadInformationObject *)threadInfoWithIdentifier:(NSString *)threadID boardHints:(NSDictionary *)hints;
71+
72+//- (BSThreadInformationObject *)resisterThreadInformationWithContentsOfFileURL:(NSURL *)fileURL;
73+
74+- (void)removeThreadInfoWithIdentifier:(NSString *)threadID baordID:(NSNumber *)baordID;
75+
76+- (void)setLabel:(NSUInteger)code boardName:(NSString *)boardName threadIdentifier:(NSString *)identifier;
77+- (void)setLabel:(NSUInteger)code threadInformation:(id /* BSThreadInformationObject * */)thread;
78+- (void)setIsDatOchi:(BOOL)flag threadInformation:(id /* BSThreadInformationObject * */)thread;
79+- (void)toggleDatOchiOfThreadInformation:(id /* BSThreadInformationObject * */)thread;
80+
81+//
82+//- (NSDictionary *)attributesForThreadsListWithContentsOfFile:(NSString *)filePath;
83+
84+// ログファイルに整合させる
85+//- (BOOL)rebuildFromLogFolder:(NSString *)folderPath boardID:(NSNumber *)boardID;
86+//- (BOOL)rebuildFromLogFolder:(NSString *)folderPath boardID:(NSNumber *)boardID error:(NSError **)error;
87+
88+// 未使用データを削除する
89+- (void)deleteUnusedInfomationsOnBoardID:(NSNumber *)boardID;
90+
91+// データをリセットする
92+//- (void)cleanUpItemsWhichHasBeenRemoved:(NSArray *)filenames;
93+
94+// Favorites Accessor
95+- (NSArray *)favoritesThreadInformation;
96+- (BOOL)addFavoritesThreadIdentifier:(NSString *)threadID boardName:(NSString *)boardName;
97+- (BOOL)removeFavoritesThreadIdentifier:(NSString *)threadID boardName:(NSString *)boardName;
98+- (void)moveFavorites:(NSArray *)favorites afterFavorite:(id)favorite;
99+
100+
101+//- (void)threadTextDownloader:(ThreadTextDownloader *)downloader didUpdateWithContents:(NSDictionary *)userInfo;
102+
103+@end
104+
105+#ifndef DATABASE_MANAGER_ENABLE
106+NSString *tableNameForKey(NSString *key);
107+#endif
108+
109+NSUInteger indexOfIdentifier(NSArray *array, NSString *identifier);
110+id itemOfTitle(NSArray *array, NSString *searchTitle);
111+
112+extern NSString *const BSCoreDataModelBoardInformationName;
113+extern NSString *const BSCoreDataModelThreadInformationName;
114+extern NSString *const BSCoreDataModelBoardHistoryName;
115+extern NSString *const BSCoreDataModelThreadItemName;
116+extern NSString *const BSCoreDataModelFavoriteName;
117+extern NSString *const BSCoreDataModelSurviveThreadItemsName;
118+
119+
120+// find BSBoardInformationObject Hints keys.
121+extern NSString *const BSBoardInformationObjectHintID; // NSNumber
122+extern NSString *const BSBoardInformationObjectHintURL; // NSString (not NSURL)
123+extern NSString *const BSBoardInformationObjectHintName; //NSString
124+
125+
126+extern NSString *const BSCoreDataManagerFailExuteFetchException;
127+
128+
129+extern NSString *const BSCoreDataDidFinishUpdateDownloadedOrDeletedThreadInfoNotification;
130+extern NSString *const BSCoreDataWillUpdateThreadItemNotification;
131+extern NSString *const BSCoreDataWillDeleteThreadItemsNotification;
132+
133+extern NSString *const BSCoreDataWantsThreadItemsUpdateNotification;
134+extern NSString *const BSCoreDataUserInfoBoardNameKey;
135+extern NSString *const BSCoreDataUserInfoThreadIDKey;
136+extern NSString *const BSCoreDataUserInfoThreadCountKey;
137+extern NSString *const BSCoreDataUserInfoThreadModDateKey;
138+extern NSString *const BSCoreDataUserInfoThreadPathsArrayKey;
139+extern NSString *const BSCoreDataUserInfoUpdateTypeKey;
140+extern NSString *const BSCoreDataUserInfoIsDBInsertedKey;
141+extern NSString *const BSCoreDataUserInfoThreadStatusKey;
142+
143+
144+extern NSString *const UserInfoBoardNameKey;
145+extern NSString *const UserInfoThreadIDKey;
146+extern NSString *const UserInfoThreadCountKey;
147+extern NSString *const UserInfoThreadModDateKey;
148+extern NSString *const UserInfoThreadPathsArrayKey;
149+extern NSString *const UserInfoUpdateTypeKey;
150+extern NSString *const UserInfoIsDBInsertedKey;
151+extern NSString *const UserInfoThreadStatusKey;
--- /dev/null
+++ b/BathyScapheDataConverter/BSCoreDataManager.m
@@ -0,0 +1,438 @@
1+//
2+// BSCoreDataManager.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import "BSCoreDataManager.h"
10+
11+//#import "CMRReplyMessenger.h"
12+#import "SQLiteDB.h"
13+
14+#import "BSDCAppDelegate.h"
15+
16+
17+@implementation BSCoreDataManager
18+NSString *const BSCoreDataModelBoardInformationName = @"BoardInformation";
19+NSString *const BSCoreDataModelThreadInformationName = @"ThreadInformation";
20+NSString *const BSCoreDataModelBoardHistoryName = @"BoardHistory";
21+NSString *const BSCoreDataModelThreadItemName = @"ThreadItem";
22+NSString *const BSCoreDataModelFavoriteName = @"Favorite";
23+NSString *const BSCoreDataModelSurviveThreadItemsName = @"SurviveThreadItems";
24+
25+
26+NSString *const BSBoardInformationObjectHintID = @"BSBoardInformationObjectHintID";
27+NSString *const BSBoardInformationObjectHintURL = @"BSBoardInformationObjectHintURL";
28+NSString *const BSBoardInformationObjectHintName = @"BSBoardInformationObjectHintName";
29+
30+NSString *const BSCoreDataManagerFailExuteFetchException = @"BSCoreDataManagerFailExuteFetchException";
31+
32+
33+NSString *const BSCoreDataDidFinishUpdateDownloadedOrDeletedThreadInfoNotification = @"BSCoreDataDidFinishUpdateDownloadedOrDeletedThreadInfoNotification";
34+NSString *const BSCoreDataWillUpdateThreadItemNotification = @"BSCoreDataWillUpdateThreadItemNotification";
35+NSString *const BSCoreDataWillDeleteThreadItemsNotification = @"BSCoreDataWillDeleteThreadItemsNotification";
36+
37+
38+NSString *const BSCoreDataWantsThreadItemsUpdateNotification = @"BSCoreDataWantsThreadItemsUpdateNotification";
39+NSString *const BSCoreDataUserInfoBoardNameKey = @"BoardName";
40+NSString *const BSCoreDataUserInfoThreadIDKey = @"Identifier";
41+NSString *const BSCoreDataUserInfoThreadCountKey = @"Count";
42+NSString *const BSCoreDataUserInfoThreadModDateKey = @"ModDate";
43+NSString *const BSCoreDataUserInfoThreadPathsArrayKey = @"Files";
44+NSString *const BSCoreDataUserInfoUpdateTypeKey = @"UpdateType";
45+NSString *const BSCoreDataUserInfoIsDBInsertedKey = @"IsInsert";
46+NSString *const BSCoreDataUserInfoThreadStatusKey = @"ThreadStatus";
47+
48+static BSCoreDataManager *defaultManager;
49+
50+@synthesize managedObjectContext;
51+
52+
53+- (void)deleteOldSurviveItems
54+{
55+ NSArray *array = nil;
56+ @try {
57+ array = [self fetchDataForEntityName:BSCoreDataModelSurviveThreadItemsName predicate:nil];
58+ }
59+ @catch(id ex) {
60+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
61+ return;
62+ }
63+ @throw;
64+ }
65+ if(0 == [array count]) {
66+ return;
67+ }
68+
69+ NSManagedObjectContext *moc = [self managedObjectContext];
70+ for(id obj in array) {
71+ [moc deleteObject:obj];
72+ }
73+ [self saveAction:nil];
74+}
75++ (BSCoreDataManager *)defaultManager
76+{
77+ if(defaultManager) return defaultManager;
78+
79+ defaultManager = [[[self class] alloc] init];
80+ [defaultManager deleteOldSurviveItems];
81+
82+ return defaultManager;
83+}
84++ (BSCoreDataManager *)oneTimeEditor
85+{
86+ BSCoreDataManager *result = [[[self alloc] init] autorelease];
87+ result->oneTimeEditor = YES;
88+
89+ return result;
90+}
91+
92+- (id)init
93+{
94+ [super init];
95+
96+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
97+ [nc addObserver:self selector:@selector(applicationWillTerminate:) name:NSApplicationWillTerminateNotification object:NSApp];
98+// [nc addObserver:self selector:@selector(finishWriteMesssage:) name:CMRReplyMessengerDidFinishPostingNotification object:nil];
99+
100+ return self;
101+}
102+
103+/**
104+ Creates, retains, and returns the managed object model for the application
105+ by merging all of the models found in the application bundle.
106+ */
107+
108+- (NSManagedObjectModel *)managedObjectModel
109+{
110+ if(managedObjectModel != nil) {
111+ return managedObjectModel;
112+ }
113+
114+ managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
115+ return managedObjectModel;
116+}
117+
118+- (NSURL *)storeURL
119+{
120+// NSString *storePath = [[CMRFileManager defaultManager] supportFilepathWithName:@"BathyScaphe.qdb"
121+// resolvingFileRef:nil];
122+//
123+// NSURL *url = [NSURL fileURLWithPath:storePath];
124+//
125+// return url;
126+
127+ return [BSDCAppDelegate bathyScapheSupportFolderURL];
128+}
129+
130+/**
131+ Returns the persistent store coordinator for the application. This
132+ implementation will create and return a coordinator, having added the
133+ store for the application to it. (The folder for the store is created,
134+ if necessary.)
135+ */
136+
137+- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
138+{
139+ if(persistentStoreCoordinator != nil) {
140+ return persistentStoreCoordinator;
141+ }
142+
143+ NSError *error;
144+
145+ NSURL *url = [self storeURL];
146+
147+ persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
148+ if(!persistentStoreCoordinator) {
149+ NSLog(@"Could not create store coordinator");
150+ exit(-1);
151+ }
152+
153+ NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
154+ [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
155+ nil];
156+
157+ if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:&error]){
158+ [[NSApplication sharedApplication] presentError:error];
159+ NSLog(@"Error -> %@", error);// localizedDescription]);
160+ }
161+
162+ return persistentStoreCoordinator;
163+}
164+
165+
166+/**
167+ Returns the managed object context for the application (which is already
168+ bound to the persistent store coordinator for the application.)
169+ */
170+
171+- (NSManagedObjectContext *)managedObjectContext
172+{
173+ if(oneTimeEditor) {
174+ if(managedObjectContext != nil) {
175+ return managedObjectContext;
176+ }
177+
178+ NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
179+ if(coordinator != nil) {
180+ managedObjectContext = [[NSManagedObjectContext alloc] init];
181+ [managedObjectContext setPersistentStoreCoordinator: coordinator];
182+ [managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
183+ [managedObjectContext setUndoManager:nil];
184+
185+ [[NSNotificationCenter defaultCenter] addObserver:[[self class] defaultManager]
186+ selector:@selector(anotherContextDidSave:)
187+ name:NSManagedObjectContextDidSaveNotification
188+ object:managedObjectContext];
189+ }
190+ return managedObjectContext;
191+ }
192+
193+ if(![NSThread isMainThread]) {
194+ id moc = [[[NSThread currentThread] threadDictionary] objectForKey:@"BSCoreDataManagerManagedObjectContext"];
195+ if(moc) return moc;
196+
197+ moc = [[[NSManagedObjectContext alloc] init] autorelease];
198+ [moc setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
199+ [[[NSThread currentThread] threadDictionary] setObject:moc
200+ forKey:@"BSCoreDataManagerManagedObjectContext"];
201+
202+ [[NSNotificationCenter defaultCenter] addObserver:self
203+ selector:@selector(anotherContextDidSave:)
204+ name:NSManagedObjectContextDidSaveNotification
205+ object:moc];
206+
207+ [moc setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
208+ [moc setUndoManager:nil];
209+
210+ return moc;
211+ }
212+
213+ if(managedObjectContext != nil) {
214+ return managedObjectContext;
215+ }
216+
217+ NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
218+ if(coordinator != nil) {
219+ managedObjectContext = [[NSManagedObjectContext alloc] init];
220+ [managedObjectContext setPersistentStoreCoordinator: coordinator];
221+ [managedObjectContext setUndoManager:nil];
222+ }
223+
224+ return managedObjectContext;
225+}
226+
227+
228+/**
229+ Performs the save action for the application, which is to send the save:
230+ message to the application's managed object context. Any encountered errors
231+ are presented to the user.
232+ */
233+
234+- (IBAction)saveAction:(id)sender
235+{
236+ NSError *error = nil;
237+ if([self.managedObjectContext commitEditing]) {
238+ if([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error]) {
239+ [[NSApplication sharedApplication] presentError:error];
240+ }
241+ if(![NSThread isMainThread]) {
242+ [self.managedObjectContext reset];
243+// NSLog(@"Reset on Thread(%p).", [NSThread currentThread]);
244+ }
245+ }
246+}
247+
248+
249+/**
250+ Implementation of the applicationShouldTerminate: method, used here to
251+ handle the saving of changes in the application managed object context
252+ before the application terminates.
253+ */
254+
255+//- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
256+- (void)applicationWillTerminate:(id)notification
257+{
258+ NSError *error;
259+ NSUInteger reply = NSTerminateNow;
260+
261+ if(managedObjectContext != nil) {
262+ if([managedObjectContext commitEditing]) {
263+ if([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
264+
265+ // This error handling simply presents error information in a panel with an
266+ // "Ok" button, which does not include any attempt at error recovery (meaning,
267+ // attempting to fix the error.) As a result, this implementation will
268+ // present the information to the user and then follow up with a panel asking
269+ // if the user wishes to "Quit Anyway", without saving the changes.
270+
271+ // Typically, this process should be altered to include application-specific
272+ // recovery steps.
273+
274+ BOOL errorResult = [[NSApplication sharedApplication] presentError:error];
275+
276+ if(errorResult == YES) {
277+ reply = NSTerminateCancel;
278+ } else {
279+
280+ NSInteger alertReturn = NSRunAlertPanel(nil, @"Could not save changes while quitting. Quit anyway?" , @"Quit anyway", @"Cancel", nil);
281+ if(alertReturn == NSAlertAlternateReturn) {
282+ reply = NSTerminateCancel;
283+ }
284+ }
285+ }
286+ } else {
287+ reply = NSTerminateCancel;
288+ }
289+ }
290+
291+ return;// reply;
292+}
293+
294+
295+/**
296+ Implementation of dealloc, to release the retained variables.
297+ */
298+
299+- (void)dealloc
300+{
301+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
302+ if(oneTimeEditor) {
303+ [self saveAction:nil];
304+ [nc removeObserver:[[self class] defaultManager] name:nil object:managedObjectContext];
305+ }
306+
307+ [nc removeObserver:self name:nil object:managedObjectContext];
308+ [nc removeObserver:self name:nil object:NSApp];
309+// [nc removeObserver:self name:CMRReplyMessengerDidFinishPostingNotification object:nil];
310+
311+ [managedObjectContext release], managedObjectContext = nil;
312+ [persistentStoreCoordinator release], persistentStoreCoordinator = nil;
313+ [managedObjectModel release], managedObjectModel = nil;
314+ [super dealloc];
315+}
316+
317+
318+- (void)anotherContextDidSave:(NSNotification *)notification
319+{
320+ [managedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
321+ withObject:notification
322+ waitUntilDone:YES];
323+}
324+
325+- (void)refresh
326+{
327+ if([NSThread isMainThread]) {
328+ [self saveAction:nil];
329+// [managedObjectContext release];
330+// managedObjectContext = nil;
331+ [self.managedObjectContext reset];
332+// NSLog(@"Reset on Main Thread.");
333+
334+ return;
335+ }
336+
337+ [[[NSThread currentThread] threadDictionary] removeObjectForKey:@"BSCoreDataManagerManagedObjectContext"];
338+// [self.managedObjectContext reset];
339+// NSLog(@"Reset on Not Main Thread(%p).", [NSThread currentThread]);
340+}
341+
342+
343+- (NSArray *)fetchDataForEntityName:(NSString *)entityName sortDescriptors:(NSArray *)sortDescriptors predicate:(NSPredicate *)predicate;
344+{
345+ NSManagedObjectContext *context = self.managedObjectContext;
346+ NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
347+ NSEntityDescription *entity = [NSEntityDescription entityForName:entityName
348+ inManagedObjectContext:context];
349+
350+ [fetch setEntity:entity];
351+ [fetch setPredicate:predicate];
352+ if(sortDescriptors) {
353+ [fetch setSortDescriptors:sortDescriptors];
354+ }
355+
356+ NSError *error = nil;
357+ NSArray *array = [context executeFetchRequest:fetch
358+ error:&error];
359+ if(!array) {
360+ NSString *errorString = nil;
361+ if(error) {
362+ errorString = [NSString stringWithFormat:@"Can not execute request: %@", error];
363+ } else {
364+ errorString = @"Can not execute request.";
365+ }
366+ [NSException raise:BSCoreDataManagerFailExuteFetchException format:@"%@", errorString];
367+ }
368+
369+// NSLog(@"Fetch on Thread(%p).", [NSThread currentThread]);
370+
371+ return array;
372+}
373+- (NSArray *)fetchDataForEntityName:(NSString *)entityName sortDescriptors:(NSArray *)sortDescriptors predicateFormat:(NSString *)format, ...
374+{
375+ NSPredicate *predicate = nil;
376+
377+ if(format) {
378+ va_list ap;
379+ va_start(ap, format);
380+ predicate = [NSPredicate predicateWithFormat:format arguments:ap];
381+ va_end(ap);
382+ }
383+
384+ return [self fetchDataForEntityName:entityName sortDescriptors:sortDescriptors predicate:predicate];
385+}
386+- (NSArray *)fetchDataForEntityName:(NSString *)entityName predicate:(NSPredicate *)predicate
387+{
388+ return [self fetchDataForEntityName:entityName sortDescriptors:nil predicate:predicate];
389+}
390+- (NSArray *)fetchDataForEntityName:(NSString *)entityName predicateFormat:(NSString *)format, ...
391+{
392+ NSPredicate *predicate = nil;
393+
394+ if(format) {
395+ va_list ap;
396+ va_start(ap, format);
397+ predicate = [NSPredicate predicateWithFormat:format arguments:ap];
398+ va_end(ap);
399+ }
400+
401+ return [self fetchDataForEntityName:entityName sortDescriptors:nil predicate:predicate];
402+}
403+
404+- (void)doVacuum
405+{
406+ SQLiteDB *db;
407+ NSURL *storeURL = [self storeURL];
408+ db = [[[SQLiteDB alloc] initWithDatabasePath:[storeURL path]] autorelease];
409+
410+ [db performQuery:@"VACUUM;"];
411+}
412+
413+@end
414+
415+
416+@implementation NSString(BSThreadListUpdateTaskAddition)
417+- (NSComparisonResult)numericCompare:(NSString *)string
418+{
419+ return [self compare:string options:NSNumericSearch];
420+}
421+@end
422+
423+
424+@implementation NSNumber(BSThreadListUpdateTaskAddition)
425+- (NSComparisonResult)numericCompare:(id)obj
426+{
427+ return [self compare:obj];
428+}
429+@end
430+
431+
432+@implementation NSDate(BSThreadListUpdateTaskAddition)
433+- (NSComparisonResult)numericCompare:(id)obj
434+{
435+ return [self compare:obj];
436+}
437+@end
438+
--- /dev/null
+++ b/BathyScapheDataConverter/BSCoreDataManager_DataAccessor.m
@@ -0,0 +1,1096 @@
1+//
2+// BSCoreDataManager_DataAccessor.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/11/03.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+
10+#import "DatabaseManager.h"
11+
12+#import "BSCoreDataManager.h"
13+
14+#import "BSBoardInformationObject.h"
15+#import "BSThreadInformationObject.h"
16+#import "BSBoardThreadItemsObject.h"
17+#import "BSFavoriteObject.h"
18+#import "BSBoardHistoryObject.h"
19+
20+//#import "ThreadTextDownloader.h"
21+//#import "CMRThreadSignature.h"
22+//#import "AppDefaults.h"
23+//#import "CMRDocumentFileManager.h"
24+
25+//#import "CMRReplyMessenger.h"
26+
27+
28+@interface BSCoreDataManager (BSCoreDataModelAccessPrivate)
29+- (void)makeThreadsListsUpdateCursor;
30+@end
31+
32+@implementation BSCoreDataManager (BSCoreDataModelAccess)
33+
34+#pragma mark #### Board Information Accessor ####
35+- (BSBoardInformationObject *)findBSBoardInformationObjectForHints:(NSDictionary *)hints
36+{
37+ NSNumber *boardID = [hints objectForKey:BSBoardInformationObjectHintID];
38+ NSString *boardURL = [hints objectForKey:BSBoardInformationObjectHintURL];
39+ NSString *boardName = [hints objectForKey:BSBoardInformationObjectHintName];
40+
41+ NSArray *array = nil;
42+ NSPredicate *predicate = nil;
43+
44+
45+ @try {
46+ if(boardID) {
47+ predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"boardID", boardID];
48+ array = [self fetchDataForEntityName:BSCoreDataModelBoardInformationName
49+ predicate:predicate];
50+ if([array count] != 0) return [array lastObject];
51+
52+ // boardID is primary!
53+ return nil;
54+ }
55+ if(boardURL) {
56+ predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"boardURL", boardURL];
57+ array = [self fetchDataForEntityName:BSCoreDataModelBoardInformationName
58+ predicate:predicate];
59+ if([array count] != 0) return [array lastObject];
60+ }
61+ if(boardName) {
62+ // [cd]は旧・mac板(旧・Mac板)対応 Mac OS X 10.5では動かない。
63+ if(floor(NSAppKitVersionNumber) < 1000) {
64+ predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"boardName", boardName];
65+ } else {
66+ predicate = [NSPredicate predicateWithFormat:@"%K =[cd] %@", @"boardName", boardName];
67+ }
68+
69+ array = [self fetchDataForEntityName:BSCoreDataModelBoardInformationName
70+ predicate:predicate];
71+ if([array count] != 0) return [array lastObject];
72+ }
73+
74+ // board history
75+ if(boardURL) {
76+ predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"boardURL", boardURL];
77+ array = [self fetchDataForEntityName:BSCoreDataModelBoardHistoryName
78+ predicate:predicate];
79+ if([array count] != 0) {
80+ return [[array lastObject] valueForKey:@"board"];
81+ }
82+ }
83+ if(boardName) {
84+ predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"boardName", boardName];
85+ array = [self fetchDataForEntityName:BSCoreDataModelBoardHistoryName
86+ predicate:predicate];
87+ if([array count] != 0) {
88+ return [[array lastObject] valueForKey:@"board"];
89+ }
90+ }
91+ }
92+ @catch (id ex) {
93+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
94+ return nil;
95+ }
96+ @throw;
97+ }
98+
99+ return nil;
100+}
101+
102+- (BSBoardInformationObject *)resisterBoardInformationWithName:(NSString *)name URLString:(NSString *)urlString
103+{
104+ // check same board already exist
105+ NSDictionary *hints = [NSDictionary dictionaryWithObject:name forKey:BSBoardInformationObjectHintName];
106+ id sameName = [self findBSBoardInformationObjectForHints:hints];
107+ hints = [NSDictionary dictionaryWithObject:urlString forKey:BSBoardInformationObjectHintURL];
108+ id sameURL = [self findBSBoardInformationObjectForHints:hints];
109+ if(sameName && sameURL && [sameName isEqual:sameURL]) return sameName;
110+
111+ if(sameURL) {
112+ [self setName:name toBoard:sameURL];
113+ return sameURL;
114+ }
115+
116+ // getting max boardID
117+ NSManagedObjectContext *context = self.managedObjectContext;
118+ NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
119+ NSEntityDescription *entity = [NSEntityDescription entityForName:BSCoreDataModelBoardInformationName
120+ inManagedObjectContext:context];
121+ [fetch setEntity:entity];
122+ NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"boardID"
123+ ascending:NO] autorelease];
124+ [fetch setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
125+ [fetch setFetchLimit:1];
126+
127+ NSError *error = nil;
128+ NSArray *array = [context executeFetchRequest:fetch
129+ error:&error];
130+ if(!array) {
131+ NSString *errorString = nil;
132+ if(error) {
133+ errorString = [NSString stringWithFormat:@"Can not execute request: %@", error];
134+ } else {
135+ errorString = @"Can not execute request.";
136+ }
137+ NSLog(@"%@", errorString);
138+
139+ return nil;
140+ }
141+
142+ NSUInteger newID = NSUIntegerMax;
143+ BSBoardInformationObject *maxBoardIDboard = [array lastObject];
144+ if(!maxBoardIDboard) {
145+ newID = 1;
146+ } else {
147+ newID = [maxBoardIDboard.boardID unsignedIntegerValue] + 1;
148+ }
149+
150+ // resister
151+ BSBoardInformationObject *board = nil;
152+ board = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelBoardInformationName
153+ inManagedObjectContext:self.managedObjectContext];
154+ if(!board) return nil;
155+ board.boardID = [NSNumber numberWithUnsignedInteger:newID];
156+ board.boardName = name;
157+ board.boardURL = urlString;
158+
159+ [self saveAction:nil];
160+
161+ return board;
162+}
163+- (void)setName:(NSString *)name toBoard:(BSBoardInformationObject *)board
164+{
165+ if(!board) {
166+ NSLog(@"board is nil.");
167+ return;
168+ }
169+ if(!name || [name length] == 0) {
170+ NSLog(@"name is nil or empty.");
171+ return;
172+ }
173+
174+ if([name isEqualToString:board.boardName]) return;
175+
176+ // check same history
177+ NSArray *array = nil;
178+ @try {
179+ array = [self fetchDataForEntityName:BSCoreDataModelBoardHistoryName
180+ predicateFormat:@"%K = %@ AND %K = %@",
181+ @"board", board, @"boardName", name];
182+ }
183+ @catch (id ex) {
184+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
185+ return;
186+ }
187+ @throw;
188+ }
189+
190+ if([array count] != 0) {
191+ NSLog(@"Already exist in history.");
192+ board.boardName = name;
193+ return;
194+ }
195+
196+ BSBoardHistoryObject *history = nil;
197+ history = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelBoardHistoryName
198+ inManagedObjectContext:self.managedObjectContext];
199+ if(!history) {
200+ NSLog(@"Could not insert history.");
201+ return;
202+ }
203+ history.board = board;
204+ history.boardName = board.boardName;
205+
206+ board.boardName = name;
207+
208+ [self saveAction:nil];
209+}
210+- (void)setName:(NSString *)name toBoardID:(NSNumber *)boardID
211+{
212+ NSDictionary *hints = [NSDictionary dictionaryWithObject:boardID
213+ forKey:BSBoardInformationObjectHintID];
214+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
215+ [self setName:name toBoard:board];
216+}
217+
218+
219+- (void)setURLString:(NSString *)urlString toBoard:(BSBoardInformationObject *)board
220+{
221+ if(!board) {
222+ NSLog(@"board is nil.");
223+ return;
224+ }
225+ if(!urlString || [urlString length] == 0) {
226+ NSLog(@"urlString is nil or empty.");
227+ return;
228+ }
229+
230+ if([urlString isEqualToString:board.boardURL]) return;
231+
232+ // check same history
233+ NSArray *array = nil;
234+ @try {
235+ array = [self fetchDataForEntityName:BSCoreDataModelBoardHistoryName
236+ predicateFormat:@"%K = %@ AND %K = %@",
237+ @"board", board, @"boardURL", urlString];
238+ }
239+ @catch (id ex) {
240+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
241+ return;
242+ }
243+ @throw;
244+ }
245+
246+ if([array count] != 0) {
247+ NSLog(@"Already exist in history.");
248+ board.boardURL = urlString;
249+ return;
250+ }
251+
252+ BSBoardHistoryObject *history = nil;
253+ history = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelBoardHistoryName
254+ inManagedObjectContext:self.managedObjectContext];
255+ if(!history) {
256+ NSLog(@"Could not insert history.");
257+ return;
258+ }
259+ history.board = board;
260+ history.boardURL = board.boardURL;
261+
262+ board.boardURL = urlString;
263+
264+ [self saveAction:nil];
265+}
266+- (void)setURLString:(NSString *)urlString toBoardID:(NSNumber *)boardID
267+{
268+ NSDictionary *hints = [NSDictionary dictionaryWithObject:boardID
269+ forKey:BSBoardInformationObjectHintID];
270+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
271+ [self setURLString:urlString toBoard:board];
272+}
273+
274+- (NSNumber *)boardIDFromBoardURL:(NSString *)urlString
275+{
276+ NSDictionary *hints = [NSDictionary dictionaryWithObject:urlString
277+ forKey:BSBoardInformationObjectHintURL];
278+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
279+
280+ return board.boardID;
281+}
282+- (NSString *)urlStringFromBoardID:(NSNumber *)boardID
283+{
284+ NSDictionary *hints = [NSDictionary dictionaryWithObject:boardID
285+ forKey:BSBoardInformationObjectHintID];
286+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
287+
288+ return board.boardURL;
289+}
290+- (NSNumber *)boardIDFromBoardName:(NSString *)boardName
291+{
292+ NSDictionary *hints = [NSDictionary dictionaryWithObject:boardName
293+ forKey:BSBoardInformationObjectHintName];
294+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
295+
296+ return board.boardID;
297+}
298+- (NSString *)urlStringFromBoardName:(NSString *)boardName
299+{
300+ NSDictionary *hints = [NSDictionary dictionaryWithObject:boardName
301+ forKey:BSBoardInformationObjectHintName];
302+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
303+
304+ return board.boardURL;
305+}
306+- (NSString *)boardNameFromBoardID:(NSNumber *)boardID
307+{
308+ NSDictionary *hints = [NSDictionary dictionaryWithObject:boardID
309+ forKey:BSBoardInformationObjectHintID];
310+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
311+
312+ return board.boardName;
313+}
314+- (NSString *)boardNameFromBoardURL:(NSString *)urlString
315+{
316+ NSDictionary *hints = [NSDictionary dictionaryWithObject:urlString
317+ forKey:BSBoardInformationObjectHintURL];
318+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
319+
320+ return board.boardName;
321+}
322+
323+// for BoardManager-BoardListRepiar
324+- (void)delaySaveForRemoveBoardInformation
325+{
326+ [self saveAction:nil];
327+}
328+- (BOOL)removeBoardInformationWithURL:(NSString *)urlString
329+{
330+ NSDictionary *hints = [NSDictionary dictionaryWithObject:urlString
331+ forKey:BSBoardInformationObjectHintURL];
332+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
333+ if(board) {
334+ [self.managedObjectContext deleteObject:board];
335+ }
336+
337+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(delaySaveForRemoveBoardInformation) object:nil];
338+ [self performSelector:@selector(delaySaveForRemoveBoardInformation) withObject:nil afterDelay:0.3];
339+ return YES;
340+}
341+
342+#pragma mark #### Thread Information Accessor ####
343+- (void)deleteOldSurviveThreadItem:(NSArray *)array
344+{
345+// // remove all object without last one.
346+// if([array count] < 2) return;
347+// NSManagedObjectContext *moc = [self managedObjectContext];
348+// NSUInteger i = 0;
349+// for(i = 0; i < [array count] - 1; i++) {
350+// [moc deleteObject:[array objectAtIndex:i]];
351+// }
352+}
353+- (NSArray *)threadInfoWithBoardID:(NSNumber *)boardID
354+{
355+ NSArray *array = nil;
356+ @try {
357+ array = [self fetchDataForEntityName:BSCoreDataModelSurviveThreadItemsName
358+ predicateFormat:@"%K = %@", @"board.boardID", boardID];
359+ }
360+ @catch(id ex) {
361+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
362+ return [NSArray array];
363+ }
364+ @throw;
365+ }
366+ if(0 == [array count]) {
367+ return array;
368+ }
369+ [self performSelectorOnMainThread:@selector(deleteOldSurviveThreadItem:) withObject:array waitUntilDone:NO];
370+
371+ id obj = [array lastObject];
372+
373+ NSSet *threadsSet = [obj valueForKeyPath:@"items"];
374+ return [threadsSet allObjects];
375+}
376+- (NSArray *)cachedThreadInfoWithBoardID:(NSNumber *)boardID
377+{
378+ NSArray *array = nil;
379+ @try {
380+ array = [self fetchDataForEntityName:BSCoreDataModelThreadInformationName
381+ predicateFormat:@"%K = %@ AND %K != nil",
382+ @"board.boardID", boardID, @"numberOfRead"];
383+ }
384+ @catch(id ex) {
385+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
386+ return [NSArray array];
387+ }
388+ @throw;
389+ }
390+
391+ return array;
392+}
393+- (BSThreadInformationObject *)threadInfoWithIdentifier:(NSString *)threadID boardInfo:(BSBoardInformationObject *)board
394+{
395+ NSArray *array = nil;
396+ @try {
397+ array = [self fetchDataForEntityName:BSCoreDataModelThreadInformationName
398+ predicateFormat:@"%K = %@ AND %K = %@",
399+ @"board", board,
400+ @"threadID", threadID];
401+ }
402+ @catch (id ex) {
403+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
404+ return nil;
405+ }
406+ @throw;
407+ }
408+
409+ if([array count] == 0) return nil;
410+
411+ return [array lastObject];
412+}
413+- (BSThreadInformationObject *)threadInfoWithIdentifier:(NSString *)threadID boardHints:(NSDictionary *)hints
414+{
415+ BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
416+ if(!board) return nil;
417+
418+ return [self threadInfoWithIdentifier:threadID boardInfo:board];
419+}
420+
421+- (BSThreadInformationObject *)resisterThreadInformationWithIdentifier:(NSString *)identifier
422+ name:(NSString *)name
423+ intoBoard:(BSBoardInformationObject *)board
424+{
425+ BSThreadInformationObject *thread = nil;
426+
427+ thread = [self threadInfoWithIdentifier:identifier boardInfo:board];
428+ if(thread) return thread;
429+
430+ thread = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelThreadInformationName
431+ inManagedObjectContext:self.managedObjectContext];
432+ thread.threadID = identifier;
433+ thread.threadName = name;
434+ thread.board = board;
435+
436+ // if you send message saveAction:, you must set threadStatus property.
437+
438+ return thread;
439+}
440+//- (BSThreadInformationObject *)resisterThreadInformationWithContentsOfFileURL:(NSURL *)fileURL
441+//{
442+// NSString *filepath = [fileURL path];
443+// NSDictionary *hoge = [NSDictionary dictionaryWithContentsOfFile:filepath];
444+// NSString *datNum, *title, *boardName;
445+// NSUInteger count;
446+// NSDate *date;
447+// CMRThreadUserStatus *s;
448+// id rep;
449+// BOOL isDatOchi;
450+// NSUInteger label = 0;
451+//
452+// datNum = [hoge objectForKey:ThreadPlistIdentifierKey];
453+// if (!datNum) return NO;
454+// title = [hoge objectForKey:CMRThreadTitleKey];
455+// if (!title) return NO;
456+// boardName = [hoge objectForKey:ThreadPlistBoardNameKey];
457+// if (!boardName) return NO;
458+// count = [[hoge objectForKey: ThreadPlistContentsKey] count];
459+//
460+// rep = [hoge objectForKey:CMRThreadUserStatusKey];
461+// s = [CMRThreadUserStatus objectWithPropertyListRepresentation:rep];
462+// isDatOchi = (s ? [s isDatOchiThread] : NO);
463+// label = (s ? [s label] : 0);
464+//
465+// date = [hoge objectForKey:CMRThreadModifiedDateKey];
466+//
467+// NSDictionary *hints = [NSDictionary dictionaryWithObject:boardName forKey:BSBoardInformationObjectHintName];
468+// BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
469+// if(!board) {
470+// CMRDocumentFileManager *dfm = [CMRDocumentFileManager defaultManager];
471+// NSString *otherBoardName = [dfm boardNameWithLogPath:filepath];
472+// hints = [NSDictionary dictionaryWithObject:otherBoardName forKey:BSBoardInformationObjectHintName];
473+// board = [self findBSBoardInformationObjectForHints:hints];
474+// if(!board) {
475+// NSLog(@"Board not resistered.");
476+// return NO;
477+// }
478+// }
479+//
480+// BSThreadInformationObject *thread = [self resisterThreadInformationWithIdentifier:datNum
481+// name:title
482+// intoBoard:board];
483+// thread.numberOfAll = thread.numberOfRead = [NSNumber numberWithUnsignedInteger:count];
484+// thread.modifiedDate = date;
485+// thread.threadLabel = [NSNumber numberWithUnsignedInteger:label];
486+// thread.isDatOchi = [NSNumber numberWithBool:isDatOchi];
487+//
488+// [self saveAction:nil];
489+//
490+// return thread;
491+//}
492+
493+- (void)removeThreadInfoWithIdentifier:(NSString *)threadID baordID:(NSNumber *)boardID
494+{
495+ NSArray *array = nil;
496+ @try {
497+ array = [self fetchDataForEntityName:BSCoreDataModelThreadInformationName
498+ predicateFormat:@"%K = %@ AND %K = %@",
499+ @"threadID", threadID, @"board.boardID", boardID];
500+ }
501+ @catch (id ex) {
502+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
503+ return;
504+ }
505+ @throw;
506+ }
507+ if([array count] == 0) return;
508+
509+ [self.managedObjectContext deleteObject:[array lastObject]];
510+ [self saveAction:nil];
511+
512+ [self makeThreadsListsUpdateCursor];
513+}
514+
515+- (void)setLabel:(NSUInteger)code boardName:(NSString *)boardName threadIdentifier:(NSString *)identifier
516+{
517+ NSArray *array = nil;
518+ @try {
519+ array = [self fetchDataForEntityName:BSCoreDataModelThreadInformationName
520+ predicateFormat:@"%K = %@ AND %K = %@",
521+ @"threadID", identifier,
522+ @"board.boardName", boardName];
523+ }
524+ @catch (id ex) {
525+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
526+ return;
527+ }
528+ @throw;
529+ }
530+
531+ if(0 == [array count]) {
532+ NSLog(@"Could not find thread for boatdName(%@) and threadID(%@)", boardName, identifier);
533+ return;
534+ }
535+ BSThreadInformationObject *thread = [array lastObject];
536+ thread.threadLabel = [NSNumber numberWithUnsignedInteger:code];
537+
538+ [self saveAction:nil];
539+}
540+- (void)setLabel:(NSUInteger)code threadInformation:(id /* BSThreadInformationObject * */)thread
541+{
542+ if(![thread isKindOfClass:[BSThreadInformationObject class]]
543+ && ![thread isKindOfClass:[BSThreadListItemObject class]]) {
544+ NSLog(@"thread is not threadObject.");
545+ return;
546+ }
547+ BSThreadInformationObject *aThread = thread;
548+ aThread.threadLabel = [NSNumber numberWithUnsignedInteger:code];
549+}
550+- (void)setIsDatOchi:(BOOL)flag threadInformation:(id /* BSThreadInformationObject * */)thread
551+{
552+ if(![thread isKindOfClass:[BSThreadInformationObject class]]
553+ && ![thread isKindOfClass:[BSThreadListItemObject class]]) {
554+ NSLog(@"thread is not threadObject.");
555+ return;
556+ }
557+
558+ BSThreadInformationObject *aThread = thread;
559+ aThread.isDatOchi = [NSNumber numberWithBool:flag];
560+}
561+- (void)toggleDatOchiOfThreadInformation:(id /* BSThreadInformationObject * */)thread
562+{
563+ if(![thread isKindOfClass:[BSThreadInformationObject class]]
564+ && ![thread isKindOfClass:[BSThreadListItemObject class]]) {
565+ NSLog(@"thread is not threadObject.");
566+ return;
567+ }
568+
569+ BSThreadInformationObject *aThread = thread;
570+ BOOL flag = [aThread.isDatOchi boolValue];
571+ aThread.isDatOchi = [NSNumber numberWithBool:!flag];
572+}
573+
574+//- (NSDictionary *)attributesForThreadsListWithContentsOfFile:(NSString *)inFilePath
575+//{
576+// CMRDocumentFileManager *dfm = [CMRDocumentFileManager defaultManager];
577+// NSString *boardName = [dfm boardNameWithLogPath:inFilePath];
578+// NSString *threadID = [dfm datIdentifierWithLogPath:inFilePath];
579+//
580+// if(!boardName) return nil;
581+// if(!threadID) return nil;
582+//
583+// NSDictionary *hints = [NSDictionary dictionaryWithObject:boardName
584+// forKey:BSBoardInformationObjectHintName];
585+//
586+// BSThreadInformationObject *thread = [self threadInfoWithIdentifier:threadID
587+// boardHints:hints];
588+// if(!thread) return nil;
589+//
590+// return thread.attribute;
591+//}
592+
593+//- (void)threadTextDownloader:(ThreadTextDownloader *)downloader didUpdateWithContents:(NSDictionary *)userInfo
594+//{
595+// CMRThreadSignature *signature;
596+//
597+// UTILAssertKindOfClass(downloader, ThreadTextDownloader);
598+// UTILAssertNotNil(userInfo);
599+// UTILAssertKindOfClass(userInfo, NSDictionary);
600+//
601+// signature = [downloader threadSignature];
602+// UTILAssertNotNil(signature);
603+//
604+// NSDate *modDate = [userInfo objectForKey:@"ttd_date"];
605+// NSNumber *numCount = [userInfo objectForKey:@"ttd_count"];
606+// if (!modDate) {
607+// if ([[NSUserDefaults standardUserDefaults] boolForKey:BSUserDebugEnabledKey]) {
608+// NSLog(@"** USER DEBUG ** Why? modDate is nil.");
609+// }
610+// } else {
611+// if ([[NSUserDefaults standardUserDefaults] boolForKey:BSUserDebugEnabledKey]) {
612+// NSLog(@"** USER DEBUG ** OK. modDate is %@.", modDate);
613+// }
614+// }
615+//
616+// NSString *threadID = [signature identifier];
617+// NSString *boardName = [signature boardName];
618+//
619+// NSDictionary *hints = [NSDictionary dictionaryWithObjectsAndKeys:
620+// boardName, BSBoardInformationObjectHintName,
621+// [[downloader boardURL] absoluteString], BSBoardInformationObjectHintURL,
622+// nil];
623+// BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
624+// if(!board) {
625+// NSLog(@"Could not find board.");
626+// NSLog(@"#### I NEED TO WRITE CODE RESISTER BOARD HERE!! ####");
627+// return;
628+// }
629+//
630+// NSArray *array = [self fetchDataForEntityName:BSCoreDataModelThreadInformationName
631+// predicateFormat:@"%K = %@ AND %K = %@",
632+// @"board", board, @"threadID", threadID];
633+// BSThreadInformationObject *thread;
634+// if(0 != [array count]) {
635+// thread = [array lastObject];
636+// } else {
637+// thread = [self resisterThreadInformationWithIdentifier:threadID
638+// name:[downloader threadTitle]
639+// intoBoard:board];
640+// thread.isDatOchi = [NSNumber numberWithBool:[downloader useMaru]];
641+// }
642+// thread.numberOfAll = numCount;
643+// thread.numberOfRead = numCount;
644+// thread.modifiedDate = modDate;
645+//
646+// NSNotification *notification = [NSNotification notificationWithName:BSCoreDataWillUpdateThreadItemNotification
647+// object:self];
648+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:)
649+// withObject:notification
650+// waitUntilDone:YES];
651+// if ([CMRPref sortsImmediately]) {
652+// [self makeThreadsListsUpdateCursor];
653+// } else {
654+// NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
655+// threadID, BSCoreDataUserInfoThreadIDKey,
656+// numCount, BSCoreDataUserInfoThreadCountKey,
657+// modDate, BSCoreDataUserInfoThreadModDateKey,
658+// boardName, BSCoreDataUserInfoBoardNameKey,
659+// [NSNumber numberWithBool:[array count] == 0], BSCoreDataUserInfoIsDBInsertedKey,
660+// NULL];
661+//
662+// NSNotification *notification = [NSNotification notificationWithName:BSCoreDataWantsThreadItemsUpdateNotification
663+// object:self
664+// userInfo:userInfo];
665+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:)
666+// withObject:notification waitUntilDone:NO];
667+// }
668+//
669+// [self saveAction:nil];
670+//}
671+- (void)makeThreadsListsUpdateCursor
672+{
673+ NSNotification *notification = [NSNotification notificationWithName:BSCoreDataDidFinishUpdateDownloadedOrDeletedThreadInfoNotification
674+ object:self];
675+ [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:)
676+ withObject:notification
677+ waitUntilDone:NO];
678+}
679+
680+//- (BOOL)rebuildFromFilePath:(NSString *)filepath withBoardID:(NSNumber *)boardID
681+//{
682+// NSDictionary *hoge = [NSDictionary dictionaryWithContentsOfFile:filepath];
683+// NSString *datNum, *title;
684+// NSUInteger count, numberOfAll;
685+// NSDate *date;
686+// CMRThreadUserStatus *s;
687+// id rep;
688+// BOOL isDatOchi;
689+// NSUInteger labelCode;
690+//
691+// datNum = [hoge objectForKey:ThreadPlistIdentifierKey];
692+// if (!datNum) return NO;
693+// title = [hoge objectForKey:CMRThreadTitleKey];
694+// if (!title) return NO;
695+// count = [[hoge objectForKey: ThreadPlistContentsKey] count];
696+//
697+// rep = [hoge objectForKey:CMRThreadUserStatusKey];
698+// s = [CMRThreadUserStatus objectWithPropertyListRepresentation:rep];
699+// isDatOchi = (s ? [s isDatOchiThread] : NO);
700+// labelCode = (s ? [s label] : 0);
701+// date = [hoge objectForKey:CMRThreadModifiedDateKey];
702+//
703+// NSDictionary *hints = [NSDictionary dictionaryWithObject:boardID
704+// forKey:BSBoardInformationObjectHintID];
705+// BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
706+// BSThreadInformationObject *thread = [self threadInfoWithIdentifier:datNum
707+// boardInfo:board];
708+// if(!thread) {
709+// thread = [self resisterThreadInformationWithIdentifier:datNum
710+// name:title
711+// intoBoard:board];
712+// }
713+//
714+// numberOfAll = [thread.numberOfAll unsignedIntegerValue];
715+// numberOfAll = MAX(numberOfAll, count);
716+//
717+// thread.numberOfAll = [NSNumber numberWithUnsignedInteger:numberOfAll];
718+// thread.numberOfRead = [NSNumber numberWithUnsignedInteger:count];
719+// thread.modifiedDate = date;
720+// thread.isDatOchi = [NSNumber numberWithBool:isDatOchi];
721+// thread.threadLabel = [NSNumber numberWithInteger:labelCode];
722+//
723+// return YES;
724+//}
725+
726+//static NSError *fileContentsErrorObject(NSArray *filepaths)
727+//{
728+// NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:filepaths, DatabaseManagerInvalidFilePathsArrayKey,
729+// NSLocalizedStringFromTable(@"RebuildingErrorAlert", @"DatabaseManager", nil), NSLocalizedDescriptionKey,
730+// NSLocalizedStringFromTable(@"RebuildingErrorMessage", @"DatabaseManager", nil), NSLocalizedRecoverySuggestionErrorKey,
731+// [NSArray arrayWithObjects:NSLocalizedStringFromTable(@"RebuildingErrorOK", @"DatabaseManager", nil),
732+// NSLocalizedStringFromTable(@"RebuildingErrorShowFiles", @"DatabaseManager", nil), nil], NSLocalizedRecoveryOptionsErrorKey,
733+// NULL];
734+// return [NSError errorWithDomain:BSBathyScapheErrorDomain code:DatabaseManagerRebuildLogFileContentsError userInfo:dict];
735+//}
736+//- (BOOL)rebuildFromLogFolder:(NSString *)folderPath boardID:(NSNumber *)boardID error:(NSError **)error
737+//{
738+// NSDirectoryEnumerator *iter = [[NSFileManager defaultManager] enumeratorAtPath:folderPath];
739+// NSString *fileName, *filePath;
740+// NSAutoreleasePool *pool = nil;
741+//
742+// NSDate *date1 = [NSDate dateWithTimeIntervalSinceNow:0.0];
743+//
744+// NSMutableArray *invalidFiles = [NSMutableArray array];
745+//
746+// for(fileName in iter) {
747+// pool = [[NSAutoreleasePool alloc] init];
748+// if ([[fileName pathExtension] isEqualToString:@"thread"]) {
749+// filePath = [folderPath stringByAppendingPathComponent:fileName];
750+// if(![self rebuildFromFilePath:filePath withBoardID:boardID]) {
751+// [invalidFiles addObject:filePath];
752+// }
753+// }
754+// [pool release];
755+// pool = nil;
756+// }
757+//
758+// NSDate *date2 = [NSDate dateWithTimeIntervalSinceNow:0.0];
759+// NSLog(@"Work time is %.3f", [date2 timeIntervalSinceDate:date1]);
760+//
761+// if ((error != NULL) && ([invalidFiles count] > 0)) {
762+// *error = fileContentsErrorObject(invalidFiles);
763+// }
764+//
765+// return YES;
766+//}
767+
768+// 未使用データを削除する
769+- (void)deleteUnusedInfomationsOnBoardID:(NSNumber *)boardID
770+{
771+
772+ NSArray *alivals = [self fetchDataForEntityName:BSCoreDataModelSurviveThreadItemsName
773+ predicateFormat:@"%K = %@",
774+ @"board.boardID", boardID];
775+ if([alivals count] == 0) return;
776+
777+ BSBoardThreadItemsObject *alivalThreads = [alivals lastObject];
778+ id threads = [alivalThreads.items valueForKey:@"thread"];
779+ NSArray *array = [self fetchDataForEntityName:BSCoreDataModelThreadInformationName
780+ predicateFormat:@"%K = %@ AND %K = NULL AND NOT SELF IN %@",
781+ @"board.boardID", boardID,
782+ @"numberOfRead",
783+ threads];
784+
785+// UTILDebugWrite1(@"Unused items count is %d", [array count]);
786+ for(BSThreadInformationObject *thread in array) {
787+ if([thread.numberOfRead integerValue] == 0) {
788+ [self.managedObjectContext deleteObject:thread];
789+ }
790+ }
791+}
792+
793+// データをリセットする
794+//- (void)cleanUpItemsWhichHasBeenRemoved:(NSArray *)filenames
795+//{
796+//#warning CHECK THIS! お気に入り、ラベル等はどうする?
797+// for(NSString *path in filenames) {
798+// // search baordID and threadID.
799+// CMRDocumentFileManager *dfm = [CMRDocumentFileManager defaultManager];
800+// NSString *threadID = [dfm datIdentifierWithLogPath:path];
801+// NSString *boardName = [dfm boardNameWithLogPath:path];
802+//
803+// NSDictionary *hints = [NSDictionary dictionaryWithObject:boardName
804+// forKey:BSBoardInformationObjectHintName];
805+// BSBoardInformationObject *board = [self findBSBoardInformationObjectForHints:hints];
806+// if(!board) continue;
807+//
808+// // get BSThreadInformationObject
809+// BSThreadInformationObject *thread = nil;
810+// thread = [self threadInfoWithIdentifier:threadID
811+// boardInfo:board];
812+//
813+// thread.numberOfRead = nil;
814+// thread.modifiedDate = nil;
815+// }
816+//
817+//
818+// NSNotification *notification = [NSNotification notificationWithName:BSCoreDataWillDeleteThreadItemsNotification
819+// object:self];
820+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:)
821+// withObject:notification
822+// waitUntilDone:YES];
823+// if ([CMRPref sortsImmediately]) {
824+// [self makeThreadsListsUpdateCursor];
825+// } else {
826+// NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
827+// filenames, UserInfoThreadPathsArrayKey,
828+// nil];
829+// NSNotification *notification = [NSNotification notificationWithName:BSCoreDataWantsThreadItemsUpdateNotification
830+// object:self
831+// userInfo:userInfo];
832+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:)
833+// withObject:notification
834+// waitUntilDone:NO];
835+// }
836+//}
837+
838+
839+#pragma mark #### Favorites Accessor ####
840+- (NSArray *)favoritesThreadInformation
841+{
842+ NSArray *array = nil;
843+ @try {
844+ array = [self fetchDataForEntityName:BSCoreDataModelFavoriteName
845+ predicateFormat:nil];
846+ }
847+ @catch(id ex) {
848+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
849+ return [NSArray array];
850+ }
851+ @throw;
852+ }
853+
854+ return array;
855+}
856+- (NSArray *)sortedFavorites
857+{
858+ NSEntityDescription *entry = [NSEntityDescription entityForName:BSCoreDataModelFavoriteName
859+ inManagedObjectContext:self.managedObjectContext];
860+ NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
861+ [fetch setEntity:entry];
862+ NSSortDescriptor *sorter = [[[NSSortDescriptor alloc] initWithKey:@"index"
863+ ascending:YES] autorelease];
864+ [fetch setSortDescriptors:[NSArray arrayWithObject:sorter]];
865+
866+ NSError *error = nil;
867+ NSArray *array = [self.managedObjectContext executeFetchRequest:fetch error:&error];
868+ if(!array) {
869+ if(error) {
870+ NSLog(@"fail fetch reason -> %@", error);
871+ }
872+ }
873+
874+ return array;
875+}
876+- (void)packFavIndex
877+{
878+ NSArray *array = [self sortedFavorites];
879+
880+ NSUInteger newIndex = 1000;
881+ for(BSFavoriteObject *fav in array) {
882+ fav.index = [NSNumber numberWithInteger:newIndex];
883+ newIndex += 1000;
884+ }
885+}
886+
887+- (BOOL)addFavoritesThreadIdentifier:(NSString *)threadID boardName:(NSString *)boardName
888+{
889+ NSDictionary *hints = [NSDictionary dictionaryWithObject:boardName
890+ forKey:BSBoardInformationObjectHintName];
891+ BSThreadInformationObject *thread = [self threadInfoWithIdentifier:threadID
892+ boardHints:hints];
893+ if(!thread) {
894+ // 登録する?
895+ return NO;
896+ }
897+
898+ NSArray *array = nil;
899+ @try {
900+ array = [self fetchDataForEntityName:BSCoreDataModelFavoriteName
901+ predicateFormat:@"%K = %@",
902+ @"thread", thread];
903+ }
904+ @catch(id ex) {
905+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
906+ return NO;
907+ }
908+ @throw;
909+ }
910+
911+ if([array count] != 0) {
912+ // 既にお気に入りです!
913+ return NO;
914+ }
915+
916+ BSFavoriteObject *fav = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelFavoriteName
917+ inManagedObjectContext:self.managedObjectContext];
918+ if(!fav) {
919+ // 登録出来ません!
920+ return NO;
921+ }
922+ fav.thread = thread;
923+ fav.index = [NSNumber numberWithLongLong:LLONG_MAX];
924+
925+ [self packFavIndex];
926+ [self saveAction:nil];
927+
928+ return YES;
929+}
930+- (BOOL)removeFavoritesThreadIdentifier:(NSString *)threadID boardName:(NSString *)boardName
931+{
932+ NSDictionary *hints = [NSDictionary dictionaryWithObject:boardName
933+ forKey:BSBoardInformationObjectHintName];
934+ BSThreadInformationObject *thread = [self threadInfoWithIdentifier:threadID
935+ boardHints:hints];
936+ if(!thread) {
937+ // 登録する?
938+ return NO;
939+ }
940+
941+ NSArray *array = nil;
942+ @try {
943+ array = [self fetchDataForEntityName:BSCoreDataModelFavoriteName
944+ predicateFormat:@"%K = %@",
945+ @"thread", thread];
946+ }
947+ @catch(id ex) {
948+ if([[ex name] isEqualToString:BSCoreDataManagerFailExuteFetchException]) {
949+ return NO;
950+ }
951+ @throw;
952+ }
953+
954+ if([array count] == 0) {
955+ // 既にお気に入りじゃありません
956+ return NO;
957+ }
958+
959+ [self.managedObjectContext deleteObject:[array lastObject]];
960+ [self saveAction:nil];
961+
962+ return YES;
963+}
964+
965+- (void)moveToFirstFavorites:(NSArray *)favorites
966+{
967+ NSArray *array = [self sortedFavorites];
968+ BSFavoriteObject *first = [array objectAtIndex:0];
969+
970+ NSUInteger step = [first.index unsignedIntegerValue] / ([favorites count] + 1);
971+ NSUInteger insertPoint = step;
972+ for(BSFavoriteObject *fav in favorites) {
973+ fav.index = [NSNumber numberWithUnsignedInteger:insertPoint];
974+ insertPoint += step;
975+ }
976+
977+ [self packFavIndex];
978+
979+// UTILNotifyName(BSCoreDataWillUpdateThreadItemNotification);
980+}
981+- (void)moveToLastFavorites:(NSArray *)favorites
982+{
983+ NSArray *array = [self sortedFavorites];
984+ BSFavoriteObject *last = [array lastObject];
985+
986+ NSUInteger lastIndex = [last.index unsignedIntegerValue];
987+ NSUInteger newIndex = lastIndex + 1000;
988+ for(BSFavoriteObject *fav in favorites) {
989+ fav.index = [NSNumber numberWithUnsignedInteger:newIndex];
990+ newIndex += 1000;
991+ }
992+
993+// UTILNotifyName(BSCoreDataWillUpdateThreadItemNotification);
994+}
995+- (void)moveFavorites:(NSArray *)favorites afterFavorite:(id)favorite
996+{
997+ if([favorites count] == 0) return;
998+ if([favorites count] >= 1000) {
999+ NSLog(@"we can not move favorites over thousand.");
1000+ return;
1001+ }
1002+
1003+ BSFavoriteObject *after = favorite;
1004+ NSArray *array = [self sortedFavorites];
1005+
1006+ if(!favorite) {
1007+ return [self moveToFirstFavorites:favorites];
1008+ }
1009+ NSUInteger targetIndex = [array indexOfObject:favorite];
1010+ if(targetIndex == [array count] - 1) {
1011+ return [self moveToLastFavorites:favorites];
1012+ }
1013+
1014+ BSFavoriteObject *before = nil;
1015+ if(targetIndex != 0) {
1016+ before = [array objectAtIndex:targetIndex - 1];
1017+ }
1018+
1019+ NSUInteger diff = [after.index unsignedIntegerValue] - [before.index unsignedIntegerValue];
1020+ if(diff - 1 < [favorites count]) {
1021+ [self packFavIndex];
1022+ return [self moveFavorites:favorites afterFavorite:favorite];
1023+ }
1024+
1025+ NSInteger step = diff / ([favorites count] + 1);
1026+ NSInteger insertPoint = [after.index unsignedIntegerValue] + step;
1027+ for(BSFavoriteObject *fav in favorites) {
1028+ fav.index = [NSNumber numberWithUnsignedInteger:insertPoint];
1029+ insertPoint += step;
1030+ }
1031+
1032+ [self packFavIndex];
1033+ [self saveAction:nil];
1034+
1035+// UTILNotifyName(BSCoreDataWillUpdateThreadItemNotification);
1036+ return;
1037+}
1038+
1039+
1040+#pragma mark #### Reply ####
1041+//- (void)finishWriteMesssage:(NSNotification *)aNotification
1042+//{
1043+// id obj = [aNotification object];
1044+// UTILAssertKindOfClass(obj, [CMRReplyMessenger class]);
1045+//
1046+// NSString *boardName = [obj boardName];
1047+// NSString *threadID = [obj datIdentifier];
1048+// NSDate *writeDate = [obj modifiedDate];
1049+//
1050+// NSDictionary *hints = [NSDictionary dictionaryWithObject:boardName forKey:BSBoardInformationObjectHintName];
1051+// BSThreadInformationObject *threadInfo = [self threadInfoWithIdentifier:threadID
1052+// boardHints:hints];
1053+//
1054+// threadInfo.lastWrittenDate = writeDate;
1055+//}
1056+@end
1057+
1058+
1059+NSUInteger indexOfIdentifier(NSArray *array, NSString *search)
1060+{
1061+ NSUInteger i;
1062+ NSUInteger count;
1063+ id object;
1064+ id identifier;
1065+
1066+ count = [array count];
1067+ if (count == 0) {
1068+ return NSNotFound;
1069+ }
1070+ for (i = 0; i < count; i++ ) {
1071+ object = [array objectAtIndex:i];
1072+ identifier = [object identifier];
1073+ if ([search isEqualTo:identifier]) {
1074+ return i;
1075+ }
1076+ }
1077+
1078+ return NSNotFound;
1079+}
1080+
1081+id itemOfTitle(NSArray *array, NSString *searchTitle)
1082+{
1083+ NSString *title;
1084+ NSString *adjustedSearchTitle = [searchTitle stringByAppendingString:@" "];
1085+
1086+ for(id object in array) {
1087+ // if ([object isKindOfClass:[BSThreadListItem class]]) NSLog(@"Class OK");
1088+ title = [object threadName];
1089+ NSLog(@"title check: '%@'", title);
1090+ if ([adjustedSearchTitle isEqualToString:title]) {
1091+ return object;
1092+ }
1093+ }
1094+
1095+ return nil;
1096+}
--- a/BathyScapheDataConverter/BSDCAppDelegate.h
+++ b/BathyScapheDataConverter/BSDCAppDelegate.h
@@ -12,4 +12,6 @@
1212
1313 @property (assign) IBOutlet NSWindow *window;
1414
15++ (NSURL *)bathyScapheSupportFolderURL;
16++ (NSString *)bathyScapheSupportFolderPath;
1517 @end
--- a/BathyScapheDataConverter/BSDCAppDelegate.m
+++ b/BathyScapheDataConverter/BSDCAppDelegate.m
@@ -22,4 +22,35 @@
2222 // Insert code here to initialize your application
2323 }
2424
25+
26++ (NSURL *)bathyScapheSupportFolderURL
27+{
28+ return [NSURL fileURLWithPath:[self bathyScapheSupportFolderPath]];
29+}
30++ (NSString *)bathyScapheSupportFolderPath
31+{
32+ static NSString *bathyscapheSupportFolderPath = nil;
33+
34+ if(bathyscapheSupportFolderPath) return bathyscapheSupportFolderPath;
35+
36+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
37+ NSUserDomainMask,
38+ YES);
39+ if(!paths || [paths count] == 0) {
40+ NSLog(@"Could not find Application Support folder");
41+ exit(-1);
42+ }
43+
44+ NSString *supportFolder = [paths objectAtIndex:0];
45+ if([supportFolder length] == 0) {
46+ NSLog(@"Could not find Application SUpport folder");
47+ exit(-2);
48+ }
49+
50+ bathyscapheSupportFolderPath = [supportFolder stringByAppendingPathComponent:@"BathyScaphe"];
51+ [bathyscapheSupportFolderPath retain];
52+
53+ return bathyscapheSupportFolderPath;
54+}
55+
2556 @end
--- /dev/null
+++ b/BathyScapheDataConverter/BSDatabaseTranslator.h
@@ -0,0 +1,20 @@
1+//
2+// BSDatabaseTranslator.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import <Cocoa/Cocoa.h>
10+
11+
12+@interface BSDatabaseTranslator : NSObject
13+{
14+ IBOutlet NSWindow *window;
15+ IBOutlet NSProgressIndicator *progress;
16+ IBOutlet NSTextField *information;
17+}
18+- (void)translate;
19+
20+@end
--- /dev/null
+++ b/BathyScapheDataConverter/BSDatabaseTranslator.m
@@ -0,0 +1,338 @@
1+//
2+// BSDatabaseTranslator.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import "BSDatabaseTranslator.h"
10+
11+
12+#import "DatabaseManager.h"
13+#import "BSCoreDataManager.h"
14+
15+#import "BSBoardInformationObject.h"
16+#import "BSThreadInformationObject.h"
17+#import "BSFavoriteObject.h"
18+#import "BSBoardHistoryObject.h"
19+
20+
21+
22+@implementation BSDatabaseTranslator
23+
24+static inline NSDate *dateFromData(id data)
25+{
26+ if(data == [NSNull null]) return nil;
27+ return [NSDate dateWithTimeIntervalSince1970:[data doubleValue]];
28+}
29+static inline NSNumber *numberFromData(id data)
30+{
31+ if(data == [NSNull null]) return nil;
32+ return [NSNumber numberWithDouble:[data doubleValue]];
33+}
34+static inline id nilIfNSNull(id obj)
35+{
36+ if([NSNull null] == obj) return nil;
37+ return obj;
38+}
39+
40++ (NSString *)localizableStringsTableName
41+{
42+ return NSStringFromClass([self class]);
43+}
44+- (void)setInformationText:(NSString *)anInformation
45+{
46+ information.stringValue = anInformation;
47+ [information display];
48+}
49+
50+- (void)loadPanel
51+{
52+
53+ [NSBundle loadNibNamed:@"DatabaseUpdatePanel" owner:self];
54+
55+ [self setInformationText:@""];
56+
57+ NSRect mainScreenFrame = [[NSScreen mainScreen] visibleFrame];
58+ NSPoint center = NSMakePoint(NSMidX(mainScreenFrame), NSMidY(mainScreenFrame));
59+
60+ NSRect windowFrame = [window frame];
61+ NSPoint origin = NSMakePoint(center.x - windowFrame.size.width / 2, center.y - windowFrame.size.height / 2 + 100);
62+ [window setFrameOrigin:origin];
63+
64+ [window makeKeyAndOrderFront:nil];
65+ [progress setUsesThreadedAnimation:YES];
66+ [progress startAnimation:nil];
67+}
68+- (void)dealloc
69+{
70+ [progress stopAnimation:nil];
71+ [window close];
72+
73+ [super dealloc];
74+}
75+
76+- (BOOL)hasCoreData
77+{
78+ BOOL hasCoreData = NO;
79+
80+ BSCoreDataManager *coreDataManager = [BSCoreDataManager defaultManager];
81+ NSManagedObjectContext *context = coreDataManager.managedObjectContext;
82+ NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
83+ NSEntityDescription *entity = [NSEntityDescription entityForName:BSCoreDataModelThreadInformationName
84+ inManagedObjectContext:context];
85+ [fetch setEntity:entity];
86+ [fetch setFetchLimit:1];
87+
88+ NSError *error = nil;
89+ NSArray *result = [context executeFetchRequest:fetch
90+ error:&error];
91+ if(!result) {
92+ if(error) {
93+ NSLog(@"Can not execute request: %@", error);
94+ } else {
95+ NSLog(@"Can not execute request.");
96+ }
97+ NSBeep();
98+ exit(-4);
99+ }
100+ if(0 != [result count]) {
101+ hasCoreData = YES;
102+ }
103+
104+ return hasCoreData;
105+}
106+- (void)translateBoard
107+{
108+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
109+ BSCoreDataManager *coreDataManager = [BSCoreDataManager defaultManager];
110+ NSManagedObjectContext *context = coreDataManager.managedObjectContext;
111+
112+ id <SQLiteCursor> cursor = nil;
113+ NSString *query = nil;
114+
115+ NSUInteger i, rowCount;
116+
117+ // translate board
118+ if([db beginTransaction]) {
119+
120+ query = [NSString stringWithFormat:
121+ @"SELECT * FROM %@",
122+ BoardInfoTableName];
123+
124+ cursor = [db cursorForSQL:query];
125+
126+ progress.maxValue = [cursor rowCount];
127+
128+ for(i = 0, rowCount = [cursor rowCount]; i < rowCount; i++) {
129+ NSAutoreleasePool *pool01 = [[NSAutoreleasePool alloc] init];
130+ id <SQLiteRow> row = [cursor rowAtIndex:i];
131+
132+ progress.doubleValue += 1;
133+
134+ // dummyのデータを除去
135+ if([[row valueForColumn:BoardIDColumn] integerValue] == 0) continue;
136+
137+ BSBoardInformationObject *obj = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelBoardInformationName
138+ inManagedObjectContext:context];
139+ obj.boardID = numberFromData([row valueForColumn:BoardIDColumn]);
140+ obj.boardName = [row valueForColumn:BoardNameColumn];
141+ obj.boardURL = [row valueForColumn:BoardURLColumn];
142+
143+ // translate thread
144+ query = [NSString stringWithFormat:
145+ @"SELECT * FROM %@ WHERE %@ = %@",
146+ ThreadInfoTableName, BoardIDColumn, obj.boardID];
147+ id <SQLiteCursor> cursor02 = [db cursorForSQL:query];
148+ NSUInteger j, threadCount;
149+ for(j = 0, threadCount = [cursor02 rowCount]; j < threadCount; j++) {
150+ NSAutoreleasePool *pool02 = [[NSAutoreleasePool alloc] init];
151+ id <SQLiteRow> thread = [cursor02 rowAtIndex:j];
152+
153+ BSThreadInformationObject *obj02 = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelThreadInformationName
154+ inManagedObjectContext:context];
155+ obj02.board = obj;
156+ obj02.threadID = [thread valueForColumn:ThreadIDColumn];
157+ obj02.threadName = [thread valueForColumn:ThreadNameColumn];
158+ obj02.numberOfAll = numberFromData([thread valueForColumn:NumberOfAllColumn]);
159+ obj02.numberOfRead = numberFromData([thread valueForColumn:NumberOfReadColumn]);
160+ obj02.modifiedDate = dateFromData([thread valueForColumn:ModifiedDateColumn]);
161+ obj02.threadStatus = numberFromData([thread valueForColumn:ThreadStatusColumn]);
162+ obj02.threadLabel = numberFromData([thread valueForColumn:ThreadLabelColumn]);
163+ obj02.lastWrittenDate = dateFromData([thread valueForColumn:LastWrittenDateColumn]);
164+ obj02.isDatOchi = numberFromData([thread valueForColumn:IsDatOchiColumn]);
165+
166+ [pool02 release];
167+ }
168+
169+ [pool01 release];
170+ }
171+ [db commitTransaction];
172+ } else {
173+ NSLog(@"Can not begin transaction for translate board");
174+ NSBeep();
175+ exit(-3);
176+ }
177+}
178+- (void)translateFavorite
179+{
180+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
181+ BSCoreDataManager *coreDataManager = [BSCoreDataManager defaultManager];
182+ NSManagedObjectContext *context = coreDataManager.managedObjectContext;
183+
184+ id <SQLiteCursor> cursor = nil;
185+ NSString *query = nil;
186+
187+ NSUInteger i, rowCount;
188+
189+ if([db beginTransaction]) {
190+ query = [NSString stringWithFormat:
191+ @"SELECT * FROM %@",
192+ FavoritesTableName];
193+
194+ NSPredicate *predicateFormat = [NSPredicate predicateWithFormat:
195+ @"%K = $THREAD_ID AND %K = $BOARD_ID",
196+ @"threadID",
197+ @"board.boardID"];
198+
199+ cursor = [db cursorForSQL:query];
200+ progress.maxValue = [cursor rowCount];
201+
202+ for(i = 0, rowCount = [cursor rowCount]; i < rowCount; i++) {
203+ NSAutoreleasePool *pool01 = [[NSAutoreleasePool alloc] init];
204+ progress.doubleValue += 1;
205+
206+ id <SQLiteRow> row = [cursor rowAtIndex:i];
207+
208+ NSPredicate *predicate = [predicateFormat predicateWithSubstitutionVariables:
209+ [NSDictionary dictionaryWithObjectsAndKeys:
210+ [row valueForColumn:ThreadIDColumn], @"THREAD_ID",
211+ numberFromData([row valueForColumn:BoardIDColumn]), @"BOARD_ID",
212+ nil]];
213+ NSArray *result = nil;
214+ @try {
215+ result = [coreDataManager fetchDataForEntityName:BSCoreDataModelThreadInformationName
216+ predicate:predicate];
217+ }
218+ @catch (id ex) {
219+ @throw;
220+ }
221+ if(0 == [result count]) {
222+ NSLog(@"Can not find target thread object.");
223+ continue;
224+ }
225+
226+ BSFavoriteObject *obj = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelFavoriteName
227+ inManagedObjectContext:context];
228+ obj.thread = [result lastObject];
229+ obj.index = [NSNumber numberWithInteger:(i + 1) * 100];
230+
231+ [pool01 release];
232+ }
233+
234+ [db commitTransaction];
235+ } else {
236+ NSLog(@"Can not begin transaction for translate favorite");
237+ NSBeep();
238+ exit(-3);
239+ }
240+}
241+- (void)translateBoardHistory
242+{
243+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
244+ BSCoreDataManager *coreDataManager = [BSCoreDataManager defaultManager];
245+ NSManagedObjectContext *context = coreDataManager.managedObjectContext;
246+
247+ id <SQLiteCursor> cursor = nil;
248+ NSString *query = nil;
249+
250+ NSUInteger i, rowCount;
251+
252+ if([db beginTransaction]) {
253+
254+ query = [NSString stringWithFormat:
255+ @"SELECT * FROM %@",
256+ BoardInfoHistoryTableName];
257+
258+ NSPredicate *predicateFormat = [NSPredicate predicateWithFormat:
259+ @"%K = $BOARD_ID",
260+ @"boardID"];
261+
262+ cursor = [db cursorForSQL:query];
263+ progress.maxValue = [cursor rowCount];
264+
265+ for(i = 0, rowCount = [cursor rowCount]; i < rowCount; i++) {
266+ NSAutoreleasePool *pool01 = [[NSAutoreleasePool alloc] init];
267+
268+ progress.doubleValue += 1;
269+
270+ id <SQLiteRow> row = [cursor rowAtIndex:i];
271+
272+ NSPredicate *predicate = [predicateFormat predicateWithSubstitutionVariables:
273+ [NSDictionary dictionaryWithObjectsAndKeys:
274+ numberFromData([row valueForColumn:BoardIDColumn]), @"BOARD_ID",
275+ nil]];
276+ NSArray *result = nil;
277+ @try {
278+ result = [coreDataManager fetchDataForEntityName:BSCoreDataModelBoardInformationName
279+ predicate:predicate];
280+ }
281+ @catch (id ex) {
282+ @throw;
283+ }
284+ if(0 == [result count]) {
285+ NSLog(@"Can not find target board object.");
286+ continue;
287+ }
288+
289+ BSBoardHistoryObject *obj = [NSEntityDescription insertNewObjectForEntityForName:BSCoreDataModelBoardHistoryName
290+ inManagedObjectContext:context];
291+ obj.board = [result lastObject];
292+ obj.boardURL = nilIfNSNull([row valueForColumn:BoardURLColumn]);
293+ obj.boardName = nilIfNSNull([row valueForColumn:BoardNameColumn]);
294+
295+ [pool01 release];
296+ }
297+ [db commitTransaction];
298+ } else {
299+ NSLog(@"Can not begin transaction for translate board");
300+ NSBeep();
301+ exit(-3);
302+ }
303+}
304+- (void)translate
305+{
306+ NSDate *date01 = [NSDate dateWithTimeIntervalSinceNow:0.0];
307+
308+ if([self hasCoreData]) return;
309+
310+ [self loadPanel];
311+
312+// [self setInformationText:[self localizedString:@"translate board."]];
313+ progress.doubleValue = 0;
314+ [progress setIndeterminate:NO];
315+ [progress display];
316+ [self translateBoard];
317+
318+// [self setInformationText:[self localizedString:@"translate favorites."]];
319+ progress.doubleValue = 0;
320+ [progress display];
321+ [self translateFavorite];
322+
323+// [self setInformationText:[self localizedString:@"translate board history."]];
324+ progress.doubleValue = 0;
325+ [progress display];
326+ [self translateBoardHistory];
327+
328+// [self setInformationText:[self localizedString:@"finalize database"]];
329+ [progress setIndeterminate:YES];
330+ [progress startAnimation:nil];
331+
332+ [[BSCoreDataManager defaultManager] saveAction:nil];
333+
334+ NSDate *date02 = [NSDate dateWithTimeIntervalSinceNow:0.0];
335+
336+ NSLog(@"Translate time -> %.3f", [date02 timeIntervalSinceDate:date01]);
337+}
338+@end
--- /dev/null
+++ b/BathyScapheDataConverter/BSFavoriteObject.h
@@ -0,0 +1,21 @@
1+//
2+// BSFavoriteObject.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import <CoreData/CoreData.h>
10+#import "BSThreadListItemObject.h"
11+
12+@class BSThreadInformationObject;
13+
14+@interface BSFavoriteObject : BSThreadListItemObject
15+{
16+}
17+
18+@end
19+
20+
21+
--- /dev/null
+++ b/BathyScapheDataConverter/BSFavoriteObject.m
@@ -0,0 +1,16 @@
1+//
2+// BSFavoriteObject.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import "BSFavoriteObject.h"
10+
11+#import "BSThreadInformationObject.h"
12+#import "BSThreadListItemObject.h"
13+
14+@implementation BSFavoriteObject
15+
16+@end
--- /dev/null
+++ b/BathyScapheDataConverter/BSThreadInformationObject.h
@@ -0,0 +1,49 @@
1+//
2+// BSThreadInformationObject.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import <CoreData/CoreData.h>
10+
11+@class BSBoardInformationObject;
12+@class BSThreadListItemObject;
13+
14+@interface BSThreadInformationObject : NSManagedObject
15+{
16+}
17+
18+@property (nonatomic, retain) NSString * threadID;
19+@property (nonatomic, retain) NSDate * creationDate;
20+@property (nonatomic, retain) NSString * threadName;
21+@property (nonatomic, retain) NSNumber * numberOfAll;
22+@property (nonatomic, retain) NSNumber * numberOfRead;
23+@property (nonatomic, retain) NSNumber * numberOfDifference;
24+@property (nonatomic, retain) NSDate * modifiedDate;
25+@property (nonatomic, retain) NSDate * lastWrittenDate;
26+@property (nonatomic, retain) NSNumber * threadLabel;
27+@property (nonatomic, retain) NSNumber * threadStatus;
28+@property (nonatomic, retain) NSNumber * isDatOchi;
29+@property (nonatomic, retain) NSNumber * isNew;
30+@property (nonatomic, retain) NSNumber * isHeadModified;
31+@property (nonatomic, retain) NSNumber * threadAboneType;
32+@property (nonatomic, retain) NSSet* threadListItems;
33+@property (nonatomic, retain) BSBoardInformationObject * board;
34+
35+
36+//@property (nonatomic, readonly) NSDictionary *attribute;
37+
38+//- (void)updateStatus;
39+@end
40+
41+
42+@interface BSThreadInformationObject (CoreDataGeneratedAccessors)
43+- (void)addThreadListItemsObject:(BSThreadListItemObject *)value;
44+- (void)removeThreadListItemsObject:(BSThreadListItemObject *)value;
45+- (void)addThreadListItems:(NSSet *)value;
46+- (void)removeThreadListItems:(NSSet *)value;
47+
48+@end
49+
--- /dev/null
+++ b/BathyScapheDataConverter/BSThreadInformationObject.m
@@ -0,0 +1,249 @@
1+//
2+// BSThreadInformationObject.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/12.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import "BSThreadInformationObject.h"
10+
11+#import "BSBoardInformationObject.h"
12+#import "BSThreadListItemObject.h"
13+
14+//#import "CMRDocumentFileManager.h"
15+
16+@implementation BSThreadInformationObject
17+
18+@dynamic threadLabel;
19+@dynamic threadID;
20+@dynamic numberOfRead;
21+@dynamic numberOfDifference;
22+@dynamic lastWrittenDate;
23+@dynamic isDatOchi;
24+@dynamic threadName;
25+@dynamic numberOfAll;
26+@dynamic modifiedDate;
27+@dynamic isNew;
28+@dynamic threadStatus;
29+@dynamic threadAboneType;
30+@dynamic isHeadModified;
31+@dynamic creationDate;
32+@dynamic threadListItems;
33+@dynamic board;
34+
35+
36++ (NSSet *)keyPathsForValuesAffectingNumberOfDifference
37+{
38+ return [NSSet setWithObjects:@"numberOfRead", @"numberOfAll", nil];
39+}
40++ (NSSet *)keyPathsForValuesAffectingCreationDate
41+{
42+ return [NSSet setWithObjects:@"threadID", nil];
43+}
44++ (NSSet *)keyPathsForValuesAffectingIsDatOchi
45+{
46+ return [NSSet setWithObjects:@"threadStatus", nil];
47+}
48++ (NSSet *)keyPathsForValuesAffectingIsNew
49+{
50+ return [NSSet setWithObjects:@"threadStatus", nil];
51+}
52+
53+- (NSString *)identifier
54+{
55+ return self.threadID;
56+}
57+
58+- (NSNumber *)threadstatus
59+{
60+ return self.threadStatus;
61+}
62+- (NSNumber *)threadnumber
63+{
64+ return nil;
65+}
66+- (NSString *)threadname
67+{
68+ return self.threadName;
69+}
70+- (NSDate *)lastwrittendate
71+{
72+ return self.lastWrittenDate;
73+}
74+- (NSDate *)modifieddate
75+{
76+ return self.modifiedDate;
77+}
78+- (NSNumber *)numberofall
79+{
80+ return self.numberOfAll;
81+}
82+- (NSNumber *)numberofread
83+{
84+ return self.numberOfRead;
85+}
86+- (NSNumber *)numberofdifference
87+{
88+ return self.numberOfDifference;
89+}
90+//- (NSNumber *)ikioi
91+//{
92+// return [self valueForKey:BSThreadEnergyKey];
93+//}
94+- (NSString *)boardname
95+{
96+ return self.board.boardName;
97+}
98+- (NSString *)threadid
99+{
100+ return self.threadID;
101+}
102+- (NSNumber *)threadlabel
103+{
104+ return self.threadLabel;
105+}
106+
107+- (NSString *)boardName
108+{
109+ return self.board.boardName;
110+}
111+
112+
113+- (NSNumber *)numberOfDifference
114+{
115+ NSNumber *all = self.numberOfAll;
116+ NSNumber *read = self.numberOfRead;
117+ if(!all || !read) return nil;
118+ if(all == (id)[NSNull null] || read == (id)[NSNull null]) return (id)[NSNull null];
119+
120+ return [NSNumber numberWithInteger:[self.numberOfAll integerValue] - [self.numberOfRead integerValue]];
121+}
122+- (void)setThreadID:(NSString *)value
123+{
124+ [self willChangeValueForKey:@"threadID"];
125+ [self setPrimitiveValue:value forKey:@"threadID"];
126+ [self didChangeValueForKey:@"threadID"];
127+
128+ NSTimeInterval threadIDNumber = [self.threadID doubleValue];
129+ NSDate *aDate = [NSDate dateWithTimeIntervalSince1970:threadIDNumber];
130+
131+ self.creationDate = aDate;
132+}
133+- (void)setNumberOfAll:(NSNumber *)value
134+{
135+ [self willChangeValueForKey:@"numberOfAll"];
136+ [self setPrimitiveValue:value forKey:@"numberOfAll"];
137+ [self didChangeValueForKey:@"numberOfAll"];
138+
139+// [self updateStatus];
140+}
141+- (void)setNumberOfRead:(NSNumber *)value
142+{
143+ [self willChangeValueForKey:@"numberOfRead"];
144+ [self setPrimitiveValue:value forKey:@"numberOfRead"];
145+ [self didChangeValueForKey:@"numberOfRead"];
146+
147+// [self updateStatus];
148+}
149+
150+- (NSUInteger)label
151+{
152+ return [self.threadLabel unsignedIntegerValue];
153+}
154+- (BOOL)datOchi
155+{
156+ return [self.isDatOchi boolValue];
157+}
158+- (NSUInteger)status
159+{
160+ return [self.threadStatus unsignedIntegerValue];
161+}
162+
163+- (NSNumber *)threadNumber
164+{
165+ return nil;
166+}
167+//- (id)valueForUndefinedKey:(NSString *)key
168+//{
169+// if([key isEqualToString:CMRThreadTitleKey]) {
170+// return self.threadName;
171+// }
172+// if([key isEqualToString:CMRThreadNumberOfMessagesKey]) {
173+// return self.numberOfAll;
174+// }
175+// if([key isEqualToString:CMRThreadLastLoadedNumberKey]) {
176+// return self.numberOfRead;
177+// }
178+// if([key isEqualToString:CMRThreadNumberOfUpdatedKey]) {
179+// return self.numberOfDifference;
180+// }
181+// if([key isEqualToString:ThreadPlistIdentifierKey]) {
182+// return self.creationDate;
183+// }
184+// if([key isEqualToString:@"LastWrittenDate"]) {
185+// return self.lastWrittenDate;
186+// }
187+//
188+// if([key isEqualToString:BSThreadEnergyKey]) {
189+// NSInteger res = [self.numberOfAll integerValue];
190+// CGFloat createDateTime = [self.creationDate timeIntervalSince1970];
191+//
192+// CGFloat currentDateTime = [[NSDate dateWithTimeIntervalSinceNow:0.0] timeIntervalSince1970];
193+//
194+// CGFloat deltaTime = currentDateTime - createDateTime;
195+// if(deltaTime == 0) return nil;
196+//
197+// CGFloat ikioi = (res * 60 * 60 * 24) / deltaTime;
198+//
199+// return [NSNumber numberWithDouble:ikioi];
200+// }
201+//
202+// if([key isEqualToString:ThreadPlistBoardNameKey]) {
203+// return self.board.boardName;
204+// }
205+//
206+//
207+// return [super valueForUndefinedKey:key];
208+//}
209+
210+
211+//- (NSString *)threadFilePath
212+//{
213+// return [[CMRDocumentFileManager defaultManager] threadPathWithBoardName:self.board.boardName
214+// datIdentifier:self.threadID];
215+//}
216+//- (NSDictionary *)attribute
217+//{
218+// NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:7];
219+//
220+// [result setValue:self.threadName forKey:CMRThreadTitleKey];
221+// [result setValue:[self.numberOfAll stringValue] forKey:CMRThreadNumberOfMessagesKey];
222+// [result setValue:self.threadID forKey:ThreadPlistIdentifierKey];
223+// [result setValue:self.board.boardName forKey:ThreadPlistBoardNameKey];
224+// [result setValue:self.threadStatus forKey:CMRThreadStatusKey];
225+// [result setValue:self.modifiedDate forKey:CMRThreadModifiedDateKey];
226+// [result setValue:[self threadFilePath] forKey:CMRThreadLogFilepathKey];
227+//
228+// return result;
229+//}
230+
231+//- (void)updateStatus
232+//{
233+//// NSLog(@"%s: Why did not update automatic?", __PRETTY_FUNCTION__);
234+//
235+// NSNumber *diff = self.numberOfDifference;
236+// if(!diff || diff == (id)[NSNull null]) {
237+// self.threadStatus = [NSNumber numberWithInteger:ThreadNoCacheStatus];
238+// return;
239+// }
240+//
241+// NSInteger diffValue = [diff integerValue];
242+// if(0 == diffValue) {
243+// self.threadStatus = [NSNumber numberWithInteger:ThreadLogCachedStatus];
244+// } else {
245+// self.threadStatus = [NSNumber numberWithInteger:ThreadUpdatedStatus];
246+// }
247+//}
248+
249+@end
--- /dev/null
+++ b/BathyScapheDataConverter/BSThreadItemObject.h
@@ -0,0 +1,23 @@
1+//
2+// BSThreadItemObject.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/17.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import <CoreData/CoreData.h>
10+#import "BSThreadListItemObject.h"
11+
12+@class BSBoardThreadItemsObject;
13+
14+@interface BSThreadItemObject : BSThreadListItemObject
15+{
16+}
17+
18+@property (nonatomic, retain) BSBoardThreadItemsObject * owner;
19+
20+@end
21+
22+
23+
--- /dev/null
+++ b/BathyScapheDataConverter/BSThreadItemObject.m
@@ -0,0 +1,17 @@
1+//
2+// BSThreadItemObject.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/17.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import "BSThreadItemObject.h"
10+
11+#import "BSBoardThreadItemsObject.h"
12+
13+@implementation BSThreadItemObject
14+
15+@dynamic owner;
16+
17+@end
--- /dev/null
+++ b/BathyScapheDataConverter/BSThreadListItemObject.h
@@ -0,0 +1,23 @@
1+//
2+// BSThreadListItemObject.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/17.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import <CoreData/CoreData.h>
10+
11+@class BSThreadInformationObject;
12+
13+@interface BSThreadListItemObject : NSManagedObject
14+{
15+}
16+
17+@property (nonatomic, retain) NSNumber * index;
18+@property (nonatomic, retain) BSThreadInformationObject * thread;
19+
20+@end
21+
22+
23+
--- /dev/null
+++ b/BathyScapheDataConverter/BSThreadListItemObject.m
@@ -0,0 +1,103 @@
1+//
2+// BSThreadListItemObject.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 10/10/17.
6+// Copyright 2010 masakih. All rights reserved.
7+//
8+
9+#import "BSThreadListItemObject.h"
10+
11+#import "BSThreadInformationObject.h"
12+
13+#include <objc/runtime.h>
14+
15+@implementation BSThreadListItemObject
16+
17+@dynamic index;
18+@dynamic thread;
19+
20+static NSMethodSignature *sSig = nil;
21+
22+
23+- (NSNumber *)threadnumber
24+{
25+ return self.index;
26+}
27+- (NSNumber *)threadNumber
28+{
29+ return self.index;
30+}
31+
32+
33+
34+- (NSMethodSignature *)sig
35+{
36+ if(sSig) return sSig;
37+
38+ Method method = class_getInstanceMethod([self class], @selector(returnNil));
39+ const char *encode = method_getTypeEncoding(method);
40+ sSig = [[NSMethodSignature signatureWithObjCTypes:encode] retain];
41+
42+ return sSig;
43+}
44+- (id)returnNil
45+{
46+ return nil;
47+}
48+- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
49+{
50+ if([self.thread respondsToSelector:aSelector]) {
51+ return [self.thread methodSignatureForSelector:aSelector];
52+ }
53+ if(!self.thread) {
54+// NSLog(@"%s thread is nil", __PRETTY_FUNCTION__);
55+ NSString *selName = NSStringFromSelector(aSelector);
56+ if(![selName hasSuffix:@":"]) {
57+ return [self sig];
58+ }
59+ }
60+
61+ return [super methodSignatureForSelector:aSelector];
62+}
63+- (void)forwardInvocation:(NSInvocation *)anInvocation
64+{
65+ SEL selector = [anInvocation selector];
66+ if([self.thread respondsToSelector:selector]) {
67+ [anInvocation invokeWithTarget:self.thread];
68+ return;
69+ }
70+
71+ NSMethodSignature *sig = [anInvocation methodSignature];
72+ if(sig == [self sig]) {
73+ [anInvocation setSelector:@selector(returnNil)];
74+ [anInvocation invokeWithTarget:self];
75+ return;
76+ }
77+}
78+
79+- (id)valueForUndefinedKey:(NSString *)key
80+{
81+ id result = nil;
82+
83+ @try {
84+ result = [self.thread valueForKey:key];
85+ }
86+ @catch (id ex) {
87+ NSLog(@"%@", ex);
88+ @throw;
89+ }
90+
91+ return result;
92+}
93+- (void)setValue:(id)value forUndefinedKey:(NSString *)key
94+{
95+ @try {
96+ [self.thread setValue:value forKey:key];
97+ }
98+ @catch (id ex) {
99+ NSLog(@"%@", ex);
100+ @throw;
101+ }
102+}
103+@end
--- /dev/null
+++ b/BathyScapheDataConverter/BathyScapheCore.xcdatamodel/.svn/entries
@@ -0,0 +1,96 @@
1+10
2+
3+dir
4+1365
5+svn+ssh://masakih@svn.sourceforge.jp/svnroot/bathyscaphe/bathyscaphe/branches/v201-BASED-BRANCH/application/source/CoredataModels/BathyScapheCore.xcdatamodel
6+svn+ssh://masakih@svn.sourceforge.jp/svnroot/bathyscaphe
7+
8+
9+
10+2010-12-22T12:25:36.272234Z
11+1297
12+masakih
13+
14+
15+
16+
17+
18+
19+
20+
21+
22+
23+
24+
25+
26+
27+b61fe662-1e22-0410-9ebe-d5d0f6be7d5c
28+
29+elements
30+file
31+
32+
33+
34+
35+2011-06-15T15:43:12.000000Z
36+32c6cef238f15beb4cca02f7093173d0
37+2010-12-22T12:25:36.272234Z
38+1297
39+masakih
40+has-props
41+
42+
43+
44+
45+
46+
47+
48+
49+
50+
51+
52+
53+
54+
55+
56+
57+
58+
59+
60+
61+66047
62+
63+layout
64+file
65+
66+
67+
68+
69+2011-06-15T15:43:12.000000Z
70+bd77e6c535d1aec5d31c4146d604feea
71+2010-12-22T12:25:36.272234Z
72+1297
73+masakih
74+has-props
75+
76+
77+
78+
79+
80+
81+
82+
83+
84+
85+
86+
87+
88+
89+
90+
91+
92+
93+
94+
95+21422
96+
--- /dev/null
+++ b/BathyScapheDataConverter/BathyScapheCore.xcdatamodel/.svn/prop-base/elements.svn-base
@@ -0,0 +1,5 @@
1+K 13
2+svn:mime-type
3+V 24
4+application/octet-stream
5+END
--- /dev/null
+++ b/BathyScapheDataConverter/BathyScapheCore.xcdatamodel/.svn/prop-base/layout.svn-base
@@ -0,0 +1,5 @@
1+K 13
2+svn:mime-type
3+V 24
4+application/octet-stream
5+END
Binary files /dev/null and b/BathyScapheDataConverter/BathyScapheCore.xcdatamodel/.svn/text-base/elements.svn-base differ
Binary files /dev/null and b/BathyScapheDataConverter/BathyScapheCore.xcdatamodel/.svn/text-base/layout.svn-base differ
Binary files /dev/null and b/BathyScapheDataConverter/BathyScapheCore.xcdatamodel/elements differ
Binary files /dev/null and b/BathyScapheDataConverter/BathyScapheCore.xcdatamodel/layout differ
--- /dev/null
+++ b/BathyScapheDataConverter/EntityDescription.txt
@@ -0,0 +1,34 @@
1+
2+各エンティティの説明 ()内はクラス名
3+
4+ThreadInformation (ThreadInformationObject) スレッドの情報
5+ creationDateはthreadID設定時に自動計算される
6+ threadStatusはnumberOfAll, numberOfReadが更新された時自動的に更新される
7+ numberOfDifferernceはthreadStatusが更新された時に同時に更新される
8+ isNew, isHeadModifiedはthreadStatusより計算される(今の所未使用のため未実装)
9+
10+BoardInformation (BSBoardInformationObject) 掲示板の情報
11+ 特記事項なし
12+
13+BoardHistory (BSBoardHistoryObject) 掲示板の変更履歴(板名変更、URL変更)
14+ 特記事項なし
15+
16+ThreadListItem (BSThreadListItemObject) スレッド一覧に表示するために用いられる代理オブジェクト。(抽象エンティティ)
17+ thread 実際に表示される情報
18+ index スレッド一覧の番号に当たる情報
19+
20+Fovorite (BSFavoriteObject) お気に入りを保持する(ThreadListItemを継承)
21+ 特記事項なし
22+
23+ThreadItem (BSThreadItemObject) 通常の掲示板のスレッドを保持する。スレッドの位置(番号)はこのエンティティにのみ保持される。(ThreadListItemを継承)
24+ owner SurviveThreadItems
25+
26+SurviveThreadItems (BSBoardThreadItemsObject) Subject.TXTより生成される。掲示板上のDAT落ちでない(生きている)スレッドを持つ。
27+ baord 対応する掲示板
28+ items ThreadItemの集合。削除ルールがカスケードに指定されているため、このエンティティを削除すれば対応するThreadItemがすべて削除される。
29+
30+
31+注記:
32+ スマート掲示板におけるスレッド一覧の内容は直接ThreadInformationを参照している。
33+ ただし、ThreadListItem(のクラス)がThreadInformation(のクラス)と同じように振る舞えるため同じように扱って問題ない
34+ むしろ、表面上はすべての掲示板アイテムがThreadInformationの集合を返すとして扱えば良い
--- /dev/null
+++ b/DatabaseManager-DatabaseAccess.m
@@ -0,0 +1,1360 @@
1+//
2+// DatabaseManager-DatabaseAccess.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 05/07/17.
6+// Copyright 2005-2008 BathyScaphe Project. All rights reserved.
7+// encoding="UTF-8"
8+//
9+
10+#import "DatabaseManager.h"
11+
12+#import "SQLiteDB.h"
13+//#import "CMRThreadAttributes.h"
14+//#import "CMRDocumentFileManager.h"
15+
16+static NSMutableDictionary *boardIDNameCache = nil;
17+static NSLock *boardIDNumberCacheLock = nil;
18+NSString *const DatabaseManagerInvalidFilePathsArrayKey = @"FilePathsArray";
19+
20+@implementation DatabaseManager (DatabaseAccess)
21+- (NSUInteger)boardIDForURLStringExceptingHistory:(NSString *)urlString
22+{
23+ NSMutableString *query;
24+ NSString *prepareURL;
25+ SQLiteDB *db;
26+ id <SQLiteCursor> cursor;
27+ id value;
28+
29+ db = [self databaseForCurrentThread];
30+ if (!db) {
31+ return NSNotFound;
32+ }
33+
34+ prepareURL = [SQLiteDB prepareStringForQuery:urlString];
35+ query = [NSMutableString stringWithFormat:@"SELECT %@ FROM %@", BoardIDColumn, BoardInfoTableName];
36+ [query appendFormat:@"\n\tWHERE %@ = '%@'", BoardURLColumn, prepareURL];
37+ cursor = [db performQuery:query];
38+
39+ if (!cursor || [cursor rowCount] == 0) {
40+ return NSNotFound;
41+ }
42+
43+ value = [cursor valueForColumn:BoardIDColumn atRow:0];
44+ if (!value) {
45+ return NSNotFound;
46+ }
47+ if (![value respondsToSelector:@selector(integerValue)]) {
48+ NSLog (@"%@ is broken.", BoardInfoTableName);
49+ return NSNotFound;
50+ }
51+
52+ return (NSUInteger)[value integerValue];
53+}
54+
55+// return NSNotFound, if not registered.
56+- (NSUInteger)boardIDForURLString:(NSString *)urlString
57+{
58+ NSMutableString *query;
59+ NSString *prepareURL;
60+ SQLiteDB *db;
61+ id <SQLiteCursor> cursor;
62+ id value;
63+ BOOL found = NO;
64+
65+ db = [self databaseForCurrentThread];
66+ if (!db) {
67+ return NSNotFound;
68+ }
69+
70+ prepareURL = [SQLiteDB prepareStringForQuery:urlString];
71+ query = [NSMutableString stringWithFormat:@"SELECT %@ FROM %@", BoardIDColumn, BoardInfoTableName];
72+ [query appendFormat:@"\n\tWHERE %@ = '%@'", BoardURLColumn, prepareURL];
73+ cursor = [db performQuery:query];
74+
75+ if (cursor && [cursor rowCount]) {
76+ found = YES;
77+ }
78+
79+ if (!found) {
80+ query = [NSMutableString stringWithFormat:@"SELECT %@ FROM %@", BoardIDColumn, BoardInfoHistoryTableName];
81+ [query appendFormat:@"\n\tWHERE %@ = '%@'", BoardURLColumn, prepareURL];
82+ cursor = [db performQuery:query];
83+ if (cursor && [cursor rowCount]) {
84+ found = YES;
85+ }
86+ }
87+
88+ if (!found) {
89+ NSURL *tmp = [NSURL URLWithString:urlString];
90+ if ([[tmp host] hasSuffix:@".2ch.net"]) {
91+ query = [NSMutableString stringWithFormat:@"SELECT %@ FROM %@", BoardIDColumn, BoardInfoTableName];
92+ [query appendFormat:@"\n\tWHERE %@ LIKE '%%%@/'", BoardURLColumn, [tmp path]];
93+ cursor = [db performQuery:query];
94+ if (cursor && [cursor rowCount]) {
95+ found = YES;
96+ }
97+ }
98+ }
99+
100+ if (!found) {
101+ return NSNotFound;
102+ }
103+
104+ value = [cursor valueForColumn:BoardIDColumn atRow:0];
105+ if (!value) {
106+ return NSNotFound;
107+ }
108+ if (![value respondsToSelector:@selector(integerValue)]) {
109+ NSLog (@"%@ or %@ is broken.", BoardInfoTableName, BoardInfoHistoryTableName );
110+ return NSNotFound;
111+ }
112+
113+ return (NSUInteger)[value integerValue];
114+}
115+
116+- (NSString *)urlStringForBoardID:(NSUInteger)boardID
117+{
118+ NSMutableString *query;
119+ NSURL *url;
120+ SQLiteDB *db;
121+ id<SQLiteCursor> cursor;
122+ id value;
123+
124+ if (boardID == 0) {
125+ return nil;
126+ }
127+
128+ db = [self databaseForCurrentThread];
129+ if (!db) {
130+ return nil;
131+ }
132+
133+// query = [NSMutableString stringWithFormat:@"SELECT %@ FROM %@", BoardURLColumn, BoardInfoTableName];
134+// [query appendFormat:@"\n\tWHERE %@ = %lu", BoardIDColumn, (unsigned long)boardID];
135+ query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = %lu", BoardURLColumn, BoardInfoTableName, BoardIDColumn, (unsigned long)boardID];
136+ cursor = [db performQuery:query];
137+
138+ if (!cursor || ![cursor rowCount]) {
139+ return nil;
140+ }
141+
142+ value = [cursor valueForColumn:BoardURLColumn atRow:0];
143+ if (!value) {
144+ return nil;
145+ }
146+
147+ url = [NSURL URLWithString:value];
148+ if (!url) {
149+ NSLog(@"[%@ -%@]: %@ is broken.", NSStringFromClass([self class]), NSStringFromSelector(_cmd), BoardInfoTableName);
150+ return nil;
151+ }
152+
153+ return value;
154+}
155+// return nil, if not registered.
156+- (NSArray *) boardIDsForName : (NSString *) name
157+{
158+ NSMutableString *query;
159+ NSString *prepareName;
160+ SQLiteDB *db;
161+ id <SQLiteCursor> cursor;
162+ id value;
163+ BOOL found = NO;
164+
165+ db = [self databaseForCurrentThread];
166+ if (!db) {
167+ return nil;
168+ }
169+
170+ if(!boardIDNameCache) {
171+ boardIDNameCache = [[NSMutableDictionary alloc] init];
172+ boardIDNumberCacheLock = [[NSLock alloc] init];
173+ if(!boardIDNumberCacheLock) {
174+ [boardIDNameCache release];
175+ boardIDNameCache = nil;
176+ }
177+ }
178+
179+ if(boardIDNameCache) {
180+ id idArray;
181+
182+ idArray = [boardIDNameCache objectForKey:name];
183+ if(idArray) {
184+ return idArray;
185+ }
186+ }
187+
188+ prepareName = [SQLiteDB prepareStringForQuery : name];
189+ query = [NSMutableString stringWithFormat: @"SELECT %@ FROM %@", BoardIDColumn, BoardInfoTableName];
190+ [query appendFormat: @"\n\tWHERE %@ LIKE '%@'", BoardNameColumn, prepareName];
191+ cursor = [db performQuery : query];
192+
193+ if (cursor && [cursor rowCount]) {
194+ found = YES;
195+ }
196+
197+ if (!found) {
198+ query = [NSMutableString stringWithFormat: @"SELECT %@ FROM %@", BoardIDColumn, BoardInfoHistoryTableName];
199+ [query appendFormat: @"\n\tWHERE %@ LIKE '%@'", BoardNameColumn, prepareName];
200+ cursor = [db performQuery : query];
201+ if (cursor && [cursor rowCount]) {
202+ found = YES;
203+ }
204+ }
205+
206+ if (!found) {
207+ return nil;
208+ }
209+
210+ value = [cursor valuesForColumn : BoardIDColumn];
211+ if([value count] != 0 ) {
212+ [boardIDNumberCacheLock lock];
213+ [boardIDNameCache setObject:value forKey:name];
214+ [boardIDNumberCacheLock unlock];
215+ }
216+ return [value count] > 0 ? value : nil;
217+}
218+- (NSString *) nameForBoardID : (NSUInteger) boardID
219+{
220+ NSMutableString *query;
221+ SQLiteDB *db;
222+ id <SQLiteCursor> cursor;
223+ id value;
224+
225+ if (boardID == 0) return nil;
226+
227+ db = [self databaseForCurrentThread];
228+ if (!db) {
229+ return nil;
230+ }
231+
232+ query = [NSMutableString stringWithFormat: @"SELECT %@ FROM %@", BoardNameColumn, BoardInfoTableName];
233+ [query appendFormat: @"\n\tWHERE %@ = %lu", BoardIDColumn, (unsigned long)boardID];
234+ cursor = [db performQuery : query];
235+
236+ if (!cursor || ![cursor rowCount]) {
237+ return nil;
238+ }
239+
240+ value = [cursor valueForColumn : BoardNameColumn atRow : 0];
241+
242+ return value;
243+}
244+
245+// raise DatabaseManagerCantFountKeyExseption.
246+- (id)valueForKey:(NSString *)key boardID:(NSUInteger)boardID threadID:(NSString *)threadID
247+{
248+ NSString *query;
249+ SQLiteDB *db;
250+ id <SQLiteCursor> cursor;
251+ id value;
252+
253+ if (boardID == 0) return nil;
254+
255+ db = [self databaseForCurrentThread];
256+ if (!db) {
257+ return NO;
258+ }
259+
260+ query = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ = %lu AND %@ = %@",
261+ BoardThreadInfoViewName,
262+ BoardIDColumn, (unsigned long)boardID,
263+ ThreadIDColumn, threadID];
264+ cursor = [db performQuery : query];
265+ if (!cursor || ![cursor rowCount]) {
266+ return nil;
267+ }
268+
269+ value = [cursor valueForColumn : key atRow : 0];
270+
271+ return value;
272+}
273+
274+//- (void)setValue:(id)value forKey:(NSString *)key boardID:(NSUInteger)boardID threadID:(NSString *)threadID;
275+
276+
277+- (BOOL) registerBoardName : (NSString *) name URLString : (NSString *) urlString
278+{
279+ BOOL result = NO;
280+
281+ NSMutableString *query;
282+ NSString *prepareName;
283+ NSString *prepareURL;
284+ SQLiteDB *db;
285+
286+ // checking URL.
287+ {
288+ if(!urlString) {
289+ NSLog(@"urlString is nil.");
290+ return NO;
291+ }
292+ id url = [NSURL URLWithString : urlString];
293+ if (!url) {
294+ NSLog(@"urlString (%@) is NOT url.", urlString);
295+ return NO;
296+ }
297+ }
298+
299+ db = [self databaseForCurrentThread];
300+ if (!db) {
301+ return NO;
302+ }
303+
304+ prepareName = [SQLiteDB prepareStringForQuery : name];
305+ prepareURL = [SQLiteDB prepareStringForQuery : urlString];
306+ query = [NSMutableString stringWithFormat: @"INSERT INTO %@", BoardInfoTableName];
307+ [query appendFormat: @" ( %@, %@, %@ ) ", BoardIDColumn, BoardNameColumn, BoardURLColumn];
308+ [query appendFormat: @"VALUES ( (SELECT max(%@) FROM %@) + 1, '%@', '%@' ) ",
309+ BoardIDColumn, BoardInfoTableName, prepareName, prepareURL];
310+ [db performQuery : query];
311+
312+ result = ([db lastErrorID] == 0);
313+ if(!result) {
314+ NSLog(@"Fail registerBoard.\nReson: %@", [db lastError]);
315+ }
316+ return result;
317+}
318+
319+/*- (BOOL)deleteBoardOfBoardID:(NSUInteger)boardID
320+{
321+ SQLiteDB *db;
322+ NSString *query;
323+
324+ [self recache];
325+
326+ db = [self databaseForCurrentThread];
327+ if (!db) {
328+ return NO;
329+ }
330+
331+ query = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = %u", BoardInfoTableName, BoardIDColumn, boardID];
332+ [db performQuery:query];
333+
334+ BOOL result = ([db lastErrorID] == 0);
335+ if(!result) {
336+ NSLog(@"Fail deleteBoard.\nReson: %@", [db lastError]);
337+ }
338+ return result;
339+}
340+}*/
341+
342+/*
343+ - (BOOL) registerBoardNamesAndURLs : (NSArray *) array;
344+ */
345+
346+- (BOOL) moveBoardID : (NSUInteger) boardID
347+ toURLString : (NSString *) urlString
348+{
349+ NSMutableString *query;
350+ SQLiteDB *db;
351+ NSString *currentURLString;
352+ NSString *prepareURLString;
353+
354+ BOOL inTransactionBlock = NO;
355+
356+ if (!urlString || ![urlString length]) {
357+ NSLog(@"urlString MUST NOT be nil or NOT zero length.");
358+ return NO;
359+ }
360+
361+ db = [self databaseForCurrentThread];
362+ if (!db) {
363+ return NO;
364+ }
365+
366+ currentURLString = [self urlStringForBoardID : boardID];
367+ if ([currentURLString isEqualTo : urlString]) return YES;
368+
369+ if(![db beginTransaction]) {
370+ if([db lastErrorID] == 0) {
371+ inTransactionBlock = YES;
372+ } else {
373+ return NO;
374+ }
375+ }
376+
377+ prepareURLString = [SQLiteDB prepareStringForQuery : currentURLString];
378+ query = [NSMutableString string];
379+ [query appendFormat: @"INSERT INTO %@", BoardInfoHistoryTableName];
380+ [query appendFormat: @"\t (%@, %@) ", BoardIDColumn, BoardURLColumn];
381+ [query appendFormat: @"\tVALUES (%lu, '%@') ", (unsigned long)boardID, prepareURLString];
382+
383+ [db performQuery : query];
384+ if ([db lastErrorID] != 0 && [db lastErrorID] != SQLITE_CONSTRAINT) {
385+ NSLog(@"Fail insert into %@", BoardInfoHistoryTableName);
386+ [db rollbackTransaction];
387+
388+ return NO;
389+ }
390+
391+ prepareURLString = [SQLiteDB prepareStringForQuery : urlString];
392+ query = [NSMutableString string];
393+ [query appendFormat: @"UPDATE %@", BoardInfoTableName];
394+ [query appendFormat: @"\tSET %@ = '%@'", BoardURLColumn, prepareURLString];
395+ [query appendFormat: @"\tWHERE %@ = %lu", BoardIDColumn, (unsigned long)boardID];
396+
397+ [db performQuery : query];
398+ if ([db lastErrorID] != 0) {
399+ NSLog(@"Fail update %@", BoardInfoTableName);
400+ [db rollbackTransaction];
401+
402+ return NO;
403+ }
404+
405+ if(!inTransactionBlock) {
406+ [db commitTransaction];
407+ }
408+
409+ return YES;
410+}
411+
412+- (BOOL) renameBoardID : (NSUInteger) boardID
413+ toName : (NSString *) name
414+{
415+ NSMutableString *query;
416+ SQLiteDB *db;
417+ NSString *currentName;
418+ NSString *prepareName;
419+
420+ BOOL inTransactionBlock = NO;
421+
422+ if (!name || ![name length]) {
423+ NSLog(@"name MUST NOT be nil or NOT zero length.");
424+ return NO;
425+ }
426+
427+ db = [self databaseForCurrentThread];
428+ if (!db) {
429+ return NO;
430+ }
431+
432+ currentName = [self nameForBoardID : boardID];
433+ if ([currentName isEqualTo : name]) return YES;
434+
435+ [self recache];
436+
437+ if(![db beginTransaction]) {
438+ if([db lastErrorID] == 0) {
439+ inTransactionBlock = YES;
440+ } else {
441+ return NO;
442+ }
443+ }
444+
445+ prepareName = [SQLiteDB prepareStringForQuery : currentName];
446+ query = [NSMutableString string];
447+ [query appendFormat: @"INSERT INTO %@", BoardInfoHistoryTableName];
448+ [query appendFormat: @"\t (%@, %@) ", BoardIDColumn, BoardNameColumn];
449+ [query appendFormat: @"\tVALUES (%lu, '%@') ", (unsigned long)boardID, prepareName];
450+
451+ [db performQuery : query];
452+ if ([db lastErrorID] != 0 && [db lastErrorID] != SQLITE_CONSTRAINT) {
453+ NSLog(@"Fail insert into %@", BoardInfoHistoryTableName);
454+ [db rollbackTransaction];
455+
456+ return NO;
457+ }
458+
459+ prepareName = [SQLiteDB prepareStringForQuery : name];
460+ query = [NSMutableString string];
461+ [query appendFormat: @"UPDATE %@", BoardInfoTableName];
462+ [query appendFormat: @"\tSET %@ = '%@'", BoardNameColumn, prepareName];
463+ [query appendFormat: @"\tWHERE %@ = %lu", BoardIDColumn, (unsigned long)boardID];
464+
465+ [db performQuery : query];
466+ if ([db lastErrorID] != 0) {
467+ NSLog(@"Fail insert into %@", BoardInfoHistoryTableName);
468+ [db rollbackTransaction];
469+
470+ return NO;
471+ }
472+
473+ if(!inTransactionBlock) {
474+ [db commitTransaction];
475+ }
476+ return YES;
477+}
478+
479+/*
480+ - (BOOL) registerThreadName : (NSString *) name
481+ threadIdentifier : (NSString *) identifier
482+ intoBoardID : (NSUInteger) boardID;
483+ - (BOOL) registerThreadNamesAndThreadIdentifiers : (NSArray *) array
484+ intoBoardID : (NSUInteger) boardID;
485+ */
486+- (BOOL)isThreadIdentifierRegistered:(NSString *)identifier onBoardID:(NSUInteger)boardID
487+{
488+ return [self isThreadIdentifierRegistered:identifier onBoardID:boardID numberOfAll:NULL];
489+}
490+
491+- (BOOL)isThreadIdentifierRegistered:(NSString *)identifier onBoardID:(NSUInteger)boardID numberOfAll:(NSUInteger *)number
492+{
493+ SQLiteDB *db = [self databaseForCurrentThread];
494+
495+ if (!db) {
496+ return NO;
497+ }
498+
499+ NSString *query;
500+ id<SQLiteCursor> cursor;
501+ query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = %lu AND %@ = %@",
502+ NumberOfAllColumn, ThreadInfoTableName, BoardIDColumn, (unsigned long)boardID, ThreadIDColumn, identifier];
503+ cursor = [db performQuery:query];
504+
505+ if (cursor && ([cursor rowCount] > 0)) {
506+ if (number != NULL) {
507+ id value = [cursor valueForColumn:NumberOfAllColumn atRow:0];
508+ if ([value isKindOfClass:[NSString class]]) {
509+ *number = [value integerValue];
510+ }
511+ }
512+ return YES;
513+ }
514+
515+ return NO;
516+}
517+
518+- (BOOL) isFavoriteThreadIdentifier : (NSString *) identifier
519+ onBoardID : (NSUInteger) boardID
520+{
521+ NSMutableString *query;
522+ SQLiteDB *db;
523+ id<SQLiteCursor> cursor;
524+ id value;
525+ BOOL isFavorite = NO;
526+
527+ db = [self databaseForCurrentThread];
528+ if (!db) {
529+ return NO;
530+ }
531+
532+ query = [NSMutableString stringWithFormat: @"SELECT count(*) FROM %@ WHERE %@ = %lu AND %@ = %@",
533+ FavoritesTableName, BoardIDColumn, (unsigned long)boardID, ThreadIDColumn, identifier];
534+ cursor = [db performQuery : query];
535+ if (cursor && [cursor rowCount]) {
536+ value = [cursor valueForColumn : @"count(*)" atRow : 0];
537+ if ([value integerValue]) {
538+ isFavorite = YES;
539+ }
540+ }
541+
542+ return isFavorite;
543+}
544+- (BOOL) appendFavoriteThreadIdentifier : (NSString *) identifier
545+ onBoardID : (NSUInteger) boardID
546+{
547+ NSMutableString *query;
548+ SQLiteDB *db;
549+
550+ db = [self databaseForCurrentThread];
551+ if (!db) {
552+ return NO;
553+ }
554+
555+ if([db beginTransaction]) {
556+ query = [NSMutableString stringWithFormat: @"INSERT INTO %@", FavoritesTableName];
557+ [query appendFormat: @" ( %@, %@ ) ", BoardIDColumn, ThreadIDColumn];
558+ [query appendFormat: @" VALUES ( %lu, %@ ) ", (unsigned long)boardID, identifier];
559+ [db performQuery : query];
560+ if([db lastErrorID] != 0) goto abort;
561+
562+ [db commitTransaction];
563+ } else {
564+ return NO;
565+ }
566+
567+ return YES;
568+
569+abort:
570+ NSLog(@"FAIL append Favorote. Reason : %@", [db lastError]);
571+ [db rollbackTransaction];
572+ return NO;
573+}
574+- (BOOL) removeFavoriteThreadIdentifier : (NSString *) identifier
575+ onBoardID : (NSUInteger) boardID
576+{
577+ NSMutableString *query;
578+ SQLiteDB *db;
579+
580+ db = [self databaseForCurrentThread];
581+ if (!db) {
582+ return NO;
583+ }
584+
585+ if([db beginTransaction]) {
586+ query = [NSMutableString stringWithFormat: @"DELETE FROM %@", FavoritesTableName];
587+ [query appendFormat: @" WHERE %@ = %lu", BoardIDColumn, (unsigned long)boardID];
588+ [query appendFormat: @" AND %@ = %@", ThreadIDColumn, identifier];
589+ [db performQuery : query];
590+ if([db lastErrorID] != 0) goto abort;
591+
592+ [db commitTransaction];
593+ } else {
594+ return NO;
595+ }
596+
597+ return YES;
598+
599+abort:
600+ NSLog(@"FAIL delete Favorote. Reason : %@", [db lastError]);
601+ [db rollbackTransaction];
602+ return NO;
603+}
604+
605+//- (BOOL)registerThreadFromFilePath:(NSString *)filepath
606+//{
607+// return [self registerThreadFromFilePath:filepath needsDisplay:YES];
608+//}
609+
610+//- (BOOL)registerThreadFromFilePath:(NSString *)filepath needsDisplay:(BOOL)flag
611+//{
612+// NSDictionary *hoge = [NSDictionary dictionaryWithContentsOfFile:filepath];
613+// NSString *datNum, *title, *boardName;
614+// NSUInteger count;
615+// NSDate *date;
616+// CMRThreadUserStatus *s;
617+// id rep;
618+// NSUInteger boardID;
619+// BOOL isDatOchi;
620+// NSUInteger label = 0;
621+//
622+// datNum = [hoge objectForKey:ThreadPlistIdentifierKey];
623+// if (!datNum) return NO;
624+// title = [hoge objectForKey:CMRThreadTitleKey];
625+// if (!title) return NO;
626+// boardName = [hoge objectForKey:ThreadPlistBoardNameKey];
627+// if (!boardName) return NO;
628+// count = [[hoge objectForKey: ThreadPlistContentsKey] count];
629+//
630+// rep = [hoge objectForKey:CMRThreadUserStatusKey];
631+// s = [CMRThreadUserStatus objectWithPropertyListRepresentation:rep];
632+// isDatOchi = (s ? [s isDatOchiThread] : NO);
633+// label = (s ? [s label] : 0);
634+//
635+// date = [hoge objectForKey:CMRThreadModifiedDateKey];
636+//
637+// NSArray *boardIDs = [self boardIDsForName:boardName];
638+// if (!boardIDs || [boardIDs count] == 0) {
639+// CMRDocumentFileManager *dfm = [CMRDocumentFileManager defaultManager];
640+// NSString *otherBoardName = [dfm boardNameWithLogPath:filepath];
641+// if(![otherBoardName isEqualToString:boardName]) {
642+// boardIDs = [self boardIDsForName:otherBoardName];
643+// if(!boardIDs || [boardIDs count] == 0) {
644+// NSLog(@"board %@ is not registered.(%@)", otherBoardName, filepath);
645+// return NO;
646+// }
647+// } else {
648+// NSLog(@"board %@ is not registered.(%@)", boardName, filepath);
649+// return NO;
650+// }
651+// }
652+// boardID = [[boardIDs objectAtIndex:0] unsignedIntegerValue];
653+//
654+// BOOL isSuccess = [self insertThreadOfIdentifier:datNum title:title count:count date:date isDatOchi:isDatOchi atBoard:boardID];
655+// [self setLabel:label boardName:boardName threadIdentifier:datNum];
656+// if (isSuccess && flag) {
657+// [self makeThreadsListsUpdateCursor];
658+// return YES;
659+// }
660+// return isSuccess;
661+//}
662+
663+- (NSString *) threadTitleFromBoardName:(NSString *)boadName threadIdentifier:(NSString *)identifier
664+{
665+ NSString *boardID;
666+ NSArray *boardIDs;
667+ NSString *query;
668+ SQLiteDB *db;
669+ id<SQLiteCursor> cursor;
670+
671+ NSString *title = nil;
672+
673+// UTILAssertKindOfClass(boadName, NSString);
674+// UTILAssertKindOfClass(identifier, NSString);
675+ if([boadName length] == 0) return nil;
676+ if([identifier length] == 0) return nil;
677+
678+ boardIDs = [self boardIDsForName:boadName];
679+ if(!boardIDs || [boardIDs count] == 0) return nil;
680+
681+ boardID = [boardIDs objectAtIndex:0];
682+
683+ db = [self databaseForCurrentThread];
684+ if (!db) {
685+ return nil;
686+ }
687+
688+ query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = %@ AND %@ = %@",
689+ ThreadNameColumn,
690+ ThreadInfoTableName,
691+ BoardIDColumn, boardID,
692+ ThreadIDColumn, identifier,
693+ nil];
694+ cursor = [db performQuery: query];
695+ if (cursor && [cursor rowCount]) {
696+ title = [cursor valueForColumn : ThreadNameColumn atRow : 0];
697+ }
698+
699+ return title;
700+}
701+
702+- (void)setLastWriteDate:(NSDate *)writeDate atBoardID:(NSUInteger)boardID threadIdentifier:(NSString *)identifier
703+{
704+ NSString *query;
705+ SQLiteDB *db;
706+// UTILAssertKindOfClass(identifier, NSString);
707+
708+ if([identifier length] == 0) return;
709+
710+ db = [self databaseForCurrentThread];
711+ if (!db) {
712+ return;
713+ }
714+
715+ query = [NSString stringWithFormat:@"UPDATE %@ SET %@ = %.0lf WHERE %@ = %lu AND %@ = %@",
716+ ThreadInfoTableName,
717+ LastWrittenDateColumn, [writeDate timeIntervalSince1970],
718+ BoardIDColumn, (unsigned long)boardID,
719+ ThreadIDColumn, identifier,
720+ nil];
721+ [db performQuery: query];
722+ if ([db lastErrorID] != 0) {
723+ NSLog(@"Fail update LastWrittenDate.");
724+ }
725+}
726+
727+
728+//- (BOOL)setThreadStatus:(ThreadStatus)status modifiedDate:(NSDate *)date atBoardID:(NSUInteger)boardID threadIdentifier:(NSString *)identifier
729+//{
730+// NSString *query;
731+// SQLiteDB *db;
732+//
733+// if ([identifier length] == 0) {
734+// return NO;
735+// }
736+//
737+// db = [self databaseForCurrentThread];
738+// if (!db) {
739+// return NO;
740+// }
741+//
742+// if (date) {
743+// NSTimeInterval intSince1970;
744+// intSince1970 = [date timeIntervalSince1970];
745+//
746+// query = [NSString stringWithFormat:@"UPDATE %@ SET %@ = %ld, %@ = %.0lf WHERE %@ = %lu AND %@ = %@",
747+// ThreadInfoTableName,
748+// ThreadStatusColumn, (long)status,
749+// ModifiedDateColumn, intSince1970,
750+// BoardIDColumn, (unsigned long)boardID,
751+// ThreadIDColumn, identifier,
752+// nil];
753+// } else {
754+// query = [NSString stringWithFormat:@"UPDATE %@ SET %@ = %ld WHERE %@ = %lu AND %@ = %@",
755+// ThreadInfoTableName,
756+// ThreadStatusColumn, (long)status,
757+// BoardIDColumn, (unsigned long)boardID,
758+// ThreadIDColumn, identifier,
759+// nil];
760+// }
761+// [db performQuery:query];
762+// if ([db lastErrorID] != 0) {
763+// NSLog(@"Fail update ThreadStatus.");
764+// return NO;
765+// }
766+// return YES;
767+//}
768+
769+- (void) setIsDatOchi:(BOOL)flag
770+ boardName:(NSString *)boardName
771+ threadIdentifier:(NSString *)identifier
772+{
773+ NSString *boardID;
774+ NSArray *boardIDs;
775+ NSString *query;
776+ SQLiteDB *db;
777+
778+// UTILAssertKindOfClass(boardName, NSString);
779+// UTILAssertKindOfClass(identifier, NSString);
780+ if([boardName length] == 0) return;
781+ if([identifier length] == 0) return;
782+
783+ boardIDs = [self boardIDsForName:boardName];
784+ if(!boardIDs || [boardIDs count] == 0) return;
785+
786+ boardID = [boardIDs objectAtIndex:0];
787+
788+ db = [self databaseForCurrentThread];
789+ if (!db) {
790+ return;
791+ }
792+
793+ query = [NSString stringWithFormat:@"UPDATE %@ SET %@ = %ld WHERE %@ = %@ AND %@ = %@",
794+ ThreadInfoTableName,
795+ IsDatOchiColumn, flag ? 1L : 0L,
796+ BoardIDColumn, boardID,
797+ ThreadIDColumn, identifier,
798+ nil];
799+ [db performQuery: query];
800+ if ([db lastErrorID] != 0) {
801+ NSLog(@"Fail update IsDatOchi.");
802+ }
803+}
804+- (BOOL)isDatOchiBoardName:(NSString *)boardName threadIdentifier:(NSString *)identifier
805+{
806+ NSString *boardID;
807+ NSArray *boardIDs;
808+ NSString *query;
809+ SQLiteDB *db;
810+ id<SQLiteCursor> cursor;
811+
812+ BOOL result = NO;
813+
814+// UTILAssertKindOfClass(boardName, NSString);
815+// UTILAssertKindOfClass(identifier, NSString);
816+ if([boardName length] == 0) return NO;
817+ if([identifier length] == 0) return NO;
818+
819+ boardIDs = [self boardIDsForName:boardName];
820+ if(!boardIDs || [boardIDs count] == 0) return NO;
821+
822+ boardID = [boardIDs objectAtIndex:0];
823+
824+ db = [self databaseForCurrentThread];
825+ if (!db) {
826+ return NO;
827+ }
828+
829+ query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = %@ AND %@ = %@",
830+ IsDatOchiColumn,
831+ ThreadInfoTableName,
832+ BoardIDColumn, boardID,
833+ ThreadIDColumn, identifier,
834+ nil];
835+ cursor = [db performQuery: query];
836+ if (cursor && [cursor rowCount]) {
837+ result = [[cursor valueForColumn : IsDatOchiColumn atRow : 0] integerValue];
838+ }
839+
840+ return result;
841+}
842+
843+- (void)setLabel:(NSUInteger)code
844+ boardName:(NSString *)boardName
845+threadIdentifier:(NSString *)identifier
846+{
847+ NSString *boardID;
848+ NSArray *boardIDs;
849+ NSString *query;
850+ SQLiteDB *db;
851+
852+ if ([boardName length] == 0) return;
853+ if ([identifier length] == 0) return;
854+
855+ boardIDs = [self boardIDsForName:boardName];
856+ if (!boardIDs || [boardIDs count] == 0) return;
857+
858+ boardID = [boardIDs objectAtIndex:0];
859+
860+ db = [self databaseForCurrentThread];
861+ if (!db) {
862+ return;
863+ }
864+
865+ query = [NSString stringWithFormat:@"UPDATE %@ SET %@ = %lu WHERE %@ = %@ AND %@ = %@",
866+ ThreadInfoTableName,
867+ ThreadLabelColumn, (unsigned long)code,
868+ BoardIDColumn, boardID,
869+ ThreadIDColumn, identifier,
870+ nil];
871+ [db performQuery:query];
872+ if ([db lastErrorID] != 0) {
873+ NSLog(@"Fail update threadLabel.");
874+ } else {
875+ NSNotification *notification = [NSNotification notificationWithName:DatabaseDidUpdateThreadLabelNotification object:self];
876+ [[NSNotificationQueue defaultQueue] enqueueNotification:notification
877+ postingStyle:NSPostWhenIdle
878+ coalesceMask:(NSNotificationCoalescingOnName|NSNotificationCoalescingOnSender)
879+ forModes:nil];
880+ }
881+}
882+
883+- (NSUInteger)labelBoardName:(NSString *)boardName threadIdentifier:(NSString *)identifier
884+{
885+ NSString *boardID;
886+ NSArray *boardIDs;
887+ NSString *query;
888+ SQLiteDB *db;
889+ id<SQLiteCursor> cursor;
890+
891+ NSUInteger result = 0;
892+
893+ if([boardName length] == 0) return NO;
894+ if([identifier length] == 0) return NO;
895+
896+ boardIDs = [self boardIDsForName:boardName];
897+ if(!boardIDs || [boardIDs count] == 0) return NO;
898+
899+ boardID = [boardIDs objectAtIndex:0];
900+
901+ db = [self databaseForCurrentThread];
902+ if (!db) {
903+ return NO;
904+ }
905+
906+ query = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = %@ AND %@ = %@",
907+ ThreadLabelColumn,
908+ ThreadInfoTableName,
909+ BoardIDColumn, boardID,
910+ ThreadIDColumn, identifier,
911+ nil];
912+ cursor = [db performQuery: query];
913+ if (cursor && [cursor rowCount]) {
914+ result = [[cursor valueForColumn : IsDatOchiColumn atRow : 0] unsignedIntegerValue];
915+ }
916+
917+ return result;
918+}
919+#pragma mark Testing...
920+
921+static NSString *const DMDA_TEMP_THREAD_INFO_TABLE = @"DMDA_TEMP_THREAD_INFO_TABLE";
922+static inline NSString *numberOfAllQuery()
923+{
924+ static NSString *query = nil;
925+ if(!query) {
926+ query = [[NSString alloc] initWithFormat:
927+ @"SELECT %@ FROM %@ WHERE %@ = ? AND %@ = ?",
928+ NumberOfAllColumn, ThreadInfoTableName/*DMDA_TEMP_THREAD_INFO_TABLE*/, BoardIDColumn, ThreadIDColumn];
929+ }
930+ return query;
931+}
932+static inline NSUInteger numberOfAllOfBoardIDAndThreadIDInDatabase(NSNumber *boardID, NSString *threadID, SQLiteDB *db)
933+{
934+ NSUInteger result = 0;
935+
936+ SQLiteReservedQuery *rQuery = [db reservedQuery:numberOfAllQuery()];
937+ const char *format = F_NSNumberOfInt F_NSString;
938+ id<SQLiteCursor> cursor = [rQuery cursorWithFormat:format, boardID, threadID, nil];
939+ if (cursor && [cursor rowCount]) {
940+ result = [[cursor valueForColumn:NumberOfAllColumn atRow:0] unsignedIntegerValue];
941+ }
942+
943+ return result;
944+}
945+static inline NSString *lastWrittenDateQuery()
946+{
947+ static NSString *query2 = nil;
948+ if(!query2) {
949+ query2 = [[NSString alloc] initWithFormat:
950+ @"SELECT %@ FROM %@ WHERE %@ = ? AND %@ = ?",
951+ LastWrittenDateColumn, DMDA_TEMP_THREAD_INFO_TABLE, BoardIDColumn, ThreadIDColumn];
952+ }
953+ return query2;
954+}
955+static inline id lastWrittenDateOfBoardIDAndThreadIDInDatabase(NSNumber *boardID, NSString *threadID, SQLiteDB *db)
956+{
957+ id result = nil;
958+
959+ SQLiteReservedQuery *rQuery = [db reservedQuery:lastWrittenDateQuery()];
960+ const char *format = F_NSNumberOfInt F_NSString;
961+ id<SQLiteCursor> cursor = [rQuery cursorWithFormat:format, boardID, threadID, nil];
962+
963+ if(SQLITE_OK != [db lastErrorID]) {
964+ NSLog(@"Fail lastWrittenDateOfBoardIDAndThreadIDInDatabase Reason -> %@", [db lastError]);
965+ }
966+ if (cursor && [cursor rowCount]) {
967+ result = [cursor valueForColumn:LastWrittenDateColumn atRow:0];
968+ }
969+
970+ return result;
971+}
972+static NSString *rebuildQuery()
973+{
974+ static NSString *query = nil;
975+ if(!query) {
976+ query = [[NSString alloc] initWithFormat:
977+ @"REPLACE INTO %@ (%@, %@, %@, %@, %@, %@, %@, %@, %@)"
978+ @"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
979+ ThreadInfoTableName,
980+ BoardIDColumn, ThreadIDColumn,
981+ ThreadNameColumn, NumberOfAllColumn, NumberOfReadColumn, ModifiedDateColumn, LastWrittenDateColumn, IsDatOchiColumn, ThreadLabelColumn];
982+ }
983+ return query;
984+}
985+
986+//static NSError *fileContentsErrorObject(NSArray *filepaths)
987+//{
988+// NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:filepaths, DatabaseManagerInvalidFilePathsArrayKey,
989+// NSLocalizedStringFromTable(@"RebuildingErrorAlert", @"DatabaseManager", nil), NSLocalizedDescriptionKey,
990+// NSLocalizedStringFromTable(@"RebuildingErrorMessage", @"DatabaseManager", nil), NSLocalizedRecoverySuggestionErrorKey,
991+// [NSArray arrayWithObjects:NSLocalizedStringFromTable(@"RebuildingErrorOK", @"DatabaseManager", nil),
992+// NSLocalizedStringFromTable(@"RebuildingErrorShowFiles", @"DatabaseManager", nil), nil], NSLocalizedRecoveryOptionsErrorKey,
993+// NULL];
994+// return [NSError errorWithDomain:BSBathyScapheErrorDomain code:DatabaseManagerRebuildLogFileContentsError userInfo:dict];
995+//}
996+
997+//static NSError *dbErrorObject(NSInteger errorID, NSString *errorMessage)
998+//{
999+// NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInteger:errorID], @"lastErrorID", errorMessage, @"lastError", NULL];
1000+// return [NSError errorWithDomain:BSBathyScapheErrorDomain code:DatabaseManagerRebuildLogFileDBError userInfo:dict];
1001+//}
1002+
1003+//- (BOOL)rebuildFromFilePath:(NSString *)filepath withBoardID:(NSNumber *)boardID isDBError:(BOOL *)dbErrFlagPtr
1004+//{
1005+// SQLiteDB *db = [self databaseForCurrentThread];
1006+//
1007+// NSDictionary *fileContents = [NSDictionary dictionaryWithContentsOfFile:filepath];
1008+// NSString *datNum, *title;
1009+// NSUInteger count, numberOfAll;
1010+// NSDate *date;
1011+// id lastWrittenDate = nil;
1012+// CMRThreadUserStatus *s;
1013+// id rep;
1014+// BOOL isDatOchi;
1015+// NSUInteger labelCode;
1016+//
1017+// datNum = [fileContents objectForKey:ThreadPlistIdentifierKey];
1018+// if (!datNum) {
1019+// if (dbErrFlagPtr != NULL) {
1020+// *dbErrFlagPtr = NO;
1021+// }
1022+// return NO;
1023+// }
1024+//
1025+// title = [fileContents objectForKey:CMRThreadTitleKey];
1026+// if (!title) {
1027+// if (dbErrFlagPtr != NULL) {
1028+// *dbErrFlagPtr = NO;
1029+// }
1030+// return NO;
1031+// }
1032+//
1033+// count = [[fileContents objectForKey:ThreadPlistContentsKey] count];
1034+//
1035+// rep = [fileContents objectForKey:CMRThreadUserStatusKey];
1036+// s = [CMRThreadUserStatus objectWithPropertyListRepresentation:rep];
1037+// isDatOchi = (s ? [s isDatOchiThread] : NO);
1038+// labelCode = (s ? [s label] : 0);
1039+//
1040+// date = [fileContents objectForKey:CMRThreadModifiedDateKey];
1041+// double interval = 0;
1042+// if (date && [date isKindOfClass:[NSDate class]]) {
1043+// interval = [date timeIntervalSince1970];
1044+// }
1045+//
1046+// lastWrittenDate = lastWrittenDateOfBoardIDAndThreadIDInDatabase(boardID ,datNum, db);
1047+//
1048+// numberOfAll = numberOfAllOfBoardIDAndThreadIDInDatabase(boardID ,datNum, db);
1049+// numberOfAll = MAX(numberOfAll, count);
1050+//
1051+// SQLiteReservedQuery *rQuery = [db reservedQuery:rebuildQuery()];
1052+// const char *format = F_NSNumberOfInt F_NSString F_NSString F_Int F_Int F_Double F_NSNumberOfDouble F_Int F_Int;
1053+// [rQuery cursorWithFormat:format, boardID, datNum, title, numberOfAll, count, interval, lastWrittenDate, (NSInteger)isDatOchi, labelCode];
1054+// if ([db lastErrorID] != 0) {
1055+// if (dbErrFlagPtr != NULL) {
1056+// *dbErrFlagPtr = YES;
1057+// }
1058+// return NO;
1059+// }
1060+//
1061+// return YES;
1062+//}
1063+
1064+//- (BOOL)rebuildStatusInBoardID:(NSNumber *)boardID
1065+//{
1066+// SQLiteDB *db = [self databaseForCurrentThread];
1067+// if (!db) {
1068+// return NO;
1069+// }
1070+//
1071+// NSString *query;
1072+//
1073+// // set ThreadLogCachedStatus if NumberOfReadColumn is not 0
1074+// query = [NSString stringWithFormat:
1075+// @"UPDATE %@ SET %@ = %lu "
1076+// @"WHERE %@ = %@ AND %@ <> 0",
1077+// ThreadInfoTableName, ThreadStatusColumn, (unsigned long)ThreadLogCachedStatus,
1078+// BoardIDColumn, boardID, NumberOfReadColumn];
1079+// [db performQuery:query];
1080+// if ([db lastErrorID] != 0) {
1081+// NSLog(@"Fail to update. Reason: %@", [db lastError]);
1082+// return NO;
1083+// }
1084+//
1085+// // set ThreadUpdatedStatus if NumberOfAllColumn > NumberOfReadColumn
1086+// query = [NSString stringWithFormat:
1087+// @"UPDATE %@ SET %@ = %lu "
1088+// @"WHERE %@ = %@ AND %@ > %@",
1089+// ThreadInfoTableName, ThreadStatusColumn, (unsigned long)ThreadUpdatedStatus,
1090+// BoardIDColumn, boardID, NumberOfAllColumn, NumberOfReadColumn];
1091+// [db performQuery:query];
1092+// if ([db lastErrorID] != 0) {
1093+// NSLog(@"Fail to update. Reason: %@", [db lastError]);
1094+// return NO;
1095+// }
1096+//
1097+// return YES;
1098+//}
1099+
1100+//- (BOOL)createRebuildTempTableForBoardID:(id)boardID
1101+//{
1102+// // TEMP TABLE だと -rebuildFromLogFolder:boardID: 以外の場所からこのメソッドを呼んでテーブルを作った場合に
1103+// // -rebuildFromFilePath:withBoardID: でアクセスできない。
1104+// // どうせあとで DROP TABLE しているから普通の TABLE にしてやり過ごしてみる。
1105+// NSString *query = [NSString stringWithFormat:
1106+//// @"CREATE TEMP TABLE %@ AS SELECT %@, %@, %@, %@ FROM %@ WHERE %@ = %@",
1107+// @"CREATE TABLE %@ AS SELECT %@, %@, %@ FROM %@ WHERE %@ = %@",
1108+// DMDA_TEMP_THREAD_INFO_TABLE,
1109+// /*NumberOfAllColumn,*/ LastWrittenDateColumn, BoardIDColumn, ThreadIDColumn,
1110+// ThreadInfoTableName,
1111+// BoardIDColumn, boardID];
1112+// SQLiteDB *db = [self databaseForCurrentThread];
1113+// [db performQuery:query];
1114+// if([db lastErrorID] != SQLITE_OK) {
1115+// NSLog(@"Fail create temp table(%@) Reason: %@", DMDA_TEMP_THREAD_INFO_TABLE, [db lastError]);
1116+// }
1117+// return [db lastErrorID] == SQLITE_OK;
1118+//}
1119+//- (BOOL)dropRebuildTempTable
1120+//{
1121+// NSString *query = [NSString stringWithFormat:@"DROP TABLE IF EXISTS %@", DMDA_TEMP_THREAD_INFO_TABLE];
1122+// SQLiteDB *db = [self databaseForCurrentThread];
1123+// [db performQuery:query];
1124+// if([db lastErrorID] != SQLITE_OK) {
1125+// NSLog(@"Fail drop temp table(%@) Reason: %@", DMDA_TEMP_THREAD_INFO_TABLE, [db lastError]);
1126+// }
1127+// return [db lastErrorID] == SQLITE_OK;
1128+//}
1129+
1130+//- (BOOL)rebuildFromLogFolder:(NSString *)folderPath boardID:(NSNumber *)boardID error:(NSError **)errorPtr
1131+//{
1132+// SQLiteDB *db = [self databaseForCurrentThread];
1133+//
1134+// NSDirectoryEnumerator *iter = [[NSFileManager defaultManager] enumeratorAtPath:folderPath];
1135+// NSString *fileName, *filePath;
1136+// NSAutoreleasePool *pool = nil;
1137+// BOOL success;
1138+// NSMutableArray *invalidFiles = [NSMutableArray array];
1139+//
1140+// NSDate *date1 = [NSDate dateWithTimeIntervalSinceNow:0.0];
1141+//
1142+// if(db && [db beginTransaction]) {
1143+// // deleteAllRecordsOfBoard: をここで呼び出してしまうと、この前で実行された
1144+// // -[BSDBThreadsListDBUpdateTask2 run] で DB に投入した、最新のスレッド一覧データが
1145+// // 一緒に吹っ飛んでしまう。これでは再構築終了後にログの存在するスレッドのデータしか残らない。
1146+// // 以前のように -[BSDBThreadList rebuildThreadsList] に場所を戻してみる。
1147+//// [self createRebuildTempTableForBoardID:boardID];
1148+//// [self deleteAllRecordsOfBoard:[boardID unsignedIntegerValue]];
1149+//
1150+// while (fileName = [iter nextObject]) {
1151+// pool = [[NSAutoreleasePool alloc] init];
1152+// if ([[fileName pathExtension] isEqualToString:@"thread"]) {
1153+// BOOL isDBErr;
1154+// filePath = [folderPath stringByAppendingPathComponent:fileName];
1155+// success = [self rebuildFromFilePath:filePath withBoardID:boardID isDBError:&isDBErr];
1156+// if (!success) {
1157+// if (isDBErr) {
1158+// goto abort;
1159+// } else {
1160+// [invalidFiles addObject:filePath];
1161+// }
1162+// }
1163+// }
1164+// [pool release];
1165+// pool = nil;
1166+// }
1167+// [self dropRebuildTempTable];
1168+// [self rebuildStatusInBoardID:boardID];
1169+//
1170+// [db commitTransaction];
1171+// }
1172+//
1173+// if ((errorPtr != NULL) && ([invalidFiles count] > 0)) {
1174+// *errorPtr = fileContentsErrorObject(invalidFiles);
1175+// }
1176+// NSDate *date2 = [NSDate dateWithTimeIntervalSinceNow:0.0];
1177+// NSLog(@"Work time is %.3f", [date2 timeIntervalSinceDate:date1]);
1178+//
1179+// return YES;
1180+//
1181+// abort:{
1182+// NSLog(@"Fail insertOrUpdateFromLogFiles. ErrorID -> %ld. Reason: %@", (long)[db lastErrorID], [db lastError] );
1183+// if (errorPtr != NULL) {
1184+// *errorPtr = dbErrorObject([db lastErrorID], [db lastError]);
1185+// }
1186+// [db rollbackTransaction];
1187+// [pool release];
1188+//
1189+// return NO;
1190+// }
1191+//}
1192+
1193+
1194+NSString *escapeQuotes(NSString *str)
1195+{
1196+ NSRange range = [str rangeOfString:@"'" options:NSLiteralSearch];
1197+ if (range.location == NSNotFound) {
1198+ return str;
1199+ } else {
1200+ NSMutableString *newStr = [str mutableCopy];
1201+ [newStr replaceOccurrencesOfString:@"'" withString:@"''" options:NSLiteralSearch range:NSMakeRange(0, [newStr length])];
1202+ return [newStr autorelease];
1203+ }
1204+}
1205+
1206+- (BOOL)isRegisteredWithFavoritesTable:(NSString *)identifier atBoard:(NSUInteger)boardID
1207+{
1208+ SQLiteDB *db = [self databaseForCurrentThread];
1209+ if (!db) {
1210+ return NO;
1211+ }
1212+ NSString *query = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ = %lu AND %@ = %@",
1213+ FavoritesTableName, BoardIDColumn, (unsigned long)boardID, ThreadIDColumn, identifier];
1214+ id<SQLiteCursor> cursor;
1215+ cursor = [db cursorForSQL:query];
1216+ if (cursor && [cursor rowCount]) {
1217+ return YES;
1218+ }
1219+ return NO;
1220+}
1221+
1222+- (BOOL)removeThreadOfIdentifier:(NSString *)identifier atBoard:(NSUInteger)boardID
1223+{
1224+ SQLiteDB *db = [self databaseForCurrentThread];
1225+ if (!db) {
1226+ return NO;
1227+ }
1228+
1229+ if (![self isThreadIdentifierRegistered:identifier onBoardID:boardID numberOfAll:NULL]) {
1230+ return NO;
1231+ }
1232+ NSString *sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@ = %lu AND %@ = %@",
1233+ ThreadInfoTableName, BoardIDColumn, (unsigned long)boardID, ThreadIDColumn, identifier];
1234+ [db cursorForSQL:sql];
1235+
1236+ if ([db lastErrorID] != 0) {
1237+ NSLog(@"Fail to remove. Reason: %@", [db lastError]);
1238+ return NO;
1239+ }
1240+ NSNotification *notification = [NSNotification notificationWithName:DatabaseDidFinishUpdateDownloadedOrDeletedThreadInfoNotification object:self];
1241+ [self performSelectorOnMainThread:@selector(makeThreadsListUpdateCursorWhenIdle:) withObject:notification waitUntilDone:NO];
1242+ return YES;
1243+}
1244+
1245+- (BOOL)insertThreadOfIdentifier:(NSString *)identifier
1246+ title:(NSString *)title
1247+ count:(NSUInteger)count
1248+ date:(NSDate *)date
1249+ isDatOchi:(BOOL)flag
1250+ atBoard:(NSUInteger)boardID
1251+{
1252+ SQLiteDB *db = [self databaseForCurrentThread];
1253+ if (!db) {
1254+ return NO;
1255+ }
1256+
1257+ double interval = 0;
1258+ if (date && [date isKindOfClass:[NSDate class]]) {
1259+ interval = [date timeIntervalSince1970];
1260+ }
1261+
1262+ NSUInteger number = 0;
1263+ NSUInteger /*ThreadStatus*/ status = 1 << 1;//ThreadLogCachedStatus;
1264+ NSMutableString *sql;
1265+
1266+ if ([self isThreadIdentifierRegistered:identifier onBoardID:boardID numberOfAll:&number]) {
1267+ if (number < count) {
1268+ number = count;
1269+ } else if (number > count) {
1270+ status = (1 << 2) | (1 << 1);//ThreadUpdatedStatus;
1271+ }
1272+
1273+ sql = [NSMutableString stringWithFormat:@"UPDATE %@ ", ThreadInfoTableName];
1274+ [sql appendFormat:@"SET %@ = %lu, %@ = %lu, %@ = %lu, %@ = %.0lf, %@ = %lu ",
1275+ NumberOfAllColumn, (unsigned long)number,
1276+ NumberOfReadColumn, (unsigned long)count,
1277+ ThreadStatusColumn, (unsigned long)status,
1278+ ModifiedDateColumn, interval,
1279+ IsDatOchiColumn, (flag ? 1UL : 0UL)];
1280+ [sql appendFormat:@"WHERE %@ = %lu AND %@ = %@",
1281+ BoardIDColumn, (unsigned long)boardID, ThreadIDColumn, identifier];
1282+
1283+ [db cursorForSQL:sql];
1284+
1285+ if ([db lastErrorID] != 0) {
1286+ NSLog(@"Fail to update. Reason: %@", [db lastError]);
1287+ return NO;
1288+ }
1289+
1290+ } else {
1291+ sql = [NSString stringWithFormat:@"INSERT INTO %@ ( %@, %@, %@, %@, %@, %@, %@, %@ ) VALUES ( %lu, %@, '%@', %lu, %lu, %.0lf, %lu, %lu)",
1292+ ThreadInfoTableName,
1293+ BoardIDColumn, ThreadIDColumn, ThreadNameColumn, NumberOfAllColumn, NumberOfReadColumn, ModifiedDateColumn, ThreadStatusColumn,
1294+ IsDatOchiColumn,
1295+ (unsigned long)boardID, identifier, escapeQuotes(title), (unsigned long)count, (unsigned long)count, interval, (unsigned long)status,
1296+ (flag ? 1UL : 0UL)];
1297+ [db cursorForSQL:sql];
1298+
1299+ if ([db lastErrorID] != 0) {
1300+ NSLog(@"Fail Insert. ErrorID -> %ld. Reason: %@", (long)[db lastErrorID], [db lastError]);
1301+ return NO;
1302+ }
1303+
1304+ }
1305+
1306+ return YES;
1307+}
1308+
1309+- (void)makeThreadsListUpdateCursorWhenIdle:(NSNotification *)notification
1310+{
1311+ [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostWhenIdle];
1312+}
1313+
1314+//- (BOOL)insertThreadOfAttributes:(CMRThreadAttributes *)attr shouldUpdateCursor:(BOOL)flag
1315+//{
1316+// BOOL result;
1317+// NSUInteger boardID;
1318+// NSArray *boardIDs = [self boardIDsForName:[attr boardName]];
1319+// if (!boardIDs || [boardIDs count] == 0) {
1320+// return NO;
1321+// }
1322+// boardID = [[boardIDs objectAtIndex:0] unsignedIntegerValue];
1323+//
1324+// result = [self insertThreadOfIdentifier:[[attr threadSignature] identifier]
1325+// title:[attr threadTitle]
1326+// count:[attr numberOfLoadedMessages]
1327+// date:[attr modifiedDate]
1328+// isDatOchi:YES
1329+// atBoard:boardID];
1330+// if (result && flag) {
1331+// NSNotification *notification = [NSNotification notificationWithName:DatabaseDidFinishUpdateDownloadedOrDeletedThreadInfoNotification object:self];
1332+// [self performSelectorOnMainThread:@selector(makeThreadsListUpdateCursorWhenIdle:) withObject:notification waitUntilDone:NO];
1333+// }
1334+// return result;
1335+//}
1336+
1337+- (BOOL)recache
1338+{
1339+ [boardIDNumberCacheLock lock];
1340+ [boardIDNameCache release];
1341+ boardIDNameCache = [[NSMutableDictionary alloc] init];
1342+ [boardIDNumberCacheLock unlock];
1343+
1344+ return YES;
1345+}
1346+
1347+- (BOOL)deleteAllRecordsOfBoard:(NSUInteger)boardID
1348+{
1349+ SQLiteDB *db = [self databaseForCurrentThread];
1350+ NSString *query = [NSString stringWithFormat:
1351+ @"DELETE FROM %@ WHERE %@ = %lu", ThreadInfoTableName, BoardIDColumn, (unsigned long)boardID];
1352+ if (!db) return NO;
1353+ [db cursorForSQL:query];
1354+ if ([db lastErrorID] != 0) {
1355+ NSLog(@"Fail deleteAllRecordsOfBoard:%lu. Reason: %@ (ErrorID -> %ld)", (unsigned long)boardID, [db lastError], (long)[db lastErrorID]);
1356+ return NO;
1357+ }
1358+ return YES;
1359+}
1360+@end
--- /dev/null
+++ b/DatabaseManager-Notifications.m
@@ -0,0 +1,347 @@
1+//
2+// DatabaseManager-Notifications.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 07/06/26.
6+// Copyright 2007-2010 BathyScaphe Project. All rights reserved.
7+// encoding="UTF-8"
8+//
9+
10+#import "DatabaseManager.h"
11+
12+//#import "ThreadTextDownloader.h"
13+//#import "CMRDocumentFileManager.h"
14+//#import "CMRTrashbox.h"
15+//#import "CMRReplyMessenger.h"
16+//#import "AppDefaults.h"
17+
18+NSString *const DatabaseDidFinishUpdateDownloadedOrDeletedThreadInfoNotification = @"DatabaseDidFinishUpdateDownloadedOrDeletedThreadInfoNotification";
19+
20+NSString *const DatabaseWillUpdateThreadItemNotification = @"DatabaseWillUpdateThreadItemNotification";
21+NSString *const DatabaseWillDeleteThreadItemsNotification = @"DatabaseWillDeleteThreadItemsNotification";
22+
23+NSString *const DatabaseDidUpdateThreadLabelNotification = @"DatabaseDidUpdateThreadLabelNotification";
24+
25+NSString *const DatabaseWantsThreadItemsUpdateNotification = @"DatabaseWantsThreadItemsUpdateNotification";
26+NSString *const UserInfoBoardNameKey = @"BoardName";
27+NSString *const UserInfoThreadIDKey = @"Identifier";
28+NSString *const UserInfoThreadCountKey = @"Count";
29+NSString *const UserInfoThreadModDateKey = @"ModDate";
30+NSString *const UserInfoThreadPathsArrayKey = @"Files";
31+NSString *const UserInfoUpdateTypeKey = @"UpdateType";
32+NSString *const UserInfoIsDBInsertedKey = @"IsInsert";
33+NSString *const UserInfoThreadStatusKey = @"ThreadStatus";
34+
35+
36+@implementation DatabaseManager(Notifications)
37+//-(void)registNotifications
38+//{
39+// NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
40+//
41+// [nc addObserver:self
42+// selector:@selector(finishWriteMesssage:)
43+// name:CMRReplyMessengerDidFinishPostingNotification
44+// object:nil];
45+//}
46+//
47+//#pragma mark ## Notification (Moved From BSDBThreadList) ##
48+//- (void)makeThreadsListsUpdateCursor
49+//{
50+// NSNotification *notification = [NSNotification notificationWithName:DatabaseDidFinishUpdateDownloadedOrDeletedThreadInfoNotification object:self];
51+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];
52+//}
53+//
54+//- (BOOL)searchBoardID:(NSInteger *)outBoardID threadID:(NSString **)outThreadID fromFilePath:(NSString *)inFilePath
55+//{
56+// CMRDocumentFileManager *dfm = [CMRDocumentFileManager defaultManager];
57+//
58+// if (outThreadID) {
59+// *outThreadID = [dfm datIdentifierWithLogPath:inFilePath];
60+// }
61+//
62+// if (outBoardID) {
63+// NSArray *boardIDs;
64+// NSString *boardName;
65+// id boardID;
66+//
67+// boardName = [dfm boardNameWithLogPath:inFilePath];
68+// if (!boardName) {
69+// return NO;
70+// }
71+// boardIDs = [self boardIDsForName:boardName];
72+// if (!boardIDs || [boardIDs count] == 0) {
73+// return NO;
74+// }
75+// boardID = [boardIDs objectAtIndex:0];
76+//
77+// *outBoardID = [boardID integerValue];
78+// }
79+//
80+// return YES;
81+//}
82+//
83+//- (void)updateStatus:(ThreadStatus)status modifiedDate:(NSDate *)date forThreadSignature:(CMRThreadSignature *)signature
84+//{
85+// NSString *identifier = [signature identifier];
86+// NSString *boardName = [signature boardName];
87+//
88+// NSArray *boardIDs = [self boardIDsForName:boardName];
89+// if (!boardIDs || [boardIDs count] == 0) {
90+// return;
91+// }
92+// NSUInteger boardID = [[boardIDs objectAtIndex:0] unsignedIntegerValue];
93+// if (![self setThreadStatus:status modifiedDate:date atBoardID:boardID threadIdentifier:identifier]) {
94+// return;
95+// }
96+//
97+// NSNotification *notification = [NSNotification notificationWithName:DatabaseWillUpdateThreadItemNotification object:self];
98+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES];
99+// if ([CMRPref sortsImmediately]) {
100+// [self makeThreadsListsUpdateCursor];
101+// } else {
102+// NSDictionary *userInfo;
103+// if (date) {
104+// userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
105+// identifier, UserInfoThreadIDKey,
106+// [NSNumber numberWithUnsignedInteger:status], UserInfoThreadStatusKey,
107+// date, UserInfoThreadModDateKey,
108+// boardName, UserInfoBoardNameKey,
109+// NULL];
110+// } else {
111+// userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
112+// identifier, UserInfoThreadIDKey,
113+// [NSNumber numberWithUnsignedInteger:status], UserInfoThreadStatusKey,
114+// boardName, UserInfoBoardNameKey,
115+// NULL];
116+// }
117+//
118+// NSNotification *notification = [NSNotification notificationWithName:DatabaseWantsThreadItemsUpdateNotification object:self userInfo:userInfo];
119+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];
120+// }
121+//}
122+//
123+//- (void)threadTextDownloader:(ThreadTextDownloader *)downloader didUpdateWithContents:(NSDictionary *)userInfo
124+//{
125+// CMRThreadSignature *signature;
126+//
127+// UTILAssertKindOfClass(downloader, ThreadTextDownloader);
128+// UTILAssertNotNil(userInfo);
129+// UTILAssertKindOfClass(userInfo, NSDictionary);
130+//
131+// signature = [downloader threadSignature];
132+// UTILAssertNotNil(signature);
133+//
134+// do {
135+// SQLiteDB *db;
136+// NSMutableString *sql;
137+// NSArray *boardIDs;
138+//
139+// NSDate *modDate = [userInfo objectForKey:@"ttd_date"];
140+// NSNumber *numCount = [userInfo objectForKey:@"ttd_count"];
141+// if (!modDate) {
142+// if ([[NSUserDefaults standardUserDefaults] boolForKey:BSUserDebugEnabledKey]) {
143+// NSLog(@"** USER DEBUG ** Why? modDate is nil.");
144+// }
145+// } else {
146+// if ([[NSUserDefaults standardUserDefaults] boolForKey:BSUserDebugEnabledKey]) {
147+// NSLog(@"** USER DEBUG ** OK. modDate is %@.", modDate);
148+// }
149+// }
150+// NSUInteger count = [numCount unsignedIntegerValue];
151+//
152+// NSInteger boardID = 0;
153+// NSString *threadID;
154+// NSString *boardName;
155+// NSTimeInterval intSince1970;
156+//
157+// db = [self databaseForCurrentThread];
158+// if (!db) break;
159+//
160+// threadID = [signature identifier];
161+// boardName = [signature boardName];
162+//
163+// boardIDs = [self boardIDsForName:boardName];
164+// if (!boardIDs || [boardIDs count] == 0) break;
165+//
166+// boardID = [[boardIDs objectAtIndex:0] integerValue];
167+// intSince1970 = [modDate timeIntervalSince1970];
168+//
169+//
170+// sql = [NSMutableString stringWithFormat:@"UPDATE %@ ", ThreadInfoTableName];
171+// [sql appendFormat:@"SET %@ = %lu, %@ = %lu, %@ = %lu, %@ = %.0lf ",
172+// NumberOfAllColumn, (unsigned long)count,
173+// NumberOfReadColumn, (unsigned long)count,
174+// ThreadStatusColumn, (unsigned long)ThreadLogCachedStatus,
175+// ModifiedDateColumn, intSince1970];
176+// [sql appendFormat:@"WHERE %@ = %lu AND %@ = %@",
177+// BoardIDColumn, (unsigned long)boardID, ThreadIDColumn, threadID];
178+// if ([[NSUserDefaults standardUserDefaults] boolForKey:BSUserDebugEnabledKey]) {
179+// NSLog(@"** USER DEBUG ** SQL: %@", sql);
180+// }
181+// [db cursorForSQL:sql];
182+//
183+// if ([db lastErrorID] != 0) {
184+// NSLog(@"Fail to update. Reason: %@", [db lastError] );
185+// if ([db lastErrorID] == SQLITE_BUSY) {
186+// // 少し待ってもう一度やり直してみる(ここで DB が update できないままなのは影響が大きいので)
187+// NSLog(@"Retry later...");
188+// [self performSelector:@selector(retryUpdate:) withObject:sql afterDelay:0.5];
189+// }
190+// break;
191+// }
192+//
193+// NSInteger updated = sqlite3_changes([db rowDatabase]);
194+// BOOL isInsert = (updated < 1);
195+//
196+// if ([[NSUserDefaults standardUserDefaults] boolForKey:BSUserDebugEnabledKey]) {
197+// NSLog(@"** USER DEBUG ** %ld row(s) updated.", (long)updated);
198+// }
199+//
200+// if (isInsert) {
201+// sql = [NSString stringWithFormat:@"INSERT INTO %@ ( %@, %@, %@, %@, %@, %@, %@, %@ ) VALUES ( %lu, %@, '%@', %lu, %lu, %.0lf, %lu, %lu)",
202+// ThreadInfoTableName,
203+// BoardIDColumn, ThreadIDColumn, ThreadNameColumn, NumberOfAllColumn, NumberOfReadColumn, ModifiedDateColumn, ThreadStatusColumn,
204+// IsDatOchiColumn,
205+// (unsigned long)boardID, (unsigned long)threadID, escapeQuotes([downloader threadTitle]), (unsigned long)count, (unsigned long)count, intSince1970, (unsigned long)ThreadLogCachedStatus,
206+// ([downloader useMaru] ? 1UL : 0UL)];
207+// [db cursorForSQL:sql];
208+//
209+// if ([db lastErrorID] != 0) {
210+// NSLog(@"Fail Insert. ErrorID -> %ld. Reason: %@", (long)[db lastErrorID], [db lastError]);
211+// break;
212+// }
213+// }
214+//
215+// NSNotification *notification = [NSNotification notificationWithName:DatabaseWillUpdateThreadItemNotification object:self];
216+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES];
217+// if ([CMRPref sortsImmediately]) {
218+// [self makeThreadsListsUpdateCursor];
219+// } else {
220+// NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
221+// threadID, UserInfoThreadIDKey,
222+// numCount, UserInfoThreadCountKey,
223+// modDate, UserInfoThreadModDateKey,
224+// boardName, UserInfoBoardNameKey,
225+// [NSNumber numberWithBool:isInsert], UserInfoIsDBInsertedKey,
226+// NULL];
227+//
228+// NSNotification *notification = [NSNotification notificationWithName:DatabaseWantsThreadItemsUpdateNotification object:self userInfo:userInfo];
229+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];
230+// }
231+// } while (NO);
232+//}
233+//
234+//// TODO 暫定
235+//- (void)retryUpdate:(NSString *)sql
236+//{
237+// SQLiteDB *db = [self databaseForCurrentThread];
238+// if (db) {
239+// [db cursorForSQL:sql];
240+// if ([db lastErrorID] != 0) {
241+// NSLog(@"Fail to retry update. Reason: %@", [db lastError]);
242+// return;
243+// }
244+// NSNotification *notification = [NSNotification notificationWithName:DatabaseWillUpdateThreadItemNotification object:self];
245+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES];
246+//
247+// [self makeThreadsListsUpdateCursor];
248+// }
249+//}
250+//
251+//- (void)cleanUpItemsWhichHasBeenRemoved:(NSArray *)files
252+//{
253+// SQLiteDB *db = [self databaseForCurrentThread];
254+// NSString *query;
255+//
256+// NSEnumerator *filesEnum;
257+// NSString *path;
258+//
259+// if ([db beginTransaction]) {
260+// filesEnum = [files objectEnumerator];
261+// while (path = [filesEnum nextObject]) {
262+// NSInteger boardID = 0;
263+// NSString *threadID;
264+//
265+// if ([self searchBoardID:&boardID threadID:&threadID fromFilePath:path]) {
266+// query = [NSString stringWithFormat:
267+// @"UPDATE %@\n"
268+// @"SET %@ = NULL,\n"
269+// @"%@ = NULL,\n"
270+// @"%@ = %ld,\n"
271+// @"%@ = 0,\n"
272+// @"%@ = 0,\n"
273+// @"%@ = 0\n"
274+// @"WHERE %@ = %ld\n"
275+// @"AND %@ = %@",
276+// ThreadInfoTableName,
277+// NumberOfReadColumn,
278+// ModifiedDateColumn,
279+// ThreadStatusColumn, (long)ThreadNoCacheStatus,
280+// ThreadAboneTypeColumn,
281+// ThreadLabelColumn,
282+// IsDatOchiColumn,
283+// BoardIDColumn, (long)boardID,
284+// ThreadIDColumn, threadID];
285+//
286+// [db performQuery:query];
287+// if([db lastErrorID] != 0) goto abort;
288+//
289+// query = [NSMutableString stringWithFormat:
290+// @"DELETE FROM %@"
291+// @" WHERE %@ = %lu"
292+// @" AND %@ = %@",
293+// FavoritesTableName,
294+// BoardIDColumn, (unsigned long)boardID,
295+// ThreadIDColumn, threadID];
296+// [db performQuery : query];
297+// if([db lastErrorID] != 0) goto abort;
298+// }
299+//
300+// }
301+// [db commitTransaction];
302+// }
303+//
304+// NSNotification *notification = [NSNotification notificationWithName:DatabaseWillDeleteThreadItemsNotification object:self];
305+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:YES];
306+// if ([CMRPref sortsImmediately]) {
307+//
308+// [self makeThreadsListsUpdateCursor];
309+// } else {
310+// NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
311+// files, UserInfoThreadPathsArrayKey,
312+// NULL];
313+//
314+// NSNotification *notification = [NSNotification notificationWithName:DatabaseWantsThreadItemsUpdateNotification object:self userInfo:userInfo];
315+// [[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];
316+// }
317+//
318+// return;
319+//
320+//abort:
321+// NSLog(@"FAIL delete threadInfo. Reason : %@", [db lastError]);
322+// [db rollbackTransaction];
323+//}
324+//
325+//- (void)finishWriteMesssage:(NSNotification *)aNotification
326+//{
327+// id obj = [aNotification object];
328+// UTILAssertKindOfClass(obj, [CMRReplyMessenger class]);
329+//
330+// id boardName = [obj boardName];
331+// id threadID = [obj datIdentifier];
332+// id writeDate = [obj modifiedDate];
333+//
334+// id boardIDs = [self boardIDsForName:boardName];
335+// // TODO 二つ以上あった場合
336+// NSInteger boardID = [[boardIDs objectAtIndex:0] integerValue];
337+//
338+// [self setLastWriteDate:writeDate atBoardID:boardID threadIdentifier:threadID];
339+//}
340+
341+- (void)doVacuum
342+{
343+// UTILDebugWrite(@"START VACUUM");
344+ [[self databaseForCurrentThread] performQuery:@"VACUUM"];
345+// UTILDebugWrite(@"END VACUUM");
346+}
347+@end
--- /dev/null
+++ b/DatabaseManager.h
@@ -0,0 +1,193 @@
1+//
2+// DatabaseManager.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 05/07/17.
6+// Copyright 2005-2009 BathyScaphe Project. All rights reserved.
7+// encoding="UTF-8"
8+//
9+
10+#import <Cocoa/Cocoa.h>
11+
12+#import "SQLiteDB.h"
13+
14+@class ThreadTextDownloader;
15+@class CMRThreadAttributes;
16+@class CMRThreadSignature;
17+
18+@interface DatabaseManager : NSObject
19++ (id)defaultManager;
20+
21++ (void)setupDatabase;
22+
23+- (NSString *)databasePath;
24+
25+- (SQLiteDB *)databaseForCurrentThread;
26+
27+@end
28+
29+
30+@interface DatabaseManager(DatabaseAccess)
31+// return NSNotFound, if not registered.
32+- (NSUInteger)boardIDForURLString:(NSString *)urlString;
33+- (NSUInteger)boardIDForURLStringExceptingHistory:(NSString *)urlString; // Do not search BoardInfoHistoryTable.
34+
35+// return nil, if not registered.
36+- (NSString *)urlStringForBoardID:(NSUInteger)boardID;
37+// return nil, if not registered.
38+- (NSArray *)boardIDsForName:(NSString *)name;
39+// return nil, if not registered.
40+- (NSString *)nameForBoardID:(NSUInteger)boardID;
41+
42+// raise DatabaseManagerCantFountKeyExseption.
43+- (id)valueForKey:(NSString *)key boardID:(NSUInteger)boardID threadID:(NSString *)threadID;
44+// - (void)setValue:(id)value forKey:(NSString *)key boardID:(NSUInteger)boardID threadID:(NSString *)threadID;
45+
46+- (BOOL)registerBoardName:(NSString *)name URLString:(NSString *)urlString;
47+// Currently not available.
48+// - (BOOL)registerBoardNamesAndURLs:(NSArray *)array;
49+
50+- (BOOL)moveBoardID:(NSUInteger)boardID toURLString:(NSString *)urlString;
51+- (BOOL)renameBoardID:(NSUInteger)boardID toName:(NSString *)name;
52+
53+// Currently not available.
54+// - (BOOL)registerThreadName:(NSString *)name threadIdentifier:(NSString *)identifier intoBoardID:(NSUInteger)boardID;
55+// - (BOOL)registerThreadNamesAndThreadIdentifiers:(NSArray *)array intoBoardID:(NSUInteger)boardID;
56+
57+// Added by tsawada2.
58+- (BOOL)isThreadIdentifierRegistered:(NSString *)identifier onBoardID:(NSUInteger)boardID;
59+- (BOOL)isThreadIdentifierRegistered:(NSString *)identifier onBoardID:(NSUInteger)boardID numberOfAll:(NSUInteger *)number;
60+
61+- (BOOL)isFavoriteThreadIdentifier:(NSString *)identifier onBoardID:(NSUInteger)boardID;
62+- (BOOL)appendFavoriteThreadIdentifier:(NSString *)identifier onBoardID:(NSUInteger)boardID;
63+- (BOOL)removeFavoriteThreadIdentifier:(NSString *)identifier onBoardID:(NSUInteger)boardID;
64+
65+//- (BOOL)registerThreadFromFilePath:(NSString *)filepath;
66+//- (BOOL)registerThreadFromFilePath:(NSString *)filepath needsDisplay:(BOOL)flag; // Available in Tenori Tiger.
67+//- (BOOL)rebuildFromLogFolder:(NSString *)path boardID:(NSNumber *)boardID error:(NSError **)errorPtr;
68+
69+- (NSString *)threadTitleFromBoardName:(NSString *)boadName threadIdentifier:(NSString *)identifier;
70+
71+- (void)setLastWriteDate:(NSDate *)writeDate atBoardID:(NSUInteger)boardID threadIdentifier:(NSString *)threadID;
72+// Available in BathyScaphe 2.0.
73+//- (BOOL)setThreadStatus:(ThreadStatus)status modifiedDate:(NSDate *)date atBoardID:(NSUInteger)boardID threadIdentifier:(NSString *)identifier;
74+- (void)setLabel:(NSUInteger)code
75+ boardName:(NSString *)boardName
76+threadIdentifier:(NSString *)identifier;
77+// Available in Tenori Tiger.
78+- (BOOL)insertThreadOfIdentifier:(NSString *)identifier
79+ title:(NSString *)title
80+ count:(NSUInteger)count
81+ date:(NSDate *)date
82+ isDatOchi:(BOOL)flag
83+ atBoard:(NSUInteger)boardID;
84+
85+// Available in BathyScaphe 1.6.4 "Stealth Momo" and later.
86+//- (BOOL)insertThreadOfAttributes:(CMRThreadAttributes *)attr shouldUpdateCursor:(BOOL)flag;
87+// Available in BathyScaphe 1.7 "Prima Aspalas" and later. For debugging use.
88+- (BOOL)removeThreadOfIdentifier:(NSString *)identifier atBoard:(NSUInteger)boardID;
89+
90+//- (BOOL)createRebuildTempTableForBoardID:(id)boardID;
91+- (BOOL)deleteAllRecordsOfBoard:(NSUInteger)boardID; // Available in Tenori Tiger.
92+// キャッシュを放棄
93+- (BOOL)recache;
94+@end
95+
96+
97+@interface DatabaseManager(CreateTable)
98+- (BOOL)createFavoritesTable;
99+- (BOOL)createBoardInfoTable;
100+- (BOOL)createThreadInfoTable;
101+- (BOOL)createBoardInfoHistoryTable;
102+// - (BOOL)createResponseTable;
103+
104+- (BOOL)createTempThreadNumberTable;
105+- (BOOL)createVersionTable;
106+
107+// - (BOOL)createFavThraedInfoView;
108+
109+- (BOOL)createBoardThreadInfoView;
110+@end
111+
112+
113+@interface DatabaseManager(Notifications)
114+//- (void)makeThreadsListsUpdateCursor;
115+//- (void)updateStatus:(ThreadStatus)status modifiedDate:(NSDate *)date forThreadSignature:(CMRThreadSignature *)signature;
116+//- (void)threadTextDownloader:(ThreadTextDownloader *)downloader didUpdateWithContents:(NSDictionary *)userInfo;
117+//- (void)cleanUpItemsWhichHasBeenRemoved:(NSArray *)files;
118+- (void)doVacuum;
119+@end
120+
121+// スレッド一覧テーブルカラムのIDからデータベース上のテーブル名を取得。
122+//NSString *tableNameForKey(NSString *key);
123+extern NSString *escapeQuotes(NSString *str);
124+
125+
126+extern NSString *BoardInfoTableName;
127+extern NSString *BoardIDColumn;
128+extern NSString *BoardURLColumn;
129+extern NSString *BoardNameColumn;
130+extern NSString *ThreadInfoTableName;
131+// extern NSString *BoardIDColumn; same as BoardIDColumn in BoardInfoTableName.
132+extern NSString *ThreadIDColumn;
133+extern NSString *ThreadNameColumn;
134+extern NSString *NumberOfAllColumn;
135+extern NSString *NumberOfReadColumn;
136+extern NSString *ModifiedDateColumn;
137+extern NSString *ThreadStatusColumn;
138+extern NSString *ThreadAboneTypeColumn;
139+extern NSString *ThreadLabelColumn;
140+extern NSString *LastWrittenDateColumn;
141+extern NSString *IsDatOchiColumn;
142+// extern NSString *IsFavoriteColumn; // this column is no longer used.
143+extern NSString *FavoritesTableName;
144+// extern NSString *BoardIDColumn;
145+// extern NSString *ThreadIDColumn;
146+extern NSString *BoardInfoHistoryTableName;
147+// extern NSString *BoardIDColumn;
148+// extern NSString *BoardNameColumn;
149+// extern NSString *BoardURLColumn;
150+
151+extern NSString *VersionTableName;
152+extern NSString *VersionColumn;
153+
154+extern NSString *TempThreadNumberTableName;
155+// extern NSString *BoardIDColumn;
156+// extern NSString *ThreadIDColumn;
157+extern NSString *TempThreadThreadNumberColumn;
158+
159+// extern NSString *FavThreadInfoViewName;
160+extern NSString *BoardThreadInfoViewName;
161+extern NSString *NumberOfDifferenceColumn;
162+extern NSString *IsCachedColumn;
163+extern NSString *IsUpdatedColumn;
164+extern NSString *IsNewColumn;
165+extern NSString *IsHeadModifiedColumn;
166+
167+extern NSString *FavoritesViewName;
168+
169+// Added by tsawada2 (2008-02-19)
170+extern NSString *const DatabaseDidFinishUpdateDownloadedOrDeletedThreadInfoNotification;
171+
172+extern NSString *const DatabaseWillUpdateThreadItemNotification;
173+extern NSString *const DatabaseWillDeleteThreadItemsNotification;
174+
175+extern NSString *const DatabaseDidUpdateThreadLabelNotification; // Available in BathyScaphe 2.0 "Final Moratorium" and later.
176+
177+extern NSString *const DatabaseWantsThreadItemsUpdateNotification; // Available in BathyScaphe 1.6.5 "Prima Aspalas" and later.
178+extern NSString *const UserInfoBoardNameKey;
179+extern NSString *const UserInfoThreadIDKey;
180+extern NSString *const UserInfoThreadCountKey;
181+extern NSString *const UserInfoThreadModDateKey;
182+extern NSString *const UserInfoThreadPathsArrayKey;
183+extern NSString *const UserInfoUpdateTypeKey;
184+extern NSString *const UserInfoIsDBInsertedKey;
185+extern NSString *const UserInfoThreadStatusKey;
186+
187+// Added by tsawada2 (2011-01-24)
188+enum {
189+ DatabaseManagerRebuildLogFileContentsError = 2501,
190+ DatabaseManagerRebuildLogFileDBError = 2502,
191+};
192+
193+extern NSString *const DatabaseManagerInvalidFilePathsArrayKey;
--- /dev/null
+++ b/DatabaseManager.m
@@ -0,0 +1,731 @@
1+//
2+// DatabaseManager.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 05/07/17.
6+// Copyright 2005 BathyScaphe Project. All rights reserved.
7+//
8+
9+#import "DatabaseManager.h"
10+
11+#import "SQLiteDB.h"
12+#import "DatabaseUpdater.h"
13+
14+
15+#import "BSDCAppDelegate.h"
16+
17+//#import "CMRFileManager.h"
18+//#import "AppDefaults.h"
19+
20+NSString *FavoritesTableName = @"Favorites";
21+NSString *BoardInfoTableName = @"BoardInfo";
22+NSString *ThreadInfoTableName = @"ThreadInfo";
23+NSString *BoardInfoHistoryTableName = @"BoardInfoHistory";
24+NSString *VersionTableName = @"Version";
25+NSString *VersionColumn = @"version";
26+
27+NSString *FavThreadInfoViewName = @"FavThreadInfoView";
28+NSString *BoardThreadInfoViewName = @"BoardThreadInfoView";
29+NSString *FavoritesViewName = @"FavoratesView";
30+
31+NSString *BoardIDColumn = @"boardID";
32+NSString *BoardURLColumn = @"boardURL";
33+NSString *BoardNameColumn = @"boardName";
34+NSString *ThreadIDColumn = @"threadID";
35+NSString *ThreadNameColumn = @"threadName";
36+NSString *NumberOfAllColumn = @"numberOfAll";
37+NSString *NumberOfReadColumn = @"numberOfRead";
38+NSString *ModifiedDateColumn = @"modifiedDate";
39+NSString *ThreadStatusColumn = @"threadStatus";
40+NSString *ThreadAboneTypeColumn = @"threadAboneType";
41+NSString *ThreadLabelColumn = @"threadLabel";
42+NSString *LastWrittenDateColumn = @"lastWrittenDate";
43+NSString *IsDatOchiColumn = @"isDatOchi";
44+NSString *IsFavoriteColumn = @"IsFavorite";
45+NSString *NumberOfDifferenceColumn = @"numberOfDifference";
46+NSString *IsCachedColumn = @"isCached";
47+NSString *IsUpdatedColumn = @"isUpdated";
48+NSString *IsNewColumn = @"isNew";
49+NSString *IsHeadModifiedColumn = @"isHeadModified";
50+
51+NSString *TempThreadNumberTableName = @"TempThreadNumber";
52+NSString *TempThreadThreadNumberColumn = @"threadNumber";
53+
54+static NSString *ThreadDatabaseKey = @"ThreadDatabaseKey";
55+
56+//------ static ------//
57+static NSInteger sDatabaseFileVersion = 7;
58+
59+
60+@implementation DatabaseManager
61+
62+static NSZone *allocateZone = NULL;
63+
64+#ifdef USE_NSZONE_MALLOC
65+extern void setSQLiteZone(NSZone *zone);
66+
67++ (void)initialize
68+{
69+ BOOL isFirst = YES;
70+
71+ if(isFirst) {
72+ isFirst = NO;
73+
74+ allocateZone = [SQLiteDB allocateZone];
75+ }
76+}
77+#endif
78+
79++ (id) defaultManager
80+{
81+ static id _instance = nil;
82+
83+ if (!_instance) {
84+ _instance = [[self allocWithZone : allocateZone] init];
85+ if([_instance respondsToSelector:@selector(registNotifications)]) {
86+ [_instance performSelector:@selector(registNotifications)];
87+ }
88+ [self setupDatabase];
89+ }
90+
91+ return _instance;
92+}
93+- (void) dealloc
94+{
95+ [[NSNotificationCenter defaultCenter] removeObserver: self];
96+ [super dealloc];
97+}
98+
99++ (NSInteger) currentDatabaseFileVersion
100+{
101+ NSInteger version = -1;
102+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
103+
104+ if (!db) return -1;
105+
106+ // VersionTableを持っている場合。
107+ if ([[db tables] containsObject : VersionTableName]) {
108+ id query = [NSString stringWithFormat: @"SELECT %@ FROM %@",
109+ VersionColumn, VersionTableName];
110+ id cursor = [db cursorForSQL : query];
111+ if ([db lastErrorID] != 0) goto abort;
112+
113+ if([cursor rowCount] == 0) {
114+ return 0;
115+ }
116+ id verStr = [cursor valueForColumn : VersionColumn atRow:0];
117+ version = [verStr integerValue];
118+ }
119+
120+ {
121+ id cursor = [db cursorForSQL : @"PRAGMA user_version;"];
122+ if ([db lastErrorID] != 0) goto abort;
123+
124+ if([cursor rowCount] == 0) {
125+ return 0;
126+ }
127+ id verStr = [cursor valueForColumn : @"user_version" atRow:0];
128+ version = MAX(version, [verStr integerValue]);
129+ }
130+
131+ return version;
132+
133+abort:
134+ [db rollbackTransaction];
135+ return -1;
136+}
137++ (BOOL) setDBVersion : (NSInteger) newVersion
138+{
139+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
140+
141+ if (!db) return NO;
142+
143+ [db performQuery : [NSString stringWithFormat: @"PRAGMA user_version = %ld;",
144+ (long)newVersion]];
145+ if([db lastErrorID] != noErr) return NO;
146+
147+ return YES;
148+}
149+
150++ (BOOL) mustCreateTables
151+{
152+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
153+ NSString *colName = @"c";
154+
155+ if (!db) return NO;
156+
157+ id cursor = [db performQuery :
158+ [NSString stringWithFormat: @"SELECT count(name) AS %@ FROM sqlite_master WHERE name LIKE '%@';",
159+ colName, [SQLiteDB prepareStringForQuery : ThreadInfoTableName]]];
160+ if([db lastErrorID] != noErr) return NO;
161+ if(!cursor) return NO;
162+ if([cursor rowCount] != 1) return NO;
163+
164+ if([[cursor valueForColumn : colName atRow : 0] integerValue] != 1) return YES;
165+
166+ return NO;
167+}
168+
169++ (void) checkDatabaseFileVersion
170+{
171+ [DatabaseUpdater updateFrom : [self currentDatabaseFileVersion] to : sDatabaseFileVersion];
172+}
173+
174++ (BOOL) createTables
175+{
176+ if (![[self defaultManager] createFavoritesTable]) {
177+ NSLog(@"Can not create Favorites tables");
178+ return NO;
179+ }
180+ if (![[self defaultManager] createBoardInfoTable]) {
181+ NSLog(@"Can not create BoardInfo tables");
182+ return NO;
183+ }
184+ if (![[self defaultManager] createThreadInfoTable]) {
185+ NSLog(@"Can not create ThreadInfo tables");
186+ return NO;
187+ }
188+ if (![[self defaultManager] createBoardInfoHistoryTable]) {
189+ NSLog(@"Can not create BoardInfoHistory tables");
190+ return NO;
191+ }
192+ if (![[self defaultManager] createTempThreadNumberTable]) {
193+ NSLog(@"Can not create TempThreadNumber tables");
194+ return NO;
195+ }
196+ if (![[self defaultManager] createBoardThreadInfoView]) {
197+ NSLog(@"Can not create BoardThreadInfo view");
198+ return NO;
199+ }
200+
201+ return [self setDBVersion : sDatabaseFileVersion];
202+}
203+
204++ (void)setupCacheSize
205+{
206+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
207+
208+ if (!db) return;
209+
210+ NSInteger cacheSize = 2000;//[SGTemplateResource(@"System - SQLite Cache Size") integerValue];
211+// UTILDebugWrite1(@"Try set sqlite cache size to %ld", (long)cacheSize);
212+ if(cacheSize <= 0) return;
213+
214+ [db performQuery:[NSString stringWithFormat: @"PRAGMA cache_size = %ld;", (long)cacheSize]];
215+ if([db lastErrorID] != noErr) {
216+// UTILDebugWrite1(@"Abort PRAGMA chach_size.\n Reason %@", [db lastError]);
217+ return;
218+ }
219+
220+// UTILDebugWrite1(@"Set sqlite cache size to %ld", (long)cacheSize);
221+}
222+
223++ (void) setupDatabase
224+{
225+ if([self mustCreateTables]) {
226+ [self createTables];
227+ } else {
228+ [self checkDatabaseFileVersion];
229+ }
230+
231+ [self setupCacheSize];
232+}
233+
234+- (NSString *) databasePath
235+{
236+// return [[CMRFileManager defaultManager] supportFilepathWithName : @"BathyScaphe.db"
237+// resolvingFileRef : nil];
238+ return [BSDCAppDelegate bathyScapheSupportFolderPath];
239+}
240+
241+- (SQLiteDB *) databaseForCurrentThread
242+{
243+ SQLiteDB *result;
244+
245+ id threadDict = [[NSThread currentThread] threadDictionary];
246+
247+ result = [threadDict objectForKey : ThreadDatabaseKey];
248+
249+ if (!result) {
250+ result = [[[SQLiteDB allocWithZone : [self zone]] initWithDatabasePath : [self databasePath]] autorelease];
251+
252+ if (!result) {
253+ NSLog(@"Can NOT create Database into %@", [self databasePath]);
254+ return nil;
255+ }
256+
257+ [threadDict setObject : result forKey : ThreadDatabaseKey];
258+
259+ // [result setIsInDebugMode : YES];
260+ // [result setSendsSQLStatementWhenNotifyingOfChanges : YES];
261+ }
262+
263+ if (![result isDatabaseOpen] && ![result open]) {
264+ NSLog(@"Can NOT open Database at %@.", [result databasePath]);
265+ return nil;
266+ }
267+
268+ return result;
269+}
270+
271+@end
272+
273+@implementation DatabaseManager (CreateTable)
274+
275+- (NSString *) commaSeparatedStringWithArray : (NSArray *) array
276+{
277+ return [array componentsJoinedByString : @","];
278+}
279+
280+- (NSArray *) favoritesColumns
281+{
282+ return [NSArray arrayWithObjects : BoardIDColumn, ThreadIDColumn, nil];
283+}
284+- (NSArray *) favoritesDataTypes
285+{
286+ return [NSArray arrayWithObjects : INTEGER_NOTNULL, TEXT_NOTNULL, nil];
287+}
288+
289+- (NSArray *) boardInfoColumns
290+{
291+ return [NSArray arrayWithObjects : BoardIDColumn, BoardNameColumn, BoardURLColumn, nil];
292+}
293+- (NSArray *) boardInfoDataTypes
294+{
295+ return [NSArray arrayWithObjects : INTERGER_PRIMARY_KEY, TEXT_NOTNULL, TEXT_NOTNULL, nil];
296+}
297+
298+- (NSArray *) threadInfoColumns
299+{
300+ return [NSArray arrayWithObjects : BoardIDColumn, ThreadIDColumn, ThreadNameColumn,
301+ NumberOfAllColumn, NumberOfReadColumn,
302+ ModifiedDateColumn, LastWrittenDateColumn,
303+ ThreadStatusColumn, ThreadAboneTypeColumn, ThreadLabelColumn,
304+ IsDatOchiColumn,
305+ nil];
306+}
307+- (NSArray *) threadInfoDataTypes
308+{
309+ return [NSArray arrayWithObjects : INTEGER_NOTNULL, INTEGER_NOTNULL, TEXT_NOTNULL,
310+ QLNumber, QLNumber,
311+ QLNumber, QLNumber,
312+ QLNumber, INTEGER_NOTNULL, INTEGER_NOTNULL,
313+ INTEGER_NOTNULL,
314+ nil];
315+}
316+
317+- (NSArray *) boardInfoHistoryColumns
318+{
319+ return [NSArray arrayWithObjects : BoardIDColumn, BoardNameColumn, BoardURLColumn, nil];
320+}
321+- (NSArray *) boardInfoHistoryDataTypes
322+{
323+ return [NSArray arrayWithObjects : INTEGER_NOTNULL, QLString, QLString, nil];
324+}
325+
326+- (NSArray *) tempThreadNumberColumns
327+{
328+ return [NSArray arrayWithObjects : BoardIDColumn, ThreadIDColumn, TempThreadThreadNumberColumn, nil];
329+}
330+- (NSArray *) tempThreadNumberDataTypes
331+{
332+ return [NSArray arrayWithObjects : INTEGER_NOTNULL, TEXT_NOTNULL, INTEGER_NOTNULL, nil];
333+}
334+
335+#pragma mark## Table creation ##
336+
337+- (NSString *) queryForCreateIndexWithMultiColumn : (NSString *) column
338+ inTable : (NSString *)table
339+ isUnique : (BOOL)flag
340+{
341+ NSString *sqlQuery = nil;
342+ NSArray *columns;
343+ NSString *idxName = column;
344+
345+ columns = [column componentsSeparatedByString : @","];
346+ if ([columns count]) {
347+ idxName = [columns componentsJoinedByString : @"_"];
348+ }
349+
350+ if (flag) {
351+ sqlQuery = [[[NSString alloc]initWithFormat: @"CREATE UNIQUE INDEX %@_%@_IDX ON %@ (%@);", table, idxName, table, column] autorelease];
352+ } else {
353+ sqlQuery = [[[NSString alloc]initWithFormat: @"CREATE INDEX %@_%@_IDX ON %@ (%@);", table, idxName, table, column] autorelease];
354+ }
355+
356+ return sqlQuery;
357+}
358+- (BOOL) createTable : (NSString *) tableName
359+ columns : (NSArray *)columns
360+ dataTypes : (NSArray *)dataTypes
361+ defaultValues : (NSArray *)defaultValues
362+ checkConstrains : (NSArray *)checkConstrains
363+ indexQueries : (NSArray *)indexQuery
364+{
365+ BOOL isOK = NO;
366+
367+ SQLiteDB *db = [self databaseForCurrentThread];
368+ if (!db) return NO;
369+
370+ isOK = [db createTable : tableName
371+ columns : columns
372+ datatypes : dataTypes
373+ defaultValues : defaultValues
374+ checkConstrains : checkConstrains];
375+ if (!isOK) goto finish;
376+
377+ if (indexQuery && [indexQuery count]) {
378+ for (NSString *query in indexQuery) {
379+ [db performQuery : query];
380+ isOK = ([db lastErrorID] == 0);
381+ if (!isOK) goto finish;
382+ }
383+ }
384+
385+finish:
386+ return isOK;
387+}
388+- (BOOL) createTable : (NSString *) tableName
389+ withColumns : (NSArray *)columns
390+ andDataTypes : (NSArray *)dataTypes
391+ andIndexQueries : (NSArray *)indexQuery
392+{
393+ BOOL isOK = NO;
394+
395+ SQLiteDB *db = [self databaseForCurrentThread];
396+ if (!db) return NO;
397+
398+ isOK = [db createTable : tableName
399+ withColumns : columns
400+ andDatatypes : dataTypes];
401+ if (!isOK) goto finish;
402+
403+ if (indexQuery && [indexQuery count]) {
404+ for (NSString *query in indexQuery) {
405+ [db performQuery : query];
406+ isOK = ([db lastErrorID] == 0);
407+ if (!isOK) goto finish;
408+ }
409+ }
410+
411+finish:
412+ return isOK;
413+}
414+- (BOOL) createFavoritesTable
415+{
416+ BOOL isOK = NO;
417+ NSString *query;
418+
419+ SQLiteDB *db = [self databaseForCurrentThread];
420+ if (!db) return NO;
421+
422+ if ([[db tables] containsObject : FavoritesTableName]) {
423+ return YES;
424+ }
425+
426+ query = [self queryForCreateIndexWithMultiColumn : [self commaSeparatedStringWithArray : [self favoritesColumns]]
427+ inTable : FavoritesTableName
428+ isUnique : YES];
429+ if ([db beginTransaction]) {
430+ isOK = [self createTable : FavoritesTableName
431+ withColumns : [self favoritesColumns]
432+ andDataTypes : [self favoritesDataTypes]
433+ andIndexQueries : [NSArray arrayWithObject : query]];
434+ if (!isOK) goto abort;
435+
436+ [db commitTransaction];
437+ [db save];
438+ }
439+
440+ return isOK;
441+
442+abort:
443+
444+ NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
445+ [db rollbackTransaction];
446+ return NO;
447+}
448+- (BOOL) createBoardInfoTable
449+{
450+ BOOL isOK = NO;
451+ NSString *query;
452+
453+ SQLiteDB *db = [self databaseForCurrentThread];
454+ if (!db) return NO;
455+
456+ if ([[db tables] containsObject : BoardInfoTableName]) {
457+ return YES;
458+ }
459+
460+ if ([db beginTransaction]) {
461+ isOK = [self createTable : BoardInfoTableName
462+ withColumns : [self boardInfoColumns]
463+ andDataTypes : [self boardInfoDataTypes]
464+ andIndexQueries : nil];
465+ if (!isOK) goto abort;
466+
467+ isOK = [db createIndexForColumn : BoardIDColumn
468+ inTable : BoardInfoTableName
469+ isUnique : YES];
470+ if (!isOK) goto abort;
471+
472+ isOK = [db createIndexForColumn : BoardURLColumn
473+ inTable : BoardInfoTableName
474+ isUnique : YES];
475+ if (!isOK) goto abort;
476+
477+ // dummy data for set BoardIDColumn to 0.
478+ query = [NSString stringWithFormat: @"INSERT INTO %@ (%@, %@, %@) VALUES(0, '', '')",
479+ BoardInfoTableName, BoardIDColumn, BoardURLColumn, BoardNameColumn];
480+ [db performQuery : query];
481+ isOK = ([db lastErrorID] == 0);
482+ if (!isOK) goto abort;
483+
484+ [db commitTransaction];
485+ [db save];
486+ }
487+
488+ return isOK;
489+
490+abort:
491+ NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
492+ [db rollbackTransaction];
493+ return NO;
494+}
495+- (BOOL) createThreadInfoTable
496+{
497+ BOOL isOK = NO;
498+ NSString *query;
499+ NSMutableArray *indexies;
500+
501+ SQLiteDB *db = [self databaseForCurrentThread];
502+ if (!db) return NO;
503+
504+ if ([[db tables] containsObject : ThreadInfoTableName]) {
505+ return YES;
506+ }
507+
508+ indexies =[NSMutableArray arrayWithCapacity:3];
509+ query = [self queryForCreateIndexWithMultiColumn : [NSString stringWithFormat: @"%@", BoardIDColumn]
510+ inTable : ThreadInfoTableName
511+ isUnique : NO];
512+ [indexies addObject:query];
513+ query = [self queryForCreateIndexWithMultiColumn : [NSString stringWithFormat: @"%@", ThreadIDColumn]
514+ inTable : ThreadInfoTableName
515+ isUnique : NO];
516+ [indexies addObject:query];
517+ query = [self queryForCreateIndexWithMultiColumn : [NSString stringWithFormat: @"%@,%@", BoardIDColumn, ThreadIDColumn]
518+ inTable : ThreadInfoTableName
519+ isUnique : YES];
520+ [indexies addObject:query];
521+ if ([db beginTransaction]) {
522+ id n = [NSNull null];
523+ id defaultValues = [NSArray arrayWithObjects:n,n,n,n,n,n,n,n,@"0",@"0",@"0",nil];
524+ id checkConstrains = [NSArray arrayWithObjects:n,n,n,n,n,n,n,n,
525+ [NSString stringWithFormat:@"%@ >= 0", ThreadAboneTypeColumn],
526+ [NSString stringWithFormat:@"%@ >= 0", ThreadLabelColumn],
527+ [NSString stringWithFormat:@"%@ IN (0,1)", IsDatOchiColumn],
528+ nil];
529+ isOK = [self createTable : ThreadInfoTableName
530+ columns : [self threadInfoColumns]
531+ dataTypes : [self threadInfoDataTypes]
532+ defaultValues : defaultValues
533+ checkConstrains : checkConstrains
534+ indexQueries : indexies];
535+ if (!isOK) goto abort;
536+
537+ // dummy data for set ThreadIDColumn to 0.
538+ query = [NSString stringWithFormat: @"INSERT INTO %@ (%@, %@, %@) VALUES(0, 0, '')",
539+ ThreadInfoTableName, BoardIDColumn, ThreadIDColumn, ThreadNameColumn];
540+ [db performQuery : query];
541+ isOK = ([db lastErrorID] == 0);
542+ if (!isOK) goto abort;
543+
544+ [db commitTransaction];
545+ [db save];
546+ }
547+
548+ return isOK;
549+
550+abort:
551+ NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
552+ [db rollbackTransaction];
553+ return NO;
554+}
555+- (BOOL) createBoardInfoHistoryTable
556+{
557+ BOOL isOK = NO;
558+
559+ SQLiteDB *db = [self databaseForCurrentThread];
560+ if (!db) return NO;
561+
562+ if ([[db tables] containsObject : BoardInfoHistoryTableName]) {
563+ return YES;
564+ }
565+
566+ if ([db beginTransaction]) {
567+ isOK = [self createTable : BoardInfoHistoryTableName
568+ withColumns : [self boardInfoHistoryColumns]
569+ andDataTypes : [self boardInfoHistoryDataTypes]
570+ andIndexQueries : nil];
571+ if (!isOK) goto abort;
572+
573+ isOK = [db createIndexForColumn : BoardIDColumn
574+ inTable : BoardInfoHistoryTableName
575+ isUnique : NO];
576+ if (!isOK) goto abort;
577+
578+ [db commitTransaction];
579+ [db save];
580+ }
581+
582+ return isOK;
583+
584+abort:
585+ NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
586+ [db rollbackTransaction];
587+ return NO;
588+}
589+
590+- (BOOL) createTempThreadNumberTable
591+{
592+ BOOL isOK = NO;
593+ NSString *query;
594+
595+ SQLiteDB *db = [self databaseForCurrentThread];
596+ if (!db) return NO;
597+
598+ if ([[db tables] containsObject : TempThreadNumberTableName]) {
599+ return YES;
600+ }
601+
602+ query = [self queryForCreateIndexWithMultiColumn : [NSString stringWithFormat: @"%@,%@", BoardIDColumn, ThreadIDColumn]
603+ inTable : TempThreadNumberTableName
604+ isUnique : YES];
605+
606+ if ([db beginTransaction]) {
607+ isOK = [self createTable : TempThreadNumberTableName
608+ withColumns : [self tempThreadNumberColumns]
609+ andDataTypes : [self tempThreadNumberDataTypes]
610+ andIndexQueries : [NSArray arrayWithObject : query]];
611+ if (!isOK) goto abort;
612+
613+ [db commitTransaction];
614+ [db save];
615+ }
616+
617+ return isOK;
618+
619+abort:
620+ NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
621+ [db rollbackTransaction];
622+ return NO;
623+}
624+
625+- (BOOL) createVersionTable
626+{
627+ BOOL isOK = NO;
628+
629+ SQLiteDB *db = [self databaseForCurrentThread];
630+ if (!db) return NO;
631+
632+ if ([[db tables] containsObject : VersionTableName]) {
633+ return YES;
634+ }
635+
636+ if ([db beginTransaction]) {
637+ isOK = [self createTable : VersionTableName
638+ withColumns : [NSArray arrayWithObject:VersionColumn]
639+ andDataTypes : [NSArray arrayWithObject:NUMERIC_NOTNULL]
640+ andIndexQueries : nil];
641+ if (!isOK) goto abort;
642+
643+ //
644+ id query = [NSString stringWithFormat: @"REPLACE INTO %@ (%@) VALUES(%ld)",
645+ VersionTableName, VersionColumn, sDatabaseFileVersion];
646+ [db performQuery : query];
647+ isOK = ([db lastErrorID] == 0);
648+ if (!isOK) goto abort;
649+
650+ [db commitTransaction];
651+ [db save];
652+ }
653+
654+ return isOK;
655+
656+abort:
657+ NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
658+ [db rollbackTransaction];
659+ return NO;
660+}
661+
662+ - (BOOL) createBoardThreadInfoView
663+ {
664+ BOOL isOK = NO;
665+ NSMutableString *query;
666+
667+ SQLiteDB *db = [self databaseForCurrentThread];
668+ if (!db) return NO;
669+
670+ if ([[db tables] containsObject : BoardThreadInfoViewName]) {
671+ return YES;
672+ }
673+
674+ query = [NSMutableString stringWithFormat: @"CREATE VIEW %@ AS\n", BoardThreadInfoViewName];
675+ [query appendFormat: @"\tSELECT *, (%@ - %@) AS %@ FROM %@ INNER JOIN %@",
676+ NumberOfAllColumn, NumberOfReadColumn, NumberOfDifferenceColumn,
677+ ThreadInfoTableName, BoardInfoTableName];
678+ [query appendFormat: @" USING(%@) ", BoardIDColumn];
679+
680+ if ([db beginTransaction]) {
681+ [db performQuery : query];
682+ isOK = ([db lastErrorID] == 0);
683+ if (!isOK) goto abort;
684+
685+ [db commitTransaction];
686+ [db save];
687+ }
688+
689+ return isOK;
690+
691+abort:
692+ NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
693+ [db rollbackTransaction];
694+ return NO;
695+ }
696+
697+
698+@end
699+
700+#pragma mark -
701+//NSString *tableNameForKey( NSString *sortKey )
702+//{
703+// NSString *sortCol = nil;
704+//
705+// if ([sortKey isEqualTo : CMRThreadTitleKey]) {
706+// sortCol = ThreadNameColumn;
707+// } else if ([sortKey isEqualTo : CMRThreadLastLoadedNumberKey]) {
708+// sortCol = NumberOfReadColumn;
709+// } else if ([sortKey isEqualTo : CMRThreadNumberOfMessagesKey]) {
710+// sortCol = NumberOfAllColumn;
711+// } else if ([sortKey isEqualTo : CMRThreadNumberOfUpdatedKey]) {
712+// sortCol = NumberOfDifferenceColumn;
713+// } else if ([sortKey isEqualTo : CMRThreadSubjectIndexKey]) {
714+// sortCol = TempThreadThreadNumberColumn;
715+// } else if ([sortKey isEqualTo : CMRThreadStatusKey]) {
716+// sortCol = ThreadStatusColumn;
717+// } else if ([sortKey isEqualTo : CMRThreadModifiedDateKey]) {
718+// sortCol = ModifiedDateColumn;
719+// } else if ([sortKey isEqualTo : ThreadPlistIdentifierKey]) {
720+// sortCol = ThreadIDColumn;
721+// } else if ([sortKey isEqualTo : ThreadPlistBoardNameKey]) {
722+// sortCol = BoardNameColumn;
723+// } else if ([sortKey isEqualTo : LastWrittenDateColumn]) {
724+// sortCol = LastWrittenDateColumn;
725+// } else if ([sortKey isEqualTo : BSThreadEnergyKey]) {
726+// sortCol = sortKey;
727+// }
728+//
729+// return [sortCol lowercaseString];
730+//}
731+
--- /dev/null
+++ b/DatabaseUpdater.h
@@ -0,0 +1,26 @@
1+//
2+// DatabaseUpdater.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 07/02/03.
6+// Copyright 2007 BathyScaphe Project. All rights reserved.
7+//
8+
9+#import <Cocoa/Cocoa.h>
10+
11+#import "DatabaseManager.h"
12+
13+@interface DatabaseUpdater : NSObject
14+{
15+ IBOutlet NSWindow *window;
16+ IBOutlet NSProgressIndicator *progress;
17+ IBOutlet NSTextField *information;
18+}
19+
20++ (BOOL)updateFrom:(NSInteger)fromVersion to:(NSInteger)toVersion;
21+
22+@end
23+
24+@interface DatabaseUpdater(UpdateMethod)
25+- (BOOL) updateDB;
26+@end
\ No newline at end of file
--- /dev/null
+++ b/DatabaseUpdater.m
@@ -0,0 +1,462 @@
1+//
2+// DatabaseUpdater.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 07/02/03.
6+// Copyright 2007 BathyScaphe Project. All rights reserved.
7+//
8+
9+#import "DatabaseUpdater.h"
10+
11+@interface DatabaseUpdater(ForSubclasses)
12+- (BOOL)useProgressPanel;
13+
14+- (void)setInformationText:(NSString *)information;
15+@end
16+
17+/*
18+ * Version 0: 初期データベース
19+ * Version 1: Version Table を導入
20+ * Version 2: BoardInfoHistory 上のインデックスを修正
21+ * Version 3: Version Table を廃止。 ThreadInfo Table に IsDatOchi カラムを追加
22+ * Version 4: Favorites Table を廃止。 ThreadInfo Table に IsFavorite カラムを追加
23+ * Version 5: BoardThreadInfoView を変更。 isCached, isUpdated, isNew, isHeadModified カラムを追加
24+ * Version 6: This is mine!
25+ * Version 7: ThreadInfo Table の ThreadLabelColumn と ThreadAboneTypeColumn に NOT NULL 制約を追加
26+ */
27+
28+@interface DatabaseUpdaterOneToTow : DatabaseUpdater
29+@end
30+@interface DatabaseUpdaterToThree : DatabaseUpdater
31+@end
32+@interface DatabaseUpdaterToFour : DatabaseUpdater
33+@end
34+@interface DatabaseUpdaterToFive : DatabaseUpdater
35+@end
36+@interface DatabaseUpdaterToSeven : DatabaseUpdater
37+@end
38+
39+
40+@implementation DatabaseUpdater
41+
42+- (id)init
43+{
44+ [super init];
45+
46+ if([self useProgressPanel]) {
47+ [NSBundle loadNibNamed:@"DatabaseUpdatePanel" owner:self];
48+
49+ [self setInformationText:@""];
50+
51+ NSRect mainScreenFrame = [[NSScreen mainScreen] visibleFrame];
52+ NSPoint center = NSMakePoint(NSMidX(mainScreenFrame), NSMidY(mainScreenFrame));
53+
54+ NSRect windowFrame = [window frame];
55+ NSPoint origin = NSMakePoint(center.x - windowFrame.size.width / 2, center.y - windowFrame.size.height / 2 + 100);
56+ [window setFrameOrigin:origin];
57+
58+ [window makeKeyAndOrderFront:nil];
59+ [progress setUsesThreadedAnimation:YES];
60+ [progress startAnimation:nil];
61+ }
62+
63+ return self;
64+}
65+- (void)dealloc
66+{
67+ [progress stopAnimation:nil];
68+ [window close];
69+
70+ [super dealloc];
71+}
72+
73+- (BOOL)backupDatabase
74+{
75+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
76+ NSString *databasePath = [db databasePath];
77+ if(!databasePath) {
78+ NSLog(@"Could not open database");
79+ return NO;
80+ }
81+
82+ NSString *backupPath = databasePath;
83+ NSFileManager *fm = [NSFileManager defaultManager];
84+ BOOL exist = YES;
85+ do {
86+ backupPath = [backupPath stringByAppendingString:@"~"];
87+ exist = [fm fileExistsAtPath:backupPath];
88+ } while(exist);
89+
90+// if(![fm copyPath:databasePath toPath:backupPath handler:nil]) {
91+ if (![fm copyItemAtPath:databasePath toPath:backupPath error:NULL]) {
92+ NSLog(@"Could not backup database");
93+ return NO;
94+ }
95+
96+ return YES;
97+}
98+
99++ (BOOL)updateFrom:(NSInteger)fromVersion to:(NSInteger)toVersion
100+{
101+ BOOL result = YES;
102+
103+ if(fromVersion < 0) return YES;
104+
105+ if(fromVersion < 2 && toVersion >= 2) {
106+ result = [[[[DatabaseUpdaterOneToTow alloc] init] autorelease] updateDB];
107+ }
108+ if(!result) return result;
109+
110+ if(fromVersion < 3 && toVersion >= 3) {
111+ result = [[[[DatabaseUpdaterToThree alloc] init] autorelease] updateDB];
112+ }
113+ if(!result) return result;
114+
115+ if(fromVersion < 4 && toVersion >= 4) {
116+ result = [[[[DatabaseUpdaterToFour alloc] init] autorelease] updateDB];
117+ }
118+ if(!result) return result;
119+
120+ if(fromVersion < 5 && toVersion >= 5) {
121+ result = [[[[DatabaseUpdaterToFive alloc] init] autorelease] updateDB];
122+ }
123+ if(!result) return result;
124+
125+ if(fromVersion < 7 && toVersion >= 7) {
126+ result = [[[[DatabaseUpdaterToSeven alloc] init] autorelease] updateDB];
127+ }
128+ if(!result) return result;
129+
130+ return result;
131+}
132+
133+- (BOOL)updateVersion:(NSInteger)newVersion usingDB:(SQLiteDB *)db
134+{
135+ if (!db) return NO;
136+
137+ [db performQuery : [NSString stringWithFormat: @"PRAGMA user_version = %ld;",
138+ (long)newVersion]];
139+ if([db lastErrorID] != noErr) return NO;
140+
141+ return YES;
142+}
143+
144+- (void)setInformationText:(NSString *)anInformation
145+{
146+ information.stringValue = anInformation;
147+ [information display];
148+}
149++ (NSString *)localizableStringsTableName
150+{
151+ return @"DatabaseUpdater";
152+}
153+
154+@end
155+
156+
157+/*
158+ * Version 0 -> 2
159+ * Version 1 -> 2
160+ *
161+ * BoardInfoHistoryTableName 上の BoardIDColumn のインデックスが UNIQUE インデックスになっていたのを
162+ * 通常のインデックスに変更
163+ */
164+@implementation DatabaseUpdaterOneToTow
165+- (BOOL) updateDB
166+{
167+ BOOL isOK = NO;
168+
169+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
170+ if (!db) return NO;
171+
172+ if ([db beginTransaction]) {
173+ isOK = [db deleteIndexForColumn : BoardIDColumn inTable : BoardInfoHistoryTableName];
174+ if (!isOK) goto abort;
175+
176+ isOK = [db createIndexForColumn : BoardIDColumn
177+ inTable : BoardInfoHistoryTableName
178+ isUnique : NO];
179+ if (!isOK) goto abort;
180+
181+ if(![self updateVersion : 2 usingDB : db]) goto abort;
182+
183+ [db commitTransaction];
184+ [db save];
185+ }
186+
187+ return isOK;
188+
189+abort:
190+ NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
191+ [db rollbackTransaction];
192+ return NO;
193+}
194+@end
195+
196+/*
197+ * Version 2 -> 3
198+ *
199+ * ThreadInfo Table に IsDatOchiColumn カラムを追加
200+ */
201+@implementation DatabaseUpdaterToThree
202+- (BOOL) updateDB
203+{
204+ BOOL isOK = NO;
205+
206+ SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
207+ if (!db) return NO;
208+
209+ if ([db beginTransaction]) {
210+ id query = [NSString stringWithFormat: @"ALTER TABLE %@ ADD COLUMN %@ %@ DEFAULT 0 CHECK(%@ IN (0,1))",
211+ ThreadInfoTableName, IsDatOchiColumn, INTEGER_NOTNULL, IsDatOchiColumn];
212+ [db cursorForSQL : query];
213+ if ([db lastErrorID] != 0) goto abort;
214+
215+ if(![self updateVersion : 3 usingDB : db]) goto abort;
216+
217+ [db commitTransaction];
218+ [db save];
219+ }
220+
221+ return isOK;
222+
223+abort:
224+ NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
225+ [db rollbackTransaction];
226+ return NO;
227+}
228+@end
229+
230+/*
231+ * Version 3 -> 4
232+ *
233+ * ThreadInfo Table に IsFavoriteColumn カラムを追加
234+ */
235+@implementation DatabaseUpdaterToFour
236+
237+- (BOOL) updateDB
238+{
239+ return YES;
240+}
241+@end
242+
243+/*
244+ * Version 4 -> 5
245+ *
246+ * BoardThreadInfoView を変更。 isCached, isUpdated, isNew, isHeadModified カラムを追加
247+ */
248+@implementation DatabaseUpdaterToFive
249+//- (BOOL) updateDB
250+//{
251+// BOOL isOK = NO;
252+//
253+// SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
254+// if (!db) return NO;
255+//
256+// if ([db beginTransaction]) {
257+// id query = [NSString stringWithFormat: @"DROP VIEW %@;", BoardThreadInfoViewName];
258+// [db cursorForSQL : query];
259+// if ([db lastErrorID] != 0) goto abort;
260+//
261+// query = [NSMutableString stringWithFormat: @"CREATE VIEW %@ AS\n", BoardThreadInfoViewName];
262+// [query appendFormat: @"\tSELECT *, (%@ - %@) AS %@\n",
263+// NumberOfAllColumn, NumberOfReadColumn, NumberOfDifferenceColumn];
264+// [query appendFormat: @", NOT(%@ - %ld) AS %@\n",
265+// ThreadStatusColumn, (long)ThreadLogCachedStatus, IsCachedColumn];
266+// [query appendFormat: @", NOT(%@ - %ld) AS %@\n",
267+// ThreadStatusColumn, (long)ThreadUpdatedStatus, IsUpdatedColumn];
268+// [query appendFormat: @", NOT(%@ - %ld) AS %@\n",
269+// ThreadStatusColumn, (long)ThreadNewCreatedStatus, IsNewColumn];
270+// [query appendFormat: @", NOT(%@ - %ld) AS %@\n",
271+// ThreadStatusColumn, (long)ThreadHeadModifiedStatus, IsHeadModifiedColumn];
272+// [query appendFormat: @"FROM %@ INNER JOIN %@ USING(%@) ",
273+// ThreadInfoTableName, BoardInfoTableName, BoardIDColumn];
274+//
275+// [db cursorForSQL : query];
276+// if ([db lastErrorID] != 0) goto abort;
277+//
278+//
279+// if(![self updateVersion : 5 usingDB : db]) goto abort;
280+//
281+// [db commitTransaction];
282+// [db save];
283+// }
284+//
285+// return isOK;
286+//
287+//abort:
288+// NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
289+// [db rollbackTransaction];
290+// return NO;
291+//}
292+@end
293+
294+
295+/*
296+ * Version 5 -> 7
297+ *
298+ * BoardThreadInfoView を変更。 isCached, isUpdated, isNew, isHeadModified カラムを追加
299+ */
300+@implementation DatabaseUpdaterToSeven
301+//- (BOOL)useProgressPanel
302+//{
303+// return YES;
304+//}
305+//- (BOOL) updateDB
306+//{
307+// BOOL isOK = NO;
308+//
309+// [self backupDatabase];
310+// [self setInformationText:[self localizedString:@"prepare database"]];
311+//
312+// SQLiteDB *db = [[DatabaseManager defaultManager] databaseForCurrentThread];
313+// if (!db) return NO;
314+//
315+// if ([db beginTransaction]) {
316+// NSString *tempTable = @"temporaryTable";
317+//
318+// // create table copy on memory
319+// id query = [NSString stringWithFormat: @"CREATE TEMP TABLE %@ AS SELECT * FROM %@",
320+// tempTable, ThreadInfoTableName];
321+// [db cursorForSQL: query];
322+// if ([db lastErrorID] != 0) goto abort;
323+//
324+// // drop original
325+// [db cursorForSQL:@"DROP TABLE ThreadInfo"];
326+// if ([db lastErrorID] != 0) goto abort;
327+//
328+// query = [NSString stringWithFormat:
329+// @"CREATE TABLE %@"
330+// "(%@ INTEGER NOT NULL ,"
331+// "%@ INTEGER NOT NULL , "
332+// "%@ TEXT NOT NULL , "
333+// "%@ NUMERIC, "
334+// "%@ NUMERIC , "
335+// "%@ NUMERIC , "
336+// "%@ NUMERIC , "
337+// "%@ NUMERIC , "
338+// "%@ INTEGER NOT NULL DEFAULT 0 CHECK(%@ >= 0), "
339+// "%@ INTEGER NOT NULL DEFAULT 0 CHECK(%@ >= 0), "
340+// "%@ INTEGER NOT NULL DEFAULT 0 CHECK(%@ IN (0,1)))"
341+// ,
342+// ThreadInfoTableName,
343+// BoardIDColumn,
344+// ThreadIDColumn,
345+// ThreadNameColumn,
346+// NumberOfAllColumn,
347+// NumberOfReadColumn,
348+// ModifiedDateColumn,
349+// LastWrittenDateColumn,
350+// ThreadStatusColumn,
351+// ThreadAboneTypeColumn, ThreadAboneTypeColumn,
352+// ThreadLabelColumn, ThreadLabelColumn,
353+// IsDatOchiColumn, IsDatOchiColumn];
354+// [db cursorForSQL: query];
355+// if ([db lastErrorID] != 0) goto abort;
356+//
357+// // create indexes
358+// query = [NSString stringWithFormat:
359+// @"CREATE INDEX ThreadInfo_boardID_IDX ON %@ (%@)",
360+// ThreadInfoTableName, BoardIDColumn];
361+// [db cursorForSQL: query];
362+// if ([db lastErrorID] != 0) goto abort;
363+//
364+// query = [NSString stringWithFormat:
365+// @"CREATE UNIQUE INDEX ThreadInfo_boardID_threadID_IDX ON %@ (%@,%@)",
366+// ThreadInfoTableName, BoardIDColumn, ThreadIDColumn];
367+// [db cursorForSQL: query];
368+// if ([db lastErrorID] != 0) goto abort;
369+//
370+// query = [NSString stringWithFormat:
371+// @"CREATE INDEX ThreadInfo_threadID_IDX ON %@ (%@)",
372+// ThreadInfoTableName, ThreadIDColumn];
373+// [db cursorForSQL: query];
374+// if ([db lastErrorID] != 0) goto abort;
375+//
376+//
377+// // register original data
378+// [self setInformationText:[self localizedString:@"register to new database"]];
379+// id <SQLiteMutableCursor> result;
380+//
381+// query = [NSString stringWithFormat:@"SELECT count(*) AS c FROM %@", tempTable];
382+// result = [db cursorForSQL:query];
383+// if ([db lastErrorID] != 0) goto abort;
384+// [progress setMaxValue:[[result valueForColumn:@"c" atRow:0] integerValue]];
385+// progress.doubleValue = 0;
386+// [progress setIndeterminate:NO];
387+//
388+// query = [NSString stringWithFormat:
389+// @"SELECT * FROM %@", tempTable];
390+// result = [db cursorForSQL: query];
391+// if ([db lastErrorID] != 0) goto abort;
392+//
393+// query = [[NSString alloc] initWithFormat:
394+// @"INSERT INTO %@"
395+// "(%@, %@, %@, "
396+// "%@, %@, "
397+// "%@, %@, "
398+// "%@, %@, "
399+// "%@, %@) "
400+// "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
401+// ,
402+// ThreadInfoTableName,
403+// BoardIDColumn, ThreadIDColumn, ThreadNameColumn,
404+// NumberOfAllColumn, NumberOfReadColumn,
405+// ModifiedDateColumn, LastWrittenDateColumn,
406+// ThreadStatusColumn, ThreadAboneTypeColumn,
407+// ThreadLabelColumn, IsDatOchiColumn];
408+// SQLiteReservedQuery *rQuery = [db reservedQuery:query];
409+//
410+// id aNull = [NSNull null];
411+// NSUInteger i, count;
412+// for(i = 0, count = [result rowCount]; i < count; i++) {
413+// id <SQLiteRow> row = [result rowAtIndex:i];
414+//
415+// [rQuery cursorWithFormat:"jjsjjjjjjjj",
416+// [row valueForColumn:BoardIDColumn],
417+// [row valueForColumn:ThreadIDColumn],
418+// [row valueForColumn:ThreadNameColumn],
419+// [row valueForColumn:NumberOfAllColumn],
420+// [row valueForColumn:NumberOfReadColumn],
421+// [row valueForColumn:ModifiedDateColumn],
422+// [row valueForColumn:LastWrittenDateColumn],
423+// [row valueForColumn:ThreadStatusColumn],
424+// [row valueForColumn:ThreadAboneTypeColumn] == aNull ? [NSNumber numberWithInt:0] : [row valueForColumn:ThreadAboneTypeColumn],
425+// [row valueForColumn:ThreadLabelColumn] == aNull ? [NSNumber numberWithInt:0] : [row valueForColumn:ThreadLabelColumn],
426+// [row valueForColumn:IsDatOchiColumn]
427+// ];
428+//
429+// [NSApp nextEventMatchingMask:NSAnyEventMask
430+// untilDate:[NSDate dateWithTimeIntervalSinceNow:0.000001]
431+// inMode:NSDefaultRunLoopMode
432+// dequeue:NO];
433+// progress.doubleValue += 1;
434+// }
435+//
436+// // drop temporary table
437+// query = [NSString stringWithFormat: @"DROP TABLE %@", tempTable];
438+// [db cursorForSQL: query];
439+// if ([db lastErrorID] != 0) goto abort;
440+//
441+// if(![self updateVersion: 7 usingDB: db]) goto abort;
442+//
443+// [db commitTransaction];
444+// [db save];
445+// }
446+//
447+// // vacuum
448+// [self setInformationText:[self localizedString:@"finalize database"]];
449+// [progress setIndeterminate:YES];
450+// [progress startAnimation:nil];
451+// [db cursorForSQL:@"VACUUM"];
452+// if ([db lastErrorID] != 0) goto abort;
453+//
454+// return isOK;
455+//
456+//abort:
457+// NSLog(@"Fail Database operation. Reason: \n%@", [db lastError]);
458+// [db rollbackTransaction];
459+//
460+// return NO;
461+//}
462+@end
--- /dev/null
+++ b/SQLiteDB.h
@@ -0,0 +1,147 @@
1+//
2+// SQLiteDB.h
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 05/12/12.
6+// Copyright 2005 BathyScaphe Project. All rights reserved.
7+//
8+
9+#import <Cocoa/Cocoa.h>
10+
11+#import "sqlite3.h"
12+
13+@protocol SQLiteRow <NSObject>
14+- (NSUInteger) columnCount;
15+- (NSArray *) columnNames;
16+- (id) valueForColumn : (NSString *) column;
17+@end
18+
19+@protocol SQLiteCursor <NSObject>
20+- (NSUInteger) columnCount;
21+- (NSArray *) columnNames;
22+
23+- (NSUInteger) rowCount;
24+- (id) valueForColumn : (NSString *) column atRow : (NSUInteger) row;
25+- (NSArray *) valuesForColumn : (NSString *) column;
26+- (id <SQLiteRow>) rowAtIndex : (NSUInteger) row;
27+- (NSArray *) arrayForTableView;
28+@end
29+
30+@protocol SQLiteMutableCursor <SQLiteCursor>
31+- (BOOL) appendRow : (id <SQLiteRow>) row;
32+- (BOOL) appendCursor : (id <SQLiteCursor>) cursor;
33+@end
34+
35+@class SQLiteReservedQuery;
36+
37+@interface SQLiteDB : NSObject
38+{
39+ NSString *mPath;
40+ sqlite3 *mDatabase;
41+
42+ BOOL _isOpen;
43+ BOOL _transaction;
44+
45+ NSMutableDictionary *reservedQueries;
46+}
47+
48+#ifdef USE_NSZONE_MALLOC
49++ (NSZone *)allocateZone;
50+#endif
51+
52+- (id) initWithDatabasePath : (NSString *) path;
53+
54++ (NSString *) prepareStringForQuery : (NSString *) inString;
55+
56+- (void) setDatabaseFile : (NSString *) path;
57+- (NSString *) databasePath;
58+
59+- (sqlite3 *) rowDatabase;
60+
61+- (BOOL) open;
62+- (NSInteger) close;
63+- (BOOL) isDatabaseOpen;
64+
65+- (NSString *) lastError;
66+- (NSInteger) lastErrorID;
67+
68+- (id <SQLiteMutableCursor>) cursorForSQL : (NSString *) sqlString;
69+- (id <SQLiteMutableCursor>) performQuery : (NSString *) sqlString; // alias cursorForSQL. for compatible QuickLite.
70+
71+- (SQLiteReservedQuery *) reservedQuery : (NSString *) sqlString;
72+
73+@end
74+
75+@interface SQLiteDB (DatabaseAccessor)
76+
77+- (NSArray *) tables;
78+
79+- (BOOL) beginTransaction;
80+- (BOOL) commitTransaction;
81+- (BOOL) rollbackTransaction;
82+
83+- (BOOL) save; // do nothing. for compatible QuickLite.
84+
85+- (BOOL) createTable : (NSString *) table withColumns : (NSArray *) columns andDatatypes : (NSArray *) datatypes;
86+- (BOOL) createTable : (NSString *) table
87+ columns : (NSArray *) columns
88+ datatypes : (NSArray *) datatypes
89+ defaultValues : (NSArray *)defaultValues
90+ checkConstrains : (NSArray *)checkConstrains;
91+- (BOOL) createTemporaryTable : (NSString *) table withColumns : (NSArray *) columns andDatatypes : (NSArray *) datatypes;
92+- (BOOL) createTemporaryTable : (NSString *) table
93+ columns : (NSArray *) columns
94+ datatypes : (NSArray *) datatypes
95+ defaultValues : (NSArray *)defaultValues
96+ checkConstrains : (NSArray *)checkConstrains;
97+
98+
99+- (BOOL) createIndexForColumn : (NSString *) column inTable : (NSString *) table isUnique : (BOOL) isUnique;
100+
101+
102+- (BOOL) deleteIndexForColumn:(NSString *)column inTable:(NSString *)table;
103+
104+@end
105+
106+@interface SQLiteDB (ResercedQuerySupport)
107+- (SQLiteReservedQuery *)reservedQueryWithKey:(NSString *)key;
108+- (void)setReservedQuery:(SQLiteReservedQuery *)query forKey:(NSString *)key;
109+@end
110+
111+@interface SQLiteReservedQuery : NSObject
112+{
113+ sqlite3_stmt *m_stmt;
114+}
115++ (id) sqliteReservedQueryWithQuery : (NSString *) sqlString usingSQLiteDB : (SQLiteDB *) db;
116+- (id) initWithQuery : (NSString *) sqlString usingSQLiteDB : (SQLiteDB *) db;
117+
118+- (id <SQLiteMutableCursor>) cursorForBindValues : (NSArray *) values;
119+
120+#define F_NSString "s"
121+#define F_Int "i"
122+#define F_Double "d"
123+#define F_Null "n"
124+#define F_NSNumberOfInt "j"
125+#define F_NSNumberOfDouble "e"
126+
127+- (id <SQLiteMutableCursor>)cursorWithFormat:(const char *)format, ...;
128+@end
129+
130+
131+extern NSString *QLString; // alias TEXT. for compatible QuickLite.
132+extern NSString *QLNumber; // alias NUMERIC. for compatible QuickLite.
133+extern NSString *QLDateTime; // alias TEXT. for compatible QuickLite. NOTE :
134+
135+extern NSString *INTERGER_PRIMARY_KEY;
136+extern NSString *TEXT_NOTNULL;
137+extern NSString *TEXT_UNIQUE;
138+extern NSString *TEXT_NOTNULL_UNIQUE;
139+extern NSString *INTEGER_NOTNULL;
140+extern NSString *INTERGER_UNIQUE;
141+extern NSString *INTERGER_NOTNULL_UNIQUE;
142+extern NSString *NUMERIC_NOTNULL;
143+extern NSString *NUMERIC_UNIQUE;
144+extern NSString *NUMERIC_NOTNULL_UNIQUE;
145+extern NSString *NONE_NOTNULL;
146+extern NSString *NONE_UNIQUE;
147+extern NSString *NONE_NOTNULL_UNIQUE;
--- /dev/null
+++ b/SQLiteDB.m
@@ -0,0 +1,961 @@
1+//
2+// SQLiteDB.m
3+// BathyScaphe
4+//
5+// Created by Hori,Masaki on 05/12/12.
6+// Copyright 2005 BathyScaphe Project. All rights reserved.
7+//
8+
9+#import "SQLiteDB.h"
10+
11+#import "sqlite3.h"
12+
13+#import <sys/time.h>
14+
15+@interface NSDictionary (SQLiteRow) <SQLiteRow>
16+@end
17+@interface NSMutableDictionary (SQLiteMutableCursor) <SQLiteMutableCursor>
18+@end
19+
20+@implementation SQLiteDB
21+
22+
23+static NSString *TestColumnNames = @"ColumnNames";
24+static NSString *TestValues = @"Values";
25+
26+
27+NSString *QLString = @"TEXT";
28+NSString *QLNumber = @"NUMERIC";
29+NSString *QLDateTime = @"TEXT";
30+
31+NSString *INTERGER_PRIMARY_KEY =@"INTEGER PRIMARY KEY";
32+
33+NSString *TEXT_NOTNULL = @"TEXT NOT NULL";
34+NSString *TEXT_UNIQUE = @"TEXT UNIQUE";
35+NSString *TEXT_NOTNULL_UNIQUE = @"TEXT UNIQUE NOT NULL";
36+NSString *INTEGER_NOTNULL = @"INTEGER NOT NULL";
37+NSString *INTEGER_UNIQUE = @"INTEGER UNIQUE";
38+NSString *INTEGER_NOTNULL_UNIQUE = @"INTEGER UNIQUE NOT NULL";
39+NSString *NUMERIC_NOTNULL = @"NUMERIC NOT NULL";
40+NSString *NUMERIC_UNIQUE = @"NUMERIC UNIQUE";
41+NSString *NUMERIC_NOTNULL_UNIQUE = @"NUMERIC UNIQUE NOT NULL";
42+NSString *NONE_NOTNULL = @"NOT NULL";
43+NSString *NONE_UNIQUE = @"UNIQUE";
44+NSString *NONE_NOTNULL_UNIQUE = @"UNIQUE NOT NULL";
45+
46+double debug_clock()
47+{
48+ double t;
49+ struct timeval tv;
50+ gettimeofday(&tv, NULL);
51+ t = tv.tv_sec + (double)tv.tv_usec*1e-6;
52+ return t;
53+}
54+void debug_log(const char *p,...)
55+{
56+ NSUserDefaults *d = [NSUserDefaults standardUserDefaults];
57+
58+ if([d boolForKey:@"SQLITE_DEBUG_LOG"]) {
59+ va_list args;
60+ va_start(args, p);
61+ vfprintf(stderr, p, args);
62+ }
63+}
64+void debug_log_time(double t1, double t2)
65+{
66+ debug_log( "total time : \t%02.4lf\n",(t2) - (t1));
67+}
68+
69+NSInteger progressHandler(void *obj)
70+{
71+ // NSLog(@"Enter progressHandler ->%@", obj);
72+
73+ return SQLITE_OK;
74+}
75+
76+
77+
78+static NSZone *allocateZone = NULL;
79++ (NSZone *)allocateZone
80+{
81+ return allocateZone;
82+}
83+#ifdef USE_NSZONE_MALLOC
84+extern void setSQLiteZone(NSZone *zone);
85+
86++ (void)initialize
87+{
88+ static BOOL isFirst = YES;
89+
90+ if(isFirst) {
91+ isFirst = NO;
92+
93+ allocateZone = NSCreateZone(NSPageSize(), NSPageSize(), NO);
94+ NSAssert(allocateZone, @"Can NOT allocate zone.");
95+
96+ NSSetZoneName(allocateZone, @"SQLite Zone");
97+ setSQLiteZone(allocateZone);
98+ }
99+}
100+#endif
101+
102++ (NSString *) prepareStringForQuery : (NSString *) inString
103+{
104+ NSString *str;
105+ const char *p;
106+ char *q;
107+
108+ p = [inString UTF8String];
109+ q = sqlite3_mprintf("%q", p);
110+ str = [NSString stringWithUTF8String : q];
111+ sqlite3_free(q);
112+
113+ return str;
114+}
115+
116+- (id) initWithDatabasePath : (NSString *) path
117+{
118+ if (self = [super init]) {
119+ [self setDatabaseFile : path];
120+ _isOpen = NO;
121+ reservedQueries = [[NSMutableDictionary alloc] init];
122+ }
123+
124+ return self;
125+}
126+
127+- (void) dealloc
128+{
129+ [self close];
130+ [mPath release];
131+ [reservedQueries release];
132+
133+ [super dealloc];
134+}
135+
136+- (NSString *) lastError
137+{
138+ if (!mDatabase) return nil;
139+
140+ return [NSString stringWithUTF8String : sqlite3_errmsg(mDatabase)];
141+}
142+- (NSInteger) lastErrorID
143+{
144+ if (!mDatabase) return 0;
145+
146+ return sqlite3_errcode(mDatabase);
147+}
148+
149+- (void) setDatabaseFile : (NSString *) path
150+{
151+ id temp = mPath;
152+ mPath = [path copy];
153+ [temp release];
154+
155+ [self open];
156+}
157+- (NSString *) databasePath
158+{
159+ return [NSString stringWithString : mPath];
160+}
161+
162+- (sqlite3 *) rowDatabase
163+{
164+ return mDatabase;
165+}
166+
167+- (BOOL) open
168+{
169+ const char *filepath = [mPath fileSystemRepresentation];
170+ NSInteger result;
171+
172+ if ([self isDatabaseOpen]) {
173+ [self close];
174+ }
175+
176+// UTILDebugWrite(@"Start Open database.");
177+ result = sqlite3_open_v2(filepath, &mDatabase, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
178+ if(result != SQLITE_OK) {
179+ NSLog(@"Can not open database. \nFile -> %@.\nError Code : %ld", mPath, (long)result);
180+ [mPath release];
181+ mPath = nil;
182+ mDatabase = NULL;
183+
184+ return NO;
185+ }/* else {
186+ sqlite3_progress_handler(mDatabase, 1, progressHandler, self);
187+ }*/
188+
189+ _isOpen = YES;
190+
191+ return YES;
192+}
193+- (NSInteger) close
194+{
195+ NSInteger result = NO;
196+ const NSInteger challengeTime = 1000;
197+ NSInteger count = 0;
198+
199+ [reservedQueries removeAllObjects];
200+
201+ if (mDatabase) {
202+// UTILDebugWrite(@"Start Closing database.");
203+ sqlite3_stmt *pStmt;
204+ while( (pStmt = sqlite3_next_stmt(mDatabase, 0))!=0 ){
205+ sqlite3_finalize(pStmt);
206+ }
207+ do {
208+ result = sqlite3_close(mDatabase);
209+ count++;
210+ } while (result == SQLITE_BUSY && count < challengeTime);
211+ if(count == challengeTime) {
212+ NSLog(@"give up! can not close database.");
213+ }
214+ mDatabase = NULL;
215+
216+// UTILDebugWrite(@"End Closing database.");
217+ }
218+
219+ _isOpen = NO;
220+
221+ return result;
222+}
223+- (BOOL) isDatabaseOpen
224+{
225+ return _isOpen;
226+}
227+
228+id <SQLiteRow> makeRowFromSTMT(sqlite3_stmt *stmt, NSArray *columns)
229+{
230+ NSNull *nsNull = [NSNull null];
231+
232+ CFMutableDictionaryRef result;
233+ NSInteger i, columnCount = sqlite3_column_count(stmt);
234+
235+ result = CFDictionaryCreateMutable(kCFAllocatorDefault,
236+ columnCount,
237+ &kCFTypeDictionaryKeyCallBacks,
238+ &kCFTypeDictionaryValueCallBacks);
239+ if(!result) return nil;
240+
241+ for (i = 0; i < columnCount; i++) {
242+ // const char *columnName = sqlite3_column_name(stmt, i);
243+ const unsigned char *value = sqlite3_column_text(stmt, i);
244+ id v = nil;
245+
246+ if (value) {
247+ v = (id)CFStringCreateWithCString(kCFAllocatorDefault,
248+ (const char*)value,
249+ kCFStringEncodingUTF8);
250+ }
251+ if (v) {
252+ CFDictionaryAddValue(result, CFArrayGetValueAtIndex((CFArrayRef)columns, i), v);
253+ }
254+
255+
256+ if(v && v != nsNull) {
257+ CFRelease(v);
258+ }
259+ }
260+
261+ return [(id)result autorelease];
262+}
263+
264+NSArray *columnsFromSTMT(sqlite3_stmt *stmt)
265+{
266+ CFMutableArrayRef result;
267+ NSInteger i, columnCount = sqlite3_column_count(stmt);
268+
269+ result = CFArrayCreateMutable(kCFAllocatorDefault,
270+ columnCount,
271+ &kCFTypeArrayCallBacks);
272+ if(!result) return nil;
273+
274+ for (i = 0; i < columnCount; i++) {
275+ const char *columnName = sqlite3_column_name(stmt, i);
276+ CFStringRef colStr;
277+ CFMutableStringRef lowerColStr;
278+
279+ colStr = CFStringCreateWithCString(kCFAllocatorDefault,
280+ columnName,
281+ kCFStringEncodingUTF8);
282+ lowerColStr = CFStringCreateMutableCopy(kCFAllocatorDefault,
283+ CFStringGetLength(colStr),
284+ colStr);
285+ CFStringLowercase(lowerColStr, CFLocaleGetSystem());
286+ CFArrayAppendValue(result, lowerColStr);
287+ CFRelease(colStr);
288+ CFRelease(lowerColStr);
289+ }
290+
291+ return [(id)result autorelease];
292+}
293+
294+NSArray *valuesForSTMT(sqlite3_stmt *stmt, NSArray *culumns)
295+{
296+ NSInteger result;
297+ BOOL finishFetch = NO;
298+ id <SQLiteRow> dict;
299+ CFMutableArrayRef values;
300+
301+ values = CFArrayCreateMutable(kCFAllocatorDefault,
302+ 0,
303+ &kCFTypeArrayCallBacks);
304+ if(!values) return nil;
305+
306+ NSInteger busyCount = 0;
307+ do {
308+ BOOL updateCursor = NO;
309+
310+ result = sqlite3_step(stmt);
311+
312+ switch (result) {
313+ case SQLITE_BUSY :
314+ busyCount++;
315+ break;
316+ case SQLITE_OK :
317+ case SQLITE_DONE :
318+ finishFetch = YES;
319+ busyCount = 0;
320+ break;
321+ case SQLITE_ROW :
322+ updateCursor = YES;
323+ busyCount = 0;
324+ break;
325+ case SQLITE_SCHEMA:
326+ continue;
327+ default :
328+ // sqlite3_finalize(stmt);
329+ CFRelease(values);
330+ return nil;
331+ break;
332+ }
333+
334+ if (updateCursor) {
335+ dict = makeRowFromSTMT(stmt, culumns);
336+ if (dict) {
337+ CFArrayAppendValue(values, dict);
338+ }
339+ }
340+
341+ if(busyCount>1000) {
342+ fprintf(stderr, "Give up! sqlite3_step() return SQLITE_BUSY thousand times.\n");
343+ CFRelease(values);
344+ return nil;
345+ }
346+
347+ } while (!finishFetch);
348+
349+ return [(id)values autorelease];
350+}
351+
352+id<SQLiteMutableCursor> cursorFromSTMT(sqlite3_stmt *stmt)
353+{
354+ id columns, values;
355+ id<SQLiteMutableCursor> cursor;
356+
357+ double time00, time01;
358+
359+ time00 = debug_clock();
360+ columns = columnsFromSTMT(stmt);
361+ values = valuesForSTMT(stmt, columns);
362+ time01 = debug_clock();
363+ debug_log_time(time00, time01);
364+
365+ if(!columns || !values) {
366+ return nil;
367+ }
368+ cursor = [NSDictionary dictionaryWithObjectsAndKeys : columns, TestColumnNames,
369+ values, TestValues, nil];
370+
371+ return cursor;
372+}
373+
374+- (id <SQLiteMutableCursor>) cursorForSQL : (NSString *) sqlString
375+{
376+ const char *sql;
377+ sqlite3_stmt *stmt;
378+ NSInteger result;
379+ id <SQLiteMutableCursor> cursor;
380+
381+ if (!mDatabase) {
382+ return nil;
383+ }
384+ if (!sqlString) {
385+ return nil;
386+ }
387+
388+ sql = [sqlString UTF8String];
389+
390+ result = sqlite3_prepare_v2(mDatabase, sql, strlen(sql) , &stmt, &sql);
391+ if(result != SQLITE_OK) return nil;
392+
393+ debug_log("send query %s\n", [sqlString UTF8String]);
394+
395+ cursor = cursorFromSTMT(stmt);
396+ sqlite3_finalize(stmt);
397+
398+ return cursor;
399+}
400+
401+- (id <SQLiteMutableCursor>) performQuery : (NSString *) sqlString
402+{
403+ return [self cursorForSQL : sqlString];
404+}
405+
406+- (SQLiteReservedQuery *) reservedQuery : (NSString *) sqlString
407+{
408+ return [SQLiteReservedQuery sqliteReservedQueryWithQuery : sqlString usingSQLiteDB : self];
409+}
410+@end
411+
412+@implementation SQLiteDB (DatabaseAccessor)
413+
414+- (NSArray *) tables
415+{
416+ id cursor;
417+ id sql = [NSString stringWithFormat: @"%s",
418+ "SELECT name FROM sqlite_master WHERE type = 'table' OR type = 'view' \
419+ UNION \
420+ SELECT name FROM sqlite_temp_master \
421+ WHERE type = 'table' OR type = 'view'"];
422+
423+ cursor = [self cursorForSQL : sql];
424+
425+ return [cursor valuesForColumn : @"Name"];
426+}
427+- (BOOL) beginTransaction
428+{
429+ if (_transaction) {
430+ NSLog(@"Already begin transaction.");
431+
432+ return NO;
433+ }
434+
435+ _transaction = YES;
436+
437+ [self performQuery : @"BEGIN"];
438+
439+ return [self lastErrorID] == 0;
440+}
441+- (BOOL) commitTransaction
442+{
443+ if (!_transaction) {
444+ NSLog(@"Not begin transaction.");
445+
446+ return NO;
447+ }
448+
449+ _transaction = NO;
450+
451+ [self performQuery : @"COMMIT"];
452+
453+ return [self lastErrorID] == 0;
454+}
455+- (BOOL) rollbackTransaction
456+{
457+ if (!_transaction) {
458+ NSLog(@"Not begin transaction.");
459+
460+ return NO;
461+ }
462+
463+ _transaction = NO;
464+
465+ [self performQuery : @"ROLLBACK"];
466+
467+ return [self lastErrorID] == 0;
468+}
469+
470+// do nothing. for compatible QuickLite.
471+- (BOOL) save { return YES; }
472+
473+- (NSString *) defaultValue : (id) inValue forDatatype : (NSString *) datatype
474+{
475+ NSString *defaultValue = nil;
476+
477+ if(!inValue || inValue == [NSNull null]) {
478+ return nil;
479+ }
480+
481+ if(!datatype || (id)datatype == [NSNull null]) {
482+ defaultValue = [[self class] prepareStringForQuery : [inValue stringValue]];
483+ }
484+
485+ NSRange range;
486+ NSString *lower = [datatype lowercaseString];
487+ if(!lower) return nil;
488+
489+ range = [lower rangeOfString : @"text"];
490+ if(range.length != 0) {
491+ defaultValue = [NSString stringWithFormat: @"'%@'", [[self class] prepareStringForQuery : [inValue stringValue]]];
492+ }
493+
494+ range = [lower rangeOfString : @"integer"];
495+ if(range.length != 0) {
496+ defaultValue = [NSString stringWithFormat: @"%ld", [inValue integerValue]];
497+ }
498+
499+ range = [lower rangeOfString : @"numelic"];
500+ if(range.length != 0) {
501+ defaultValue = [NSString stringWithFormat: @"%0.0f", [inValue doubleValue]];
502+ }
503+
504+ if(defaultValue) {
505+ return [NSString stringWithFormat: @"DEFAULT %@", defaultValue];
506+ }
507+
508+ return nil;
509+}
510+
511+- (NSString *) checkConstraint : (id) checkConstraint
512+{
513+ if(!checkConstraint || checkConstraint == [NSNull null]) {
514+ return nil;
515+ }
516+
517+ return [NSString stringWithFormat: @"CHECK(%@)", checkConstraint];;
518+}
519+
520+- (BOOL) createTemporaryTable : (NSString *) table
521+ columns : (NSArray *) columns
522+ datatypes : (NSArray *) datatypes
523+ defaultValues : (NSArray *) defaultValues
524+ checkConstrains : (NSArray *) checkConstrains
525+ isTemporary : (BOOL) isTemporary
526+{
527+ NSUInteger i;
528+ NSUInteger columnCount = [columns count];
529+ NSMutableString *sql;
530+ BOOL useDefaultValues = NO;
531+ BOOL useCheck = NO;
532+
533+ if (columnCount != [datatypes count]) return NO;
534+ if (columnCount == 0) return NO;
535+
536+ useDefaultValues = defaultValues ? YES :NO;
537+ if(useDefaultValues && columnCount != [defaultValues count]) return NO;
538+ useCheck = checkConstrains ? YES :NO;
539+ if(useDefaultValues && columnCount != [checkConstrains count]) return NO;
540+
541+ sql = [NSMutableString stringWithFormat: @"CREATE %@ TABLE %@ (",
542+ isTemporary ? @"TEMPORARY" : @"", table];
543+
544+ for (i = 0; i < columnCount; i++) {
545+ [sql appendFormat: @"%@ %@", [columns objectAtIndex : i], [datatypes objectAtIndex : i]];
546+ if(useDefaultValues) {
547+ NSString *d = [self defaultValue: [defaultValues objectAtIndex : i ]
548+ forDatatype : [datatypes objectAtIndex : i]];
549+ if(d) {
550+ [sql appendFormat: @" %@", d];
551+ }
552+ }
553+ if(useCheck) {
554+ NSString *c = [self checkConstraint : [checkConstrains objectAtIndex : i ]];
555+ if(c && (id)c != [NSNull null]) {
556+ [sql appendFormat: @" %@", c];
557+ }
558+ }
559+
560+ if (i != columnCount - 1) {
561+ [sql appendString : @","];
562+ }
563+ }
564+ [sql appendString : @") "];
565+
566+ [self performQuery : sql];
567+
568+ return [self lastErrorID] == 0;
569+}
570+
571+
572+- (BOOL) createTable : (NSString *) table
573+ withColumns : (NSArray *) columns
574+ andDatatypes : (NSArray *) datatypes
575+ isTemporary : (BOOL) isTemporary
576+{
577+ return [self createTemporaryTable : table
578+ columns : columns
579+ datatypes : datatypes
580+ defaultValues : nil
581+ checkConstrains : nil
582+ isTemporary : NO];
583+}
584+- (BOOL) createTable : (NSString *) table withColumns : (NSArray *) columns andDatatypes : (NSArray *) datatypes
585+{
586+ return [self createTable : table
587+ withColumns : columns
588+ andDatatypes : datatypes
589+ isTemporary : NO];
590+}
591+- (BOOL) createTable : (NSString *) table
592+ columns : (NSArray *) columns
593+ datatypes : (NSArray *) datatypes
594+ defaultValues : (NSArray *)defaultValues
595+ checkConstrains : (NSArray *)checkConstrains
596+{
597+ return [self createTemporaryTable : table
598+ columns : columns
599+ datatypes : datatypes
600+ defaultValues : defaultValues
601+ checkConstrains : checkConstrains
602+ isTemporary : NO];
603+}
604+- (BOOL) createTemporaryTable : (NSString *) table
605+ withColumns : (NSArray *) columns
606+ andDatatypes : (NSArray *) datatypes
607+{
608+ return [self createTable : table
609+ withColumns : columns
610+ andDatatypes : datatypes
611+ isTemporary : YES];
612+}
613+- (BOOL) createTemporaryTable : (NSString *) table
614+ columns : (NSArray *) columns
615+ datatypes : (NSArray *) datatypes
616+ defaultValues : (NSArray *)defaultValues
617+ checkConstrains : (NSArray *)checkConstrains
618+{
619+ return [self createTemporaryTable : table
620+ columns : columns
621+ datatypes : datatypes
622+ defaultValues : defaultValues
623+ checkConstrains : checkConstrains
624+ isTemporary : YES];
625+}
626+
627+- (NSString *)indexNameForColumn:(NSString *)column inTable:(NSString *)table
628+{
629+ return [NSString stringWithFormat:@"%@_%@_INDEX", table, column];
630+}
631+- (BOOL) createIndexForColumn : (NSString *) column inTable : (NSString *) table isUnique : (BOOL) isUnique
632+{
633+ NSString *sql;
634+
635+ sql = [NSString stringWithFormat: @"CREATE %@ INDEX %@ ON %@ ( %@ ) ",
636+ isUnique ? @"UNIQUE" : @"",
637+ [self indexNameForColumn:column inTable:table],
638+ table, column];
639+
640+ [self performQuery : sql];
641+
642+ return [self lastErrorID] == 0;
643+}
644+
645+- (BOOL) deleteIndexForColumn:(NSString *)column inTable:(NSString *)table
646+{
647+ NSString *sql;
648+
649+ sql = [NSString stringWithFormat: @"DROP INDEX %@",
650+ [self indexNameForColumn:column inTable:table]];
651+
652+ [self performQuery : sql];
653+
654+ return [self lastErrorID] == 0;
655+}
656+
657+@end
658+
659+@implementation SQLiteDB (ResercedQuerySupport)
660+
661+- (SQLiteReservedQuery *)reservedQueryWithKey:(NSString *)key
662+{
663+ return [reservedQueries objectForKey:key];
664+}
665+
666+- (void)setReservedQuery:(SQLiteReservedQuery *)query forKey:(NSString *)key
667+{
668+ [reservedQueries setObject:query forKey:key];
669+}
670+
671+@end
672+
673+@implementation SQLiteReservedQuery
674+
675++ (id) sqliteReservedQueryWithQuery : (NSString *) sqlString usingSQLiteDB : (SQLiteDB *) db
676+{
677+ id result = [db reservedQueryWithKey:sqlString];
678+ if(result) return result;
679+
680+ return [[[self alloc] initWithQuery : sqlString usingSQLiteDB : db] autorelease];
681+}
682+
683+- (id) initWithQuery : (NSString *) sqlString usingSQLiteDB : (SQLiteDB *) db
684+{
685+ self = [super init];
686+
687+ if (self) {
688+
689+ id stockedQuery = [db reservedQueryWithKey:sqlString];
690+ if(stockedQuery) {
691+ [self autorelease];
692+ return [stockedQuery retain];
693+ }
694+
695+ const char *sql = [sqlString UTF8String];
696+ NSInteger result;
697+
698+ result = sqlite3_prepare_v2([db rowDatabase], sql, strlen(sql) , &m_stmt, &sql);
699+ if (result != SQLITE_OK) goto fail;
700+
701+ [db setReservedQuery:self forKey:sqlString];
702+
703+ debug_log("create statment %s\n", [sqlString UTF8String]);
704+ }
705+
706+ debug_log("#### CREATE RESERVED STATMENT ####\n");
707+
708+ return self;
709+
710+fail :
711+ [self release];
712+ return nil;
713+}
714+
715+- (void) dealloc
716+{
717+ sqlite3_finalize(m_stmt);
718+
719+ debug_log("#### DELETE RESERVED STATMENT ####\n");
720+
721+ [super dealloc];
722+}
723+
724+void objectDeallocator(void *obj)
725+{
726+ // NSLog(@"??? DEALLOC ???");
727+}
728+- (id <SQLiteMutableCursor>) cursorForBindValues : (NSArray *) bindValues
729+{
730+ NSInteger error;
731+ NSInteger paramCount;
732+ NSUInteger i, valuesCount;
733+ id value;
734+
735+ id <SQLiteMutableCursor> cursor;
736+
737+ error = sqlite3_reset(m_stmt);
738+ if (SQLITE_OK != error) return nil;
739+ error = sqlite3_clear_bindings(m_stmt);
740+ if (SQLITE_OK != error) return nil;
741+
742+ valuesCount = [bindValues count];
743+ paramCount = sqlite3_bind_parameter_count(m_stmt);
744+ if (valuesCount != paramCount) {
745+ NSLog(@"Missmatch bindValues count!!");
746+ return nil;
747+ }
748+ for (i = 0; i < valuesCount; i++) {
749+ value = [bindValues objectAtIndex : i];
750+
751+ if ([value isKindOfClass : [NSNumber class]]) {
752+ NSInteger intValue = [value integerValue];
753+ error = sqlite3_bind_int(m_stmt, i+1, intValue);
754+ if (SQLITE_OK != error) return nil;
755+ } else if ([value isKindOfClass : [NSString class]]) {
756+ const char *str = [value UTF8String];
757+ error = sqlite3_bind_text(m_stmt, i+1, str, strlen(str) , objectDeallocator);
758+ if (SQLITE_OK != error) return nil;
759+ } else if (value == [NSNull null]) {
760+ error = sqlite3_bind_null(m_stmt, i+1);
761+ if (SQLITE_OK != error) return nil;
762+ } else {
763+ NSLog(@"cursorForBindValues : NOT supported type.");
764+ return nil;
765+ }
766+ }
767+
768+ cursor = cursorFromSTMT(m_stmt);
769+
770+ error = sqlite3_reset(m_stmt);
771+ if(error != SQLITE_OK) {
772+ NSLog(@"fail sqlite3_reset().");
773+ }
774+
775+ return cursor;
776+}
777+
778+static inline BOOL setNullIfNil(sqlite3_stmt *m_stmt, NSInteger i, id obj, NSInteger *outError)
779+{
780+ NSInteger error = SQLITE_OK;
781+ if(!obj || obj == [NSNull null]) {
782+ error = sqlite3_bind_null(m_stmt, i);
783+ if(outError) *outError = error;
784+ return YES;
785+ }
786+
787+ return NO;
788+}
789+#define fString 's'
790+#define fInt 'i'
791+#define fDouble 'd'
792+#define fNull 'n'
793+#define fNInt 'j'
794+#define fNDouble 'e'
795+- (id <SQLiteMutableCursor>)cursorWithFormat:(const char *)format, ...
796+{
797+ NSInteger error;
798+ NSUInteger i;
799+ id <SQLiteMutableCursor> cursor;
800+
801+ error = sqlite3_reset(m_stmt);
802+ if (SQLITE_OK != error) return nil;
803+ error = sqlite3_clear_bindings(m_stmt);
804+ if (SQLITE_OK != error) return nil;
805+
806+ va_list ap;
807+ id s;
808+ NSInteger d;
809+ double fd;
810+
811+ va_start(ap, format);
812+ i = 0;
813+ while(*format) {
814+ i++;
815+ switch(*format++) {
816+ case fString:
817+ s = va_arg(ap, NSString *);
818+ if(!setNullIfNil(m_stmt, i, s, &error)) {
819+ const char *str = [s UTF8String];
820+ error = sqlite3_bind_text(m_stmt, i, str, strlen(str) , objectDeallocator);
821+ }
822+ break;
823+ case fInt:
824+ d = va_arg(ap, NSInteger);
825+ error = sqlite3_bind_int(m_stmt, i, d);
826+ break;
827+ case fDouble:
828+ fd = va_arg(ap, double);
829+ error = sqlite3_bind_double(m_stmt, i, fd);
830+ break;
831+ case fNull:
832+ error = sqlite3_bind_null(m_stmt, i);
833+ break;
834+ case fNInt:
835+ s = va_arg(ap, NSNumber *);
836+ if(!setNullIfNil(m_stmt, i, s, &error)) {
837+ d = [s integerValue];
838+ error = sqlite3_bind_int(m_stmt, i, d);
839+ }
840+ break;
841+ case fNDouble:
842+ s = va_arg(ap, NSNumber *);
843+ if(!setNullIfNil(m_stmt, i, s, &error)) {
844+ fd = [s doubleValue];
845+ error = sqlite3_bind_double(m_stmt, i, fd);
846+ }
847+ break;
848+ default:
849+ NSLog(@"cursorForBindValues : NOT supported type.");
850+ error = -1;
851+ break;
852+ }
853+ if(SQLITE_OK != error) goto fail;
854+ }
855+ va_end(ap);
856+
857+ cursor = cursorFromSTMT(m_stmt);
858+
859+ error = sqlite3_reset(m_stmt);
860+
861+ return cursor;
862+
863+fail:{
864+ va_end(ap);
865+// error = sqlite3_reset(m_stmt);
866+ return nil;
867+}
868+}
869+@end
870+
871+@implementation NSDictionary (SQLiteRow)
872+- (NSUInteger) columnCount
873+{
874+ return [self count];
875+}
876+- (NSArray *) columnNames
877+{
878+ return [self allKeys];
879+}
880+- (id) valueForColumn : (NSString *) column
881+{
882+ NSString *lower = [column lowercaseString];
883+ id result = [self objectForKey : lower];
884+ return result ? result : [NSNull null];
885+}
886+@end
887+
888+@implementation NSMutableDictionary (SQLiteCursor)
889+
890+- (NSUInteger) columnCount
891+{
892+ return [[self objectForKey : TestColumnNames] count];
893+}
894+- (NSArray *) columnNames
895+{
896+ return [self objectForKey : TestColumnNames];
897+}
898+
899+- (NSUInteger) rowCount
900+{
901+ return [[self objectForKey : TestValues] count];
902+}
903+- (id) valueForColumn : (NSString *) column atRow : (NSUInteger) row
904+{
905+ id lower = [column lowercaseString];
906+ return [[self rowAtIndex : row] valueForColumn : lower];
907+}
908+- (NSArray *) valuesForColumn : (NSString *) column;
909+{
910+ id lower = [column lowercaseString];
911+ NSMutableArray *result;
912+ NSUInteger i, rowCount = [self rowCount];
913+
914+ if (rowCount == 0 || [self columnCount] == 0) return nil;
915+
916+ result = [NSMutableArray arrayWithCapacity : rowCount];
917+ for (i = 0; i < rowCount; i++) {
918+ id value = [self valueForColumn : lower atRow : i];
919+ if (value) {
920+ [result addObject : value];
921+ }
922+ }
923+
924+ return result;
925+}
926+- (id <SQLiteRow>) rowAtIndex : (NSUInteger) row
927+{
928+ return [[self arrayForTableView] objectAtIndex : row];
929+}
930+- (NSArray *) arrayForTableView
931+{
932+ id result = [self objectForKey : TestValues];
933+
934+ if (!result) {
935+ result = [NSMutableArray array];
936+ [self setObject : result forKey : TestValues];
937+ }
938+
939+ return result;
940+}
941+
942+- (BOOL) appendRow : (id <SQLiteRow>) row
943+{
944+ if ([row columnCount] != [self columnCount]) return NO;
945+ if (![[row columnNames] isEqual : [self columnNames]]) return NO;
946+
947+ [(NSMutableArray *)[self arrayForTableView] addObject : row];
948+
949+ return YES;
950+}
951+- (BOOL) appendCursor : (id <SQLiteCursor>) cursor
952+{
953+ if ([cursor columnCount] != [self columnCount]) return NO;
954+ if (![[cursor columnNames] isEqual : [self columnNames]]) return NO;
955+
956+ [(NSMutableArray *)[self arrayForTableView] addObjectsFromArray : [cursor arrayForTableView]];
957+
958+ return YES;
959+}
960+
961+@end
--- /dev/null
+++ b/sqlite3.c
@@ -0,0 +1,131878 @@
1+/******************************************************************************
2+** This file is an amalgamation of many separate C source files from SQLite
3+** version 3.7.9. By combining all the individual C code files into this
4+** single large file, the entire code can be compiled as a single translation
5+** unit. This allows many compilers to do optimizations that would not be
6+** possible if the files were compiled separately. Performance improvements
7+** of 5% or more are commonly seen when SQLite is compiled as a single
8+** translation unit.
9+**
10+** This file is all you need to compile SQLite. To use SQLite in other
11+** programs, you need this file and the "sqlite3.h" header file that defines
12+** the programming interface to the SQLite library. (If you do not have
13+** the "sqlite3.h" header file at hand, you will find a copy embedded within
14+** the text of this file. Search for "Begin file sqlite3.h" to find the start
15+** of the embedded sqlite3.h header file.) Additional code files may be needed
16+** if you want a wrapper to interface SQLite with your choice of programming
17+** language. The code for the "sqlite3" command-line shell is also in a
18+** separate file. This file contains only code for the core SQLite library.
19+*/
20+#define SQLITE_CORE 1
21+#define SQLITE_AMALGAMATION 1
22+#ifndef SQLITE_PRIVATE
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+/*
310+** Include standard header files as necessary
311+*/
312+#ifdef HAVE_STDINT_H
313+#include <stdint.h>
314+#endif
315+#ifdef HAVE_INTTYPES_H
316+#include <inttypes.h>
317+#endif
318+
319+/*
320+** The following macros are used to cast pointers to integers and
321+** integers to pointers. The way you do this varies from one compiler
322+** to the next, so we have developed the following set of #if statements
323+** to generate appropriate macros for a wide range of compilers.
324+**
325+** The correct "ANSI" way to do this is to use the intptr_t type.
326+** Unfortunately, that typedef is not available on all compilers, or
327+** if it is available, it requires an #include of specific headers
328+** that vary from one machine to the next.
329+**
330+** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
331+** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
332+** So we have to define the macros in different ways depending on the
333+** compiler.
334+*/
335+#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
336+# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
337+# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
338+#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
339+# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
340+# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
341+#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
342+# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
343+# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
344+#else /* Generates a warning - but it always works */
345+# define SQLITE_INT_TO_PTR(X) ((void*)(X))
346+# define SQLITE_PTR_TO_INT(X) ((int)(X))
347+#endif
348+
349+/*
350+** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
351+** 0 means mutexes are permanently disable and the library is never
352+** threadsafe. 1 means the library is serialized which is the highest
353+** level of threadsafety. 2 means the libary is multithreaded - multiple
354+** threads can use SQLite as long as no two threads try to use the same
355+** database connection at the same time.
356+**
357+** Older versions of SQLite used an optional THREADSAFE macro.
358+** We support that for legacy.
359+*/
360+#if !defined(SQLITE_THREADSAFE)
361+#if defined(THREADSAFE)
362+# define SQLITE_THREADSAFE THREADSAFE
363+#else
364+# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
365+#endif
366+#endif
367+
368+/*
369+** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
370+** It determines whether or not the features related to
371+** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can
372+** be overridden at runtime using the sqlite3_config() API.
373+*/
374+#if !defined(SQLITE_DEFAULT_MEMSTATUS)
375+# define SQLITE_DEFAULT_MEMSTATUS 1
376+#endif
377+
378+/*
379+** Exactly one of the following macros must be defined in order to
380+** specify which memory allocation subsystem to use.
381+**
382+** SQLITE_SYSTEM_MALLOC // Use normal system malloc()
383+** SQLITE_WIN32_MALLOC // Use Win32 native heap API
384+** SQLITE_MEMDEBUG // Debugging version of system malloc()
385+**
386+** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the
387+** assert() macro is enabled, each call into the Win32 native heap subsystem
388+** will cause HeapValidate to be called. If heap validation should fail, an
389+** assertion will be triggered.
390+**
391+** (Historical note: There used to be several other options, but we've
392+** pared it down to just these three.)
393+**
394+** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
395+** the default.
396+*/
397+#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)>1
398+# error "At most one of the following compile-time configuration options\
399+ is allows: SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG"
400+#endif
401+#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)==0
402+# define SQLITE_SYSTEM_MALLOC 1
403+#endif
404+
405+/*
406+** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the
407+** sizes of memory allocations below this value where possible.
408+*/
409+#if !defined(SQLITE_MALLOC_SOFT_LIMIT)
410+# define SQLITE_MALLOC_SOFT_LIMIT 1024
411+#endif
412+
413+/*
414+** We need to define _XOPEN_SOURCE as follows in order to enable
415+** recursive mutexes on most Unix systems. But Mac OS X is different.
416+** The _XOPEN_SOURCE define causes problems for Mac OS X we are told,
417+** so it is omitted there. See ticket #2673.
418+**
419+** Later we learn that _XOPEN_SOURCE is poorly or incorrectly
420+** implemented on some systems. So we avoid defining it at all
421+** if it is already defined or if it is unneeded because we are
422+** not doing a threadsafe build. Ticket #2681.
423+**
424+** See also ticket #2741.
425+*/
426+#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) && SQLITE_THREADSAFE
427+# define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */
428+#endif
429+
430+/*
431+** The TCL headers are only needed when compiling the TCL bindings.
432+*/
433+#if defined(SQLITE_TCL) || defined(TCLSH)
434+# include <tcl.h>
435+#endif
436+
437+/*
438+** Many people are failing to set -DNDEBUG=1 when compiling SQLite.
439+** Setting NDEBUG makes the code smaller and run faster. So the following
440+** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1
441+** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out
442+** feature.
443+*/
444+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
445+# define NDEBUG 1
446+#endif
447+
448+/*
449+** The testcase() macro is used to aid in coverage testing. When
450+** doing coverage testing, the condition inside the argument to
451+** testcase() must be evaluated both true and false in order to
452+** get full branch coverage. The testcase() macro is inserted
453+** to help ensure adequate test coverage in places where simple
454+** condition/decision coverage is inadequate. For example, testcase()
455+** can be used to make sure boundary values are tested. For
456+** bitmask tests, testcase() can be used to make sure each bit
457+** is significant and used at least once. On switch statements
458+** where multiple cases go to the same block of code, testcase()
459+** can insure that all cases are evaluated.
460+**
461+*/
462+#ifdef SQLITE_COVERAGE_TEST
463+SQLITE_PRIVATE void sqlite3Coverage(int);
464+# define testcase(X) if( X ){ sqlite3Coverage(__LINE__); }
465+#else
466+# define testcase(X)
467+#endif
468+
469+/*
470+** The TESTONLY macro is used to enclose variable declarations or
471+** other bits of code that are needed to support the arguments
472+** within testcase() and assert() macros.
473+*/
474+#if !defined(NDEBUG) || defined(SQLITE_COVERAGE_TEST)
475+# define TESTONLY(X) X
476+#else
477+# define TESTONLY(X)
478+#endif
479+
480+/*
481+** Sometimes we need a small amount of code such as a variable initialization
482+** to setup for a later assert() statement. We do not want this code to
483+** appear when assert() is disabled. The following macro is therefore
484+** used to contain that setup code. The "VVA" acronym stands for
485+** "Verification, Validation, and Accreditation". In other words, the
486+** code within VVA_ONLY() will only run during verification processes.
487+*/
488+#ifndef NDEBUG
489+# define VVA_ONLY(X) X
490+#else
491+# define VVA_ONLY(X)
492+#endif
493+
494+/*
495+** The ALWAYS and NEVER macros surround boolean expressions which
496+** are intended to always be true or false, respectively. Such
497+** expressions could be omitted from the code completely. But they
498+** are included in a few cases in order to enhance the resilience
499+** of SQLite to unexpected behavior - to make the code "self-healing"
500+** or "ductile" rather than being "brittle" and crashing at the first
501+** hint of unplanned behavior.
502+**
503+** In other words, ALWAYS and NEVER are added for defensive code.
504+**
505+** When doing coverage testing ALWAYS and NEVER are hard-coded to
506+** be true and false so that the unreachable code then specify will
507+** not be counted as untested code.
508+*/
509+#if defined(SQLITE_COVERAGE_TEST)
510+# define ALWAYS(X) (1)
511+# define NEVER(X) (0)
512+#elif !defined(NDEBUG)
513+# define ALWAYS(X) ((X)?1:(assert(0),0))
514+# define NEVER(X) ((X)?(assert(0),1):0)
515+#else
516+# define ALWAYS(X) (X)
517+# define NEVER(X) (X)
518+#endif
519+
520+/*
521+** Return true (non-zero) if the input is a integer that is too large
522+** to fit in 32-bits. This macro is used inside of various testcase()
523+** macros to verify that we have tested SQLite for large-file support.
524+*/
525+#define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0)
526+
527+/*
528+** The macro unlikely() is a hint that surrounds a boolean
529+** expression that is usually false. Macro likely() surrounds
530+** a boolean expression that is usually true. GCC is able to
531+** use these hints to generate better code, sometimes.
532+*/
533+#if defined(__GNUC__) && 0
534+# define likely(X) __builtin_expect((X),1)
535+# define unlikely(X) __builtin_expect((X),0)
536+#else
537+# define likely(X) !!(X)
538+# define unlikely(X) !!(X)
539+#endif
540+
541+/************** Include sqlite3.h in the middle of sqliteInt.h ***************/
542+/************** Begin file sqlite3.h *****************************************/
543+/*
544+** 2001 September 15
545+**
546+** The author disclaims copyright to this source code. In place of
547+** a legal notice, here is a blessing:
548+**
549+** May you do good and not evil.
550+** May you find forgiveness for yourself and forgive others.
551+** May you share freely, never taking more than you give.
552+**
553+*************************************************************************
554+** This header file defines the interface that the SQLite library
555+** presents to client programs. If a C-function, structure, datatype,
556+** or constant definition does not appear in this file, then it is
557+** not a published API of SQLite, is subject to change without
558+** notice, and should not be referenced by programs that use SQLite.
559+**
560+** Some of the definitions that are in this file are marked as
561+** "experimental". Experimental interfaces are normally new
562+** features recently added to SQLite. We do not anticipate changes
563+** to experimental interfaces but reserve the right to make minor changes
564+** if experience from use "in the wild" suggest such changes are prudent.
565+**
566+** The official C-language API documentation for SQLite is derived
567+** from comments in this file. This file is the authoritative source
568+** on how SQLite interfaces are suppose to operate.
569+**
570+** The name of this file under configuration management is "sqlite.h.in".
571+** The makefile makes some minor changes to this file (such as inserting
572+** the version number) and changes its name to "sqlite3.h" as
573+** part of the build process.
574+*/
575+#ifndef _SQLITE3_H_
576+#define _SQLITE3_H_
577+#include <stdarg.h> /* Needed for the definition of va_list */
578+
579+/*
580+** Make sure we can call this stuff from C++.
581+*/
582+#if 0
583+extern "C" {
584+#endif
585+
586+
587+/*
588+** Add the ability to override 'extern'
589+*/
590+#ifndef SQLITE_EXTERN
591+# define SQLITE_EXTERN extern
592+#endif
593+
594+#ifndef SQLITE_API
595+# define SQLITE_API
596+#endif
597+
598+
599+/*
600+** These no-op macros are used in front of interfaces to mark those
601+** interfaces as either deprecated or experimental. New applications
602+** should not use deprecated interfaces - they are support for backwards
603+** compatibility only. Application writers should be aware that
604+** experimental interfaces are subject to change in point releases.
605+**
606+** These macros used to resolve to various kinds of compiler magic that
607+** would generate warning messages when they were used. But that
608+** compiler magic ended up generating such a flurry of bug reports
609+** that we have taken it all out and gone back to using simple
610+** noop macros.
611+*/
612+#define SQLITE_DEPRECATED
613+#define SQLITE_EXPERIMENTAL
614+
615+/*
616+** Ensure these symbols were not defined by some previous header file.
617+*/
618+#ifdef SQLITE_VERSION
619+# undef SQLITE_VERSION
620+#endif
621+#ifdef SQLITE_VERSION_NUMBER
622+# undef SQLITE_VERSION_NUMBER
623+#endif
624+
625+/*
626+** CAPI3REF: Compile-Time Library Version Numbers
627+**
628+** ^(The [SQLITE_VERSION] C preprocessor macro in the sqlite3.h header
629+** evaluates to a string literal that is the SQLite version in the
630+** format "X.Y.Z" where X is the major version number (always 3 for
631+** SQLite3) and Y is the minor version number and Z is the release number.)^
632+** ^(The [SQLITE_VERSION_NUMBER] C preprocessor macro resolves to an integer
633+** with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same
634+** numbers used in [SQLITE_VERSION].)^
635+** The SQLITE_VERSION_NUMBER for any given release of SQLite will also
636+** be larger than the release from which it is derived. Either Y will
637+** be held constant and Z will be incremented or else Y will be incremented
638+** and Z will be reset to zero.
639+**
640+** Since version 3.6.18, SQLite source code has been stored in the
641+** <a href="http://www.fossil-scm.org/">Fossil configuration management
642+** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
643+** a string which identifies a particular check-in of SQLite
644+** within its configuration management system. ^The SQLITE_SOURCE_ID
645+** string contains the date and time of the check-in (UTC) and an SHA1
646+** hash of the entire source tree.
647+**
648+** See also: [sqlite3_libversion()],
649+** [sqlite3_libversion_number()], [sqlite3_sourceid()],
650+** [sqlite_version()] and [sqlite_source_id()].
651+*/
652+#define SQLITE_VERSION "3.7.9"
653+#define SQLITE_VERSION_NUMBER 3007009
654+#define SQLITE_SOURCE_ID "2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e"
655+
656+/*
657+** CAPI3REF: Run-Time Library Version Numbers
658+** KEYWORDS: sqlite3_version, sqlite3_sourceid
659+**
660+** These interfaces provide the same information as the [SQLITE_VERSION],
661+** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
662+** but are associated with the library instead of the header file. ^(Cautious
663+** programmers might include assert() statements in their application to
664+** verify that values returned by these interfaces match the macros in
665+** the header, and thus insure that the application is
666+** compiled with matching library and header files.
667+**
668+** <blockquote><pre>
669+** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
670+** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
671+** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
672+** </pre></blockquote>)^
673+**
674+** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION]
675+** macro. ^The sqlite3_libversion() function returns a pointer to the
676+** to the sqlite3_version[] string constant. The sqlite3_libversion()
677+** function is provided for use in DLLs since DLL users usually do not have
678+** direct access to string constants within the DLL. ^The
679+** sqlite3_libversion_number() function returns an integer equal to
680+** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns
681+** a pointer to a string constant whose value is the same as the
682+** [SQLITE_SOURCE_ID] C preprocessor macro.
683+**
684+** See also: [sqlite_version()] and [sqlite_source_id()].
685+*/
686+SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
687+SQLITE_API const char *sqlite3_libversion(void);
688+SQLITE_API const char *sqlite3_sourceid(void);
689+SQLITE_API int sqlite3_libversion_number(void);
690+
691+/*
692+** CAPI3REF: Run-Time Library Compilation Options Diagnostics
693+**
694+** ^The sqlite3_compileoption_used() function returns 0 or 1
695+** indicating whether the specified option was defined at
696+** compile time. ^The SQLITE_ prefix may be omitted from the
697+** option name passed to sqlite3_compileoption_used().
698+**
699+** ^The sqlite3_compileoption_get() function allows iterating
700+** over the list of options that were defined at compile time by
701+** returning the N-th compile time option string. ^If N is out of range,
702+** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
703+** prefix is omitted from any strings returned by
704+** sqlite3_compileoption_get().
705+**
706+** ^Support for the diagnostic functions sqlite3_compileoption_used()
707+** and sqlite3_compileoption_get() may be omitted by specifying the
708+** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
709+**
710+** See also: SQL functions [sqlite_compileoption_used()] and
711+** [sqlite_compileoption_get()] and the [compile_options pragma].
712+*/
713+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
714+SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
715+SQLITE_API const char *sqlite3_compileoption_get(int N);
716+#endif
717+
718+/*
719+** CAPI3REF: Test To See If The Library Is Threadsafe
720+**
721+** ^The sqlite3_threadsafe() function returns zero if and only if
722+** SQLite was compiled mutexing code omitted due to the
723+** [SQLITE_THREADSAFE] compile-time option being set to 0.
724+**
725+** SQLite can be compiled with or without mutexes. When
726+** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes
727+** are enabled and SQLite is threadsafe. When the
728+** [SQLITE_THREADSAFE] macro is 0,
729+** the mutexes are omitted. Without the mutexes, it is not safe
730+** to use SQLite concurrently from more than one thread.
731+**
732+** Enabling mutexes incurs a measurable performance penalty.
733+** So if speed is of utmost importance, it makes sense to disable
734+** the mutexes. But for maximum safety, mutexes should be enabled.
735+** ^The default behavior is for mutexes to be enabled.
736+**
737+** This interface can be used by an application to make sure that the
738+** version of SQLite that it is linking against was compiled with
739+** the desired setting of the [SQLITE_THREADSAFE] macro.
740+**
741+** This interface only reports on the compile-time mutex setting
742+** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with
743+** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
744+** can be fully or partially disabled using a call to [sqlite3_config()]
745+** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
746+** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
747+** sqlite3_threadsafe() function shows only the compile-time setting of
748+** thread safety, not any run-time changes to that setting made by
749+** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
750+** is unchanged by calls to sqlite3_config().)^
751+**
752+** See the [threading mode] documentation for additional information.
753+*/
754+SQLITE_API int sqlite3_threadsafe(void);
755+
756+/*
757+** CAPI3REF: Database Connection Handle
758+** KEYWORDS: {database connection} {database connections}
759+**
760+** Each open SQLite database is represented by a pointer to an instance of
761+** the opaque structure named "sqlite3". It is useful to think of an sqlite3
762+** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and
763+** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()]
764+** is its destructor. There are many other interfaces (such as
765+** [sqlite3_prepare_v2()], [sqlite3_create_function()], and
766+** [sqlite3_busy_timeout()] to name but three) that are methods on an
767+** sqlite3 object.
768+*/
769+typedef struct sqlite3 sqlite3;
770+
771+/*
772+** CAPI3REF: 64-Bit Integer Types
773+** KEYWORDS: sqlite_int64 sqlite_uint64
774+**
775+** Because there is no cross-platform way to specify 64-bit integer types
776+** SQLite includes typedefs for 64-bit signed and unsigned integers.
777+**
778+** The sqlite3_int64 and sqlite3_uint64 are the preferred type definitions.
779+** The sqlite_int64 and sqlite_uint64 types are supported for backwards
780+** compatibility only.
781+**
782+** ^The sqlite3_int64 and sqlite_int64 types can store integer values
783+** between -9223372036854775808 and +9223372036854775807 inclusive. ^The
784+** sqlite3_uint64 and sqlite_uint64 types can store integer values
785+** between 0 and +18446744073709551615 inclusive.
786+*/
787+#ifdef SQLITE_INT64_TYPE
788+ typedef SQLITE_INT64_TYPE sqlite_int64;
789+ typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
790+#elif defined(_MSC_VER) || defined(__BORLANDC__)
791+ typedef __int64 sqlite_int64;
792+ typedef unsigned __int64 sqlite_uint64;
793+#else
794+ typedef long long int sqlite_int64;
795+ typedef unsigned long long int sqlite_uint64;
796+#endif
797+typedef sqlite_int64 sqlite3_int64;
798+typedef sqlite_uint64 sqlite3_uint64;
799+
800+/*
801+** If compiling for a processor that lacks floating point support,
802+** substitute integer for floating-point.
803+*/
804+#ifdef SQLITE_OMIT_FLOATING_POINT
805+# define double sqlite3_int64
806+#endif
807+
808+/*
809+** CAPI3REF: Closing A Database Connection
810+**
811+** ^The sqlite3_close() routine is the destructor for the [sqlite3] object.
812+** ^Calls to sqlite3_close() return SQLITE_OK if the [sqlite3] object is
813+** successfully destroyed and all associated resources are deallocated.
814+**
815+** Applications must [sqlite3_finalize | finalize] all [prepared statements]
816+** and [sqlite3_blob_close | close] all [BLOB handles] associated with
817+** the [sqlite3] object prior to attempting to close the object. ^If
818+** sqlite3_close() is called on a [database connection] that still has
819+** outstanding [prepared statements] or [BLOB handles], then it returns
820+** SQLITE_BUSY.
821+**
822+** ^If [sqlite3_close()] is invoked while a transaction is open,
823+** the transaction is automatically rolled back.
824+**
825+** The C parameter to [sqlite3_close(C)] must be either a NULL
826+** pointer or an [sqlite3] object pointer obtained
827+** from [sqlite3_open()], [sqlite3_open16()], or
828+** [sqlite3_open_v2()], and not previously closed.
829+** ^Calling sqlite3_close() with a NULL pointer argument is a
830+** harmless no-op.
831+*/
832+SQLITE_API int sqlite3_close(sqlite3 *);
833+
834+/*
835+** The type for a callback function.
836+** This is legacy and deprecated. It is included for historical
837+** compatibility and is not documented.
838+*/
839+typedef int (*sqlite3_callback)(void*,int,char**, char**);
840+
841+/*
842+** CAPI3REF: One-Step Query Execution Interface
843+**
844+** The sqlite3_exec() interface is a convenience wrapper around
845+** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
846+** that allows an application to run multiple statements of SQL
847+** without having to use a lot of C code.
848+**
849+** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded,
850+** semicolon-separate SQL statements passed into its 2nd argument,
851+** in the context of the [database connection] passed in as its 1st
852+** argument. ^If the callback function of the 3rd argument to
853+** sqlite3_exec() is not NULL, then it is invoked for each result row
854+** coming out of the evaluated SQL statements. ^The 4th argument to
855+** sqlite3_exec() is relayed through to the 1st argument of each
856+** callback invocation. ^If the callback pointer to sqlite3_exec()
857+** is NULL, then no callback is ever invoked and result rows are
858+** ignored.
859+**
860+** ^If an error occurs while evaluating the SQL statements passed into
861+** sqlite3_exec(), then execution of the current statement stops and
862+** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec()
863+** is not NULL then any error message is written into memory obtained
864+** from [sqlite3_malloc()] and passed back through the 5th parameter.
865+** To avoid memory leaks, the application should invoke [sqlite3_free()]
866+** on error message strings returned through the 5th parameter of
867+** of sqlite3_exec() after the error message string is no longer needed.
868+** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors
869+** occur, then sqlite3_exec() sets the pointer in its 5th parameter to
870+** NULL before returning.
871+**
872+** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec()
873+** routine returns SQLITE_ABORT without invoking the callback again and
874+** without running any subsequent SQL statements.
875+**
876+** ^The 2nd argument to the sqlite3_exec() callback function is the
877+** number of columns in the result. ^The 3rd argument to the sqlite3_exec()
878+** callback is an array of pointers to strings obtained as if from
879+** [sqlite3_column_text()], one for each column. ^If an element of a
880+** result row is NULL then the corresponding string pointer for the
881+** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the
882+** sqlite3_exec() callback is an array of pointers to strings where each
883+** entry represents the name of corresponding result column as obtained
884+** from [sqlite3_column_name()].
885+**
886+** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer
887+** to an empty string, or a pointer that contains only whitespace and/or
888+** SQL comments, then no SQL statements are evaluated and the database
889+** is not changed.
890+**
891+** Restrictions:
892+**
893+** <ul>
894+** <li> The application must insure that the 1st parameter to sqlite3_exec()
895+** is a valid and open [database connection].
896+** <li> The application must not close [database connection] specified by
897+** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
898+** <li> The application must not modify the SQL statement text passed into
899+** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
900+** </ul>
901+*/
902+SQLITE_API int sqlite3_exec(
903+ sqlite3*, /* An open database */
904+ const char *sql, /* SQL to be evaluated */
905+ int (*callback)(void*,int,char**,char**), /* Callback function */
906+ void *, /* 1st argument to callback */
907+ char **errmsg /* Error msg written here */
908+);
909+
910+/*
911+** CAPI3REF: Result Codes
912+** KEYWORDS: SQLITE_OK {error code} {error codes}
913+** KEYWORDS: {result code} {result codes}
914+**
915+** Many SQLite functions return an integer result code from the set shown
916+** here in order to indicates success or failure.
917+**
918+** New error codes may be added in future versions of SQLite.
919+**
920+** See also: [SQLITE_IOERR_READ | extended result codes],
921+** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes].
922+*/
923+#define SQLITE_OK 0 /* Successful result */
924+/* beginning-of-error-codes */
925+#define SQLITE_ERROR 1 /* SQL error or missing database */
926+#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
927+#define SQLITE_PERM 3 /* Access permission denied */
928+#define SQLITE_ABORT 4 /* Callback routine requested an abort */
929+#define SQLITE_BUSY 5 /* The database file is locked */
930+#define SQLITE_LOCKED 6 /* A table in the database is locked */
931+#define SQLITE_NOMEM 7 /* A malloc() failed */
932+#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
933+#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
934+#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
935+#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
936+#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
937+#define SQLITE_FULL 13 /* Insertion failed because database is full */
938+#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
939+#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
940+#define SQLITE_EMPTY 16 /* Database is empty */
941+#define SQLITE_SCHEMA 17 /* The database schema changed */
942+#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
943+#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
944+#define SQLITE_MISMATCH 20 /* Data type mismatch */
945+#define SQLITE_MISUSE 21 /* Library used incorrectly */
946+#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
947+#define SQLITE_AUTH 23 /* Authorization denied */
948+#define SQLITE_FORMAT 24 /* Auxiliary database format error */
949+#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
950+#define SQLITE_NOTADB 26 /* File opened that is not a database file */
951+#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
952+#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
953+/* end-of-error-codes */
954+
955+/*
956+** CAPI3REF: Extended Result Codes
957+** KEYWORDS: {extended error code} {extended error codes}
958+** KEYWORDS: {extended result code} {extended result codes}
959+**
960+** In its default configuration, SQLite API routines return one of 26 integer
961+** [SQLITE_OK | result codes]. However, experience has shown that many of
962+** these result codes are too coarse-grained. They do not provide as
963+** much information about problems as programmers might like. In an effort to
964+** address this, newer versions of SQLite (version 3.3.8 and later) include
965+** support for additional result codes that provide more detailed information
966+** about errors. The extended result codes are enabled or disabled
967+** on a per database connection basis using the
968+** [sqlite3_extended_result_codes()] API.
969+**
970+** Some of the available extended result codes are listed here.
971+** One may expect the number of extended result codes will be expand
972+** over time. Software that uses extended result codes should expect
973+** to see new result codes in future releases of SQLite.
974+**
975+** The SQLITE_OK result code will never be extended. It will always
976+** be exactly zero.
977+*/
978+#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
979+#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
980+#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
981+#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
982+#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))
983+#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))
984+#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8))
985+#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8))
986+#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8))
987+#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8))
988+#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8))
989+#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8))
990+#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8))
991+#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8))
992+#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))
993+#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))
994+#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))
995+#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8))
996+#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8))
997+#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
998+#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
999+#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
1000+#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
1001+#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
1002+#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
1003+#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
1004+#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
1005+#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
1006+
1007+/*
1008+** CAPI3REF: Flags For File Open Operations
1009+**
1010+** These bit values are intended for use in the
1011+** 3rd parameter to the [sqlite3_open_v2()] interface and
1012+** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
1013+*/
1014+#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
1015+#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
1016+#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */
1017+#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */
1018+#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
1019+#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */
1020+#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */
1021+#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
1022+#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
1023+#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
1024+#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
1025+#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
1026+#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
1027+#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
1028+#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
1029+#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
1030+#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
1031+#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
1032+#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
1033+
1034+/* Reserved: 0x00F00000 */
1035+
1036+/*
1037+** CAPI3REF: Device Characteristics
1038+**
1039+** The xDeviceCharacteristics method of the [sqlite3_io_methods]
1040+** object returns an integer which is a vector of the these
1041+** bit values expressing I/O characteristics of the mass storage
1042+** device that holds the file that the [sqlite3_io_methods]
1043+** refers to.
1044+**
1045+** The SQLITE_IOCAP_ATOMIC property means that all writes of
1046+** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
1047+** mean that writes of blocks that are nnn bytes in size and
1048+** are aligned to an address which is an integer multiple of
1049+** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means
1050+** that when data is appended to a file, the data is appended
1051+** first then the size of the file is extended, never the other
1052+** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
1053+** information is written to disk in the same order as calls
1054+** to xWrite().
1055+*/
1056+#define SQLITE_IOCAP_ATOMIC 0x00000001
1057+#define SQLITE_IOCAP_ATOMIC512 0x00000002
1058+#define SQLITE_IOCAP_ATOMIC1K 0x00000004
1059+#define SQLITE_IOCAP_ATOMIC2K 0x00000008
1060+#define SQLITE_IOCAP_ATOMIC4K 0x00000010
1061+#define SQLITE_IOCAP_ATOMIC8K 0x00000020
1062+#define SQLITE_IOCAP_ATOMIC16K 0x00000040
1063+#define SQLITE_IOCAP_ATOMIC32K 0x00000080
1064+#define SQLITE_IOCAP_ATOMIC64K 0x00000100
1065+#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
1066+#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
1067+#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
1068+
1069+/*
1070+** CAPI3REF: File Locking Levels
1071+**
1072+** SQLite uses one of these integer values as the second
1073+** argument to calls it makes to the xLock() and xUnlock() methods
1074+** of an [sqlite3_io_methods] object.
1075+*/
1076+#define SQLITE_LOCK_NONE 0
1077+#define SQLITE_LOCK_SHARED 1
1078+#define SQLITE_LOCK_RESERVED 2
1079+#define SQLITE_LOCK_PENDING 3
1080+#define SQLITE_LOCK_EXCLUSIVE 4
1081+
1082+/*
1083+** CAPI3REF: Synchronization Type Flags
1084+**
1085+** When SQLite invokes the xSync() method of an
1086+** [sqlite3_io_methods] object it uses a combination of
1087+** these integer values as the second argument.
1088+**
1089+** When the SQLITE_SYNC_DATAONLY flag is used, it means that the
1090+** sync operation only needs to flush data to mass storage. Inode
1091+** information need not be flushed. If the lower four bits of the flag
1092+** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics.
1093+** If the lower four bits equal SQLITE_SYNC_FULL, that means
1094+** to use Mac OS X style fullsync instead of fsync().
1095+**
1096+** Do not confuse the SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags
1097+** with the [PRAGMA synchronous]=NORMAL and [PRAGMA synchronous]=FULL
1098+** settings. The [synchronous pragma] determines when calls to the
1099+** xSync VFS method occur and applies uniformly across all platforms.
1100+** The SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags determine how
1101+** energetic or rigorous or forceful the sync operations are and
1102+** only make a difference on Mac OSX for the default SQLite code.
1103+** (Third-party VFS implementations might also make the distinction
1104+** between SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL, but among the
1105+** operating systems natively supported by SQLite, only Mac OSX
1106+** cares about the difference.)
1107+*/
1108+#define SQLITE_SYNC_NORMAL 0x00002
1109+#define SQLITE_SYNC_FULL 0x00003
1110+#define SQLITE_SYNC_DATAONLY 0x00010
1111+
1112+/*
1113+** CAPI3REF: OS Interface Open File Handle
1114+**
1115+** An [sqlite3_file] object represents an open file in the
1116+** [sqlite3_vfs | OS interface layer]. Individual OS interface
1117+** implementations will
1118+** want to subclass this object by appending additional fields
1119+** for their own use. The pMethods entry is a pointer to an
1120+** [sqlite3_io_methods] object that defines methods for performing
1121+** I/O operations on the open file.
1122+*/
1123+typedef struct sqlite3_file sqlite3_file;
1124+struct sqlite3_file {
1125+ const struct sqlite3_io_methods *pMethods; /* Methods for an open file */
1126+};
1127+
1128+/*
1129+** CAPI3REF: OS Interface File Virtual Methods Object
1130+**
1131+** Every file opened by the [sqlite3_vfs.xOpen] method populates an
1132+** [sqlite3_file] object (or, more commonly, a subclass of the
1133+** [sqlite3_file] object) with a pointer to an instance of this object.
1134+** This object defines the methods used to perform various operations
1135+** against the open file represented by the [sqlite3_file] object.
1136+**
1137+** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element
1138+** to a non-NULL pointer, then the sqlite3_io_methods.xClose method
1139+** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The
1140+** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen]
1141+** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element
1142+** to NULL.
1143+**
1144+** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
1145+** [SQLITE_SYNC_FULL]. The first choice is the normal fsync().
1146+** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY]
1147+** flag may be ORed in to indicate that only the data of the file
1148+** and not its inode needs to be synced.
1149+**
1150+** The integer values to xLock() and xUnlock() are one of
1151+** <ul>
1152+** <li> [SQLITE_LOCK_NONE],
1153+** <li> [SQLITE_LOCK_SHARED],
1154+** <li> [SQLITE_LOCK_RESERVED],
1155+** <li> [SQLITE_LOCK_PENDING], or
1156+** <li> [SQLITE_LOCK_EXCLUSIVE].
1157+** </ul>
1158+** xLock() increases the lock. xUnlock() decreases the lock.
1159+** The xCheckReservedLock() method checks whether any database connection,
1160+** either in this process or in some other process, is holding a RESERVED,
1161+** PENDING, or EXCLUSIVE lock on the file. It returns true
1162+** if such a lock exists and false otherwise.
1163+**
1164+** The xFileControl() method is a generic interface that allows custom
1165+** VFS implementations to directly control an open file using the
1166+** [sqlite3_file_control()] interface. The second "op" argument is an
1167+** integer opcode. The third argument is a generic pointer intended to
1168+** point to a structure that may contain arguments or space in which to
1169+** write return values. Potential uses for xFileControl() might be
1170+** functions to enable blocking locks with timeouts, to change the
1171+** locking strategy (for example to use dot-file locks), to inquire
1172+** about the status of a lock, or to break stale locks. The SQLite
1173+** core reserves all opcodes less than 100 for its own use.
1174+** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
1175+** Applications that define a custom xFileControl method should use opcodes
1176+** greater than 100 to avoid conflicts. VFS implementations should
1177+** return [SQLITE_NOTFOUND] for file control opcodes that they do not
1178+** recognize.
1179+**
1180+** The xSectorSize() method returns the sector size of the
1181+** device that underlies the file. The sector size is the
1182+** minimum write that can be performed without disturbing
1183+** other bytes in the file. The xDeviceCharacteristics()
1184+** method returns a bit vector describing behaviors of the
1185+** underlying device:
1186+**
1187+** <ul>
1188+** <li> [SQLITE_IOCAP_ATOMIC]
1189+** <li> [SQLITE_IOCAP_ATOMIC512]
1190+** <li> [SQLITE_IOCAP_ATOMIC1K]
1191+** <li> [SQLITE_IOCAP_ATOMIC2K]
1192+** <li> [SQLITE_IOCAP_ATOMIC4K]
1193+** <li> [SQLITE_IOCAP_ATOMIC8K]
1194+** <li> [SQLITE_IOCAP_ATOMIC16K]
1195+** <li> [SQLITE_IOCAP_ATOMIC32K]
1196+** <li> [SQLITE_IOCAP_ATOMIC64K]
1197+** <li> [SQLITE_IOCAP_SAFE_APPEND]
1198+** <li> [SQLITE_IOCAP_SEQUENTIAL]
1199+** </ul>
1200+**
1201+** The SQLITE_IOCAP_ATOMIC property means that all writes of
1202+** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
1203+** mean that writes of blocks that are nnn bytes in size and
1204+** are aligned to an address which is an integer multiple of
1205+** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means
1206+** that when data is appended to a file, the data is appended
1207+** first then the size of the file is extended, never the other
1208+** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
1209+** information is written to disk in the same order as calls
1210+** to xWrite().
1211+**
1212+** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill
1213+** in the unread portions of the buffer with zeros. A VFS that
1214+** fails to zero-fill short reads might seem to work. However,
1215+** failure to zero-fill short reads will eventually lead to
1216+** database corruption.
1217+*/
1218+typedef struct sqlite3_io_methods sqlite3_io_methods;
1219+struct sqlite3_io_methods {
1220+ int iVersion;
1221+ int (*xClose)(sqlite3_file*);
1222+ int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
1223+ int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
1224+ int (*xTruncate)(sqlite3_file*, sqlite3_int64 size);
1225+ int (*xSync)(sqlite3_file*, int flags);
1226+ int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize);
1227+ int (*xLock)(sqlite3_file*, int);
1228+ int (*xUnlock)(sqlite3_file*, int);
1229+ int (*xCheckReservedLock)(sqlite3_file*, int *pResOut);
1230+ int (*xFileControl)(sqlite3_file*, int op, void *pArg);
1231+ int (*xSectorSize)(sqlite3_file*);
1232+ int (*xDeviceCharacteristics)(sqlite3_file*);
1233+ /* Methods above are valid for version 1 */
1234+ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
1235+ int (*xShmLock)(sqlite3_file*, int offset, int n, int flags);
1236+ void (*xShmBarrier)(sqlite3_file*);
1237+ int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
1238+ /* Methods above are valid for version 2 */
1239+ /* Additional methods may be added in future releases */
1240+};
1241+
1242+/*
1243+** CAPI3REF: Standard File Control Opcodes
1244+**
1245+** These integer constants are opcodes for the xFileControl method
1246+** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
1247+** interface.
1248+**
1249+** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
1250+** opcode causes the xFileControl method to write the current state of
1251+** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
1252+** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
1253+** into an integer that the pArg argument points to. This capability
1254+** is used during testing and only needs to be supported when SQLITE_TEST
1255+** is defined.
1256+**
1257+** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
1258+** layer a hint of how large the database file will grow to be during the
1259+** current transaction. This hint is not guaranteed to be accurate but it
1260+** is often close. The underlying VFS might choose to preallocate database
1261+** file space based on this hint in order to help writes to the database
1262+** file run faster.
1263+**
1264+** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
1265+** extends and truncates the database file in chunks of a size specified
1266+** by the user. The fourth argument to [sqlite3_file_control()] should
1267+** point to an integer (type int) containing the new chunk-size to use
1268+** for the nominated database. Allocating database file space in large
1269+** chunks (say 1MB at a time), may reduce file-system fragmentation and
1270+** improve performance on some systems.
1271+**
1272+** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
1273+** to the [sqlite3_file] object associated with a particular database
1274+** connection. See the [sqlite3_file_control()] documentation for
1275+** additional information.
1276+**
1277+** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by
1278+** SQLite and sent to all VFSes in place of a call to the xSync method
1279+** when the database connection has [PRAGMA synchronous] set to OFF.)^
1280+** Some specialized VFSes need this signal in order to operate correctly
1281+** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most
1282+** VFSes do not need this signal and should silently ignore this opcode.
1283+** Applications should not call [sqlite3_file_control()] with this
1284+** opcode as doing so may disrupt the operation of the specialized VFSes
1285+** that do require it.
1286+**
1287+** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
1288+** retry counts and intervals for certain disk I/O operations for the
1289+** windows [VFS] in order to work to provide robustness against
1290+** anti-virus programs. By default, the windows VFS will retry file read,
1291+** file write, and file delete operations up to 10 times, with a delay
1292+** of 25 milliseconds before the first retry and with the delay increasing
1293+** by an additional 25 milliseconds with each subsequent retry. This
1294+** opcode allows those to values (10 retries and 25 milliseconds of delay)
1295+** to be adjusted. The values are changed for all database connections
1296+** within the same process. The argument is a pointer to an array of two
1297+** integers where the first integer i the new retry count and the second
1298+** integer is the delay. If either integer is negative, then the setting
1299+** is not changed but instead the prior value of that setting is written
1300+** into the array entry, allowing the current retry settings to be
1301+** interrogated. The zDbName parameter is ignored.
1302+**
1303+** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
1304+** persistent [WAL | Write AHead Log] setting. By default, the auxiliary
1305+** write ahead log and shared memory files used for transaction control
1306+** are automatically deleted when the latest connection to the database
1307+** closes. Setting persistent WAL mode causes those files to persist after
1308+** close. Persisting the files is useful when other processes that do not
1309+** have write permission on the directory containing the database file want
1310+** to read the database file, as the WAL and shared memory files must exist
1311+** in order for the database to be readable. The fourth parameter to
1312+** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
1313+** That integer is 0 to disable persistent WAL mode or 1 to enable persistent
1314+** WAL mode. If the integer is -1, then it is overwritten with the current
1315+** WAL persistence setting.
1316+**
1317+** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
1318+** a write transaction to indicate that, unless it is rolled back for some
1319+** reason, the entire database file will be overwritten by the current
1320+** transaction. This is used by VACUUM operations.
1321+*/
1322+#define SQLITE_FCNTL_LOCKSTATE 1
1323+#define SQLITE_GET_LOCKPROXYFILE 2
1324+#define SQLITE_SET_LOCKPROXYFILE 3
1325+#define SQLITE_LAST_ERRNO 4
1326+#define SQLITE_FCNTL_SIZE_HINT 5
1327+#define SQLITE_FCNTL_CHUNK_SIZE 6
1328+#define SQLITE_FCNTL_FILE_POINTER 7
1329+#define SQLITE_FCNTL_SYNC_OMITTED 8
1330+#define SQLITE_FCNTL_WIN32_AV_RETRY 9
1331+#define SQLITE_FCNTL_PERSIST_WAL 10
1332+#define SQLITE_FCNTL_OVERWRITE 11
1333+
1334+/*
1335+** CAPI3REF: Mutex Handle
1336+**
1337+** The mutex module within SQLite defines [sqlite3_mutex] to be an
1338+** abstract type for a mutex object. The SQLite core never looks
1339+** at the internal representation of an [sqlite3_mutex]. It only
1340+** deals with pointers to the [sqlite3_mutex] object.
1341+**
1342+** Mutexes are created using [sqlite3_mutex_alloc()].
1343+*/
1344+typedef struct sqlite3_mutex sqlite3_mutex;
1345+
1346+/*
1347+** CAPI3REF: OS Interface Object
1348+**
1349+** An instance of the sqlite3_vfs object defines the interface between
1350+** the SQLite core and the underlying operating system. The "vfs"
1351+** in the name of the object stands for "virtual file system". See
1352+** the [VFS | VFS documentation] for further information.
1353+**
1354+** The value of the iVersion field is initially 1 but may be larger in
1355+** future versions of SQLite. Additional fields may be appended to this
1356+** object when the iVersion value is increased. Note that the structure
1357+** of the sqlite3_vfs object changes in the transaction between
1358+** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not
1359+** modified.
1360+**
1361+** The szOsFile field is the size of the subclassed [sqlite3_file]
1362+** structure used by this VFS. mxPathname is the maximum length of
1363+** a pathname in this VFS.
1364+**
1365+** Registered sqlite3_vfs objects are kept on a linked list formed by
1366+** the pNext pointer. The [sqlite3_vfs_register()]
1367+** and [sqlite3_vfs_unregister()] interfaces manage this list
1368+** in a thread-safe way. The [sqlite3_vfs_find()] interface
1369+** searches the list. Neither the application code nor the VFS
1370+** implementation should use the pNext pointer.
1371+**
1372+** The pNext field is the only field in the sqlite3_vfs
1373+** structure that SQLite will ever modify. SQLite will only access
1374+** or modify this field while holding a particular static mutex.
1375+** The application should never modify anything within the sqlite3_vfs
1376+** object once the object has been registered.
1377+**
1378+** The zName field holds the name of the VFS module. The name must
1379+** be unique across all VFS modules.
1380+**
1381+** [[sqlite3_vfs.xOpen]]
1382+** ^SQLite guarantees that the zFilename parameter to xOpen
1383+** is either a NULL pointer or string obtained
1384+** from xFullPathname() with an optional suffix added.
1385+** ^If a suffix is added to the zFilename parameter, it will
1386+** consist of a single "-" character followed by no more than
1387+** 10 alphanumeric and/or "-" characters.
1388+** ^SQLite further guarantees that
1389+** the string will be valid and unchanged until xClose() is
1390+** called. Because of the previous sentence,
1391+** the [sqlite3_file] can safely store a pointer to the
1392+** filename if it needs to remember the filename for some reason.
1393+** If the zFilename parameter to xOpen is a NULL pointer then xOpen
1394+** must invent its own temporary name for the file. ^Whenever the
1395+** xFilename parameter is NULL it will also be the case that the
1396+** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
1397+**
1398+** The flags argument to xOpen() includes all bits set in
1399+** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()]
1400+** or [sqlite3_open16()] is used, then flags includes at least
1401+** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
1402+** If xOpen() opens a file read-only then it sets *pOutFlags to
1403+** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set.
1404+**
1405+** ^(SQLite will also add one of the following flags to the xOpen()
1406+** call, depending on the object being opened:
1407+**
1408+** <ul>
1409+** <li> [SQLITE_OPEN_MAIN_DB]
1410+** <li> [SQLITE_OPEN_MAIN_JOURNAL]
1411+** <li> [SQLITE_OPEN_TEMP_DB]
1412+** <li> [SQLITE_OPEN_TEMP_JOURNAL]
1413+** <li> [SQLITE_OPEN_TRANSIENT_DB]
1414+** <li> [SQLITE_OPEN_SUBJOURNAL]
1415+** <li> [SQLITE_OPEN_MASTER_JOURNAL]
1416+** <li> [SQLITE_OPEN_WAL]
1417+** </ul>)^
1418+**
1419+** The file I/O implementation can use the object type flags to
1420+** change the way it deals with files. For example, an application
1421+** that does not care about crash recovery or rollback might make
1422+** the open of a journal file a no-op. Writes to this journal would
1423+** also be no-ops, and any attempt to read the journal would return
1424+** SQLITE_IOERR. Or the implementation might recognize that a database
1425+** file will be doing page-aligned sector reads and writes in a random
1426+** order and set up its I/O subsystem accordingly.
1427+**
1428+** SQLite might also add one of the following flags to the xOpen method:
1429+**
1430+** <ul>
1431+** <li> [SQLITE_OPEN_DELETEONCLOSE]
1432+** <li> [SQLITE_OPEN_EXCLUSIVE]
1433+** </ul>
1434+**
1435+** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be
1436+** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE]
1437+** will be set for TEMP databases and their journals, transient
1438+** databases, and subjournals.
1439+**
1440+** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
1441+** with the [SQLITE_OPEN_CREATE] flag, which are both directly
1442+** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
1443+** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
1444+** SQLITE_OPEN_CREATE, is used to indicate that file should always
1445+** be created, and that it is an error if it already exists.
1446+** It is <i>not</i> used to indicate the file should be opened
1447+** for exclusive access.
1448+**
1449+** ^At least szOsFile bytes of memory are allocated by SQLite
1450+** to hold the [sqlite3_file] structure passed as the third
1451+** argument to xOpen. The xOpen method does not have to
1452+** allocate the structure; it should just fill it in. Note that
1453+** the xOpen method must set the sqlite3_file.pMethods to either
1454+** a valid [sqlite3_io_methods] object or to NULL. xOpen must do
1455+** this even if the open fails. SQLite expects that the sqlite3_file.pMethods
1456+** element will be valid after xOpen returns regardless of the success
1457+** or failure of the xOpen call.
1458+**
1459+** [[sqlite3_vfs.xAccess]]
1460+** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
1461+** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
1462+** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
1463+** to test whether a file is at least readable. The file can be a
1464+** directory.
1465+**
1466+** ^SQLite will always allocate at least mxPathname+1 bytes for the
1467+** output buffer xFullPathname. The exact size of the output buffer
1468+** is also passed as a parameter to both methods. If the output buffer
1469+** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is
1470+** handled as a fatal error by SQLite, vfs implementations should endeavor
1471+** to prevent this by setting mxPathname to a sufficiently large value.
1472+**
1473+** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64()
1474+** interfaces are not strictly a part of the filesystem, but they are
1475+** included in the VFS structure for completeness.
1476+** The xRandomness() function attempts to return nBytes bytes
1477+** of good-quality randomness into zOut. The return value is
1478+** the actual number of bytes of randomness obtained.
1479+** The xSleep() method causes the calling thread to sleep for at
1480+** least the number of microseconds given. ^The xCurrentTime()
1481+** method returns a Julian Day Number for the current date and time as
1482+** a floating point value.
1483+** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
1484+** Day Number multiplied by 86400000 (the number of milliseconds in
1485+** a 24-hour day).
1486+** ^SQLite will use the xCurrentTimeInt64() method to get the current
1487+** date and time if that method is available (if iVersion is 2 or
1488+** greater and the function pointer is not NULL) and will fall back
1489+** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
1490+**
1491+** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
1492+** are not used by the SQLite core. These optional interfaces are provided
1493+** by some VFSes to facilitate testing of the VFS code. By overriding
1494+** system calls with functions under its control, a test program can
1495+** simulate faults and error conditions that would otherwise be difficult
1496+** or impossible to induce. The set of system calls that can be overridden
1497+** varies from one VFS to another, and from one version of the same VFS to the
1498+** next. Applications that use these interfaces must be prepared for any
1499+** or all of these interfaces to be NULL or for their behavior to change
1500+** from one release to the next. Applications must not attempt to access
1501+** any of these methods if the iVersion of the VFS is less than 3.
1502+*/
1503+typedef struct sqlite3_vfs sqlite3_vfs;
1504+typedef void (*sqlite3_syscall_ptr)(void);
1505+struct sqlite3_vfs {
1506+ int iVersion; /* Structure version number (currently 3) */
1507+ int szOsFile; /* Size of subclassed sqlite3_file */
1508+ int mxPathname; /* Maximum file pathname length */
1509+ sqlite3_vfs *pNext; /* Next registered VFS */
1510+ const char *zName; /* Name of this virtual file system */
1511+ void *pAppData; /* Pointer to application-specific data */
1512+ int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
1513+ int flags, int *pOutFlags);
1514+ int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
1515+ int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut);
1516+ int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut);
1517+ void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename);
1518+ void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg);
1519+ void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void);
1520+ void (*xDlClose)(sqlite3_vfs*, void*);
1521+ int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut);
1522+ int (*xSleep)(sqlite3_vfs*, int microseconds);
1523+ int (*xCurrentTime)(sqlite3_vfs*, double*);
1524+ int (*xGetLastError)(sqlite3_vfs*, int, char *);
1525+ /*
1526+ ** The methods above are in version 1 of the sqlite_vfs object
1527+ ** definition. Those that follow are added in version 2 or later
1528+ */
1529+ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
1530+ /*
1531+ ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
1532+ ** Those below are for version 3 and greater.
1533+ */
1534+ int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr);
1535+ sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName);
1536+ const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
1537+ /*
1538+ ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
1539+ ** New fields may be appended in figure versions. The iVersion
1540+ ** value will increment whenever this happens.
1541+ */
1542+};
1543+
1544+/*
1545+** CAPI3REF: Flags for the xAccess VFS method
1546+**
1547+** These integer constants can be used as the third parameter to
1548+** the xAccess method of an [sqlite3_vfs] object. They determine
1549+** what kind of permissions the xAccess method is looking for.
1550+** With SQLITE_ACCESS_EXISTS, the xAccess method
1551+** simply checks whether the file exists.
1552+** With SQLITE_ACCESS_READWRITE, the xAccess method
1553+** checks whether the named directory is both readable and writable
1554+** (in other words, if files can be added, removed, and renamed within
1555+** the directory).
1556+** The SQLITE_ACCESS_READWRITE constant is currently used only by the
1557+** [temp_store_directory pragma], though this could change in a future
1558+** release of SQLite.
1559+** With SQLITE_ACCESS_READ, the xAccess method
1560+** checks whether the file is readable. The SQLITE_ACCESS_READ constant is
1561+** currently unused, though it might be used in a future release of
1562+** SQLite.
1563+*/
1564+#define SQLITE_ACCESS_EXISTS 0
1565+#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */
1566+#define SQLITE_ACCESS_READ 2 /* Unused */
1567+
1568+/*
1569+** CAPI3REF: Flags for the xShmLock VFS method
1570+**
1571+** These integer constants define the various locking operations
1572+** allowed by the xShmLock method of [sqlite3_io_methods]. The
1573+** following are the only legal combinations of flags to the
1574+** xShmLock method:
1575+**
1576+** <ul>
1577+** <li> SQLITE_SHM_LOCK | SQLITE_SHM_SHARED
1578+** <li> SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE
1579+** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED
1580+** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE
1581+** </ul>
1582+**
1583+** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
1584+** was given no the corresponding lock.
1585+**
1586+** The xShmLock method can transition between unlocked and SHARED or
1587+** between unlocked and EXCLUSIVE. It cannot transition between SHARED
1588+** and EXCLUSIVE.
1589+*/
1590+#define SQLITE_SHM_UNLOCK 1
1591+#define SQLITE_SHM_LOCK 2
1592+#define SQLITE_SHM_SHARED 4
1593+#define SQLITE_SHM_EXCLUSIVE 8
1594+
1595+/*
1596+** CAPI3REF: Maximum xShmLock index
1597+**
1598+** The xShmLock method on [sqlite3_io_methods] may use values
1599+** between 0 and this upper bound as its "offset" argument.
1600+** The SQLite core will never attempt to acquire or release a
1601+** lock outside of this range
1602+*/
1603+#define SQLITE_SHM_NLOCK 8
1604+
1605+
1606+/*
1607+** CAPI3REF: Initialize The SQLite Library
1608+**
1609+** ^The sqlite3_initialize() routine initializes the
1610+** SQLite library. ^The sqlite3_shutdown() routine
1611+** deallocates any resources that were allocated by sqlite3_initialize().
1612+** These routines are designed to aid in process initialization and
1613+** shutdown on embedded systems. Workstation applications using
1614+** SQLite normally do not need to invoke either of these routines.
1615+**
1616+** A call to sqlite3_initialize() is an "effective" call if it is
1617+** the first time sqlite3_initialize() is invoked during the lifetime of
1618+** the process, or if it is the first time sqlite3_initialize() is invoked
1619+** following a call to sqlite3_shutdown(). ^(Only an effective call
1620+** of sqlite3_initialize() does any initialization. All other calls
1621+** are harmless no-ops.)^
1622+**
1623+** A call to sqlite3_shutdown() is an "effective" call if it is the first
1624+** call to sqlite3_shutdown() since the last sqlite3_initialize(). ^(Only
1625+** an effective call to sqlite3_shutdown() does any deinitialization.
1626+** All other valid calls to sqlite3_shutdown() are harmless no-ops.)^
1627+**
1628+** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown()
1629+** is not. The sqlite3_shutdown() interface must only be called from a
1630+** single thread. All open [database connections] must be closed and all
1631+** other SQLite resources must be deallocated prior to invoking
1632+** sqlite3_shutdown().
1633+**
1634+** Among other things, ^sqlite3_initialize() will invoke
1635+** sqlite3_os_init(). Similarly, ^sqlite3_shutdown()
1636+** will invoke sqlite3_os_end().
1637+**
1638+** ^The sqlite3_initialize() routine returns [SQLITE_OK] on success.
1639+** ^If for some reason, sqlite3_initialize() is unable to initialize
1640+** the library (perhaps it is unable to allocate a needed resource such
1641+** as a mutex) it returns an [error code] other than [SQLITE_OK].
1642+**
1643+** ^The sqlite3_initialize() routine is called internally by many other
1644+** SQLite interfaces so that an application usually does not need to
1645+** invoke sqlite3_initialize() directly. For example, [sqlite3_open()]
1646+** calls sqlite3_initialize() so the SQLite library will be automatically
1647+** initialized when [sqlite3_open()] is called if it has not be initialized
1648+** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT]
1649+** compile-time option, then the automatic calls to sqlite3_initialize()
1650+** are omitted and the application must call sqlite3_initialize() directly
1651+** prior to using any other SQLite interface. For maximum portability,
1652+** it is recommended that applications always invoke sqlite3_initialize()
1653+** directly prior to using any other SQLite interface. Future releases
1654+** of SQLite may require this. In other words, the behavior exhibited
1655+** when SQLite is compiled with [SQLITE_OMIT_AUTOINIT] might become the
1656+** default behavior in some future release of SQLite.
1657+**
1658+** The sqlite3_os_init() routine does operating-system specific
1659+** initialization of the SQLite library. The sqlite3_os_end()
1660+** routine undoes the effect of sqlite3_os_init(). Typical tasks
1661+** performed by these routines include allocation or deallocation
1662+** of static resources, initialization of global variables,
1663+** setting up a default [sqlite3_vfs] module, or setting up
1664+** a default configuration using [sqlite3_config()].
1665+**
1666+** The application should never invoke either sqlite3_os_init()
1667+** or sqlite3_os_end() directly. The application should only invoke
1668+** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init()
1669+** interface is called automatically by sqlite3_initialize() and
1670+** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate
1671+** implementations for sqlite3_os_init() and sqlite3_os_end()
1672+** are built into SQLite when it is compiled for Unix, Windows, or OS/2.
1673+** When [custom builds | built for other platforms]
1674+** (using the [SQLITE_OS_OTHER=1] compile-time
1675+** option) the application must supply a suitable implementation for
1676+** sqlite3_os_init() and sqlite3_os_end(). An application-supplied
1677+** implementation of sqlite3_os_init() or sqlite3_os_end()
1678+** must return [SQLITE_OK] on success and some other [error code] upon
1679+** failure.
1680+*/
1681+SQLITE_API int sqlite3_initialize(void);
1682+SQLITE_API int sqlite3_shutdown(void);
1683+SQLITE_API int sqlite3_os_init(void);
1684+SQLITE_API int sqlite3_os_end(void);
1685+
1686+/*
1687+** CAPI3REF: Configuring The SQLite Library
1688+**
1689+** The sqlite3_config() interface is used to make global configuration
1690+** changes to SQLite in order to tune SQLite to the specific needs of
1691+** the application. The default configuration is recommended for most
1692+** applications and so this routine is usually not necessary. It is
1693+** provided to support rare applications with unusual needs.
1694+**
1695+** The sqlite3_config() interface is not threadsafe. The application
1696+** must insure that no other SQLite interfaces are invoked by other
1697+** threads while sqlite3_config() is running. Furthermore, sqlite3_config()
1698+** may only be invoked prior to library initialization using
1699+** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
1700+** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
1701+** [sqlite3_shutdown()] then it will return SQLITE_MISUSE.
1702+** Note, however, that ^sqlite3_config() can be called as part of the
1703+** implementation of an application-defined [sqlite3_os_init()].
1704+**
1705+** The first argument to sqlite3_config() is an integer
1706+** [configuration option] that determines
1707+** what property of SQLite is to be configured. Subsequent arguments
1708+** vary depending on the [configuration option]
1709+** in the first argument.
1710+**
1711+** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
1712+** ^If the option is unknown or SQLite is unable to set the option
1713+** then this routine returns a non-zero [error code].
1714+*/
1715+SQLITE_API int sqlite3_config(int, ...);
1716+
1717+/*
1718+** CAPI3REF: Configure database connections
1719+**
1720+** The sqlite3_db_config() interface is used to make configuration
1721+** changes to a [database connection]. The interface is similar to
1722+** [sqlite3_config()] except that the changes apply to a single
1723+** [database connection] (specified in the first argument).
1724+**
1725+** The second argument to sqlite3_db_config(D,V,...) is the
1726+** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
1727+** that indicates what aspect of the [database connection] is being configured.
1728+** Subsequent arguments vary depending on the configuration verb.
1729+**
1730+** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
1731+** the call is considered successful.
1732+*/
1733+SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
1734+
1735+/*
1736+** CAPI3REF: Memory Allocation Routines
1737+**
1738+** An instance of this object defines the interface between SQLite
1739+** and low-level memory allocation routines.
1740+**
1741+** This object is used in only one place in the SQLite interface.
1742+** A pointer to an instance of this object is the argument to
1743+** [sqlite3_config()] when the configuration option is
1744+** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
1745+** By creating an instance of this object
1746+** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC])
1747+** during configuration, an application can specify an alternative
1748+** memory allocation subsystem for SQLite to use for all of its
1749+** dynamic memory needs.
1750+**
1751+** Note that SQLite comes with several [built-in memory allocators]
1752+** that are perfectly adequate for the overwhelming majority of applications
1753+** and that this object is only useful to a tiny minority of applications
1754+** with specialized memory allocation requirements. This object is
1755+** also used during testing of SQLite in order to specify an alternative
1756+** memory allocator that simulates memory out-of-memory conditions in
1757+** order to verify that SQLite recovers gracefully from such
1758+** conditions.
1759+**
1760+** The xMalloc, xRealloc, and xFree methods must work like the
1761+** malloc(), realloc() and free() functions from the standard C library.
1762+** ^SQLite guarantees that the second argument to
1763+** xRealloc is always a value returned by a prior call to xRoundup.
1764+**
1765+** xSize should return the allocated size of a memory allocation
1766+** previously obtained from xMalloc or xRealloc. The allocated size
1767+** is always at least as big as the requested size but may be larger.
1768+**
1769+** The xRoundup method returns what would be the allocated size of
1770+** a memory allocation given a particular requested size. Most memory
1771+** allocators round up memory allocations at least to the next multiple
1772+** of 8. Some allocators round up to a larger multiple or to a power of 2.
1773+** Every memory allocation request coming in through [sqlite3_malloc()]
1774+** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
1775+** that causes the corresponding memory allocation to fail.
1776+**
1777+** The xInit method initializes the memory allocator. (For example,
1778+** it might allocate any require mutexes or initialize internal data
1779+** structures. The xShutdown method is invoked (indirectly) by
1780+** [sqlite3_shutdown()] and should deallocate any resources acquired
1781+** by xInit. The pAppData pointer is used as the only parameter to
1782+** xInit and xShutdown.
1783+**
1784+** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
1785+** the xInit method, so the xInit method need not be threadsafe. The
1786+** xShutdown method is only called from [sqlite3_shutdown()] so it does
1787+** not need to be threadsafe either. For all other methods, SQLite
1788+** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the
1789+** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which
1790+** it is by default) and so the methods are automatically serialized.
1791+** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other
1792+** methods must be threadsafe or else make their own arrangements for
1793+** serialization.
1794+**
1795+** SQLite will never invoke xInit() more than once without an intervening
1796+** call to xShutdown().
1797+*/
1798+typedef struct sqlite3_mem_methods sqlite3_mem_methods;
1799+struct sqlite3_mem_methods {
1800+ void *(*xMalloc)(int); /* Memory allocation function */
1801+ void (*xFree)(void*); /* Free a prior allocation */
1802+ void *(*xRealloc)(void*,int); /* Resize an allocation */
1803+ int (*xSize)(void*); /* Return the size of an allocation */
1804+ int (*xRoundup)(int); /* Round up request size to allocation size */
1805+ int (*xInit)(void*); /* Initialize the memory allocator */
1806+ void (*xShutdown)(void*); /* Deinitialize the memory allocator */
1807+ void *pAppData; /* Argument to xInit() and xShutdown() */
1808+};
1809+
1810+/*
1811+** CAPI3REF: Configuration Options
1812+** KEYWORDS: {configuration option}
1813+**
1814+** These constants are the available integer configuration options that
1815+** can be passed as the first argument to the [sqlite3_config()] interface.
1816+**
1817+** New configuration options may be added in future releases of SQLite.
1818+** Existing configuration options might be discontinued. Applications
1819+** should check the return code from [sqlite3_config()] to make sure that
1820+** the call worked. The [sqlite3_config()] interface will return a
1821+** non-zero [error code] if a discontinued or unsupported configuration option
1822+** is invoked.
1823+**
1824+** <dl>
1825+** [[SQLITE_CONFIG_SINGLETHREAD]] <dt>SQLITE_CONFIG_SINGLETHREAD</dt>
1826+** <dd>There are no arguments to this option. ^This option sets the
1827+** [threading mode] to Single-thread. In other words, it disables
1828+** all mutexing and puts SQLite into a mode where it can only be used
1829+** by a single thread. ^If SQLite is compiled with
1830+** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
1831+** it is not possible to change the [threading mode] from its default
1832+** value of Single-thread and so [sqlite3_config()] will return
1833+** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
1834+** configuration option.</dd>
1835+**
1836+** [[SQLITE_CONFIG_MULTITHREAD]] <dt>SQLITE_CONFIG_MULTITHREAD</dt>
1837+** <dd>There are no arguments to this option. ^This option sets the
1838+** [threading mode] to Multi-thread. In other words, it disables
1839+** mutexing on [database connection] and [prepared statement] objects.
1840+** The application is responsible for serializing access to
1841+** [database connections] and [prepared statements]. But other mutexes
1842+** are enabled so that SQLite will be safe to use in a multi-threaded
1843+** environment as long as no two threads attempt to use the same
1844+** [database connection] at the same time. ^If SQLite is compiled with
1845+** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
1846+** it is not possible to set the Multi-thread [threading mode] and
1847+** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
1848+** SQLITE_CONFIG_MULTITHREAD configuration option.</dd>
1849+**
1850+** [[SQLITE_CONFIG_SERIALIZED]] <dt>SQLITE_CONFIG_SERIALIZED</dt>
1851+** <dd>There are no arguments to this option. ^This option sets the
1852+** [threading mode] to Serialized. In other words, this option enables
1853+** all mutexes including the recursive
1854+** mutexes on [database connection] and [prepared statement] objects.
1855+** In this mode (which is the default when SQLite is compiled with
1856+** [SQLITE_THREADSAFE=1]) the SQLite library will itself serialize access
1857+** to [database connections] and [prepared statements] so that the
1858+** application is free to use the same [database connection] or the
1859+** same [prepared statement] in different threads at the same time.
1860+** ^If SQLite is compiled with
1861+** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
1862+** it is not possible to set the Serialized [threading mode] and
1863+** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
1864+** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
1865+**
1866+** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
1867+** <dd> ^(This option takes a single argument which is a pointer to an
1868+** instance of the [sqlite3_mem_methods] structure. The argument specifies
1869+** alternative low-level memory allocation routines to be used in place of
1870+** the memory allocation routines built into SQLite.)^ ^SQLite makes
1871+** its own private copy of the content of the [sqlite3_mem_methods] structure
1872+** before the [sqlite3_config()] call returns.</dd>
1873+**
1874+** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt>
1875+** <dd> ^(This option takes a single argument which is a pointer to an
1876+** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods]
1877+** structure is filled with the currently defined memory allocation routines.)^
1878+** This option can be used to overload the default memory allocation
1879+** routines with a wrapper that simulations memory allocation failure or
1880+** tracks memory usage, for example. </dd>
1881+**
1882+** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
1883+** <dd> ^This option takes single argument of type int, interpreted as a
1884+** boolean, which enables or disables the collection of memory allocation
1885+** statistics. ^(When memory allocation statistics are disabled, the
1886+** following SQLite interfaces become non-operational:
1887+** <ul>
1888+** <li> [sqlite3_memory_used()]
1889+** <li> [sqlite3_memory_highwater()]
1890+** <li> [sqlite3_soft_heap_limit64()]
1891+** <li> [sqlite3_status()]
1892+** </ul>)^
1893+** ^Memory allocation statistics are enabled by default unless SQLite is
1894+** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory
1895+** allocation statistics are disabled by default.
1896+** </dd>
1897+**
1898+** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
1899+** <dd> ^This option specifies a static memory buffer that SQLite can use for
1900+** scratch memory. There are three arguments: A pointer an 8-byte
1901+** aligned memory buffer from which the scratch allocations will be
1902+** drawn, the size of each scratch allocation (sz),
1903+** and the maximum number of scratch allocations (N). The sz
1904+** argument must be a multiple of 16.
1905+** The first argument must be a pointer to an 8-byte aligned buffer
1906+** of at least sz*N bytes of memory.
1907+** ^SQLite will use no more than two scratch buffers per thread. So
1908+** N should be set to twice the expected maximum number of threads.
1909+** ^SQLite will never require a scratch buffer that is more than 6
1910+** times the database page size. ^If SQLite needs needs additional
1911+** scratch memory beyond what is provided by this configuration option, then
1912+** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
1913+**
1914+** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
1915+** <dd> ^This option specifies a static memory buffer that SQLite can use for
1916+** the database page cache with the default page cache implementation.
1917+** This configuration should not be used if an application-define page
1918+** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
1919+** There are three arguments to this option: A pointer to 8-byte aligned
1920+** memory, the size of each page buffer (sz), and the number of pages (N).
1921+** The sz argument should be the size of the largest database page
1922+** (a power of two between 512 and 32768) plus a little extra for each
1923+** page header. ^The page header size is 20 to 40 bytes depending on
1924+** the host architecture. ^It is harmless, apart from the wasted memory,
1925+** to make sz a little too large. The first
1926+** argument should point to an allocation of at least sz*N bytes of memory.
1927+** ^SQLite will use the memory provided by the first argument to satisfy its
1928+** memory needs for the first N pages that it adds to cache. ^If additional
1929+** page cache memory is needed beyond what is provided by this option, then
1930+** SQLite goes to [sqlite3_malloc()] for the additional storage space.
1931+** The pointer in the first argument must
1932+** be aligned to an 8-byte boundary or subsequent behavior of SQLite
1933+** will be undefined.</dd>
1934+**
1935+** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
1936+** <dd> ^This option specifies a static memory buffer that SQLite will use
1937+** for all of its dynamic memory allocation needs beyond those provided
1938+** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
1939+** There are three arguments: An 8-byte aligned pointer to the memory,
1940+** the number of bytes in the memory buffer, and the minimum allocation size.
1941+** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts
1942+** to using its default memory allocator (the system malloc() implementation),
1943+** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
1944+** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
1945+** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
1946+** allocator is engaged to handle all of SQLites memory allocation needs.
1947+** The first pointer (the memory pointer) must be aligned to an 8-byte
1948+** boundary or subsequent behavior of SQLite will be undefined.
1949+** The minimum allocation size is capped at 2**12. Reasonable values
1950+** for the minimum allocation size are 2**5 through 2**8.</dd>
1951+**
1952+** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
1953+** <dd> ^(This option takes a single argument which is a pointer to an
1954+** instance of the [sqlite3_mutex_methods] structure. The argument specifies
1955+** alternative low-level mutex routines to be used in place
1956+** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the
1957+** content of the [sqlite3_mutex_methods] structure before the call to
1958+** [sqlite3_config()] returns. ^If SQLite is compiled with
1959+** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
1960+** the entire mutexing subsystem is omitted from the build and hence calls to
1961+** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will
1962+** return [SQLITE_ERROR].</dd>
1963+**
1964+** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt>
1965+** <dd> ^(This option takes a single argument which is a pointer to an
1966+** instance of the [sqlite3_mutex_methods] structure. The
1967+** [sqlite3_mutex_methods]
1968+** structure is filled with the currently defined mutex routines.)^
1969+** This option can be used to overload the default mutex allocation
1970+** routines with a wrapper used to track mutex usage for performance
1971+** profiling or testing, for example. ^If SQLite is compiled with
1972+** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
1973+** the entire mutexing subsystem is omitted from the build and hence calls to
1974+** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will
1975+** return [SQLITE_ERROR].</dd>
1976+**
1977+** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
1978+** <dd> ^(This option takes two arguments that determine the default
1979+** memory allocation for the lookaside memory allocator on each
1980+** [database connection]. The first argument is the
1981+** size of each lookaside buffer slot and the second is the number of
1982+** slots allocated to each database connection.)^ ^(This option sets the
1983+** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
1984+** verb to [sqlite3_db_config()] can be used to change the lookaside
1985+** configuration on individual connections.)^ </dd>
1986+**
1987+** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt>
1988+** <dd> ^(This option takes a single argument which is a pointer to
1989+** an [sqlite3_pcache_methods] object. This object specifies the interface
1990+** to a custom page cache implementation.)^ ^SQLite makes a copy of the
1991+** object and uses it for page cache memory allocations.</dd>
1992+**
1993+** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt>
1994+** <dd> ^(This option takes a single argument which is a pointer to an
1995+** [sqlite3_pcache_methods] object. SQLite copies of the current
1996+** page cache implementation into that object.)^ </dd>
1997+**
1998+** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
1999+** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
2000+** function with a call signature of void(*)(void*,int,const char*),
2001+** and a pointer to void. ^If the function pointer is not NULL, it is
2002+** invoked by [sqlite3_log()] to process each logging event. ^If the
2003+** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
2004+** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is
2005+** passed through as the first parameter to the application-defined logger
2006+** function whenever that function is invoked. ^The second parameter to
2007+** the logger function is a copy of the first parameter to the corresponding
2008+** [sqlite3_log()] call and is intended to be a [result code] or an
2009+** [extended result code]. ^The third parameter passed to the logger is
2010+** log message after formatting via [sqlite3_snprintf()].
2011+** The SQLite logging interface is not reentrant; the logger function
2012+** supplied by the application must not invoke any SQLite interface.
2013+** In a multi-threaded application, the application-defined logger
2014+** function must be threadsafe. </dd>
2015+**
2016+** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
2017+** <dd> This option takes a single argument of type int. If non-zero, then
2018+** URI handling is globally enabled. If the parameter is zero, then URI handling
2019+** is globally disabled. If URI handling is globally enabled, all filenames
2020+** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
2021+** specified as part of [ATTACH] commands are interpreted as URIs, regardless
2022+** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
2023+** connection is opened. If it is globally disabled, filenames are
2024+** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the
2025+** database connection is opened. By default, URI handling is globally
2026+** disabled. The default value may be changed by compiling with the
2027+** [SQLITE_USE_URI] symbol defined.
2028+** </dl>
2029+*/
2030+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
2031+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
2032+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
2033+#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
2034+#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
2035+#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */
2036+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
2037+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
2038+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
2039+#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
2040+#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
2041+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
2042+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
2043+#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */
2044+#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */
2045+#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
2046+#define SQLITE_CONFIG_URI 17 /* int */
2047+
2048+/*
2049+** CAPI3REF: Database Connection Configuration Options
2050+**
2051+** These constants are the available integer configuration options that
2052+** can be passed as the second argument to the [sqlite3_db_config()] interface.
2053+**
2054+** New configuration options may be added in future releases of SQLite.
2055+** Existing configuration options might be discontinued. Applications
2056+** should check the return code from [sqlite3_db_config()] to make sure that
2057+** the call worked. ^The [sqlite3_db_config()] interface will return a
2058+** non-zero [error code] if a discontinued or unsupported configuration option
2059+** is invoked.
2060+**
2061+** <dl>
2062+** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
2063+** <dd> ^This option takes three additional arguments that determine the
2064+** [lookaside memory allocator] configuration for the [database connection].
2065+** ^The first argument (the third parameter to [sqlite3_db_config()] is a
2066+** pointer to a memory buffer to use for lookaside memory.
2067+** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
2068+** may be NULL in which case SQLite will allocate the
2069+** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the
2070+** size of each lookaside buffer slot. ^The third argument is the number of
2071+** slots. The size of the buffer in the first argument must be greater than
2072+** or equal to the product of the second and third arguments. The buffer
2073+** must be aligned to an 8-byte boundary. ^If the second argument to
2074+** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
2075+** rounded down to the next smaller multiple of 8. ^(The lookaside memory
2076+** configuration for a database connection can only be changed when that
2077+** connection is not currently using lookaside memory, or in other words
2078+** when the "current value" returned by
2079+** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
2080+** Any attempt to change the lookaside memory configuration when lookaside
2081+** memory is in use leaves the configuration unchanged and returns
2082+** [SQLITE_BUSY].)^</dd>
2083+**
2084+** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
2085+** <dd> ^This option is used to enable or disable the enforcement of
2086+** [foreign key constraints]. There should be two additional arguments.
2087+** The first argument is an integer which is 0 to disable FK enforcement,
2088+** positive to enable FK enforcement or negative to leave FK enforcement
2089+** unchanged. The second parameter is a pointer to an integer into which
2090+** is written 0 or 1 to indicate whether FK enforcement is off or on
2091+** following this call. The second parameter may be a NULL pointer, in
2092+** which case the FK enforcement setting is not reported back. </dd>
2093+**
2094+** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt>
2095+** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers].
2096+** There should be two additional arguments.
2097+** The first argument is an integer which is 0 to disable triggers,
2098+** positive to enable triggers or negative to leave the setting unchanged.
2099+** The second parameter is a pointer to an integer into which
2100+** is written 0 or 1 to indicate whether triggers are disabled or enabled
2101+** following this call. The second parameter may be a NULL pointer, in
2102+** which case the trigger setting is not reported back. </dd>
2103+**
2104+** </dl>
2105+*/
2106+#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
2107+#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
2108+#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
2109+
2110+
2111+/*
2112+** CAPI3REF: Enable Or Disable Extended Result Codes
2113+**
2114+** ^The sqlite3_extended_result_codes() routine enables or disables the
2115+** [extended result codes] feature of SQLite. ^The extended result
2116+** codes are disabled by default for historical compatibility.
2117+*/
2118+SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
2119+
2120+/*
2121+** CAPI3REF: Last Insert Rowid
2122+**
2123+** ^Each entry in an SQLite table has a unique 64-bit signed
2124+** integer key called the [ROWID | "rowid"]. ^The rowid is always available
2125+** as an undeclared column named ROWID, OID, or _ROWID_ as long as those
2126+** names are not also used by explicitly declared columns. ^If
2127+** the table has a column of type [INTEGER PRIMARY KEY] then that column
2128+** is another alias for the rowid.
2129+**
2130+** ^This routine returns the [rowid] of the most recent
2131+** successful [INSERT] into the database from the [database connection]
2132+** in the first argument. ^As of SQLite version 3.7.7, this routines
2133+** records the last insert rowid of both ordinary tables and [virtual tables].
2134+** ^If no successful [INSERT]s
2135+** have ever occurred on that database connection, zero is returned.
2136+**
2137+** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
2138+** method, then this routine will return the [rowid] of the inserted
2139+** row as long as the trigger or virtual table method is running.
2140+** But once the trigger or virtual table method ends, the value returned
2141+** by this routine reverts to what it was before the trigger or virtual
2142+** table method began.)^
2143+**
2144+** ^An [INSERT] that fails due to a constraint violation is not a
2145+** successful [INSERT] and does not change the value returned by this
2146+** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK,
2147+** and INSERT OR ABORT make no changes to the return value of this
2148+** routine when their insertion fails. ^(When INSERT OR REPLACE
2149+** encounters a constraint violation, it does not fail. The
2150+** INSERT continues to completion after deleting rows that caused
2151+** the constraint problem so INSERT OR REPLACE will always change
2152+** the return value of this interface.)^
2153+**
2154+** ^For the purposes of this routine, an [INSERT] is considered to
2155+** be successful even if it is subsequently rolled back.
2156+**
2157+** This function is accessible to SQL statements via the
2158+** [last_insert_rowid() SQL function].
2159+**
2160+** If a separate thread performs a new [INSERT] on the same
2161+** database connection while the [sqlite3_last_insert_rowid()]
2162+** function is running and thus changes the last insert [rowid],
2163+** then the value returned by [sqlite3_last_insert_rowid()] is
2164+** unpredictable and might not equal either the old or the new
2165+** last insert [rowid].
2166+*/
2167+SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
2168+
2169+/*
2170+** CAPI3REF: Count The Number Of Rows Modified
2171+**
2172+** ^This function returns the number of database rows that were changed
2173+** or inserted or deleted by the most recently completed SQL statement
2174+** on the [database connection] specified by the first parameter.
2175+** ^(Only changes that are directly specified by the [INSERT], [UPDATE],
2176+** or [DELETE] statement are counted. Auxiliary changes caused by
2177+** triggers or [foreign key actions] are not counted.)^ Use the
2178+** [sqlite3_total_changes()] function to find the total number of changes
2179+** including changes caused by triggers and foreign key actions.
2180+**
2181+** ^Changes to a view that are simulated by an [INSTEAD OF trigger]
2182+** are not counted. Only real table changes are counted.
2183+**
2184+** ^(A "row change" is a change to a single row of a single table
2185+** caused by an INSERT, DELETE, or UPDATE statement. Rows that
2186+** are changed as side effects of [REPLACE] constraint resolution,
2187+** rollback, ABORT processing, [DROP TABLE], or by any other
2188+** mechanisms do not count as direct row changes.)^
2189+**
2190+** A "trigger context" is a scope of execution that begins and
2191+** ends with the script of a [CREATE TRIGGER | trigger].
2192+** Most SQL statements are
2193+** evaluated outside of any trigger. This is the "top level"
2194+** trigger context. If a trigger fires from the top level, a
2195+** new trigger context is entered for the duration of that one
2196+** trigger. Subtriggers create subcontexts for their duration.
2197+**
2198+** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
2199+** not create a new trigger context.
2200+**
2201+** ^This function returns the number of direct row changes in the
2202+** most recent INSERT, UPDATE, or DELETE statement within the same
2203+** trigger context.
2204+**
2205+** ^Thus, when called from the top level, this function returns the
2206+** number of changes in the most recent INSERT, UPDATE, or DELETE
2207+** that also occurred at the top level. ^(Within the body of a trigger,
2208+** the sqlite3_changes() interface can be called to find the number of
2209+** changes in the most recently completed INSERT, UPDATE, or DELETE
2210+** statement within the body of the same trigger.
2211+** However, the number returned does not include changes
2212+** caused by subtriggers since those have their own context.)^
2213+**
2214+** See also the [sqlite3_total_changes()] interface, the
2215+** [count_changes pragma], and the [changes() SQL function].
2216+**
2217+** If a separate thread makes changes on the same database connection
2218+** while [sqlite3_changes()] is running then the value returned
2219+** is unpredictable and not meaningful.
2220+*/
2221+SQLITE_API int sqlite3_changes(sqlite3*);
2222+
2223+/*
2224+** CAPI3REF: Total Number Of Rows Modified
2225+**
2226+** ^This function returns the number of row changes caused by [INSERT],
2227+** [UPDATE] or [DELETE] statements since the [database connection] was opened.
2228+** ^(The count returned by sqlite3_total_changes() includes all changes
2229+** from all [CREATE TRIGGER | trigger] contexts and changes made by
2230+** [foreign key actions]. However,
2231+** the count does not include changes used to implement [REPLACE] constraints,
2232+** do rollbacks or ABORT processing, or [DROP TABLE] processing. The
2233+** count does not include rows of views that fire an [INSTEAD OF trigger],
2234+** though if the INSTEAD OF trigger makes changes of its own, those changes
2235+** are counted.)^
2236+** ^The sqlite3_total_changes() function counts the changes as soon as
2237+** the statement that makes them is completed (when the statement handle
2238+** is passed to [sqlite3_reset()] or [sqlite3_finalize()]).
2239+**
2240+** See also the [sqlite3_changes()] interface, the
2241+** [count_changes pragma], and the [total_changes() SQL function].
2242+**
2243+** If a separate thread makes changes on the same database connection
2244+** while [sqlite3_total_changes()] is running then the value
2245+** returned is unpredictable and not meaningful.
2246+*/
2247+SQLITE_API int sqlite3_total_changes(sqlite3*);
2248+
2249+/*
2250+** CAPI3REF: Interrupt A Long-Running Query
2251+**
2252+** ^This function causes any pending database operation to abort and
2253+** return at its earliest opportunity. This routine is typically
2254+** called in response to a user action such as pressing "Cancel"
2255+** or Ctrl-C where the user wants a long query operation to halt
2256+** immediately.
2257+**
2258+** ^It is safe to call this routine from a thread different from the
2259+** thread that is currently running the database operation. But it
2260+** is not safe to call this routine with a [database connection] that
2261+** is closed or might close before sqlite3_interrupt() returns.
2262+**
2263+** ^If an SQL operation is very nearly finished at the time when
2264+** sqlite3_interrupt() is called, then it might not have an opportunity
2265+** to be interrupted and might continue to completion.
2266+**
2267+** ^An SQL operation that is interrupted will return [SQLITE_INTERRUPT].
2268+** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE
2269+** that is inside an explicit transaction, then the entire transaction
2270+** will be rolled back automatically.
2271+**
2272+** ^The sqlite3_interrupt(D) call is in effect until all currently running
2273+** SQL statements on [database connection] D complete. ^Any new SQL statements
2274+** that are started after the sqlite3_interrupt() call and before the
2275+** running statements reaches zero are interrupted as if they had been
2276+** running prior to the sqlite3_interrupt() call. ^New SQL statements
2277+** that are started after the running statement count reaches zero are
2278+** not effected by the sqlite3_interrupt().
2279+** ^A call to sqlite3_interrupt(D) that occurs when there are no running
2280+** SQL statements is a no-op and has no effect on SQL statements
2281+** that are started after the sqlite3_interrupt() call returns.
2282+**
2283+** If the database connection closes while [sqlite3_interrupt()]
2284+** is running then bad things will likely happen.
2285+*/
2286+SQLITE_API void sqlite3_interrupt(sqlite3*);
2287+
2288+/*
2289+** CAPI3REF: Determine If An SQL Statement Is Complete
2290+**
2291+** These routines are useful during command-line input to determine if the
2292+** currently entered text seems to form a complete SQL statement or
2293+** if additional input is needed before sending the text into
2294+** SQLite for parsing. ^These routines return 1 if the input string
2295+** appears to be a complete SQL statement. ^A statement is judged to be
2296+** complete if it ends with a semicolon token and is not a prefix of a
2297+** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within
2298+** string literals or quoted identifier names or comments are not
2299+** independent tokens (they are part of the token in which they are
2300+** embedded) and thus do not count as a statement terminator. ^Whitespace
2301+** and comments that follow the final semicolon are ignored.
2302+**
2303+** ^These routines return 0 if the statement is incomplete. ^If a
2304+** memory allocation fails, then SQLITE_NOMEM is returned.
2305+**
2306+** ^These routines do not parse the SQL statements thus
2307+** will not detect syntactically incorrect SQL.
2308+**
2309+** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
2310+** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
2311+** automatically by sqlite3_complete16(). If that initialization fails,
2312+** then the return value from sqlite3_complete16() will be non-zero
2313+** regardless of whether or not the input SQL is complete.)^
2314+**
2315+** The input to [sqlite3_complete()] must be a zero-terminated
2316+** UTF-8 string.
2317+**
2318+** The input to [sqlite3_complete16()] must be a zero-terminated
2319+** UTF-16 string in native byte order.
2320+*/
2321+SQLITE_API int sqlite3_complete(const char *sql);
2322+SQLITE_API int sqlite3_complete16(const void *sql);
2323+
2324+/*
2325+** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
2326+**
2327+** ^This routine sets a callback function that might be invoked whenever
2328+** an attempt is made to open a database table that another thread
2329+** or process has locked.
2330+**
2331+** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]
2332+** is returned immediately upon encountering the lock. ^If the busy callback
2333+** is not NULL, then the callback might be invoked with two arguments.
2334+**
2335+** ^The first argument to the busy handler is a copy of the void* pointer which
2336+** is the third argument to sqlite3_busy_handler(). ^The second argument to
2337+** the busy handler callback is the number of times that the busy handler has
2338+** been invoked for this locking event. ^If the
2339+** busy callback returns 0, then no additional attempts are made to
2340+** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned.
2341+** ^If the callback returns non-zero, then another attempt
2342+** is made to open the database for reading and the cycle repeats.
2343+**
2344+** The presence of a busy handler does not guarantee that it will be invoked
2345+** when there is lock contention. ^If SQLite determines that invoking the busy
2346+** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY]
2347+** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler.
2348+** Consider a scenario where one process is holding a read lock that
2349+** it is trying to promote to a reserved lock and
2350+** a second process is holding a reserved lock that it is trying
2351+** to promote to an exclusive lock. The first process cannot proceed
2352+** because it is blocked by the second and the second process cannot
2353+** proceed because it is blocked by the first. If both processes
2354+** invoke the busy handlers, neither will make any progress. Therefore,
2355+** SQLite returns [SQLITE_BUSY] for the first process, hoping that this
2356+** will induce the first process to release its read lock and allow
2357+** the second process to proceed.
2358+**
2359+** ^The default busy callback is NULL.
2360+**
2361+** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED]
2362+** when SQLite is in the middle of a large transaction where all the
2363+** changes will not fit into the in-memory cache. SQLite will
2364+** already hold a RESERVED lock on the database file, but it needs
2365+** to promote this lock to EXCLUSIVE so that it can spill cache
2366+** pages into the database file without harm to concurrent
2367+** readers. ^If it is unable to promote the lock, then the in-memory
2368+** cache will be left in an inconsistent state and so the error
2369+** code is promoted from the relatively benign [SQLITE_BUSY] to
2370+** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion
2371+** forces an automatic rollback of the changes. See the
2372+** <a href="/cvstrac/wiki?p=CorruptionFollowingBusyError">
2373+** CorruptionFollowingBusyError</a> wiki page for a discussion of why
2374+** this is important.
2375+**
2376+** ^(There can only be a single busy handler defined for each
2377+** [database connection]. Setting a new busy handler clears any
2378+** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()]
2379+** will also set or clear the busy handler.
2380+**
2381+** The busy callback should not take any actions which modify the
2382+** database connection that invoked the busy handler. Any such actions
2383+** result in undefined behavior.
2384+**
2385+** A busy handler must not close the database connection
2386+** or [prepared statement] that invoked the busy handler.
2387+*/
2388+SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
2389+
2390+/*
2391+** CAPI3REF: Set A Busy Timeout
2392+**
2393+** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps
2394+** for a specified amount of time when a table is locked. ^The handler
2395+** will sleep multiple times until at least "ms" milliseconds of sleeping
2396+** have accumulated. ^After at least "ms" milliseconds of sleeping,
2397+** the handler returns 0 which causes [sqlite3_step()] to return
2398+** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED].
2399+**
2400+** ^Calling this routine with an argument less than or equal to zero
2401+** turns off all busy handlers.
2402+**
2403+** ^(There can only be a single busy handler for a particular
2404+** [database connection] any any given moment. If another busy handler
2405+** was defined (using [sqlite3_busy_handler()]) prior to calling
2406+** this routine, that other busy handler is cleared.)^
2407+*/
2408+SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
2409+
2410+/*
2411+** CAPI3REF: Convenience Routines For Running Queries
2412+**
2413+** This is a legacy interface that is preserved for backwards compatibility.
2414+** Use of this interface is not recommended.
2415+**
2416+** Definition: A <b>result table</b> is memory data structure created by the
2417+** [sqlite3_get_table()] interface. A result table records the
2418+** complete query results from one or more queries.
2419+**
2420+** The table conceptually has a number of rows and columns. But
2421+** these numbers are not part of the result table itself. These
2422+** numbers are obtained separately. Let N be the number of rows
2423+** and M be the number of columns.
2424+**
2425+** A result table is an array of pointers to zero-terminated UTF-8 strings.
2426+** There are (N+1)*M elements in the array. The first M pointers point
2427+** to zero-terminated strings that contain the names of the columns.
2428+** The remaining entries all point to query results. NULL values result
2429+** in NULL pointers. All other values are in their UTF-8 zero-terminated
2430+** string representation as returned by [sqlite3_column_text()].
2431+**
2432+** A result table might consist of one or more memory allocations.
2433+** It is not safe to pass a result table directly to [sqlite3_free()].
2434+** A result table should be deallocated using [sqlite3_free_table()].
2435+**
2436+** ^(As an example of the result table format, suppose a query result
2437+** is as follows:
2438+**
2439+** <blockquote><pre>
2440+** Name | Age
2441+** -----------------------
2442+** Alice | 43
2443+** Bob | 28
2444+** Cindy | 21
2445+** </pre></blockquote>
2446+**
2447+** There are two column (M==2) and three rows (N==3). Thus the
2448+** result table has 8 entries. Suppose the result table is stored
2449+** in an array names azResult. Then azResult holds this content:
2450+**
2451+** <blockquote><pre>
2452+** azResult&#91;0] = "Name";
2453+** azResult&#91;1] = "Age";
2454+** azResult&#91;2] = "Alice";
2455+** azResult&#91;3] = "43";
2456+** azResult&#91;4] = "Bob";
2457+** azResult&#91;5] = "28";
2458+** azResult&#91;6] = "Cindy";
2459+** azResult&#91;7] = "21";
2460+** </pre></blockquote>)^
2461+**
2462+** ^The sqlite3_get_table() function evaluates one or more
2463+** semicolon-separated SQL statements in the zero-terminated UTF-8
2464+** string of its 2nd parameter and returns a result table to the
2465+** pointer given in its 3rd parameter.
2466+**
2467+** After the application has finished with the result from sqlite3_get_table(),
2468+** it must pass the result table pointer to sqlite3_free_table() in order to
2469+** release the memory that was malloced. Because of the way the
2470+** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling
2471+** function must not try to call [sqlite3_free()] directly. Only
2472+** [sqlite3_free_table()] is able to release the memory properly and safely.
2473+**
2474+** The sqlite3_get_table() interface is implemented as a wrapper around
2475+** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access
2476+** to any internal data structures of SQLite. It uses only the public
2477+** interface defined here. As a consequence, errors that occur in the
2478+** wrapper layer outside of the internal [sqlite3_exec()] call are not
2479+** reflected in subsequent calls to [sqlite3_errcode()] or
2480+** [sqlite3_errmsg()].
2481+*/
2482+SQLITE_API int sqlite3_get_table(
2483+ sqlite3 *db, /* An open database */
2484+ const char *zSql, /* SQL to be evaluated */
2485+ char ***pazResult, /* Results of the query */
2486+ int *pnRow, /* Number of result rows written here */
2487+ int *pnColumn, /* Number of result columns written here */
2488+ char **pzErrmsg /* Error msg written here */
2489+);
2490+SQLITE_API void sqlite3_free_table(char **result);
2491+
2492+/*
2493+** CAPI3REF: Formatted String Printing Functions
2494+**
2495+** These routines are work-alikes of the "printf()" family of functions
2496+** from the standard C library.
2497+**
2498+** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
2499+** results into memory obtained from [sqlite3_malloc()].
2500+** The strings returned by these two routines should be
2501+** released by [sqlite3_free()]. ^Both routines return a
2502+** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
2503+** memory to hold the resulting string.
2504+**
2505+** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
2506+** the standard C library. The result is written into the
2507+** buffer supplied as the second parameter whose size is given by
2508+** the first parameter. Note that the order of the
2509+** first two parameters is reversed from snprintf().)^ This is an
2510+** historical accident that cannot be fixed without breaking
2511+** backwards compatibility. ^(Note also that sqlite3_snprintf()
2512+** returns a pointer to its buffer instead of the number of
2513+** characters actually written into the buffer.)^ We admit that
2514+** the number of characters written would be a more useful return
2515+** value but we cannot change the implementation of sqlite3_snprintf()
2516+** now without breaking compatibility.
2517+**
2518+** ^As long as the buffer size is greater than zero, sqlite3_snprintf()
2519+** guarantees that the buffer is always zero-terminated. ^The first
2520+** parameter "n" is the total size of the buffer, including space for
2521+** the zero terminator. So the longest string that can be completely
2522+** written will be n-1 characters.
2523+**
2524+** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
2525+**
2526+** These routines all implement some additional formatting
2527+** options that are useful for constructing SQL statements.
2528+** All of the usual printf() formatting options apply. In addition, there
2529+** is are "%q", "%Q", and "%z" options.
2530+**
2531+** ^(The %q option works like %s in that it substitutes a null-terminated
2532+** string from the argument list. But %q also doubles every '\'' character.
2533+** %q is designed for use inside a string literal.)^ By doubling each '\''
2534+** character it escapes that character and allows it to be inserted into
2535+** the string.
2536+**
2537+** For example, assume the string variable zText contains text as follows:
2538+**
2539+** <blockquote><pre>
2540+** char *zText = "It's a happy day!";
2541+** </pre></blockquote>
2542+**
2543+** One can use this text in an SQL statement as follows:
2544+**
2545+** <blockquote><pre>
2546+** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
2547+** sqlite3_exec(db, zSQL, 0, 0, 0);
2548+** sqlite3_free(zSQL);
2549+** </pre></blockquote>
2550+**
2551+** Because the %q format string is used, the '\'' character in zText
2552+** is escaped and the SQL generated is as follows:
2553+**
2554+** <blockquote><pre>
2555+** INSERT INTO table1 VALUES('It''s a happy day!')
2556+** </pre></blockquote>
2557+**
2558+** This is correct. Had we used %s instead of %q, the generated SQL
2559+** would have looked like this:
2560+**
2561+** <blockquote><pre>
2562+** INSERT INTO table1 VALUES('It's a happy day!');
2563+** </pre></blockquote>
2564+**
2565+** This second example is an SQL syntax error. As a general rule you should
2566+** always use %q instead of %s when inserting text into a string literal.
2567+**
2568+** ^(The %Q option works like %q except it also adds single quotes around
2569+** the outside of the total string. Additionally, if the parameter in the
2570+** argument list is a NULL pointer, %Q substitutes the text "NULL" (without
2571+** single quotes).)^ So, for example, one could say:
2572+**
2573+** <blockquote><pre>
2574+** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
2575+** sqlite3_exec(db, zSQL, 0, 0, 0);
2576+** sqlite3_free(zSQL);
2577+** </pre></blockquote>
2578+**
2579+** The code above will render a correct SQL statement in the zSQL
2580+** variable even if the zText variable is a NULL pointer.
2581+**
2582+** ^(The "%z" formatting option works like "%s" but with the
2583+** addition that after the string has been read and copied into
2584+** the result, [sqlite3_free()] is called on the input string.)^
2585+*/
2586+SQLITE_API char *sqlite3_mprintf(const char*,...);
2587+SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
2588+SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
2589+SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
2590+
2591+/*
2592+** CAPI3REF: Memory Allocation Subsystem
2593+**
2594+** The SQLite core uses these three routines for all of its own
2595+** internal memory allocation needs. "Core" in the previous sentence
2596+** does not include operating-system specific VFS implementation. The
2597+** Windows VFS uses native malloc() and free() for some operations.
2598+**
2599+** ^The sqlite3_malloc() routine returns a pointer to a block
2600+** of memory at least N bytes in length, where N is the parameter.
2601+** ^If sqlite3_malloc() is unable to obtain sufficient free
2602+** memory, it returns a NULL pointer. ^If the parameter N to
2603+** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
2604+** a NULL pointer.
2605+**
2606+** ^Calling sqlite3_free() with a pointer previously returned
2607+** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
2608+** that it might be reused. ^The sqlite3_free() routine is
2609+** a no-op if is called with a NULL pointer. Passing a NULL pointer
2610+** to sqlite3_free() is harmless. After being freed, memory
2611+** should neither be read nor written. Even reading previously freed
2612+** memory might result in a segmentation fault or other severe error.
2613+** Memory corruption, a segmentation fault, or other severe error
2614+** might result if sqlite3_free() is called with a non-NULL pointer that
2615+** was not obtained from sqlite3_malloc() or sqlite3_realloc().
2616+**
2617+** ^(The sqlite3_realloc() interface attempts to resize a
2618+** prior memory allocation to be at least N bytes, where N is the
2619+** second parameter. The memory allocation to be resized is the first
2620+** parameter.)^ ^ If the first parameter to sqlite3_realloc()
2621+** is a NULL pointer then its behavior is identical to calling
2622+** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
2623+** ^If the second parameter to sqlite3_realloc() is zero or
2624+** negative then the behavior is exactly the same as calling
2625+** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
2626+** ^sqlite3_realloc() returns a pointer to a memory allocation
2627+** of at least N bytes in size or NULL if sufficient memory is unavailable.
2628+** ^If M is the size of the prior allocation, then min(N,M) bytes
2629+** of the prior allocation are copied into the beginning of buffer returned
2630+** by sqlite3_realloc() and the prior allocation is freed.
2631+** ^If sqlite3_realloc() returns NULL, then the prior allocation
2632+** is not freed.
2633+**
2634+** ^The memory returned by sqlite3_malloc() and sqlite3_realloc()
2635+** is always aligned to at least an 8 byte boundary, or to a
2636+** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
2637+** option is used.
2638+**
2639+** In SQLite version 3.5.0 and 3.5.1, it was possible to define
2640+** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
2641+** implementation of these routines to be omitted. That capability
2642+** is no longer provided. Only built-in memory allocators can be used.
2643+**
2644+** The Windows OS interface layer calls
2645+** the system malloc() and free() directly when converting
2646+** filenames between the UTF-8 encoding used by SQLite
2647+** and whatever filename encoding is used by the particular Windows
2648+** installation. Memory allocation errors are detected, but
2649+** they are reported back as [SQLITE_CANTOPEN] or
2650+** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
2651+**
2652+** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
2653+** must be either NULL or else pointers obtained from a prior
2654+** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have
2655+** not yet been released.
2656+**
2657+** The application must not read or write any part of
2658+** a block of memory after it has been released using
2659+** [sqlite3_free()] or [sqlite3_realloc()].
2660+*/
2661+SQLITE_API void *sqlite3_malloc(int);
2662+SQLITE_API void *sqlite3_realloc(void*, int);
2663+SQLITE_API void sqlite3_free(void*);
2664+
2665+/*
2666+** CAPI3REF: Memory Allocator Statistics
2667+**
2668+** SQLite provides these two interfaces for reporting on the status
2669+** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()]
2670+** routines, which form the built-in memory allocation subsystem.
2671+**
2672+** ^The [sqlite3_memory_used()] routine returns the number of bytes
2673+** of memory currently outstanding (malloced but not freed).
2674+** ^The [sqlite3_memory_highwater()] routine returns the maximum
2675+** value of [sqlite3_memory_used()] since the high-water mark
2676+** was last reset. ^The values returned by [sqlite3_memory_used()] and
2677+** [sqlite3_memory_highwater()] include any overhead
2678+** added by SQLite in its implementation of [sqlite3_malloc()],
2679+** but not overhead added by the any underlying system library
2680+** routines that [sqlite3_malloc()] may call.
2681+**
2682+** ^The memory high-water mark is reset to the current value of
2683+** [sqlite3_memory_used()] if and only if the parameter to
2684+** [sqlite3_memory_highwater()] is true. ^The value returned
2685+** by [sqlite3_memory_highwater(1)] is the high-water mark
2686+** prior to the reset.
2687+*/
2688+SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
2689+SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
2690+
2691+/*
2692+** CAPI3REF: Pseudo-Random Number Generator
2693+**
2694+** SQLite contains a high-quality pseudo-random number generator (PRNG) used to
2695+** select random [ROWID | ROWIDs] when inserting new records into a table that
2696+** already uses the largest possible [ROWID]. The PRNG is also used for
2697+** the build-in random() and randomblob() SQL functions. This interface allows
2698+** applications to access the same PRNG for other purposes.
2699+**
2700+** ^A call to this routine stores N bytes of randomness into buffer P.
2701+**
2702+** ^The first time this routine is invoked (either internally or by
2703+** the application) the PRNG is seeded using randomness obtained
2704+** from the xRandomness method of the default [sqlite3_vfs] object.
2705+** ^On all subsequent invocations, the pseudo-randomness is generated
2706+** internally and without recourse to the [sqlite3_vfs] xRandomness
2707+** method.
2708+*/
2709+SQLITE_API void sqlite3_randomness(int N, void *P);
2710+
2711+/*
2712+** CAPI3REF: Compile-Time Authorization Callbacks
2713+**
2714+** ^This routine registers an authorizer callback with a particular
2715+** [database connection], supplied in the first argument.
2716+** ^The authorizer callback is invoked as SQL statements are being compiled
2717+** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
2718+** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various
2719+** points during the compilation process, as logic is being created
2720+** to perform various actions, the authorizer callback is invoked to
2721+** see if those actions are allowed. ^The authorizer callback should
2722+** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the
2723+** specific action but allow the SQL statement to continue to be
2724+** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be
2725+** rejected with an error. ^If the authorizer callback returns
2726+** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY]
2727+** then the [sqlite3_prepare_v2()] or equivalent call that triggered
2728+** the authorizer will fail with an error message.
2729+**
2730+** When the callback returns [SQLITE_OK], that means the operation
2731+** requested is ok. ^When the callback returns [SQLITE_DENY], the
2732+** [sqlite3_prepare_v2()] or equivalent call that triggered the
2733+** authorizer will fail with an error message explaining that
2734+** access is denied.
2735+**
2736+** ^The first parameter to the authorizer callback is a copy of the third
2737+** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
2738+** to the callback is an integer [SQLITE_COPY | action code] that specifies
2739+** the particular action to be authorized. ^The third through sixth parameters
2740+** to the callback are zero-terminated strings that contain additional
2741+** details about the action to be authorized.
2742+**
2743+** ^If the action code is [SQLITE_READ]
2744+** and the callback returns [SQLITE_IGNORE] then the
2745+** [prepared statement] statement is constructed to substitute
2746+** a NULL value in place of the table column that would have
2747+** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
2748+** return can be used to deny an untrusted user access to individual
2749+** columns of a table.
2750+** ^If the action code is [SQLITE_DELETE] and the callback returns
2751+** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
2752+** [truncate optimization] is disabled and all rows are deleted individually.
2753+**
2754+** An authorizer is used when [sqlite3_prepare | preparing]
2755+** SQL statements from an untrusted source, to ensure that the SQL statements
2756+** do not try to access data they are not allowed to see, or that they do not
2757+** try to execute malicious statements that damage the database. For
2758+** example, an application may allow a user to enter arbitrary
2759+** SQL queries for evaluation by a database. But the application does
2760+** not want the user to be able to make arbitrary changes to the
2761+** database. An authorizer could then be put in place while the
2762+** user-entered SQL is being [sqlite3_prepare | prepared] that
2763+** disallows everything except [SELECT] statements.
2764+**
2765+** Applications that need to process SQL from untrusted sources
2766+** might also consider lowering resource limits using [sqlite3_limit()]
2767+** and limiting database size using the [max_page_count] [PRAGMA]
2768+** in addition to using an authorizer.
2769+**
2770+** ^(Only a single authorizer can be in place on a database connection
2771+** at a time. Each call to sqlite3_set_authorizer overrides the
2772+** previous call.)^ ^Disable the authorizer by installing a NULL callback.
2773+** The authorizer is disabled by default.
2774+**
2775+** The authorizer callback must not do anything that will modify
2776+** the database connection that invoked the authorizer callback.
2777+** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
2778+** database connections for the meaning of "modify" in this paragraph.
2779+**
2780+** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the
2781+** statement might be re-prepared during [sqlite3_step()] due to a
2782+** schema change. Hence, the application should ensure that the
2783+** correct authorizer callback remains in place during the [sqlite3_step()].
2784+**
2785+** ^Note that the authorizer callback is invoked only during
2786+** [sqlite3_prepare()] or its variants. Authorization is not
2787+** performed during statement evaluation in [sqlite3_step()], unless
2788+** as stated in the previous paragraph, sqlite3_step() invokes
2789+** sqlite3_prepare_v2() to reprepare a statement after a schema change.
2790+*/
2791+SQLITE_API int sqlite3_set_authorizer(
2792+ sqlite3*,
2793+ int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
2794+ void *pUserData
2795+);
2796+
2797+/*
2798+** CAPI3REF: Authorizer Return Codes
2799+**
2800+** The [sqlite3_set_authorizer | authorizer callback function] must
2801+** return either [SQLITE_OK] or one of these two constants in order
2802+** to signal SQLite whether or not the action is permitted. See the
2803+** [sqlite3_set_authorizer | authorizer documentation] for additional
2804+** information.
2805+**
2806+** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code]
2807+** from the [sqlite3_vtab_on_conflict()] interface.
2808+*/
2809+#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
2810+#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
2811+
2812+/*
2813+** CAPI3REF: Authorizer Action Codes
2814+**
2815+** The [sqlite3_set_authorizer()] interface registers a callback function
2816+** that is invoked to authorize certain SQL statement actions. The
2817+** second parameter to the callback is an integer code that specifies
2818+** what action is being authorized. These are the integer action codes that
2819+** the authorizer callback may be passed.
2820+**
2821+** These action code values signify what kind of operation is to be
2822+** authorized. The 3rd and 4th parameters to the authorization
2823+** callback function will be parameters or NULL depending on which of these
2824+** codes is used as the second parameter. ^(The 5th parameter to the
2825+** authorizer callback is the name of the database ("main", "temp",
2826+** etc.) if applicable.)^ ^The 6th parameter to the authorizer callback
2827+** is the name of the inner-most trigger or view that is responsible for
2828+** the access attempt or NULL if this access attempt is directly from
2829+** top-level SQL code.
2830+*/
2831+/******************************************* 3rd ************ 4th ***********/
2832+#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */
2833+#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */
2834+#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */
2835+#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */
2836+#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */
2837+#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */
2838+#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */
2839+#define SQLITE_CREATE_VIEW 8 /* View Name NULL */
2840+#define SQLITE_DELETE 9 /* Table Name NULL */
2841+#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */
2842+#define SQLITE_DROP_TABLE 11 /* Table Name NULL */
2843+#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */
2844+#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */
2845+#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */
2846+#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */
2847+#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */
2848+#define SQLITE_DROP_VIEW 17 /* View Name NULL */
2849+#define SQLITE_INSERT 18 /* Table Name NULL */
2850+#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */
2851+#define SQLITE_READ 20 /* Table Name Column Name */
2852+#define SQLITE_SELECT 21 /* NULL NULL */
2853+#define SQLITE_TRANSACTION 22 /* Operation NULL */
2854+#define SQLITE_UPDATE 23 /* Table Name Column Name */
2855+#define SQLITE_ATTACH 24 /* Filename NULL */
2856+#define SQLITE_DETACH 25 /* Database Name NULL */
2857+#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */
2858+#define SQLITE_REINDEX 27 /* Index Name NULL */
2859+#define SQLITE_ANALYZE 28 /* Table Name NULL */
2860+#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */
2861+#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */
2862+#define SQLITE_FUNCTION 31 /* NULL Function Name */
2863+#define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */
2864+#define SQLITE_COPY 0 /* No longer used */
2865+
2866+/*
2867+** CAPI3REF: Tracing And Profiling Functions
2868+**
2869+** These routines register callback functions that can be used for
2870+** tracing and profiling the execution of SQL statements.
2871+**
2872+** ^The callback function registered by sqlite3_trace() is invoked at
2873+** various times when an SQL statement is being run by [sqlite3_step()].
2874+** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the
2875+** SQL statement text as the statement first begins executing.
2876+** ^(Additional sqlite3_trace() callbacks might occur
2877+** as each triggered subprogram is entered. The callbacks for triggers
2878+** contain a UTF-8 SQL comment that identifies the trigger.)^
2879+**
2880+** ^The callback function registered by sqlite3_profile() is invoked
2881+** as each SQL statement finishes. ^The profile callback contains
2882+** the original statement text and an estimate of wall-clock time
2883+** of how long that statement took to run. ^The profile callback
2884+** time is in units of nanoseconds, however the current implementation
2885+** is only capable of millisecond resolution so the six least significant
2886+** digits in the time are meaningless. Future versions of SQLite
2887+** might provide greater resolution on the profiler callback. The
2888+** sqlite3_profile() function is considered experimental and is
2889+** subject to change in future versions of SQLite.
2890+*/
2891+SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
2892+SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
2893+ void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
2894+
2895+/*
2896+** CAPI3REF: Query Progress Callbacks
2897+**
2898+** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
2899+** function X to be invoked periodically during long running calls to
2900+** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
2901+** database connection D. An example use for this
2902+** interface is to keep a GUI updated during a large query.
2903+**
2904+** ^The parameter P is passed through as the only parameter to the
2905+** callback function X. ^The parameter N is the number of
2906+** [virtual machine instructions] that are evaluated between successive
2907+** invocations of the callback X.
2908+**
2909+** ^Only a single progress handler may be defined at one time per
2910+** [database connection]; setting a new progress handler cancels the
2911+** old one. ^Setting parameter X to NULL disables the progress handler.
2912+** ^The progress handler is also disabled by setting N to a value less
2913+** than 1.
2914+**
2915+** ^If the progress callback returns non-zero, the operation is
2916+** interrupted. This feature can be used to implement a
2917+** "Cancel" button on a GUI progress dialog box.
2918+**
2919+** The progress handler callback must not do anything that will modify
2920+** the database connection that invoked the progress handler.
2921+** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
2922+** database connections for the meaning of "modify" in this paragraph.
2923+**
2924+*/
2925+SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
2926+
2927+/*
2928+** CAPI3REF: Opening A New Database Connection
2929+**
2930+** ^These routines open an SQLite database file as specified by the
2931+** filename argument. ^The filename argument is interpreted as UTF-8 for
2932+** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte
2933+** order for sqlite3_open16(). ^(A [database connection] handle is usually
2934+** returned in *ppDb, even if an error occurs. The only exception is that
2935+** if SQLite is unable to allocate memory to hold the [sqlite3] object,
2936+** a NULL will be written into *ppDb instead of a pointer to the [sqlite3]
2937+** object.)^ ^(If the database is opened (and/or created) successfully, then
2938+** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The
2939+** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain
2940+** an English language description of the error following a failure of any
2941+** of the sqlite3_open() routines.
2942+**
2943+** ^The default encoding for the database will be UTF-8 if
2944+** sqlite3_open() or sqlite3_open_v2() is called and
2945+** UTF-16 in the native byte order if sqlite3_open16() is used.
2946+**
2947+** Whether or not an error occurs when it is opened, resources
2948+** associated with the [database connection] handle should be released by
2949+** passing it to [sqlite3_close()] when it is no longer required.
2950+**
2951+** The sqlite3_open_v2() interface works like sqlite3_open()
2952+** except that it accepts two additional parameters for additional control
2953+** over the new database connection. ^(The flags parameter to
2954+** sqlite3_open_v2() can take one of
2955+** the following three values, optionally combined with the
2956+** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
2957+** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
2958+**
2959+** <dl>
2960+** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
2961+** <dd>The database is opened in read-only mode. If the database does not
2962+** already exist, an error is returned.</dd>)^
2963+**
2964+** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
2965+** <dd>The database is opened for reading and writing if possible, or reading
2966+** only if the file is write protected by the operating system. In either
2967+** case the database must already exist, otherwise an error is returned.</dd>)^
2968+**
2969+** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
2970+** <dd>The database is opened for reading and writing, and is created if
2971+** it does not already exist. This is the behavior that is always used for
2972+** sqlite3_open() and sqlite3_open16().</dd>)^
2973+** </dl>
2974+**
2975+** If the 3rd parameter to sqlite3_open_v2() is not one of the
2976+** combinations shown above optionally combined with other
2977+** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
2978+** then the behavior is undefined.
2979+**
2980+** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
2981+** opens in the multi-thread [threading mode] as long as the single-thread
2982+** mode has not been set at compile-time or start-time. ^If the
2983+** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens
2984+** in the serialized [threading mode] unless single-thread was
2985+** previously selected at compile-time or start-time.
2986+** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be
2987+** eligible to use [shared cache mode], regardless of whether or not shared
2988+** cache is enabled using [sqlite3_enable_shared_cache()]. ^The
2989+** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not
2990+** participate in [shared cache mode] even if it is enabled.
2991+**
2992+** ^The fourth parameter to sqlite3_open_v2() is the name of the
2993+** [sqlite3_vfs] object that defines the operating system interface that
2994+** the new database connection should use. ^If the fourth parameter is
2995+** a NULL pointer then the default [sqlite3_vfs] object is used.
2996+**
2997+** ^If the filename is ":memory:", then a private, temporary in-memory database
2998+** is created for the connection. ^This in-memory database will vanish when
2999+** the database connection is closed. Future versions of SQLite might
3000+** make use of additional special filenames that begin with the ":" character.
3001+** It is recommended that when a database filename actually does begin with
3002+** a ":" character you should prefix the filename with a pathname such as
3003+** "./" to avoid ambiguity.
3004+**
3005+** ^If the filename is an empty string, then a private, temporary
3006+** on-disk database will be created. ^This private database will be
3007+** automatically deleted as soon as the database connection is closed.
3008+**
3009+** [[URI filenames in sqlite3_open()]] <h3>URI Filenames</h3>
3010+**
3011+** ^If [URI filename] interpretation is enabled, and the filename argument
3012+** begins with "file:", then the filename is interpreted as a URI. ^URI
3013+** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
3014+** set in the fourth argument to sqlite3_open_v2(), or if it has
3015+** been enabled globally using the [SQLITE_CONFIG_URI] option with the
3016+** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
3017+** As of SQLite version 3.7.7, URI filename interpretation is turned off
3018+** by default, but future releases of SQLite might enable URI filename
3019+** interpretation by default. See "[URI filenames]" for additional
3020+** information.
3021+**
3022+** URI filenames are parsed according to RFC 3986. ^If the URI contains an
3023+** authority, then it must be either an empty string or the string
3024+** "localhost". ^If the authority is not an empty string or "localhost", an
3025+** error is returned to the caller. ^The fragment component of a URI, if
3026+** present, is ignored.
3027+**
3028+** ^SQLite uses the path component of the URI as the name of the disk file
3029+** which contains the database. ^If the path begins with a '/' character,
3030+** then it is interpreted as an absolute path. ^If the path does not begin
3031+** with a '/' (meaning that the authority section is omitted from the URI)
3032+** then the path is interpreted as a relative path.
3033+** ^On windows, the first component of an absolute path
3034+** is a drive specification (e.g. "C:").
3035+**
3036+** [[core URI query parameters]]
3037+** The query component of a URI may contain parameters that are interpreted
3038+** either by SQLite itself, or by a [VFS | custom VFS implementation].
3039+** SQLite interprets the following three query parameters:
3040+**
3041+** <ul>
3042+** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
3043+** a VFS object that provides the operating system interface that should
3044+** be used to access the database file on disk. ^If this option is set to
3045+** an empty string the default VFS object is used. ^Specifying an unknown
3046+** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is
3047+** present, then the VFS specified by the option takes precedence over
3048+** the value passed as the fourth parameter to sqlite3_open_v2().
3049+**
3050+** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or
3051+** "rwc". Attempting to set it to any other value is an error)^.
3052+** ^If "ro" is specified, then the database is opened for read-only
3053+** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
3054+** third argument to sqlite3_prepare_v2(). ^If the mode option is set to
3055+** "rw", then the database is opened for read-write (but not create)
3056+** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
3057+** been set. ^Value "rwc" is equivalent to setting both
3058+** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is
3059+** used, it is an error to specify a value for the mode parameter that is
3060+** less restrictive than that specified by the flags passed as the third
3061+** parameter.
3062+**
3063+** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or
3064+** "private". ^Setting it to "shared" is equivalent to setting the
3065+** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
3066+** sqlite3_open_v2(). ^Setting the cache parameter to "private" is
3067+** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
3068+** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
3069+** a URI filename, its value overrides any behaviour requested by setting
3070+** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
3071+** </ul>
3072+**
3073+** ^Specifying an unknown parameter in the query component of a URI is not an
3074+** error. Future versions of SQLite might understand additional query
3075+** parameters. See "[query parameters with special meaning to SQLite]" for
3076+** additional information.
3077+**
3078+** [[URI filename examples]] <h3>URI filename examples</h3>
3079+**
3080+** <table border="1" align=center cellpadding=5>
3081+** <tr><th> URI filenames <th> Results
3082+** <tr><td> file:data.db <td>
3083+** Open the file "data.db" in the current directory.
3084+** <tr><td> file:/home/fred/data.db<br>
3085+** file:///home/fred/data.db <br>
3086+** file://localhost/home/fred/data.db <br> <td>
3087+** Open the database file "/home/fred/data.db".
3088+** <tr><td> file://darkstar/home/fred/data.db <td>
3089+** An error. "darkstar" is not a recognized authority.
3090+** <tr><td style="white-space:nowrap">
3091+** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db
3092+** <td> Windows only: Open the file "data.db" on fred's desktop on drive
3093+** C:. Note that the %20 escaping in this example is not strictly
3094+** necessary - space characters can be used literally
3095+** in URI filenames.
3096+** <tr><td> file:data.db?mode=ro&cache=private <td>
3097+** Open file "data.db" in the current directory for read-only access.
3098+** Regardless of whether or not shared-cache mode is enabled by
3099+** default, use a private cache.
3100+** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td>
3101+** Open file "/home/fred/data.db". Use the special VFS "unix-nolock".
3102+** <tr><td> file:data.db?mode=readonly <td>
3103+** An error. "readonly" is not a valid option for the "mode" parameter.
3104+** </table>
3105+**
3106+** ^URI hexadecimal escape sequences (%HH) are supported within the path and
3107+** query components of a URI. A hexadecimal escape sequence consists of a
3108+** percent sign - "%" - followed by exactly two hexadecimal digits
3109+** specifying an octet value. ^Before the path or query components of a
3110+** URI filename are interpreted, they are encoded using UTF-8 and all
3111+** hexadecimal escape sequences replaced by a single byte containing the
3112+** corresponding octet. If this process generates an invalid UTF-8 encoding,
3113+** the results are undefined.
3114+**
3115+** <b>Note to Windows users:</b> The encoding used for the filename argument
3116+** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever
3117+** codepage is currently defined. Filenames containing international
3118+** characters must be converted to UTF-8 prior to passing them into
3119+** sqlite3_open() or sqlite3_open_v2().
3120+*/
3121+SQLITE_API int sqlite3_open(
3122+ const char *filename, /* Database filename (UTF-8) */
3123+ sqlite3 **ppDb /* OUT: SQLite db handle */
3124+);
3125+SQLITE_API int sqlite3_open16(
3126+ const void *filename, /* Database filename (UTF-16) */
3127+ sqlite3 **ppDb /* OUT: SQLite db handle */
3128+);
3129+SQLITE_API int sqlite3_open_v2(
3130+ const char *filename, /* Database filename (UTF-8) */
3131+ sqlite3 **ppDb, /* OUT: SQLite db handle */
3132+ int flags, /* Flags */
3133+ const char *zVfs /* Name of VFS module to use */
3134+);
3135+
3136+/*
3137+** CAPI3REF: Obtain Values For URI Parameters
3138+**
3139+** This is a utility routine, useful to VFS implementations, that checks
3140+** to see if a database file was a URI that contained a specific query
3141+** parameter, and if so obtains the value of the query parameter.
3142+**
3143+** The zFilename argument is the filename pointer passed into the xOpen()
3144+** method of a VFS implementation. The zParam argument is the name of the
3145+** query parameter we seek. This routine returns the value of the zParam
3146+** parameter if it exists. If the parameter does not exist, this routine
3147+** returns a NULL pointer.
3148+**
3149+** If the zFilename argument to this function is not a pointer that SQLite
3150+** passed into the xOpen VFS method, then the behavior of this routine
3151+** is undefined and probably undesirable.
3152+*/
3153+SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
3154+
3155+
3156+/*
3157+** CAPI3REF: Error Codes And Messages
3158+**
3159+** ^The sqlite3_errcode() interface returns the numeric [result code] or
3160+** [extended result code] for the most recent failed sqlite3_* API call
3161+** associated with a [database connection]. If a prior API call failed
3162+** but the most recent API call succeeded, the return value from
3163+** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode()
3164+** interface is the same except that it always returns the
3165+** [extended result code] even when extended result codes are
3166+** disabled.
3167+**
3168+** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
3169+** text that describes the error, as either UTF-8 or UTF-16 respectively.
3170+** ^(Memory to hold the error message string is managed internally.
3171+** The application does not need to worry about freeing the result.
3172+** However, the error string might be overwritten or deallocated by
3173+** subsequent calls to other SQLite interface functions.)^
3174+**
3175+** When the serialized [threading mode] is in use, it might be the
3176+** case that a second error occurs on a separate thread in between
3177+** the time of the first error and the call to these interfaces.
3178+** When that happens, the second error will be reported since these
3179+** interfaces always report the most recent result. To avoid
3180+** this, each thread can obtain exclusive use of the [database connection] D
3181+** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning
3182+** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after
3183+** all calls to the interfaces listed here are completed.
3184+**
3185+** If an interface fails with SQLITE_MISUSE, that means the interface
3186+** was invoked incorrectly by the application. In that case, the
3187+** error code and message may or may not be set.
3188+*/
3189+SQLITE_API int sqlite3_errcode(sqlite3 *db);
3190+SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
3191+SQLITE_API const char *sqlite3_errmsg(sqlite3*);
3192+SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
3193+
3194+/*
3195+** CAPI3REF: SQL Statement Object
3196+** KEYWORDS: {prepared statement} {prepared statements}
3197+**
3198+** An instance of this object represents a single SQL statement.
3199+** This object is variously known as a "prepared statement" or a
3200+** "compiled SQL statement" or simply as a "statement".
3201+**
3202+** The life of a statement object goes something like this:
3203+**
3204+** <ol>
3205+** <li> Create the object using [sqlite3_prepare_v2()] or a related
3206+** function.
3207+** <li> Bind values to [host parameters] using the sqlite3_bind_*()
3208+** interfaces.
3209+** <li> Run the SQL by calling [sqlite3_step()] one or more times.
3210+** <li> Reset the statement using [sqlite3_reset()] then go back
3211+** to step 2. Do this zero or more times.
3212+** <li> Destroy the object using [sqlite3_finalize()].
3213+** </ol>
3214+**
3215+** Refer to documentation on individual methods above for additional
3216+** information.
3217+*/
3218+typedef struct sqlite3_stmt sqlite3_stmt;
3219+
3220+/*
3221+** CAPI3REF: Run-time Limits
3222+**
3223+** ^(This interface allows the size of various constructs to be limited
3224+** on a connection by connection basis. The first parameter is the
3225+** [database connection] whose limit is to be set or queried. The
3226+** second parameter is one of the [limit categories] that define a
3227+** class of constructs to be size limited. The third parameter is the
3228+** new limit for that construct.)^
3229+**
3230+** ^If the new limit is a negative number, the limit is unchanged.
3231+** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a
3232+** [limits | hard upper bound]
3233+** set at compile-time by a C preprocessor macro called
3234+** [limits | SQLITE_MAX_<i>NAME</i>].
3235+** (The "_LIMIT_" in the name is changed to "_MAX_".))^
3236+** ^Attempts to increase a limit above its hard upper bound are
3237+** silently truncated to the hard upper bound.
3238+**
3239+** ^Regardless of whether or not the limit was changed, the
3240+** [sqlite3_limit()] interface returns the prior value of the limit.
3241+** ^Hence, to find the current value of a limit without changing it,
3242+** simply invoke this interface with the third parameter set to -1.
3243+**
3244+** Run-time limits are intended for use in applications that manage
3245+** both their own internal database and also databases that are controlled
3246+** by untrusted external sources. An example application might be a
3247+** web browser that has its own databases for storing history and
3248+** separate databases controlled by JavaScript applications downloaded
3249+** off the Internet. The internal databases can be given the
3250+** large, default limits. Databases managed by external sources can
3251+** be given much smaller limits designed to prevent a denial of service
3252+** attack. Developers might also want to use the [sqlite3_set_authorizer()]
3253+** interface to further control untrusted SQL. The size of the database
3254+** created by an untrusted script can be contained using the
3255+** [max_page_count] [PRAGMA].
3256+**
3257+** New run-time limit categories may be added in future releases.
3258+*/
3259+SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
3260+
3261+/*
3262+** CAPI3REF: Run-Time Limit Categories
3263+** KEYWORDS: {limit category} {*limit categories}
3264+**
3265+** These constants define various performance limits
3266+** that can be lowered at run-time using [sqlite3_limit()].
3267+** The synopsis of the meanings of the various limits is shown below.
3268+** Additional information is available at [limits | Limits in SQLite].
3269+**
3270+** <dl>
3271+** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt>
3272+** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^
3273+**
3274+** [[SQLITE_LIMIT_SQL_LENGTH]] ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
3275+** <dd>The maximum length of an SQL statement, in bytes.</dd>)^
3276+**
3277+** [[SQLITE_LIMIT_COLUMN]] ^(<dt>SQLITE_LIMIT_COLUMN</dt>
3278+** <dd>The maximum number of columns in a table definition or in the
3279+** result set of a [SELECT] or the maximum number of columns in an index
3280+** or in an ORDER BY or GROUP BY clause.</dd>)^
3281+**
3282+** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
3283+** <dd>The maximum depth of the parse tree on any expression.</dd>)^
3284+**
3285+** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt>
3286+** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^
3287+**
3288+** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
3289+** <dd>The maximum number of instructions in a virtual machine program
3290+** used to implement an SQL statement. This limit is not currently
3291+** enforced, though that might be added in some future release of
3292+** SQLite.</dd>)^
3293+**
3294+** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
3295+** <dd>The maximum number of arguments on a function.</dd>)^
3296+**
3297+** [[SQLITE_LIMIT_ATTACHED]] ^(<dt>SQLITE_LIMIT_ATTACHED</dt>
3298+** <dd>The maximum number of [ATTACH | attached databases].)^</dd>
3299+**
3300+** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]]
3301+** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt>
3302+** <dd>The maximum length of the pattern argument to the [LIKE] or
3303+** [GLOB] operators.</dd>)^
3304+**
3305+** [[SQLITE_LIMIT_VARIABLE_NUMBER]]
3306+** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt>
3307+** <dd>The maximum index number of any [parameter] in an SQL statement.)^
3308+**
3309+** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
3310+** <dd>The maximum depth of recursion for triggers.</dd>)^
3311+** </dl>
3312+*/
3313+#define SQLITE_LIMIT_LENGTH 0
3314+#define SQLITE_LIMIT_SQL_LENGTH 1
3315+#define SQLITE_LIMIT_COLUMN 2
3316+#define SQLITE_LIMIT_EXPR_DEPTH 3
3317+#define SQLITE_LIMIT_COMPOUND_SELECT 4
3318+#define SQLITE_LIMIT_VDBE_OP 5
3319+#define SQLITE_LIMIT_FUNCTION_ARG 6
3320+#define SQLITE_LIMIT_ATTACHED 7
3321+#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8
3322+#define SQLITE_LIMIT_VARIABLE_NUMBER 9
3323+#define SQLITE_LIMIT_TRIGGER_DEPTH 10
3324+
3325+/*
3326+** CAPI3REF: Compiling An SQL Statement
3327+** KEYWORDS: {SQL statement compiler}
3328+**
3329+** To execute an SQL query, it must first be compiled into a byte-code
3330+** program using one of these routines.
3331+**
3332+** The first argument, "db", is a [database connection] obtained from a
3333+** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or
3334+** [sqlite3_open16()]. The database connection must not have been closed.
3335+**
3336+** The second argument, "zSql", is the statement to be compiled, encoded
3337+** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2()
3338+** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
3339+** use UTF-16.
3340+**
3341+** ^If the nByte argument is less than zero, then zSql is read up to the
3342+** first zero terminator. ^If nByte is non-negative, then it is the maximum
3343+** number of bytes read from zSql. ^When nByte is non-negative, the
3344+** zSql string ends at either the first '\000' or '\u0000' character or
3345+** the nByte-th byte, whichever comes first. If the caller knows
3346+** that the supplied string is nul-terminated, then there is a small
3347+** performance advantage to be gained by passing an nByte parameter that
3348+** is equal to the number of bytes in the input string <i>including</i>
3349+** the nul-terminator bytes as this saves SQLite from having to
3350+** make a copy of the input string.
3351+**
3352+** ^If pzTail is not NULL then *pzTail is made to point to the first byte
3353+** past the end of the first SQL statement in zSql. These routines only
3354+** compile the first statement in zSql, so *pzTail is left pointing to
3355+** what remains uncompiled.
3356+**
3357+** ^*ppStmt is left pointing to a compiled [prepared statement] that can be
3358+** executed using [sqlite3_step()]. ^If there is an error, *ppStmt is set
3359+** to NULL. ^If the input text contains no SQL (if the input is an empty
3360+** string or a comment) then *ppStmt is set to NULL.
3361+** The calling procedure is responsible for deleting the compiled
3362+** SQL statement using [sqlite3_finalize()] after it has finished with it.
3363+** ppStmt may not be NULL.
3364+**
3365+** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK];
3366+** otherwise an [error code] is returned.
3367+**
3368+** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
3369+** recommended for all new programs. The two older interfaces are retained
3370+** for backwards compatibility, but their use is discouraged.
3371+** ^In the "v2" interfaces, the prepared statement
3372+** that is returned (the [sqlite3_stmt] object) contains a copy of the
3373+** original SQL text. This causes the [sqlite3_step()] interface to
3374+** behave differently in three ways:
3375+**
3376+** <ol>
3377+** <li>
3378+** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
3379+** always used to do, [sqlite3_step()] will automatically recompile the SQL
3380+** statement and try to run it again.
3381+** </li>
3382+**
3383+** <li>
3384+** ^When an error occurs, [sqlite3_step()] will return one of the detailed
3385+** [error codes] or [extended error codes]. ^The legacy behavior was that
3386+** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code
3387+** and the application would have to make a second call to [sqlite3_reset()]
3388+** in order to find the underlying cause of the problem. With the "v2" prepare
3389+** interfaces, the underlying reason for the error is returned immediately.
3390+** </li>
3391+**
3392+** <li>
3393+** ^If the specific value bound to [parameter | host parameter] in the
3394+** WHERE clause might influence the choice of query plan for a statement,
3395+** then the statement will be automatically recompiled, as if there had been
3396+** a schema change, on the first [sqlite3_step()] call following any change
3397+** to the [sqlite3_bind_text | bindings] of that [parameter].
3398+** ^The specific value of WHERE-clause [parameter] might influence the
3399+** choice of query plan if the parameter is the left-hand side of a [LIKE]
3400+** or [GLOB] operator or if the parameter is compared to an indexed column
3401+** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
3402+** the
3403+** </li>
3404+** </ol>
3405+*/
3406+SQLITE_API int sqlite3_prepare(
3407+ sqlite3 *db, /* Database handle */
3408+ const char *zSql, /* SQL statement, UTF-8 encoded */
3409+ int nByte, /* Maximum length of zSql in bytes. */
3410+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
3411+ const char **pzTail /* OUT: Pointer to unused portion of zSql */
3412+);
3413+SQLITE_API int sqlite3_prepare_v2(
3414+ sqlite3 *db, /* Database handle */
3415+ const char *zSql, /* SQL statement, UTF-8 encoded */
3416+ int nByte, /* Maximum length of zSql in bytes. */
3417+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
3418+ const char **pzTail /* OUT: Pointer to unused portion of zSql */
3419+);
3420+SQLITE_API int sqlite3_prepare16(
3421+ sqlite3 *db, /* Database handle */
3422+ const void *zSql, /* SQL statement, UTF-16 encoded */
3423+ int nByte, /* Maximum length of zSql in bytes. */
3424+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
3425+ const void **pzTail /* OUT: Pointer to unused portion of zSql */
3426+);
3427+SQLITE_API int sqlite3_prepare16_v2(
3428+ sqlite3 *db, /* Database handle */
3429+ const void *zSql, /* SQL statement, UTF-16 encoded */
3430+ int nByte, /* Maximum length of zSql in bytes. */
3431+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
3432+ const void **pzTail /* OUT: Pointer to unused portion of zSql */
3433+);
3434+
3435+/*
3436+** CAPI3REF: Retrieving Statement SQL
3437+**
3438+** ^This interface can be used to retrieve a saved copy of the original
3439+** SQL text used to create a [prepared statement] if that statement was
3440+** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
3441+*/
3442+SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
3443+
3444+/*
3445+** CAPI3REF: Determine If An SQL Statement Writes The Database
3446+**
3447+** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if
3448+** and only if the [prepared statement] X makes no direct changes to
3449+** the content of the database file.
3450+**
3451+** Note that [application-defined SQL functions] or
3452+** [virtual tables] might change the database indirectly as a side effect.
3453+** ^(For example, if an application defines a function "eval()" that
3454+** calls [sqlite3_exec()], then the following SQL statement would
3455+** change the database file through side-effects:
3456+**
3457+** <blockquote><pre>
3458+** SELECT eval('DELETE FROM t1') FROM t2;
3459+** </pre></blockquote>
3460+**
3461+** But because the [SELECT] statement does not change the database file
3462+** directly, sqlite3_stmt_readonly() would still return true.)^
3463+**
3464+** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK],
3465+** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true,
3466+** since the statements themselves do not actually modify the database but
3467+** rather they control the timing of when other statements modify the
3468+** database. ^The [ATTACH] and [DETACH] statements also cause
3469+** sqlite3_stmt_readonly() to return true since, while those statements
3470+** change the configuration of a database connection, they do not make
3471+** changes to the content of the database files on disk.
3472+*/
3473+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
3474+
3475+/*
3476+** CAPI3REF: Dynamically Typed Value Object
3477+** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
3478+**
3479+** SQLite uses the sqlite3_value object to represent all values
3480+** that can be stored in a database table. SQLite uses dynamic typing
3481+** for the values it stores. ^Values stored in sqlite3_value objects
3482+** can be integers, floating point values, strings, BLOBs, or NULL.
3483+**
3484+** An sqlite3_value object may be either "protected" or "unprotected".
3485+** Some interfaces require a protected sqlite3_value. Other interfaces
3486+** will accept either a protected or an unprotected sqlite3_value.
3487+** Every interface that accepts sqlite3_value arguments specifies
3488+** whether or not it requires a protected sqlite3_value.
3489+**
3490+** The terms "protected" and "unprotected" refer to whether or not
3491+** a mutex is held. An internal mutex is held for a protected
3492+** sqlite3_value object but no mutex is held for an unprotected
3493+** sqlite3_value object. If SQLite is compiled to be single-threaded
3494+** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0)
3495+** or if SQLite is run in one of reduced mutex modes
3496+** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD]
3497+** then there is no distinction between protected and unprotected
3498+** sqlite3_value objects and they can be used interchangeably. However,
3499+** for maximum code portability it is recommended that applications
3500+** still make the distinction between protected and unprotected
3501+** sqlite3_value objects even when not strictly required.
3502+**
3503+** ^The sqlite3_value objects that are passed as parameters into the
3504+** implementation of [application-defined SQL functions] are protected.
3505+** ^The sqlite3_value object returned by
3506+** [sqlite3_column_value()] is unprotected.
3507+** Unprotected sqlite3_value objects may only be used with
3508+** [sqlite3_result_value()] and [sqlite3_bind_value()].
3509+** The [sqlite3_value_blob | sqlite3_value_type()] family of
3510+** interfaces require protected sqlite3_value objects.
3511+*/
3512+typedef struct Mem sqlite3_value;
3513+
3514+/*
3515+** CAPI3REF: SQL Function Context Object
3516+**
3517+** The context in which an SQL function executes is stored in an
3518+** sqlite3_context object. ^A pointer to an sqlite3_context object
3519+** is always first parameter to [application-defined SQL functions].
3520+** The application-defined SQL function implementation will pass this
3521+** pointer through into calls to [sqlite3_result_int | sqlite3_result()],
3522+** [sqlite3_aggregate_context()], [sqlite3_user_data()],
3523+** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()],
3524+** and/or [sqlite3_set_auxdata()].
3525+*/
3526+typedef struct sqlite3_context sqlite3_context;
3527+
3528+/*
3529+** CAPI3REF: Binding Values To Prepared Statements
3530+** KEYWORDS: {host parameter} {host parameters} {host parameter name}
3531+** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding}
3532+**
3533+** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
3534+** literals may be replaced by a [parameter] that matches one of following
3535+** templates:
3536+**
3537+** <ul>
3538+** <li> ?
3539+** <li> ?NNN
3540+** <li> :VVV
3541+** <li> @VVV
3542+** <li> $VVV
3543+** </ul>
3544+**
3545+** In the templates above, NNN represents an integer literal,
3546+** and VVV represents an alphanumeric identifier.)^ ^The values of these
3547+** parameters (also called "host parameter names" or "SQL parameters")
3548+** can be set using the sqlite3_bind_*() routines defined here.
3549+**
3550+** ^The first argument to the sqlite3_bind_*() routines is always
3551+** a pointer to the [sqlite3_stmt] object returned from
3552+** [sqlite3_prepare_v2()] or its variants.
3553+**
3554+** ^The second argument is the index of the SQL parameter to be set.
3555+** ^The leftmost SQL parameter has an index of 1. ^When the same named
3556+** SQL parameter is used more than once, second and subsequent
3557+** occurrences have the same index as the first occurrence.
3558+** ^The index for named parameters can be looked up using the
3559+** [sqlite3_bind_parameter_index()] API if desired. ^The index
3560+** for "?NNN" parameters is the value of NNN.
3561+** ^The NNN value must be between 1 and the [sqlite3_limit()]
3562+** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
3563+**
3564+** ^The third argument is the value to bind to the parameter.
3565+**
3566+** ^(In those routines that have a fourth argument, its value is the
3567+** number of bytes in the parameter. To be clear: the value is the
3568+** number of <u>bytes</u> in the value, not the number of characters.)^
3569+** ^If the fourth parameter is negative, the length of the string is
3570+** the number of bytes up to the first zero terminator.
3571+** If a non-negative fourth parameter is provided to sqlite3_bind_text()
3572+** or sqlite3_bind_text16() then that parameter must be the byte offset
3573+** where the NUL terminator would occur assuming the string were NUL
3574+** terminated. If any NUL characters occur at byte offsets less than
3575+** the value of the fourth parameter then the resulting string value will
3576+** contain embedded NULs. The result of expressions involving strings
3577+** with embedded NULs is undefined.
3578+**
3579+** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
3580+** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
3581+** string after SQLite has finished with it. ^The destructor is called
3582+** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(),
3583+** sqlite3_bind_text(), or sqlite3_bind_text16() fails.
3584+** ^If the fifth argument is
3585+** the special value [SQLITE_STATIC], then SQLite assumes that the
3586+** information is in static, unmanaged space and does not need to be freed.
3587+** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
3588+** SQLite makes its own private copy of the data immediately, before
3589+** the sqlite3_bind_*() routine returns.
3590+**
3591+** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
3592+** is filled with zeroes. ^A zeroblob uses a fixed amount of memory
3593+** (just an integer to hold its size) while it is being processed.
3594+** Zeroblobs are intended to serve as placeholders for BLOBs whose
3595+** content is later written using
3596+** [sqlite3_blob_open | incremental BLOB I/O] routines.
3597+** ^A negative value for the zeroblob results in a zero-length BLOB.
3598+**
3599+** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
3600+** for the [prepared statement] or with a prepared statement for which
3601+** [sqlite3_step()] has been called more recently than [sqlite3_reset()],
3602+** then the call will return [SQLITE_MISUSE]. If any sqlite3_bind_()
3603+** routine is passed a [prepared statement] that has been finalized, the
3604+** result is undefined and probably harmful.
3605+**
3606+** ^Bindings are not cleared by the [sqlite3_reset()] routine.
3607+** ^Unbound parameters are interpreted as NULL.
3608+**
3609+** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an
3610+** [error code] if anything goes wrong.
3611+** ^[SQLITE_RANGE] is returned if the parameter
3612+** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails.
3613+**
3614+** See also: [sqlite3_bind_parameter_count()],
3615+** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
3616+*/
3617+SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
3618+SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
3619+SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
3620+SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
3621+SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
3622+SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
3623+SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
3624+SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
3625+SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
3626+
3627+/*
3628+** CAPI3REF: Number Of SQL Parameters
3629+**
3630+** ^This routine can be used to find the number of [SQL parameters]
3631+** in a [prepared statement]. SQL parameters are tokens of the
3632+** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as
3633+** placeholders for values that are [sqlite3_bind_blob | bound]
3634+** to the parameters at a later time.
3635+**
3636+** ^(This routine actually returns the index of the largest (rightmost)
3637+** parameter. For all forms except ?NNN, this will correspond to the
3638+** number of unique parameters. If parameters of the ?NNN form are used,
3639+** there may be gaps in the list.)^
3640+**
3641+** See also: [sqlite3_bind_blob|sqlite3_bind()],
3642+** [sqlite3_bind_parameter_name()], and
3643+** [sqlite3_bind_parameter_index()].
3644+*/
3645+SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
3646+
3647+/*
3648+** CAPI3REF: Name Of A Host Parameter
3649+**
3650+** ^The sqlite3_bind_parameter_name(P,N) interface returns
3651+** the name of the N-th [SQL parameter] in the [prepared statement] P.
3652+** ^(SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA"
3653+** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA"
3654+** respectively.
3655+** In other words, the initial ":" or "$" or "@" or "?"
3656+** is included as part of the name.)^
3657+** ^Parameters of the form "?" without a following integer have no name
3658+** and are referred to as "nameless" or "anonymous parameters".
3659+**
3660+** ^The first host parameter has an index of 1, not 0.
3661+**
3662+** ^If the value N is out of range or if the N-th parameter is
3663+** nameless, then NULL is returned. ^The returned string is
3664+** always in UTF-8 encoding even if the named parameter was
3665+** originally specified as UTF-16 in [sqlite3_prepare16()] or
3666+** [sqlite3_prepare16_v2()].
3667+**
3668+** See also: [sqlite3_bind_blob|sqlite3_bind()],
3669+** [sqlite3_bind_parameter_count()], and
3670+** [sqlite3_bind_parameter_index()].
3671+*/
3672+SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
3673+
3674+/*
3675+** CAPI3REF: Index Of A Parameter With A Given Name
3676+**
3677+** ^Return the index of an SQL parameter given its name. ^The
3678+** index value returned is suitable for use as the second
3679+** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero
3680+** is returned if no matching parameter is found. ^The parameter
3681+** name must be given in UTF-8 even if the original statement
3682+** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
3683+**
3684+** See also: [sqlite3_bind_blob|sqlite3_bind()],
3685+** [sqlite3_bind_parameter_count()], and
3686+** [sqlite3_bind_parameter_index()].
3687+*/
3688+SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
3689+
3690+/*
3691+** CAPI3REF: Reset All Bindings On A Prepared Statement
3692+**
3693+** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset
3694+** the [sqlite3_bind_blob | bindings] on a [prepared statement].
3695+** ^Use this routine to reset all host parameters to NULL.
3696+*/
3697+SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
3698+
3699+/*
3700+** CAPI3REF: Number Of Columns In A Result Set
3701+**
3702+** ^Return the number of columns in the result set returned by the
3703+** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
3704+** statement that does not return data (for example an [UPDATE]).
3705+**
3706+** See also: [sqlite3_data_count()]
3707+*/
3708+SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
3709+
3710+/*
3711+** CAPI3REF: Column Names In A Result Set
3712+**
3713+** ^These routines return the name assigned to a particular column
3714+** in the result set of a [SELECT] statement. ^The sqlite3_column_name()
3715+** interface returns a pointer to a zero-terminated UTF-8 string
3716+** and sqlite3_column_name16() returns a pointer to a zero-terminated
3717+** UTF-16 string. ^The first parameter is the [prepared statement]
3718+** that implements the [SELECT] statement. ^The second parameter is the
3719+** column number. ^The leftmost column is number 0.
3720+**
3721+** ^The returned string pointer is valid until either the [prepared statement]
3722+** is destroyed by [sqlite3_finalize()] or until the statement is automatically
3723+** reprepared by the first call to [sqlite3_step()] for a particular run
3724+** or until the next call to
3725+** sqlite3_column_name() or sqlite3_column_name16() on the same column.
3726+**
3727+** ^If sqlite3_malloc() fails during the processing of either routine
3728+** (for example during a conversion from UTF-8 to UTF-16) then a
3729+** NULL pointer is returned.
3730+**
3731+** ^The name of a result column is the value of the "AS" clause for
3732+** that column, if there is an AS clause. If there is no AS clause
3733+** then the name of the column is unspecified and may change from
3734+** one release of SQLite to the next.
3735+*/
3736+SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
3737+SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
3738+
3739+/*
3740+** CAPI3REF: Source Of Data In A Query Result
3741+**
3742+** ^These routines provide a means to determine the database, table, and
3743+** table column that is the origin of a particular result column in
3744+** [SELECT] statement.
3745+** ^The name of the database or table or column can be returned as
3746+** either a UTF-8 or UTF-16 string. ^The _database_ routines return
3747+** the database name, the _table_ routines return the table name, and
3748+** the origin_ routines return the column name.
3749+** ^The returned string is valid until the [prepared statement] is destroyed
3750+** using [sqlite3_finalize()] or until the statement is automatically
3751+** reprepared by the first call to [sqlite3_step()] for a particular run
3752+** or until the same information is requested
3753+** again in a different encoding.
3754+**
3755+** ^The names returned are the original un-aliased names of the
3756+** database, table, and column.
3757+**
3758+** ^The first argument to these interfaces is a [prepared statement].
3759+** ^These functions return information about the Nth result column returned by
3760+** the statement, where N is the second function argument.
3761+** ^The left-most column is column 0 for these routines.
3762+**
3763+** ^If the Nth column returned by the statement is an expression or
3764+** subquery and is not a column value, then all of these functions return
3765+** NULL. ^These routine might also return NULL if a memory allocation error
3766+** occurs. ^Otherwise, they return the name of the attached database, table,
3767+** or column that query result column was extracted from.
3768+**
3769+** ^As with all other SQLite APIs, those whose names end with "16" return
3770+** UTF-16 encoded strings and the other functions return UTF-8.
3771+**
3772+** ^These APIs are only available if the library was compiled with the
3773+** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol.
3774+**
3775+** If two or more threads call one or more of these routines against the same
3776+** prepared statement and column at the same time then the results are
3777+** undefined.
3778+**
3779+** If two or more threads call one or more
3780+** [sqlite3_column_database_name | column metadata interfaces]
3781+** for the same [prepared statement] and result column
3782+** at the same time then the results are undefined.
3783+*/
3784+SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
3785+SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
3786+SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
3787+SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
3788+SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
3789+SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
3790+
3791+/*
3792+** CAPI3REF: Declared Datatype Of A Query Result
3793+**
3794+** ^(The first parameter is a [prepared statement].
3795+** If this statement is a [SELECT] statement and the Nth column of the
3796+** returned result set of that [SELECT] is a table column (not an
3797+** expression or subquery) then the declared type of the table
3798+** column is returned.)^ ^If the Nth column of the result set is an
3799+** expression or subquery, then a NULL pointer is returned.
3800+** ^The returned string is always UTF-8 encoded.
3801+**
3802+** ^(For example, given the database schema:
3803+**
3804+** CREATE TABLE t1(c1 VARIANT);
3805+**
3806+** and the following statement to be compiled:
3807+**
3808+** SELECT c1 + 1, c1 FROM t1;
3809+**
3810+** this routine would return the string "VARIANT" for the second result
3811+** column (i==1), and a NULL pointer for the first result column (i==0).)^
3812+**
3813+** ^SQLite uses dynamic run-time typing. ^So just because a column
3814+** is declared to contain a particular type does not mean that the
3815+** data stored in that column is of the declared type. SQLite is
3816+** strongly typed, but the typing is dynamic not static. ^Type
3817+** is associated with individual values, not with the containers
3818+** used to hold those values.
3819+*/
3820+SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
3821+SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
3822+
3823+/*
3824+** CAPI3REF: Evaluate An SQL Statement
3825+**
3826+** After a [prepared statement] has been prepared using either
3827+** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
3828+** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function
3829+** must be called one or more times to evaluate the statement.
3830+**
3831+** The details of the behavior of the sqlite3_step() interface depend
3832+** on whether the statement was prepared using the newer "v2" interface
3833+** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
3834+** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the
3835+** new "v2" interface is recommended for new applications but the legacy
3836+** interface will continue to be supported.
3837+**
3838+** ^In the legacy interface, the return value will be either [SQLITE_BUSY],
3839+** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE].
3840+** ^With the "v2" interface, any of the other [result codes] or
3841+** [extended result codes] might be returned as well.
3842+**
3843+** ^[SQLITE_BUSY] means that the database engine was unable to acquire the
3844+** database locks it needs to do its job. ^If the statement is a [COMMIT]
3845+** or occurs outside of an explicit transaction, then you can retry the
3846+** statement. If the statement is not a [COMMIT] and occurs within an
3847+** explicit transaction then you should rollback the transaction before
3848+** continuing.
3849+**
3850+** ^[SQLITE_DONE] means that the statement has finished executing
3851+** successfully. sqlite3_step() should not be called again on this virtual
3852+** machine without first calling [sqlite3_reset()] to reset the virtual
3853+** machine back to its initial state.
3854+**
3855+** ^If the SQL statement being executed returns any data, then [SQLITE_ROW]
3856+** is returned each time a new row of data is ready for processing by the
3857+** caller. The values may be accessed using the [column access functions].
3858+** sqlite3_step() is called again to retrieve the next row of data.
3859+**
3860+** ^[SQLITE_ERROR] means that a run-time error (such as a constraint
3861+** violation) has occurred. sqlite3_step() should not be called again on
3862+** the VM. More information may be found by calling [sqlite3_errmsg()].
3863+** ^With the legacy interface, a more specific error code (for example,
3864+** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth)
3865+** can be obtained by calling [sqlite3_reset()] on the
3866+** [prepared statement]. ^In the "v2" interface,
3867+** the more specific error code is returned directly by sqlite3_step().
3868+**
3869+** [SQLITE_MISUSE] means that the this routine was called inappropriately.
3870+** Perhaps it was called on a [prepared statement] that has
3871+** already been [sqlite3_finalize | finalized] or on one that had
3872+** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could
3873+** be the case that the same database connection is being used by two or
3874+** more threads at the same moment in time.
3875+**
3876+** For all versions of SQLite up to and including 3.6.23.1, a call to
3877+** [sqlite3_reset()] was required after sqlite3_step() returned anything
3878+** other than [SQLITE_ROW] before any subsequent invocation of
3879+** sqlite3_step(). Failure to reset the prepared statement using
3880+** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
3881+** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began
3882+** calling [sqlite3_reset()] automatically in this circumstance rather
3883+** than returning [SQLITE_MISUSE]. This is not considered a compatibility
3884+** break because any application that ever receives an SQLITE_MISUSE error
3885+** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option
3886+** can be used to restore the legacy behavior.
3887+**
3888+** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
3889+** API always returns a generic error code, [SQLITE_ERROR], following any
3890+** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call
3891+** [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the
3892+** specific [error codes] that better describes the error.
3893+** We admit that this is a goofy design. The problem has been fixed
3894+** with the "v2" interface. If you prepare all of your SQL statements
3895+** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
3896+** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces,
3897+** then the more specific [error codes] are returned directly
3898+** by sqlite3_step(). The use of the "v2" interface is recommended.
3899+*/
3900+SQLITE_API int sqlite3_step(sqlite3_stmt*);
3901+
3902+/*
3903+** CAPI3REF: Number of columns in a result set
3904+**
3905+** ^The sqlite3_data_count(P) interface returns the number of columns in the
3906+** current row of the result set of [prepared statement] P.
3907+** ^If prepared statement P does not have results ready to return
3908+** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
3909+** interfaces) then sqlite3_data_count(P) returns 0.
3910+** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
3911+** ^The sqlite3_data_count(P) routine returns 0 if the previous call to
3912+** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P)
3913+** will return non-zero if previous call to [sqlite3_step](P) returned
3914+** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum]
3915+** where it always returns zero since each step of that multi-step
3916+** pragma returns 0 columns of data.
3917+**
3918+** See also: [sqlite3_column_count()]
3919+*/
3920+SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
3921+
3922+/*
3923+** CAPI3REF: Fundamental Datatypes
3924+** KEYWORDS: SQLITE_TEXT
3925+**
3926+** ^(Every value in SQLite has one of five fundamental datatypes:
3927+**
3928+** <ul>
3929+** <li> 64-bit signed integer
3930+** <li> 64-bit IEEE floating point number
3931+** <li> string
3932+** <li> BLOB
3933+** <li> NULL
3934+** </ul>)^
3935+**
3936+** These constants are codes for each of those types.
3937+**
3938+** Note that the SQLITE_TEXT constant was also used in SQLite version 2
3939+** for a completely different meaning. Software that links against both
3940+** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not
3941+** SQLITE_TEXT.
3942+*/
3943+#define SQLITE_INTEGER 1
3944+#define SQLITE_FLOAT 2
3945+#define SQLITE_BLOB 4
3946+#define SQLITE_NULL 5
3947+#ifdef SQLITE_TEXT
3948+# undef SQLITE_TEXT
3949+#else
3950+# define SQLITE_TEXT 3
3951+#endif
3952+#define SQLITE3_TEXT 3
3953+
3954+/*
3955+** CAPI3REF: Result Values From A Query
3956+** KEYWORDS: {column access functions}
3957+**
3958+** These routines form the "result set" interface.
3959+**
3960+** ^These routines return information about a single column of the current
3961+** result row of a query. ^In every case the first argument is a pointer
3962+** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
3963+** that was returned from [sqlite3_prepare_v2()] or one of its variants)
3964+** and the second argument is the index of the column for which information
3965+** should be returned. ^The leftmost column of the result set has the index 0.
3966+** ^The number of columns in the result can be determined using
3967+** [sqlite3_column_count()].
3968+**
3969+** If the SQL statement does not currently point to a valid row, or if the
3970+** column index is out of range, the result is undefined.
3971+** These routines may only be called when the most recent call to
3972+** [sqlite3_step()] has returned [SQLITE_ROW] and neither
3973+** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently.
3974+** If any of these routines are called after [sqlite3_reset()] or
3975+** [sqlite3_finalize()] or after [sqlite3_step()] has returned
3976+** something other than [SQLITE_ROW], the results are undefined.
3977+** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()]
3978+** are called from a different thread while any of these routines
3979+** are pending, then the results are undefined.
3980+**
3981+** ^The sqlite3_column_type() routine returns the
3982+** [SQLITE_INTEGER | datatype code] for the initial data type
3983+** of the result column. ^The returned value is one of [SQLITE_INTEGER],
3984+** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value
3985+** returned by sqlite3_column_type() is only meaningful if no type
3986+** conversions have occurred as described below. After a type conversion,
3987+** the value returned by sqlite3_column_type() is undefined. Future
3988+** versions of SQLite may change the behavior of sqlite3_column_type()
3989+** following a type conversion.
3990+**
3991+** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
3992+** routine returns the number of bytes in that BLOB or string.
3993+** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts
3994+** the string to UTF-8 and then returns the number of bytes.
3995+** ^If the result is a numeric value then sqlite3_column_bytes() uses
3996+** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns
3997+** the number of bytes in that string.
3998+** ^If the result is NULL, then sqlite3_column_bytes() returns zero.
3999+**
4000+** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16()
4001+** routine returns the number of bytes in that BLOB or string.
4002+** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts
4003+** the string to UTF-16 and then returns the number of bytes.
4004+** ^If the result is a numeric value then sqlite3_column_bytes16() uses
4005+** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns
4006+** the number of bytes in that string.
4007+** ^If the result is NULL, then sqlite3_column_bytes16() returns zero.
4008+**
4009+** ^The values returned by [sqlite3_column_bytes()] and
4010+** [sqlite3_column_bytes16()] do not include the zero terminators at the end
4011+** of the string. ^For clarity: the values returned by
4012+** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of
4013+** bytes in the string, not the number of characters.
4014+**
4015+** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
4016+** even empty strings, are always zero terminated. ^The return
4017+** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
4018+**
4019+** ^The object returned by [sqlite3_column_value()] is an
4020+** [unprotected sqlite3_value] object. An unprotected sqlite3_value object
4021+** may only be used with [sqlite3_bind_value()] and [sqlite3_result_value()].
4022+** If the [unprotected sqlite3_value] object returned by
4023+** [sqlite3_column_value()] is used in any other way, including calls
4024+** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
4025+** or [sqlite3_value_bytes()], then the behavior is undefined.
4026+**
4027+** These routines attempt to convert the value where appropriate. ^For
4028+** example, if the internal representation is FLOAT and a text result
4029+** is requested, [sqlite3_snprintf()] is used internally to perform the
4030+** conversion automatically. ^(The following table details the conversions
4031+** that are applied:
4032+**
4033+** <blockquote>
4034+** <table border="1">
4035+** <tr><th> Internal<br>Type <th> Requested<br>Type <th> Conversion
4036+**
4037+** <tr><td> NULL <td> INTEGER <td> Result is 0
4038+** <tr><td> NULL <td> FLOAT <td> Result is 0.0
4039+** <tr><td> NULL <td> TEXT <td> Result is NULL pointer
4040+** <tr><td> NULL <td> BLOB <td> Result is NULL pointer
4041+** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float
4042+** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer
4043+** <tr><td> INTEGER <td> BLOB <td> Same as INTEGER->TEXT
4044+** <tr><td> FLOAT <td> INTEGER <td> Convert from float to integer
4045+** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float
4046+** <tr><td> FLOAT <td> BLOB <td> Same as FLOAT->TEXT
4047+** <tr><td> TEXT <td> INTEGER <td> Use atoi()
4048+** <tr><td> TEXT <td> FLOAT <td> Use atof()
4049+** <tr><td> TEXT <td> BLOB <td> No change
4050+** <tr><td> BLOB <td> INTEGER <td> Convert to TEXT then use atoi()
4051+** <tr><td> BLOB <td> FLOAT <td> Convert to TEXT then use atof()
4052+** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
4053+** </table>
4054+** </blockquote>)^
4055+**
4056+** The table above makes reference to standard C library functions atoi()
4057+** and atof(). SQLite does not really use these functions. It has its
4058+** own equivalent internal routines. The atoi() and atof() names are
4059+** used in the table for brevity and because they are familiar to most
4060+** C programmers.
4061+**
4062+** Note that when type conversions occur, pointers returned by prior
4063+** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
4064+** sqlite3_column_text16() may be invalidated.
4065+** Type conversions and pointer invalidations might occur
4066+** in the following cases:
4067+**
4068+** <ul>
4069+** <li> The initial content is a BLOB and sqlite3_column_text() or
4070+** sqlite3_column_text16() is called. A zero-terminator might
4071+** need to be added to the string.</li>
4072+** <li> The initial content is UTF-8 text and sqlite3_column_bytes16() or
4073+** sqlite3_column_text16() is called. The content must be converted
4074+** to UTF-16.</li>
4075+** <li> The initial content is UTF-16 text and sqlite3_column_bytes() or
4076+** sqlite3_column_text() is called. The content must be converted
4077+** to UTF-8.</li>
4078+** </ul>
4079+**
4080+** ^Conversions between UTF-16be and UTF-16le are always done in place and do
4081+** not invalidate a prior pointer, though of course the content of the buffer
4082+** that the prior pointer references will have been modified. Other kinds
4083+** of conversion are done in place when it is possible, but sometimes they
4084+** are not possible and in those cases prior pointers are invalidated.
4085+**
4086+** The safest and easiest to remember policy is to invoke these routines
4087+** in one of the following ways:
4088+**
4089+** <ul>
4090+** <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
4091+** <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
4092+** <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
4093+** </ul>
4094+**
4095+** In other words, you should call sqlite3_column_text(),
4096+** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result
4097+** into the desired format, then invoke sqlite3_column_bytes() or
4098+** sqlite3_column_bytes16() to find the size of the result. Do not mix calls
4099+** to sqlite3_column_text() or sqlite3_column_blob() with calls to
4100+** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16()
4101+** with calls to sqlite3_column_bytes().
4102+**
4103+** ^The pointers returned are valid until a type conversion occurs as
4104+** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
4105+** [sqlite3_finalize()] is called. ^The memory space used to hold strings
4106+** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned
4107+** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
4108+** [sqlite3_free()].
4109+**
4110+** ^(If a memory allocation error occurs during the evaluation of any
4111+** of these routines, a default value is returned. The default value
4112+** is either the integer 0, the floating point number 0.0, or a NULL
4113+** pointer. Subsequent calls to [sqlite3_errcode()] will return
4114+** [SQLITE_NOMEM].)^
4115+*/
4116+SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
4117+SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
4118+SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
4119+SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
4120+SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
4121+SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
4122+SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
4123+SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
4124+SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
4125+SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
4126+
4127+/*
4128+** CAPI3REF: Destroy A Prepared Statement Object
4129+**
4130+** ^The sqlite3_finalize() function is called to delete a [prepared statement].
4131+** ^If the most recent evaluation of the statement encountered no errors
4132+** or if the statement is never been evaluated, then sqlite3_finalize() returns
4133+** SQLITE_OK. ^If the most recent evaluation of statement S failed, then
4134+** sqlite3_finalize(S) returns the appropriate [error code] or
4135+** [extended error code].
4136+**
4137+** ^The sqlite3_finalize(S) routine can be called at any point during
4138+** the life cycle of [prepared statement] S:
4139+** before statement S is ever evaluated, after
4140+** one or more calls to [sqlite3_reset()], or after any call
4141+** to [sqlite3_step()] regardless of whether or not the statement has
4142+** completed execution.
4143+**
4144+** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op.
4145+**
4146+** The application must finalize every [prepared statement] in order to avoid
4147+** resource leaks. It is a grievous error for the application to try to use
4148+** a prepared statement after it has been finalized. Any use of a prepared
4149+** statement after it has been finalized can result in undefined and
4150+** undesirable behavior such as segfaults and heap corruption.
4151+*/
4152+SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
4153+
4154+/*
4155+** CAPI3REF: Reset A Prepared Statement Object
4156+**
4157+** The sqlite3_reset() function is called to reset a [prepared statement]
4158+** object back to its initial state, ready to be re-executed.
4159+** ^Any SQL statement variables that had values bound to them using
4160+** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values.
4161+** Use [sqlite3_clear_bindings()] to reset the bindings.
4162+**
4163+** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S
4164+** back to the beginning of its program.
4165+**
4166+** ^If the most recent call to [sqlite3_step(S)] for the
4167+** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
4168+** or if [sqlite3_step(S)] has never before been called on S,
4169+** then [sqlite3_reset(S)] returns [SQLITE_OK].
4170+**
4171+** ^If the most recent call to [sqlite3_step(S)] for the
4172+** [prepared statement] S indicated an error, then
4173+** [sqlite3_reset(S)] returns an appropriate [error code].
4174+**
4175+** ^The [sqlite3_reset(S)] interface does not change the values
4176+** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
4177+*/
4178+SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
4179+
4180+/*
4181+** CAPI3REF: Create Or Redefine SQL Functions
4182+** KEYWORDS: {function creation routines}
4183+** KEYWORDS: {application-defined SQL function}
4184+** KEYWORDS: {application-defined SQL functions}
4185+**
4186+** ^These functions (collectively known as "function creation routines")
4187+** are used to add SQL functions or aggregates or to redefine the behavior
4188+** of existing SQL functions or aggregates. The only differences between
4189+** these routines are the text encoding expected for
4190+** the second parameter (the name of the function being created)
4191+** and the presence or absence of a destructor callback for
4192+** the application data pointer.
4193+**
4194+** ^The first parameter is the [database connection] to which the SQL
4195+** function is to be added. ^If an application uses more than one database
4196+** connection then application-defined SQL functions must be added
4197+** to each database connection separately.
4198+**
4199+** ^The second parameter is the name of the SQL function to be created or
4200+** redefined. ^The length of the name is limited to 255 bytes in a UTF-8
4201+** representation, exclusive of the zero-terminator. ^Note that the name
4202+** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
4203+** ^Any attempt to create a function with a longer name
4204+** will result in [SQLITE_MISUSE] being returned.
4205+**
4206+** ^The third parameter (nArg)
4207+** is the number of arguments that the SQL function or
4208+** aggregate takes. ^If this parameter is -1, then the SQL function or
4209+** aggregate may take any number of arguments between 0 and the limit
4210+** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third
4211+** parameter is less than -1 or greater than 127 then the behavior is
4212+** undefined.
4213+**
4214+** ^The fourth parameter, eTextRep, specifies what
4215+** [SQLITE_UTF8 | text encoding] this SQL function prefers for
4216+** its parameters. Every SQL function implementation must be able to work
4217+** with UTF-8, UTF-16le, or UTF-16be. But some implementations may be
4218+** more efficient with one encoding than another. ^An application may
4219+** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
4220+** times with the same function but with different values of eTextRep.
4221+** ^When multiple implementations of the same function are available, SQLite
4222+** will pick the one that involves the least amount of data conversion.
4223+** If there is only a single implementation which does not care what text
4224+** encoding is used, then the fourth argument should be [SQLITE_ANY].
4225+**
4226+** ^(The fifth parameter is an arbitrary pointer. The implementation of the
4227+** function can gain access to this pointer using [sqlite3_user_data()].)^
4228+**
4229+** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are
4230+** pointers to C-language functions that implement the SQL function or
4231+** aggregate. ^A scalar SQL function requires an implementation of the xFunc
4232+** callback only; NULL pointers must be passed as the xStep and xFinal
4233+** parameters. ^An aggregate SQL function requires an implementation of xStep
4234+** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing
4235+** SQL function or aggregate, pass NULL pointers for all three function
4236+** callbacks.
4237+**
4238+** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL,
4239+** then it is destructor for the application data pointer.
4240+** The destructor is invoked when the function is deleted, either by being
4241+** overloaded or when the database connection closes.)^
4242+** ^The destructor is also invoked if the call to
4243+** sqlite3_create_function_v2() fails.
4244+** ^When the destructor callback of the tenth parameter is invoked, it
4245+** is passed a single argument which is a copy of the application data
4246+** pointer which was the fifth parameter to sqlite3_create_function_v2().
4247+**
4248+** ^It is permitted to register multiple implementations of the same
4249+** functions with the same name but with either differing numbers of
4250+** arguments or differing preferred text encodings. ^SQLite will use
4251+** the implementation that most closely matches the way in which the
4252+** SQL function is used. ^A function implementation with a non-negative
4253+** nArg parameter is a better match than a function implementation with
4254+** a negative nArg. ^A function where the preferred text encoding
4255+** matches the database encoding is a better
4256+** match than a function where the encoding is different.
4257+** ^A function where the encoding difference is between UTF16le and UTF16be
4258+** is a closer match than a function where the encoding difference is
4259+** between UTF8 and UTF16.
4260+**
4261+** ^Built-in functions may be overloaded by new application-defined functions.
4262+**
4263+** ^An application-defined function is permitted to call other
4264+** SQLite interfaces. However, such calls must not
4265+** close the database connection nor finalize or reset the prepared
4266+** statement in which the function is running.
4267+*/
4268+SQLITE_API int sqlite3_create_function(
4269+ sqlite3 *db,
4270+ const char *zFunctionName,
4271+ int nArg,
4272+ int eTextRep,
4273+ void *pApp,
4274+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
4275+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
4276+ void (*xFinal)(sqlite3_context*)
4277+);
4278+SQLITE_API int sqlite3_create_function16(
4279+ sqlite3 *db,
4280+ const void *zFunctionName,
4281+ int nArg,
4282+ int eTextRep,
4283+ void *pApp,
4284+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
4285+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
4286+ void (*xFinal)(sqlite3_context*)
4287+);
4288+SQLITE_API int sqlite3_create_function_v2(
4289+ sqlite3 *db,
4290+ const char *zFunctionName,
4291+ int nArg,
4292+ int eTextRep,
4293+ void *pApp,
4294+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
4295+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
4296+ void (*xFinal)(sqlite3_context*),
4297+ void(*xDestroy)(void*)
4298+);
4299+
4300+/*
4301+** CAPI3REF: Text Encodings
4302+**
4303+** These constant define integer codes that represent the various
4304+** text encodings supported by SQLite.
4305+*/
4306+#define SQLITE_UTF8 1
4307+#define SQLITE_UTF16LE 2
4308+#define SQLITE_UTF16BE 3
4309+#define SQLITE_UTF16 4 /* Use native byte order */
4310+#define SQLITE_ANY 5 /* sqlite3_create_function only */
4311+#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
4312+
4313+/*
4314+** CAPI3REF: Deprecated Functions
4315+** DEPRECATED
4316+**
4317+** These functions are [deprecated]. In order to maintain
4318+** backwards compatibility with older code, these functions continue
4319+** to be supported. However, new applications should avoid
4320+** the use of these functions. To help encourage people to avoid
4321+** using these functions, we are not going to tell you what they do.
4322+*/
4323+#ifndef SQLITE_OMIT_DEPRECATED
4324+SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
4325+SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
4326+SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
4327+SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
4328+SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
4329+SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64);
4330+#endif
4331+
4332+/*
4333+** CAPI3REF: Obtaining SQL Function Parameter Values
4334+**
4335+** The C-language implementation of SQL functions and aggregates uses
4336+** this set of interface routines to access the parameter values on
4337+** the function or aggregate.
4338+**
4339+** The xFunc (for scalar functions) or xStep (for aggregates) parameters
4340+** to [sqlite3_create_function()] and [sqlite3_create_function16()]
4341+** define callbacks that implement the SQL functions and aggregates.
4342+** The 3rd parameter to these callbacks is an array of pointers to
4343+** [protected sqlite3_value] objects. There is one [sqlite3_value] object for
4344+** each parameter to the SQL function. These routines are used to
4345+** extract values from the [sqlite3_value] objects.
4346+**
4347+** These routines work only with [protected sqlite3_value] objects.
4348+** Any attempt to use these routines on an [unprotected sqlite3_value]
4349+** object results in undefined behavior.
4350+**
4351+** ^These routines work just like the corresponding [column access functions]
4352+** except that these routines take a single [protected sqlite3_value] object
4353+** pointer instead of a [sqlite3_stmt*] pointer and an integer column number.
4354+**
4355+** ^The sqlite3_value_text16() interface extracts a UTF-16 string
4356+** in the native byte-order of the host machine. ^The
4357+** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
4358+** extract UTF-16 strings as big-endian and little-endian respectively.
4359+**
4360+** ^(The sqlite3_value_numeric_type() interface attempts to apply
4361+** numeric affinity to the value. This means that an attempt is
4362+** made to convert the value to an integer or floating point. If
4363+** such a conversion is possible without loss of information (in other
4364+** words, if the value is a string that looks like a number)
4365+** then the conversion is performed. Otherwise no conversion occurs.
4366+** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
4367+**
4368+** Please pay particular attention to the fact that the pointer returned
4369+** from [sqlite3_value_blob()], [sqlite3_value_text()], or
4370+** [sqlite3_value_text16()] can be invalidated by a subsequent call to
4371+** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
4372+** or [sqlite3_value_text16()].
4373+**
4374+** These routines must be called from the same thread as
4375+** the SQL function that supplied the [sqlite3_value*] parameters.
4376+*/
4377+SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
4378+SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
4379+SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
4380+SQLITE_API double sqlite3_value_double(sqlite3_value*);
4381+SQLITE_API int sqlite3_value_int(sqlite3_value*);
4382+SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
4383+SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
4384+SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
4385+SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
4386+SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
4387+SQLITE_API int sqlite3_value_type(sqlite3_value*);
4388+SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
4389+
4390+/*
4391+** CAPI3REF: Obtain Aggregate Function Context
4392+**
4393+** Implementations of aggregate SQL functions use this
4394+** routine to allocate memory for storing their state.
4395+**
4396+** ^The first time the sqlite3_aggregate_context(C,N) routine is called
4397+** for a particular aggregate function, SQLite
4398+** allocates N of memory, zeroes out that memory, and returns a pointer
4399+** to the new memory. ^On second and subsequent calls to
4400+** sqlite3_aggregate_context() for the same aggregate function instance,
4401+** the same buffer is returned. Sqlite3_aggregate_context() is normally
4402+** called once for each invocation of the xStep callback and then one
4403+** last time when the xFinal callback is invoked. ^(When no rows match
4404+** an aggregate query, the xStep() callback of the aggregate function
4405+** implementation is never called and xFinal() is called exactly once.
4406+** In those cases, sqlite3_aggregate_context() might be called for the
4407+** first time from within xFinal().)^
4408+**
4409+** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is
4410+** less than or equal to zero or if a memory allocate error occurs.
4411+**
4412+** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
4413+** determined by the N parameter on first successful call. Changing the
4414+** value of N in subsequent call to sqlite3_aggregate_context() within
4415+** the same aggregate function instance will not resize the memory
4416+** allocation.)^
4417+**
4418+** ^SQLite automatically frees the memory allocated by
4419+** sqlite3_aggregate_context() when the aggregate query concludes.
4420+**
4421+** The first parameter must be a copy of the
4422+** [sqlite3_context | SQL function context] that is the first parameter
4423+** to the xStep or xFinal callback routine that implements the aggregate
4424+** function.
4425+**
4426+** This routine must be called from the same thread in which
4427+** the aggregate SQL function is running.
4428+*/
4429+SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
4430+
4431+/*
4432+** CAPI3REF: User Data For Functions
4433+**
4434+** ^The sqlite3_user_data() interface returns a copy of
4435+** the pointer that was the pUserData parameter (the 5th parameter)
4436+** of the [sqlite3_create_function()]
4437+** and [sqlite3_create_function16()] routines that originally
4438+** registered the application defined function.
4439+**
4440+** This routine must be called from the same thread in which
4441+** the application-defined function is running.
4442+*/
4443+SQLITE_API void *sqlite3_user_data(sqlite3_context*);
4444+
4445+/*
4446+** CAPI3REF: Database Connection For Functions
4447+**
4448+** ^The sqlite3_context_db_handle() interface returns a copy of
4449+** the pointer to the [database connection] (the 1st parameter)
4450+** of the [sqlite3_create_function()]
4451+** and [sqlite3_create_function16()] routines that originally
4452+** registered the application defined function.
4453+*/
4454+SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
4455+
4456+/*
4457+** CAPI3REF: Function Auxiliary Data
4458+**
4459+** The following two functions may be used by scalar SQL functions to
4460+** associate metadata with argument values. If the same value is passed to
4461+** multiple invocations of the same SQL function during query execution, under
4462+** some circumstances the associated metadata may be preserved. This may
4463+** be used, for example, to add a regular-expression matching scalar
4464+** function. The compiled version of the regular expression is stored as
4465+** metadata associated with the SQL value passed as the regular expression
4466+** pattern. The compiled regular expression can be reused on multiple
4467+** invocations of the same function so that the original pattern string
4468+** does not need to be recompiled on each invocation.
4469+**
4470+** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
4471+** associated by the sqlite3_set_auxdata() function with the Nth argument
4472+** value to the application-defined function. ^If no metadata has been ever
4473+** been set for the Nth argument of the function, or if the corresponding
4474+** function parameter has changed since the meta-data was set,
4475+** then sqlite3_get_auxdata() returns a NULL pointer.
4476+**
4477+** ^The sqlite3_set_auxdata() interface saves the metadata
4478+** pointed to by its 3rd parameter as the metadata for the N-th
4479+** argument of the application-defined function. Subsequent
4480+** calls to sqlite3_get_auxdata() might return this data, if it has
4481+** not been destroyed.
4482+** ^If it is not NULL, SQLite will invoke the destructor
4483+** function given by the 4th parameter to sqlite3_set_auxdata() on
4484+** the metadata when the corresponding function parameter changes
4485+** or when the SQL statement completes, whichever comes first.
4486+**
4487+** SQLite is free to call the destructor and drop metadata on any
4488+** parameter of any function at any time. ^The only guarantee is that
4489+** the destructor will be called before the metadata is dropped.
4490+**
4491+** ^(In practice, metadata is preserved between function calls for
4492+** expressions that are constant at compile time. This includes literal
4493+** values and [parameters].)^
4494+**
4495+** These routines must be called from the same thread in which
4496+** the SQL function is running.
4497+*/
4498+SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
4499+SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
4500+
4501+
4502+/*
4503+** CAPI3REF: Constants Defining Special Destructor Behavior
4504+**
4505+** These are special values for the destructor that is passed in as the
4506+** final argument to routines like [sqlite3_result_blob()]. ^If the destructor
4507+** argument is SQLITE_STATIC, it means that the content pointer is constant
4508+** and will never change. It does not need to be destroyed. ^The
4509+** SQLITE_TRANSIENT value means that the content will likely change in
4510+** the near future and that SQLite should make its own private copy of
4511+** the content before returning.
4512+**
4513+** The typedef is necessary to work around problems in certain
4514+** C++ compilers. See ticket #2191.
4515+*/
4516+typedef void (*sqlite3_destructor_type)(void*);
4517+#define SQLITE_STATIC ((sqlite3_destructor_type)0)
4518+#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
4519+
4520+/*
4521+** CAPI3REF: Setting The Result Of An SQL Function
4522+**
4523+** These routines are used by the xFunc or xFinal callbacks that
4524+** implement SQL functions and aggregates. See
4525+** [sqlite3_create_function()] and [sqlite3_create_function16()]
4526+** for additional information.
4527+**
4528+** These functions work very much like the [parameter binding] family of
4529+** functions used to bind values to host parameters in prepared statements.
4530+** Refer to the [SQL parameter] documentation for additional information.
4531+**
4532+** ^The sqlite3_result_blob() interface sets the result from
4533+** an application-defined function to be the BLOB whose content is pointed
4534+** to by the second parameter and which is N bytes long where N is the
4535+** third parameter.
4536+**
4537+** ^The sqlite3_result_zeroblob() interfaces set the result of
4538+** the application-defined function to be a BLOB containing all zero
4539+** bytes and N bytes in size, where N is the value of the 2nd parameter.
4540+**
4541+** ^The sqlite3_result_double() interface sets the result from
4542+** an application-defined function to be a floating point value specified
4543+** by its 2nd argument.
4544+**
4545+** ^The sqlite3_result_error() and sqlite3_result_error16() functions
4546+** cause the implemented SQL function to throw an exception.
4547+** ^SQLite uses the string pointed to by the
4548+** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
4549+** as the text of an error message. ^SQLite interprets the error
4550+** message string from sqlite3_result_error() as UTF-8. ^SQLite
4551+** interprets the string from sqlite3_result_error16() as UTF-16 in native
4552+** byte order. ^If the third parameter to sqlite3_result_error()
4553+** or sqlite3_result_error16() is negative then SQLite takes as the error
4554+** message all text up through the first zero character.
4555+** ^If the third parameter to sqlite3_result_error() or
4556+** sqlite3_result_error16() is non-negative then SQLite takes that many
4557+** bytes (not characters) from the 2nd parameter as the error message.
4558+** ^The sqlite3_result_error() and sqlite3_result_error16()
4559+** routines make a private copy of the error message text before
4560+** they return. Hence, the calling function can deallocate or
4561+** modify the text after they return without harm.
4562+** ^The sqlite3_result_error_code() function changes the error code
4563+** returned by SQLite as a result of an error in a function. ^By default,
4564+** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error()
4565+** or sqlite3_result_error16() resets the error code to SQLITE_ERROR.
4566+**
4567+** ^The sqlite3_result_toobig() interface causes SQLite to throw an error
4568+** indicating that a string or BLOB is too long to represent.
4569+**
4570+** ^The sqlite3_result_nomem() interface causes SQLite to throw an error
4571+** indicating that a memory allocation failed.
4572+**
4573+** ^The sqlite3_result_int() interface sets the return value
4574+** of the application-defined function to be the 32-bit signed integer
4575+** value given in the 2nd argument.
4576+** ^The sqlite3_result_int64() interface sets the return value
4577+** of the application-defined function to be the 64-bit signed integer
4578+** value given in the 2nd argument.
4579+**
4580+** ^The sqlite3_result_null() interface sets the return value
4581+** of the application-defined function to be NULL.
4582+**
4583+** ^The sqlite3_result_text(), sqlite3_result_text16(),
4584+** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces
4585+** set the return value of the application-defined function to be
4586+** a text string which is represented as UTF-8, UTF-16 native byte order,
4587+** UTF-16 little endian, or UTF-16 big endian, respectively.
4588+** ^SQLite takes the text result from the application from
4589+** the 2nd parameter of the sqlite3_result_text* interfaces.
4590+** ^If the 3rd parameter to the sqlite3_result_text* interfaces
4591+** is negative, then SQLite takes result text from the 2nd parameter
4592+** through the first zero character.
4593+** ^If the 3rd parameter to the sqlite3_result_text* interfaces
4594+** is non-negative, then as many bytes (not characters) of the text
4595+** pointed to by the 2nd parameter are taken as the application-defined
4596+** function result. If the 3rd parameter is non-negative, then it
4597+** must be the byte offset into the string where the NUL terminator would
4598+** appear if the string where NUL terminated. If any NUL characters occur
4599+** in the string at a byte offset that is less than the value of the 3rd
4600+** parameter, then the resulting string will contain embedded NULs and the
4601+** result of expressions operating on strings with embedded NULs is undefined.
4602+** ^If the 4th parameter to the sqlite3_result_text* interfaces
4603+** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that
4604+** function as the destructor on the text or BLOB result when it has
4605+** finished using that result.
4606+** ^If the 4th parameter to the sqlite3_result_text* interfaces or to
4607+** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite
4608+** assumes that the text or BLOB result is in constant space and does not
4609+** copy the content of the parameter nor call a destructor on the content
4610+** when it has finished using that result.
4611+** ^If the 4th parameter to the sqlite3_result_text* interfaces
4612+** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
4613+** then SQLite makes a copy of the result into space obtained from
4614+** from [sqlite3_malloc()] before it returns.
4615+**
4616+** ^The sqlite3_result_value() interface sets the result of
4617+** the application-defined function to be a copy the
4618+** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
4619+** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
4620+** so that the [sqlite3_value] specified in the parameter may change or
4621+** be deallocated after sqlite3_result_value() returns without harm.
4622+** ^A [protected sqlite3_value] object may always be used where an
4623+** [unprotected sqlite3_value] object is required, so either
4624+** kind of [sqlite3_value] object can be used with this interface.
4625+**
4626+** If these routines are called from within the different thread
4627+** than the one containing the application-defined function that received
4628+** the [sqlite3_context] pointer, the results are undefined.
4629+*/
4630+SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
4631+SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
4632+SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
4633+SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
4634+SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
4635+SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
4636+SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
4637+SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
4638+SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
4639+SQLITE_API void sqlite3_result_null(sqlite3_context*);
4640+SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
4641+SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
4642+SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
4643+SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
4644+SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
4645+SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
4646+
4647+/*
4648+** CAPI3REF: Define New Collating Sequences
4649+**
4650+** ^These functions add, remove, or modify a [collation] associated
4651+** with the [database connection] specified as the first argument.
4652+**
4653+** ^The name of the collation is a UTF-8 string
4654+** for sqlite3_create_collation() and sqlite3_create_collation_v2()
4655+** and a UTF-16 string in native byte order for sqlite3_create_collation16().
4656+** ^Collation names that compare equal according to [sqlite3_strnicmp()] are
4657+** considered to be the same name.
4658+**
4659+** ^(The third argument (eTextRep) must be one of the constants:
4660+** <ul>
4661+** <li> [SQLITE_UTF8],
4662+** <li> [SQLITE_UTF16LE],
4663+** <li> [SQLITE_UTF16BE],
4664+** <li> [SQLITE_UTF16], or
4665+** <li> [SQLITE_UTF16_ALIGNED].
4666+** </ul>)^
4667+** ^The eTextRep argument determines the encoding of strings passed
4668+** to the collating function callback, xCallback.
4669+** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
4670+** force strings to be UTF16 with native byte order.
4671+** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
4672+** on an even byte address.
4673+**
4674+** ^The fourth argument, pArg, is an application data pointer that is passed
4675+** through as the first argument to the collating function callback.
4676+**
4677+** ^The fifth argument, xCallback, is a pointer to the collating function.
4678+** ^Multiple collating functions can be registered using the same name but
4679+** with different eTextRep parameters and SQLite will use whichever
4680+** function requires the least amount of data transformation.
4681+** ^If the xCallback argument is NULL then the collating function is
4682+** deleted. ^When all collating functions having the same name are deleted,
4683+** that collation is no longer usable.
4684+**
4685+** ^The collating function callback is invoked with a copy of the pArg
4686+** application data pointer and with two strings in the encoding specified
4687+** by the eTextRep argument. The collating function must return an
4688+** integer that is negative, zero, or positive
4689+** if the first string is less than, equal to, or greater than the second,
4690+** respectively. A collating function must always return the same answer
4691+** given the same inputs. If two or more collating functions are registered
4692+** to the same collation name (using different eTextRep values) then all
4693+** must give an equivalent answer when invoked with equivalent strings.
4694+** The collating function must obey the following properties for all
4695+** strings A, B, and C:
4696+**
4697+** <ol>
4698+** <li> If A==B then B==A.
4699+** <li> If A==B and B==C then A==C.
4700+** <li> If A&lt;B THEN B&gt;A.
4701+** <li> If A&lt;B and B&lt;C then A&lt;C.
4702+** </ol>
4703+**
4704+** If a collating function fails any of the above constraints and that
4705+** collating function is registered and used, then the behavior of SQLite
4706+** is undefined.
4707+**
4708+** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
4709+** with the addition that the xDestroy callback is invoked on pArg when
4710+** the collating function is deleted.
4711+** ^Collating functions are deleted when they are overridden by later
4712+** calls to the collation creation functions or when the
4713+** [database connection] is closed using [sqlite3_close()].
4714+**
4715+** ^The xDestroy callback is <u>not</u> called if the
4716+** sqlite3_create_collation_v2() function fails. Applications that invoke
4717+** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
4718+** check the return code and dispose of the application data pointer
4719+** themselves rather than expecting SQLite to deal with it for them.
4720+** This is different from every other SQLite interface. The inconsistency
4721+** is unfortunate but cannot be changed without breaking backwards
4722+** compatibility.
4723+**
4724+** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
4725+*/
4726+SQLITE_API int sqlite3_create_collation(
4727+ sqlite3*,
4728+ const char *zName,
4729+ int eTextRep,
4730+ void *pArg,
4731+ int(*xCompare)(void*,int,const void*,int,const void*)
4732+);
4733+SQLITE_API int sqlite3_create_collation_v2(
4734+ sqlite3*,
4735+ const char *zName,
4736+ int eTextRep,
4737+ void *pArg,
4738+ int(*xCompare)(void*,int,const void*,int,const void*),
4739+ void(*xDestroy)(void*)
4740+);
4741+SQLITE_API int sqlite3_create_collation16(
4742+ sqlite3*,
4743+ const void *zName,
4744+ int eTextRep,
4745+ void *pArg,
4746+ int(*xCompare)(void*,int,const void*,int,const void*)
4747+);
4748+
4749+/*
4750+** CAPI3REF: Collation Needed Callbacks
4751+**
4752+** ^To avoid having to register all collation sequences before a database
4753+** can be used, a single callback function may be registered with the
4754+** [database connection] to be invoked whenever an undefined collation
4755+** sequence is required.
4756+**
4757+** ^If the function is registered using the sqlite3_collation_needed() API,
4758+** then it is passed the names of undefined collation sequences as strings
4759+** encoded in UTF-8. ^If sqlite3_collation_needed16() is used,
4760+** the names are passed as UTF-16 in machine native byte order.
4761+** ^A call to either function replaces the existing collation-needed callback.
4762+**
4763+** ^(When the callback is invoked, the first argument passed is a copy
4764+** of the second argument to sqlite3_collation_needed() or
4765+** sqlite3_collation_needed16(). The second argument is the database
4766+** connection. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE],
4767+** or [SQLITE_UTF16LE], indicating the most desirable form of the collation
4768+** sequence function required. The fourth parameter is the name of the
4769+** required collation sequence.)^
4770+**
4771+** The callback function should register the desired collation using
4772+** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
4773+** [sqlite3_create_collation_v2()].
4774+*/
4775+SQLITE_API int sqlite3_collation_needed(
4776+ sqlite3*,
4777+ void*,
4778+ void(*)(void*,sqlite3*,int eTextRep,const char*)
4779+);
4780+SQLITE_API int sqlite3_collation_needed16(
4781+ sqlite3*,
4782+ void*,
4783+ void(*)(void*,sqlite3*,int eTextRep,const void*)
4784+);
4785+
4786+#ifdef SQLITE_HAS_CODEC
4787+/*
4788+** Specify the key for an encrypted database. This routine should be
4789+** called right after sqlite3_open().
4790+**
4791+** The code to implement this API is not available in the public release
4792+** of SQLite.
4793+*/
4794+SQLITE_API int sqlite3_key(
4795+ sqlite3 *db, /* Database to be rekeyed */
4796+ const void *pKey, int nKey /* The key */
4797+);
4798+
4799+/*
4800+** Change the key on an open database. If the current database is not
4801+** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
4802+** database is decrypted.
4803+**
4804+** The code to implement this API is not available in the public release
4805+** of SQLite.
4806+*/
4807+SQLITE_API int sqlite3_rekey(
4808+ sqlite3 *db, /* Database to be rekeyed */
4809+ const void *pKey, int nKey /* The new key */
4810+);
4811+
4812+/*
4813+** Specify the activation key for a SEE database. Unless
4814+** activated, none of the SEE routines will work.
4815+*/
4816+SQLITE_API void sqlite3_activate_see(
4817+ const char *zPassPhrase /* Activation phrase */
4818+);
4819+#endif
4820+
4821+#ifdef SQLITE_ENABLE_CEROD
4822+/*
4823+** Specify the activation key for a CEROD database. Unless
4824+** activated, none of the CEROD routines will work.
4825+*/
4826+SQLITE_API void sqlite3_activate_cerod(
4827+ const char *zPassPhrase /* Activation phrase */
4828+);
4829+#endif
4830+
4831+/*
4832+** CAPI3REF: Suspend Execution For A Short Time
4833+**
4834+** The sqlite3_sleep() function causes the current thread to suspend execution
4835+** for at least a number of milliseconds specified in its parameter.
4836+**
4837+** If the operating system does not support sleep requests with
4838+** millisecond time resolution, then the time will be rounded up to
4839+** the nearest second. The number of milliseconds of sleep actually
4840+** requested from the operating system is returned.
4841+**
4842+** ^SQLite implements this interface by calling the xSleep()
4843+** method of the default [sqlite3_vfs] object. If the xSleep() method
4844+** of the default VFS is not implemented correctly, or not implemented at
4845+** all, then the behavior of sqlite3_sleep() may deviate from the description
4846+** in the previous paragraphs.
4847+*/
4848+SQLITE_API int sqlite3_sleep(int);
4849+
4850+/*
4851+** CAPI3REF: Name Of The Folder Holding Temporary Files
4852+**
4853+** ^(If this global variable is made to point to a string which is
4854+** the name of a folder (a.k.a. directory), then all temporary files
4855+** created by SQLite when using a built-in [sqlite3_vfs | VFS]
4856+** will be placed in that directory.)^ ^If this variable
4857+** is a NULL pointer, then SQLite performs a search for an appropriate
4858+** temporary file directory.
4859+**
4860+** It is not safe to read or modify this variable in more than one
4861+** thread at a time. It is not safe to read or modify this variable
4862+** if a [database connection] is being used at the same time in a separate
4863+** thread.
4864+** It is intended that this variable be set once
4865+** as part of process initialization and before any SQLite interface
4866+** routines have been called and that this variable remain unchanged
4867+** thereafter.
4868+**
4869+** ^The [temp_store_directory pragma] may modify this variable and cause
4870+** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
4871+** the [temp_store_directory pragma] always assumes that any string
4872+** that this variable points to is held in memory obtained from
4873+** [sqlite3_malloc] and the pragma may attempt to free that memory
4874+** using [sqlite3_free].
4875+** Hence, if this variable is modified directly, either it should be
4876+** made NULL or made to point to memory obtained from [sqlite3_malloc]
4877+** or else the use of the [temp_store_directory pragma] should be avoided.
4878+*/
4879+SQLITE_API char *sqlite3_temp_directory;
4880+
4881+/*
4882+** CAPI3REF: Test For Auto-Commit Mode
4883+** KEYWORDS: {autocommit mode}
4884+**
4885+** ^The sqlite3_get_autocommit() interface returns non-zero or
4886+** zero if the given database connection is or is not in autocommit mode,
4887+** respectively. ^Autocommit mode is on by default.
4888+** ^Autocommit mode is disabled by a [BEGIN] statement.
4889+** ^Autocommit mode is re-enabled by a [COMMIT] or [ROLLBACK].
4890+**
4891+** If certain kinds of errors occur on a statement within a multi-statement
4892+** transaction (errors including [SQLITE_FULL], [SQLITE_IOERR],
4893+** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the
4894+** transaction might be rolled back automatically. The only way to
4895+** find out whether SQLite automatically rolled back the transaction after
4896+** an error is to use this function.
4897+**
4898+** If another thread changes the autocommit status of the database
4899+** connection while this routine is running, then the return value
4900+** is undefined.
4901+*/
4902+SQLITE_API int sqlite3_get_autocommit(sqlite3*);
4903+
4904+/*
4905+** CAPI3REF: Find The Database Handle Of A Prepared Statement
4906+**
4907+** ^The sqlite3_db_handle interface returns the [database connection] handle
4908+** to which a [prepared statement] belongs. ^The [database connection]
4909+** returned by sqlite3_db_handle is the same [database connection]
4910+** that was the first argument
4911+** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
4912+** create the statement in the first place.
4913+*/
4914+SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
4915+
4916+/*
4917+** CAPI3REF: Find the next prepared statement
4918+**
4919+** ^This interface returns a pointer to the next [prepared statement] after
4920+** pStmt associated with the [database connection] pDb. ^If pStmt is NULL
4921+** then this interface returns a pointer to the first prepared statement
4922+** associated with the database connection pDb. ^If no prepared statement
4923+** satisfies the conditions of this routine, it returns NULL.
4924+**
4925+** The [database connection] pointer D in a call to
4926+** [sqlite3_next_stmt(D,S)] must refer to an open database
4927+** connection and in particular must not be a NULL pointer.
4928+*/
4929+SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
4930+
4931+/*
4932+** CAPI3REF: Commit And Rollback Notification Callbacks
4933+**
4934+** ^The sqlite3_commit_hook() interface registers a callback
4935+** function to be invoked whenever a transaction is [COMMIT | committed].
4936+** ^Any callback set by a previous call to sqlite3_commit_hook()
4937+** for the same database connection is overridden.
4938+** ^The sqlite3_rollback_hook() interface registers a callback
4939+** function to be invoked whenever a transaction is [ROLLBACK | rolled back].
4940+** ^Any callback set by a previous call to sqlite3_rollback_hook()
4941+** for the same database connection is overridden.
4942+** ^The pArg argument is passed through to the callback.
4943+** ^If the callback on a commit hook function returns non-zero,
4944+** then the commit is converted into a rollback.
4945+**
4946+** ^The sqlite3_commit_hook(D,C,P) and sqlite3_rollback_hook(D,C,P) functions
4947+** return the P argument from the previous call of the same function
4948+** on the same [database connection] D, or NULL for
4949+** the first call for each function on D.
4950+**
4951+** The callback implementation must not do anything that will modify
4952+** the database connection that invoked the callback. Any actions
4953+** to modify the database connection must be deferred until after the
4954+** completion of the [sqlite3_step()] call that triggered the commit
4955+** or rollback hook in the first place.
4956+** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
4957+** database connections for the meaning of "modify" in this paragraph.
4958+**
4959+** ^Registering a NULL function disables the callback.
4960+**
4961+** ^When the commit hook callback routine returns zero, the [COMMIT]
4962+** operation is allowed to continue normally. ^If the commit hook
4963+** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK].
4964+** ^The rollback hook is invoked on a rollback that results from a commit
4965+** hook returning non-zero, just as it would be with any other rollback.
4966+**
4967+** ^For the purposes of this API, a transaction is said to have been
4968+** rolled back if an explicit "ROLLBACK" statement is executed, or
4969+** an error or constraint causes an implicit rollback to occur.
4970+** ^The rollback callback is not invoked if a transaction is
4971+** automatically rolled back because the database connection is closed.
4972+**
4973+** See also the [sqlite3_update_hook()] interface.
4974+*/
4975+SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
4976+SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
4977+
4978+/*
4979+** CAPI3REF: Data Change Notification Callbacks
4980+**
4981+** ^The sqlite3_update_hook() interface registers a callback function
4982+** with the [database connection] identified by the first argument
4983+** to be invoked whenever a row is updated, inserted or deleted.
4984+** ^Any callback set by a previous call to this function
4985+** for the same database connection is overridden.
4986+**
4987+** ^The second argument is a pointer to the function to invoke when a
4988+** row is updated, inserted or deleted.
4989+** ^The first argument to the callback is a copy of the third argument
4990+** to sqlite3_update_hook().
4991+** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE],
4992+** or [SQLITE_UPDATE], depending on the operation that caused the callback
4993+** to be invoked.
4994+** ^The third and fourth arguments to the callback contain pointers to the
4995+** database and table name containing the affected row.
4996+** ^The final callback parameter is the [rowid] of the row.
4997+** ^In the case of an update, this is the [rowid] after the update takes place.
4998+**
4999+** ^(The update hook is not invoked when internal system tables are
5000+** modified (i.e. sqlite_master and sqlite_sequence).)^
5001+**
5002+** ^In the current implementation, the update hook
5003+** is not invoked when duplication rows are deleted because of an
5004+** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook
5005+** invoked when rows are deleted using the [truncate optimization].
5006+** The exceptions defined in this paragraph might change in a future
5007+** release of SQLite.
5008+**
5009+** The update hook implementation must not do anything that will modify
5010+** the database connection that invoked the update hook. Any actions
5011+** to modify the database connection must be deferred until after the
5012+** completion of the [sqlite3_step()] call that triggered the update hook.
5013+** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
5014+** database connections for the meaning of "modify" in this paragraph.
5015+**
5016+** ^The sqlite3_update_hook(D,C,P) function
5017+** returns the P argument from the previous call
5018+** on the same [database connection] D, or NULL for
5019+** the first call on D.
5020+**
5021+** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
5022+** interfaces.
5023+*/
5024+SQLITE_API void *sqlite3_update_hook(
5025+ sqlite3*,
5026+ void(*)(void *,int ,char const *,char const *,sqlite3_int64),
5027+ void*
5028+);
5029+
5030+/*
5031+** CAPI3REF: Enable Or Disable Shared Pager Cache
5032+** KEYWORDS: {shared cache}
5033+**
5034+** ^(This routine enables or disables the sharing of the database cache
5035+** and schema data structures between [database connection | connections]
5036+** to the same database. Sharing is enabled if the argument is true
5037+** and disabled if the argument is false.)^
5038+**
5039+** ^Cache sharing is enabled and disabled for an entire process.
5040+** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
5041+** sharing was enabled or disabled for each thread separately.
5042+**
5043+** ^(The cache sharing mode set by this interface effects all subsequent
5044+** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
5045+** Existing database connections continue use the sharing mode
5046+** that was in effect at the time they were opened.)^
5047+**
5048+** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
5049+** successfully. An [error code] is returned otherwise.)^
5050+**
5051+** ^Shared cache is disabled by default. But this might change in
5052+** future releases of SQLite. Applications that care about shared
5053+** cache setting should set it explicitly.
5054+**
5055+** See Also: [SQLite Shared-Cache Mode]
5056+*/
5057+SQLITE_API int sqlite3_enable_shared_cache(int);
5058+
5059+/*
5060+** CAPI3REF: Attempt To Free Heap Memory
5061+**
5062+** ^The sqlite3_release_memory() interface attempts to free N bytes
5063+** of heap memory by deallocating non-essential memory allocations
5064+** held by the database library. Memory used to cache database
5065+** pages to improve performance is an example of non-essential memory.
5066+** ^sqlite3_release_memory() returns the number of bytes actually freed,
5067+** which might be more or less than the amount requested.
5068+** ^The sqlite3_release_memory() routine is a no-op returning zero
5069+** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT].
5070+*/
5071+SQLITE_API int sqlite3_release_memory(int);
5072+
5073+/*
5074+** CAPI3REF: Impose A Limit On Heap Size
5075+**
5076+** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
5077+** soft limit on the amount of heap memory that may be allocated by SQLite.
5078+** ^SQLite strives to keep heap memory utilization below the soft heap
5079+** limit by reducing the number of pages held in the page cache
5080+** as heap memory usages approaches the limit.
5081+** ^The soft heap limit is "soft" because even though SQLite strives to stay
5082+** below the limit, it will exceed the limit rather than generate
5083+** an [SQLITE_NOMEM] error. In other words, the soft heap limit
5084+** is advisory only.
5085+**
5086+** ^The return value from sqlite3_soft_heap_limit64() is the size of
5087+** the soft heap limit prior to the call. ^If the argument N is negative
5088+** then no change is made to the soft heap limit. Hence, the current
5089+** size of the soft heap limit can be determined by invoking
5090+** sqlite3_soft_heap_limit64() with a negative argument.
5091+**
5092+** ^If the argument N is zero then the soft heap limit is disabled.
5093+**
5094+** ^(The soft heap limit is not enforced in the current implementation
5095+** if one or more of following conditions are true:
5096+**
5097+** <ul>
5098+** <li> The soft heap limit is set to zero.
5099+** <li> Memory accounting is disabled using a combination of the
5100+** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
5101+** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
5102+** <li> An alternative page cache implementation is specified using
5103+** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...).
5104+** <li> The page cache allocates from its own memory pool supplied
5105+** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
5106+** from the heap.
5107+** </ul>)^
5108+**
5109+** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
5110+** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
5111+** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
5112+** the soft heap limit is enforced on every memory allocation. Without
5113+** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced
5114+** when memory is allocated by the page cache. Testing suggests that because
5115+** the page cache is the predominate memory user in SQLite, most
5116+** applications will achieve adequate soft heap limit enforcement without
5117+** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT].
5118+**
5119+** The circumstances under which SQLite will enforce the soft heap limit may
5120+** changes in future releases of SQLite.
5121+*/
5122+SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
5123+
5124+/*
5125+** CAPI3REF: Deprecated Soft Heap Limit Interface
5126+** DEPRECATED
5127+**
5128+** This is a deprecated version of the [sqlite3_soft_heap_limit64()]
5129+** interface. This routine is provided for historical compatibility
5130+** only. All new applications should use the
5131+** [sqlite3_soft_heap_limit64()] interface rather than this one.
5132+*/
5133+SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
5134+
5135+
5136+/*
5137+** CAPI3REF: Extract Metadata About A Column Of A Table
5138+**
5139+** ^This routine returns metadata about a specific column of a specific
5140+** database table accessible using the [database connection] handle
5141+** passed as the first function argument.
5142+**
5143+** ^The column is identified by the second, third and fourth parameters to
5144+** this function. ^The second parameter is either the name of the database
5145+** (i.e. "main", "temp", or an attached database) containing the specified
5146+** table or NULL. ^If it is NULL, then all attached databases are searched
5147+** for the table using the same algorithm used by the database engine to
5148+** resolve unqualified table references.
5149+**
5150+** ^The third and fourth parameters to this function are the table and column
5151+** name of the desired column, respectively. Neither of these parameters
5152+** may be NULL.
5153+**
5154+** ^Metadata is returned by writing to the memory locations passed as the 5th
5155+** and subsequent parameters to this function. ^Any of these arguments may be
5156+** NULL, in which case the corresponding element of metadata is omitted.
5157+**
5158+** ^(<blockquote>
5159+** <table border="1">
5160+** <tr><th> Parameter <th> Output<br>Type <th> Description
5161+**
5162+** <tr><td> 5th <td> const char* <td> Data type
5163+** <tr><td> 6th <td> const char* <td> Name of default collation sequence
5164+** <tr><td> 7th <td> int <td> True if column has a NOT NULL constraint
5165+** <tr><td> 8th <td> int <td> True if column is part of the PRIMARY KEY
5166+** <tr><td> 9th <td> int <td> True if column is [AUTOINCREMENT]
5167+** </table>
5168+** </blockquote>)^
5169+**
5170+** ^The memory pointed to by the character pointers returned for the
5171+** declaration type and collation sequence is valid only until the next
5172+** call to any SQLite API function.
5173+**
5174+** ^If the specified table is actually a view, an [error code] is returned.
5175+**
5176+** ^If the specified column is "rowid", "oid" or "_rowid_" and an
5177+** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
5178+** parameters are set for the explicitly declared column. ^(If there is no
5179+** explicitly declared [INTEGER PRIMARY KEY] column, then the output
5180+** parameters are set as follows:
5181+**
5182+** <pre>
5183+** data type: "INTEGER"
5184+** collation sequence: "BINARY"
5185+** not null: 0
5186+** primary key: 1
5187+** auto increment: 0
5188+** </pre>)^
5189+**
5190+** ^(This function may load one or more schemas from database files. If an
5191+** error occurs during this process, or if the requested table or column
5192+** cannot be found, an [error code] is returned and an error message left
5193+** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^
5194+**
5195+** ^This API is only available if the library was compiled with the
5196+** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined.
5197+*/
5198+SQLITE_API int sqlite3_table_column_metadata(
5199+ sqlite3 *db, /* Connection handle */
5200+ const char *zDbName, /* Database name or NULL */
5201+ const char *zTableName, /* Table name */
5202+ const char *zColumnName, /* Column name */
5203+ char const **pzDataType, /* OUTPUT: Declared data type */
5204+ char const **pzCollSeq, /* OUTPUT: Collation sequence name */
5205+ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */
5206+ int *pPrimaryKey, /* OUTPUT: True if column part of PK */
5207+ int *pAutoinc /* OUTPUT: True if column is auto-increment */
5208+);
5209+
5210+/*
5211+** CAPI3REF: Load An Extension
5212+**
5213+** ^This interface loads an SQLite extension library from the named file.
5214+**
5215+** ^The sqlite3_load_extension() interface attempts to load an
5216+** SQLite extension library contained in the file zFile.
5217+**
5218+** ^The entry point is zProc.
5219+** ^zProc may be 0, in which case the name of the entry point
5220+** defaults to "sqlite3_extension_init".
5221+** ^The sqlite3_load_extension() interface returns
5222+** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
5223+** ^If an error occurs and pzErrMsg is not 0, then the
5224+** [sqlite3_load_extension()] interface shall attempt to
5225+** fill *pzErrMsg with error message text stored in memory
5226+** obtained from [sqlite3_malloc()]. The calling function
5227+** should free this memory by calling [sqlite3_free()].
5228+**
5229+** ^Extension loading must be enabled using
5230+** [sqlite3_enable_load_extension()] prior to calling this API,
5231+** otherwise an error will be returned.
5232+**
5233+** See also the [load_extension() SQL function].
5234+*/
5235+SQLITE_API int sqlite3_load_extension(
5236+ sqlite3 *db, /* Load the extension into this database connection */
5237+ const char *zFile, /* Name of the shared library containing extension */
5238+ const char *zProc, /* Entry point. Derived from zFile if 0 */
5239+ char **pzErrMsg /* Put error message here if not 0 */
5240+);
5241+
5242+/*
5243+** CAPI3REF: Enable Or Disable Extension Loading
5244+**
5245+** ^So as not to open security holes in older applications that are
5246+** unprepared to deal with extension loading, and as a means of disabling
5247+** extension loading while evaluating user-entered SQL, the following API
5248+** is provided to turn the [sqlite3_load_extension()] mechanism on and off.
5249+**
5250+** ^Extension loading is off by default. See ticket #1863.
5251+** ^Call the sqlite3_enable_load_extension() routine with onoff==1
5252+** to turn extension loading on and call it with onoff==0 to turn
5253+** it back off again.
5254+*/
5255+SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
5256+
5257+/*
5258+** CAPI3REF: Automatically Load Statically Linked Extensions
5259+**
5260+** ^This interface causes the xEntryPoint() function to be invoked for
5261+** each new [database connection] that is created. The idea here is that
5262+** xEntryPoint() is the entry point for a statically linked SQLite extension
5263+** that is to be automatically loaded into all new database connections.
5264+**
5265+** ^(Even though the function prototype shows that xEntryPoint() takes
5266+** no arguments and returns void, SQLite invokes xEntryPoint() with three
5267+** arguments and expects and integer result as if the signature of the
5268+** entry point where as follows:
5269+**
5270+** <blockquote><pre>
5271+** &nbsp; int xEntryPoint(
5272+** &nbsp; sqlite3 *db,
5273+** &nbsp; const char **pzErrMsg,
5274+** &nbsp; const struct sqlite3_api_routines *pThunk
5275+** &nbsp; );
5276+** </pre></blockquote>)^
5277+**
5278+** If the xEntryPoint routine encounters an error, it should make *pzErrMsg
5279+** point to an appropriate error message (obtained from [sqlite3_mprintf()])
5280+** and return an appropriate [error code]. ^SQLite ensures that *pzErrMsg
5281+** is NULL before calling the xEntryPoint(). ^SQLite will invoke
5282+** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns. ^If any
5283+** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()],
5284+** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail.
5285+**
5286+** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
5287+** on the list of automatic extensions is a harmless no-op. ^No entry point
5288+** will be called more than once for each database connection that is opened.
5289+**
5290+** See also: [sqlite3_reset_auto_extension()].
5291+*/
5292+SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
5293+
5294+/*
5295+** CAPI3REF: Reset Automatic Extension Loading
5296+**
5297+** ^This interface disables all automatic extensions previously
5298+** registered using [sqlite3_auto_extension()].
5299+*/
5300+SQLITE_API void sqlite3_reset_auto_extension(void);
5301+
5302+/*
5303+** The interface to the virtual-table mechanism is currently considered
5304+** to be experimental. The interface might change in incompatible ways.
5305+** If this is a problem for you, do not use the interface at this time.
5306+**
5307+** When the virtual-table mechanism stabilizes, we will declare the
5308+** interface fixed, support it indefinitely, and remove this comment.
5309+*/
5310+
5311+/*
5312+** Structures used by the virtual table interface
5313+*/
5314+typedef struct sqlite3_vtab sqlite3_vtab;
5315+typedef struct sqlite3_index_info sqlite3_index_info;
5316+typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
5317+typedef struct sqlite3_module sqlite3_module;
5318+
5319+/*
5320+** CAPI3REF: Virtual Table Object
5321+** KEYWORDS: sqlite3_module {virtual table module}
5322+**
5323+** This structure, sometimes called a "virtual table module",
5324+** defines the implementation of a [virtual tables].
5325+** This structure consists mostly of methods for the module.
5326+**
5327+** ^A virtual table module is created by filling in a persistent
5328+** instance of this structure and passing a pointer to that instance
5329+** to [sqlite3_create_module()] or [sqlite3_create_module_v2()].
5330+** ^The registration remains valid until it is replaced by a different
5331+** module or until the [database connection] closes. The content
5332+** of this structure must not change while it is registered with
5333+** any database connection.
5334+*/
5335+struct sqlite3_module {
5336+ int iVersion;
5337+ int (*xCreate)(sqlite3*, void *pAux,
5338+ int argc, const char *const*argv,
5339+ sqlite3_vtab **ppVTab, char**);
5340+ int (*xConnect)(sqlite3*, void *pAux,
5341+ int argc, const char *const*argv,
5342+ sqlite3_vtab **ppVTab, char**);
5343+ int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
5344+ int (*xDisconnect)(sqlite3_vtab *pVTab);
5345+ int (*xDestroy)(sqlite3_vtab *pVTab);
5346+ int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
5347+ int (*xClose)(sqlite3_vtab_cursor*);
5348+ int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
5349+ int argc, sqlite3_value **argv);
5350+ int (*xNext)(sqlite3_vtab_cursor*);
5351+ int (*xEof)(sqlite3_vtab_cursor*);
5352+ int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
5353+ int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
5354+ int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *);
5355+ int (*xBegin)(sqlite3_vtab *pVTab);
5356+ int (*xSync)(sqlite3_vtab *pVTab);
5357+ int (*xCommit)(sqlite3_vtab *pVTab);
5358+ int (*xRollback)(sqlite3_vtab *pVTab);
5359+ int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
5360+ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
5361+ void **ppArg);
5362+ int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
5363+ /* The methods above are in version 1 of the sqlite_module object. Those
5364+ ** below are for version 2 and greater. */
5365+ int (*xSavepoint)(sqlite3_vtab *pVTab, int);
5366+ int (*xRelease)(sqlite3_vtab *pVTab, int);
5367+ int (*xRollbackTo)(sqlite3_vtab *pVTab, int);
5368+};
5369+
5370+/*
5371+** CAPI3REF: Virtual Table Indexing Information
5372+** KEYWORDS: sqlite3_index_info
5373+**
5374+** The sqlite3_index_info structure and its substructures is used as part
5375+** of the [virtual table] interface to
5376+** pass information into and receive the reply from the [xBestIndex]
5377+** method of a [virtual table module]. The fields under **Inputs** are the
5378+** inputs to xBestIndex and are read-only. xBestIndex inserts its
5379+** results into the **Outputs** fields.
5380+**
5381+** ^(The aConstraint[] array records WHERE clause constraints of the form:
5382+**
5383+** <blockquote>column OP expr</blockquote>
5384+**
5385+** where OP is =, &lt;, &lt;=, &gt;, or &gt;=.)^ ^(The particular operator is
5386+** stored in aConstraint[].op using one of the
5387+** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^
5388+** ^(The index of the column is stored in
5389+** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the
5390+** expr on the right-hand side can be evaluated (and thus the constraint
5391+** is usable) and false if it cannot.)^
5392+**
5393+** ^The optimizer automatically inverts terms of the form "expr OP column"
5394+** and makes other simplifications to the WHERE clause in an attempt to
5395+** get as many WHERE clause terms into the form shown above as possible.
5396+** ^The aConstraint[] array only reports WHERE clause terms that are
5397+** relevant to the particular virtual table being queried.
5398+**
5399+** ^Information about the ORDER BY clause is stored in aOrderBy[].
5400+** ^Each term of aOrderBy records a column of the ORDER BY clause.
5401+**
5402+** The [xBestIndex] method must fill aConstraintUsage[] with information
5403+** about what parameters to pass to xFilter. ^If argvIndex>0 then
5404+** the right-hand side of the corresponding aConstraint[] is evaluated
5405+** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit
5406+** is true, then the constraint is assumed to be fully handled by the
5407+** virtual table and is not checked again by SQLite.)^
5408+**
5409+** ^The idxNum and idxPtr values are recorded and passed into the
5410+** [xFilter] method.
5411+** ^[sqlite3_free()] is used to free idxPtr if and only if
5412+** needToFreeIdxPtr is true.
5413+**
5414+** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
5415+** the correct order to satisfy the ORDER BY clause so that no separate
5416+** sorting step is required.
5417+**
5418+** ^The estimatedCost value is an estimate of the cost of doing the
5419+** particular lookup. A full scan of a table with N entries should have
5420+** a cost of N. A binary search of a table of N entries should have a
5421+** cost of approximately log(N).
5422+*/
5423+struct sqlite3_index_info {
5424+ /* Inputs */
5425+ int nConstraint; /* Number of entries in aConstraint */
5426+ struct sqlite3_index_constraint {
5427+ int iColumn; /* Column on left-hand side of constraint */
5428+ unsigned char op; /* Constraint operator */
5429+ unsigned char usable; /* True if this constraint is usable */
5430+ int iTermOffset; /* Used internally - xBestIndex should ignore */
5431+ } *aConstraint; /* Table of WHERE clause constraints */
5432+ int nOrderBy; /* Number of terms in the ORDER BY clause */
5433+ struct sqlite3_index_orderby {
5434+ int iColumn; /* Column number */
5435+ unsigned char desc; /* True for DESC. False for ASC. */
5436+ } *aOrderBy; /* The ORDER BY clause */
5437+ /* Outputs */
5438+ struct sqlite3_index_constraint_usage {
5439+ int argvIndex; /* if >0, constraint is part of argv to xFilter */
5440+ unsigned char omit; /* Do not code a test for this constraint */
5441+ } *aConstraintUsage;
5442+ int idxNum; /* Number used to identify the index */
5443+ char *idxStr; /* String, possibly obtained from sqlite3_malloc */
5444+ int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
5445+ int orderByConsumed; /* True if output is already ordered */
5446+ double estimatedCost; /* Estimated cost of using this index */
5447+};
5448+
5449+/*
5450+** CAPI3REF: Virtual Table Constraint Operator Codes
5451+**
5452+** These macros defined the allowed values for the
5453+** [sqlite3_index_info].aConstraint[].op field. Each value represents
5454+** an operator that is part of a constraint term in the wHERE clause of
5455+** a query that uses a [virtual table].
5456+*/
5457+#define SQLITE_INDEX_CONSTRAINT_EQ 2
5458+#define SQLITE_INDEX_CONSTRAINT_GT 4
5459+#define SQLITE_INDEX_CONSTRAINT_LE 8
5460+#define SQLITE_INDEX_CONSTRAINT_LT 16
5461+#define SQLITE_INDEX_CONSTRAINT_GE 32
5462+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
5463+
5464+/*
5465+** CAPI3REF: Register A Virtual Table Implementation
5466+**
5467+** ^These routines are used to register a new [virtual table module] name.
5468+** ^Module names must be registered before
5469+** creating a new [virtual table] using the module and before using a
5470+** preexisting [virtual table] for the module.
5471+**
5472+** ^The module name is registered on the [database connection] specified
5473+** by the first parameter. ^The name of the module is given by the
5474+** second parameter. ^The third parameter is a pointer to
5475+** the implementation of the [virtual table module]. ^The fourth
5476+** parameter is an arbitrary client data pointer that is passed through
5477+** into the [xCreate] and [xConnect] methods of the virtual table module
5478+** when a new virtual table is be being created or reinitialized.
5479+**
5480+** ^The sqlite3_create_module_v2() interface has a fifth parameter which
5481+** is a pointer to a destructor for the pClientData. ^SQLite will
5482+** invoke the destructor function (if it is not NULL) when SQLite
5483+** no longer needs the pClientData pointer. ^The destructor will also
5484+** be invoked if the call to sqlite3_create_module_v2() fails.
5485+** ^The sqlite3_create_module()
5486+** interface is equivalent to sqlite3_create_module_v2() with a NULL
5487+** destructor.
5488+*/
5489+SQLITE_API int sqlite3_create_module(
5490+ sqlite3 *db, /* SQLite connection to register module with */
5491+ const char *zName, /* Name of the module */
5492+ const sqlite3_module *p, /* Methods for the module */
5493+ void *pClientData /* Client data for xCreate/xConnect */
5494+);
5495+SQLITE_API int sqlite3_create_module_v2(
5496+ sqlite3 *db, /* SQLite connection to register module with */
5497+ const char *zName, /* Name of the module */
5498+ const sqlite3_module *p, /* Methods for the module */
5499+ void *pClientData, /* Client data for xCreate/xConnect */
5500+ void(*xDestroy)(void*) /* Module destructor function */
5501+);
5502+
5503+/*
5504+** CAPI3REF: Virtual Table Instance Object
5505+** KEYWORDS: sqlite3_vtab
5506+**
5507+** Every [virtual table module] implementation uses a subclass
5508+** of this object to describe a particular instance
5509+** of the [virtual table]. Each subclass will
5510+** be tailored to the specific needs of the module implementation.
5511+** The purpose of this superclass is to define certain fields that are
5512+** common to all module implementations.
5513+**
5514+** ^Virtual tables methods can set an error message by assigning a
5515+** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should
5516+** take care that any prior string is freed by a call to [sqlite3_free()]
5517+** prior to assigning a new string to zErrMsg. ^After the error message
5518+** is delivered up to the client application, the string will be automatically
5519+** freed by sqlite3_free() and the zErrMsg field will be zeroed.
5520+*/
5521+struct sqlite3_vtab {
5522+ const sqlite3_module *pModule; /* The module for this virtual table */
5523+ int nRef; /* NO LONGER USED */
5524+ char *zErrMsg; /* Error message from sqlite3_mprintf() */
5525+ /* Virtual table implementations will typically add additional fields */
5526+};
5527+
5528+/*
5529+** CAPI3REF: Virtual Table Cursor Object
5530+** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
5531+**
5532+** Every [virtual table module] implementation uses a subclass of the
5533+** following structure to describe cursors that point into the
5534+** [virtual table] and are used
5535+** to loop through the virtual table. Cursors are created using the
5536+** [sqlite3_module.xOpen | xOpen] method of the module and are destroyed
5537+** by the [sqlite3_module.xClose | xClose] method. Cursors are used
5538+** by the [xFilter], [xNext], [xEof], [xColumn], and [xRowid] methods
5539+** of the module. Each module implementation will define
5540+** the content of a cursor structure to suit its own needs.
5541+**
5542+** This superclass exists in order to define fields of the cursor that
5543+** are common to all implementations.
5544+*/
5545+struct sqlite3_vtab_cursor {
5546+ sqlite3_vtab *pVtab; /* Virtual table of this cursor */
5547+ /* Virtual table implementations will typically add additional fields */
5548+};
5549+
5550+/*
5551+** CAPI3REF: Declare The Schema Of A Virtual Table
5552+**
5553+** ^The [xCreate] and [xConnect] methods of a
5554+** [virtual table module] call this interface
5555+** to declare the format (the names and datatypes of the columns) of
5556+** the virtual tables they implement.
5557+*/
5558+SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
5559+
5560+/*
5561+** CAPI3REF: Overload A Function For A Virtual Table
5562+**
5563+** ^(Virtual tables can provide alternative implementations of functions
5564+** using the [xFindFunction] method of the [virtual table module].
5565+** But global versions of those functions
5566+** must exist in order to be overloaded.)^
5567+**
5568+** ^(This API makes sure a global version of a function with a particular
5569+** name and number of parameters exists. If no such function exists
5570+** before this API is called, a new function is created.)^ ^The implementation
5571+** of the new function always causes an exception to be thrown. So
5572+** the new function is not good for anything by itself. Its only
5573+** purpose is to be a placeholder function that can be overloaded
5574+** by a [virtual table].
5575+*/
5576+SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
5577+
5578+/*
5579+** The interface to the virtual-table mechanism defined above (back up
5580+** to a comment remarkably similar to this one) is currently considered
5581+** to be experimental. The interface might change in incompatible ways.
5582+** If this is a problem for you, do not use the interface at this time.
5583+**
5584+** When the virtual-table mechanism stabilizes, we will declare the
5585+** interface fixed, support it indefinitely, and remove this comment.
5586+*/
5587+
5588+/*
5589+** CAPI3REF: A Handle To An Open BLOB
5590+** KEYWORDS: {BLOB handle} {BLOB handles}
5591+**
5592+** An instance of this object represents an open BLOB on which
5593+** [sqlite3_blob_open | incremental BLOB I/O] can be performed.
5594+** ^Objects of this type are created by [sqlite3_blob_open()]
5595+** and destroyed by [sqlite3_blob_close()].
5596+** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces
5597+** can be used to read or write small subsections of the BLOB.
5598+** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes.
5599+*/
5600+typedef struct sqlite3_blob sqlite3_blob;
5601+
5602+/*
5603+** CAPI3REF: Open A BLOB For Incremental I/O
5604+**
5605+** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located
5606+** in row iRow, column zColumn, table zTable in database zDb;
5607+** in other words, the same BLOB that would be selected by:
5608+**
5609+** <pre>
5610+** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
5611+** </pre>)^
5612+**
5613+** ^If the flags parameter is non-zero, then the BLOB is opened for read
5614+** and write access. ^If it is zero, the BLOB is opened for read access.
5615+** ^It is not possible to open a column that is part of an index or primary
5616+** key for writing. ^If [foreign key constraints] are enabled, it is
5617+** not possible to open a column that is part of a [child key] for writing.
5618+**
5619+** ^Note that the database name is not the filename that contains
5620+** the database but rather the symbolic name of the database that
5621+** appears after the AS keyword when the database is connected using [ATTACH].
5622+** ^For the main database file, the database name is "main".
5623+** ^For TEMP tables, the database name is "temp".
5624+**
5625+** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written
5626+** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set
5627+** to be a null pointer.)^
5628+** ^This function sets the [database connection] error code and message
5629+** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related
5630+** functions. ^Note that the *ppBlob variable is always initialized in a
5631+** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob
5632+** regardless of the success or failure of this routine.
5633+**
5634+** ^(If the row that a BLOB handle points to is modified by an
5635+** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
5636+** then the BLOB handle is marked as "expired".
5637+** This is true if any column of the row is changed, even a column
5638+** other than the one the BLOB handle is open on.)^
5639+** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for
5640+** an expired BLOB handle fail with a return code of [SQLITE_ABORT].
5641+** ^(Changes written into a BLOB prior to the BLOB expiring are not
5642+** rolled back by the expiration of the BLOB. Such changes will eventually
5643+** commit if the transaction continues to completion.)^
5644+**
5645+** ^Use the [sqlite3_blob_bytes()] interface to determine the size of
5646+** the opened blob. ^The size of a blob may not be changed by this
5647+** interface. Use the [UPDATE] SQL command to change the size of a
5648+** blob.
5649+**
5650+** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
5651+** and the built-in [zeroblob] SQL function can be used, if desired,
5652+** to create an empty, zero-filled blob in which to read or write using
5653+** this interface.
5654+**
5655+** To avoid a resource leak, every open [BLOB handle] should eventually
5656+** be released by a call to [sqlite3_blob_close()].
5657+*/
5658+SQLITE_API int sqlite3_blob_open(
5659+ sqlite3*,
5660+ const char *zDb,
5661+ const char *zTable,
5662+ const char *zColumn,
5663+ sqlite3_int64 iRow,
5664+ int flags,
5665+ sqlite3_blob **ppBlob
5666+);
5667+
5668+/*
5669+** CAPI3REF: Move a BLOB Handle to a New Row
5670+**
5671+** ^This function is used to move an existing blob handle so that it points
5672+** to a different row of the same database table. ^The new row is identified
5673+** by the rowid value passed as the second argument. Only the row can be
5674+** changed. ^The database, table and column on which the blob handle is open
5675+** remain the same. Moving an existing blob handle to a new row can be
5676+** faster than closing the existing handle and opening a new one.
5677+**
5678+** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
5679+** it must exist and there must be either a blob or text value stored in
5680+** the nominated column.)^ ^If the new row is not present in the table, or if
5681+** it does not contain a blob or text value, or if another error occurs, an
5682+** SQLite error code is returned and the blob handle is considered aborted.
5683+** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or
5684+** [sqlite3_blob_reopen()] on an aborted blob handle immediately return
5685+** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
5686+** always returns zero.
5687+**
5688+** ^This function sets the database handle error code and message.
5689+*/
5690+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
5691+
5692+/*
5693+** CAPI3REF: Close A BLOB Handle
5694+**
5695+** ^Closes an open [BLOB handle].
5696+**
5697+** ^Closing a BLOB shall cause the current transaction to commit
5698+** if there are no other BLOBs, no pending prepared statements, and the
5699+** database connection is in [autocommit mode].
5700+** ^If any writes were made to the BLOB, they might be held in cache
5701+** until the close operation if they will fit.
5702+**
5703+** ^(Closing the BLOB often forces the changes
5704+** out to disk and so if any I/O errors occur, they will likely occur
5705+** at the time when the BLOB is closed. Any errors that occur during
5706+** closing are reported as a non-zero return value.)^
5707+**
5708+** ^(The BLOB is closed unconditionally. Even if this routine returns
5709+** an error code, the BLOB is still closed.)^
5710+**
5711+** ^Calling this routine with a null pointer (such as would be returned
5712+** by a failed call to [sqlite3_blob_open()]) is a harmless no-op.
5713+*/
5714+SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
5715+
5716+/*
5717+** CAPI3REF: Return The Size Of An Open BLOB
5718+**
5719+** ^Returns the size in bytes of the BLOB accessible via the
5720+** successfully opened [BLOB handle] in its only argument. ^The
5721+** incremental blob I/O routines can only read or overwriting existing
5722+** blob content; they cannot change the size of a blob.
5723+**
5724+** This routine only works on a [BLOB handle] which has been created
5725+** by a prior successful call to [sqlite3_blob_open()] and which has not
5726+** been closed by [sqlite3_blob_close()]. Passing any other pointer in
5727+** to this routine results in undefined and probably undesirable behavior.
5728+*/
5729+SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
5730+
5731+/*
5732+** CAPI3REF: Read Data From A BLOB Incrementally
5733+**
5734+** ^(This function is used to read data from an open [BLOB handle] into a
5735+** caller-supplied buffer. N bytes of data are copied into buffer Z
5736+** from the open BLOB, starting at offset iOffset.)^
5737+**
5738+** ^If offset iOffset is less than N bytes from the end of the BLOB,
5739+** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is
5740+** less than zero, [SQLITE_ERROR] is returned and no data is read.
5741+** ^The size of the blob (and hence the maximum value of N+iOffset)
5742+** can be determined using the [sqlite3_blob_bytes()] interface.
5743+**
5744+** ^An attempt to read from an expired [BLOB handle] fails with an
5745+** error code of [SQLITE_ABORT].
5746+**
5747+** ^(On success, sqlite3_blob_read() returns SQLITE_OK.
5748+** Otherwise, an [error code] or an [extended error code] is returned.)^
5749+**
5750+** This routine only works on a [BLOB handle] which has been created
5751+** by a prior successful call to [sqlite3_blob_open()] and which has not
5752+** been closed by [sqlite3_blob_close()]. Passing any other pointer in
5753+** to this routine results in undefined and probably undesirable behavior.
5754+**
5755+** See also: [sqlite3_blob_write()].
5756+*/
5757+SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
5758+
5759+/*
5760+** CAPI3REF: Write Data Into A BLOB Incrementally
5761+**
5762+** ^This function is used to write data into an open [BLOB handle] from a
5763+** caller-supplied buffer. ^N bytes of data are copied from the buffer Z
5764+** into the open BLOB, starting at offset iOffset.
5765+**
5766+** ^If the [BLOB handle] passed as the first argument was not opened for
5767+** writing (the flags parameter to [sqlite3_blob_open()] was zero),
5768+** this function returns [SQLITE_READONLY].
5769+**
5770+** ^This function may only modify the contents of the BLOB; it is
5771+** not possible to increase the size of a BLOB using this API.
5772+** ^If offset iOffset is less than N bytes from the end of the BLOB,
5773+** [SQLITE_ERROR] is returned and no data is written. ^If N is
5774+** less than zero [SQLITE_ERROR] is returned and no data is written.
5775+** The size of the BLOB (and hence the maximum value of N+iOffset)
5776+** can be determined using the [sqlite3_blob_bytes()] interface.
5777+**
5778+** ^An attempt to write to an expired [BLOB handle] fails with an
5779+** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred
5780+** before the [BLOB handle] expired are not rolled back by the
5781+** expiration of the handle, though of course those changes might
5782+** have been overwritten by the statement that expired the BLOB handle
5783+** or by other independent statements.
5784+**
5785+** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
5786+** Otherwise, an [error code] or an [extended error code] is returned.)^
5787+**
5788+** This routine only works on a [BLOB handle] which has been created
5789+** by a prior successful call to [sqlite3_blob_open()] and which has not
5790+** been closed by [sqlite3_blob_close()]. Passing any other pointer in
5791+** to this routine results in undefined and probably undesirable behavior.
5792+**
5793+** See also: [sqlite3_blob_read()].
5794+*/
5795+SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
5796+
5797+/*
5798+** CAPI3REF: Virtual File System Objects
5799+**
5800+** A virtual filesystem (VFS) is an [sqlite3_vfs] object
5801+** that SQLite uses to interact
5802+** with the underlying operating system. Most SQLite builds come with a
5803+** single default VFS that is appropriate for the host computer.
5804+** New VFSes can be registered and existing VFSes can be unregistered.
5805+** The following interfaces are provided.
5806+**
5807+** ^The sqlite3_vfs_find() interface returns a pointer to a VFS given its name.
5808+** ^Names are case sensitive.
5809+** ^Names are zero-terminated UTF-8 strings.
5810+** ^If there is no match, a NULL pointer is returned.
5811+** ^If zVfsName is NULL then the default VFS is returned.
5812+**
5813+** ^New VFSes are registered with sqlite3_vfs_register().
5814+** ^Each new VFS becomes the default VFS if the makeDflt flag is set.
5815+** ^The same VFS can be registered multiple times without injury.
5816+** ^To make an existing VFS into the default VFS, register it again
5817+** with the makeDflt flag set. If two different VFSes with the
5818+** same name are registered, the behavior is undefined. If a
5819+** VFS is registered with a name that is NULL or an empty string,
5820+** then the behavior is undefined.
5821+**
5822+** ^Unregister a VFS with the sqlite3_vfs_unregister() interface.
5823+** ^(If the default VFS is unregistered, another VFS is chosen as
5824+** the default. The choice for the new VFS is arbitrary.)^
5825+*/
5826+SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
5827+SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
5828+SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
5829+
5830+/*
5831+** CAPI3REF: Mutexes
5832+**
5833+** The SQLite core uses these routines for thread
5834+** synchronization. Though they are intended for internal
5835+** use by SQLite, code that links against SQLite is
5836+** permitted to use any of these routines.
5837+**
5838+** The SQLite source code contains multiple implementations
5839+** of these mutex routines. An appropriate implementation
5840+** is selected automatically at compile-time. ^(The following
5841+** implementations are available in the SQLite core:
5842+**
5843+** <ul>
5844+** <li> SQLITE_MUTEX_OS2
5845+** <li> SQLITE_MUTEX_PTHREAD
5846+** <li> SQLITE_MUTEX_W32
5847+** <li> SQLITE_MUTEX_NOOP
5848+** </ul>)^
5849+**
5850+** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
5851+** that does no real locking and is appropriate for use in
5852+** a single-threaded application. ^The SQLITE_MUTEX_OS2,
5853+** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations
5854+** are appropriate for use on OS/2, Unix, and Windows.
5855+**
5856+** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
5857+** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
5858+** implementation is included with the library. In this case the
5859+** application must supply a custom mutex implementation using the
5860+** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
5861+** before calling sqlite3_initialize() or any other public sqlite3_
5862+** function that calls sqlite3_initialize().)^
5863+**
5864+** ^The sqlite3_mutex_alloc() routine allocates a new
5865+** mutex and returns a pointer to it. ^If it returns NULL
5866+** that means that a mutex could not be allocated. ^SQLite
5867+** will unwind its stack and return an error. ^(The argument
5868+** to sqlite3_mutex_alloc() is one of these integer constants:
5869+**
5870+** <ul>
5871+** <li> SQLITE_MUTEX_FAST
5872+** <li> SQLITE_MUTEX_RECURSIVE
5873+** <li> SQLITE_MUTEX_STATIC_MASTER
5874+** <li> SQLITE_MUTEX_STATIC_MEM
5875+** <li> SQLITE_MUTEX_STATIC_MEM2
5876+** <li> SQLITE_MUTEX_STATIC_PRNG
5877+** <li> SQLITE_MUTEX_STATIC_LRU
5878+** <li> SQLITE_MUTEX_STATIC_LRU2
5879+** </ul>)^
5880+**
5881+** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
5882+** cause sqlite3_mutex_alloc() to create
5883+** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
5884+** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
5885+** The mutex implementation does not need to make a distinction
5886+** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
5887+** not want to. ^SQLite will only request a recursive mutex in
5888+** cases where it really needs one. ^If a faster non-recursive mutex
5889+** implementation is available on the host platform, the mutex subsystem
5890+** might return such a mutex in response to SQLITE_MUTEX_FAST.
5891+**
5892+** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other
5893+** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return
5894+** a pointer to a static preexisting mutex. ^Six static mutexes are
5895+** used by the current version of SQLite. Future versions of SQLite
5896+** may add additional static mutexes. Static mutexes are for internal
5897+** use by SQLite only. Applications that use SQLite mutexes should
5898+** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
5899+** SQLITE_MUTEX_RECURSIVE.
5900+**
5901+** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
5902+** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
5903+** returns a different mutex on every call. ^But for the static
5904+** mutex types, the same mutex is returned on every call that has
5905+** the same type number.
5906+**
5907+** ^The sqlite3_mutex_free() routine deallocates a previously
5908+** allocated dynamic mutex. ^SQLite is careful to deallocate every
5909+** dynamic mutex that it allocates. The dynamic mutexes must not be in
5910+** use when they are deallocated. Attempting to deallocate a static
5911+** mutex results in undefined behavior. ^SQLite never deallocates
5912+** a static mutex.
5913+**
5914+** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
5915+** to enter a mutex. ^If another thread is already within the mutex,
5916+** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
5917+** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK]
5918+** upon successful entry. ^(Mutexes created using
5919+** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
5920+** In such cases the,
5921+** mutex must be exited an equal number of times before another thread
5922+** can enter.)^ ^(If the same thread tries to enter any other
5923+** kind of mutex more than once, the behavior is undefined.
5924+** SQLite will never exhibit
5925+** such behavior in its own use of mutexes.)^
5926+**
5927+** ^(Some systems (for example, Windows 95) do not support the operation
5928+** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
5929+** will always return SQLITE_BUSY. The SQLite core only ever uses
5930+** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^
5931+**
5932+** ^The sqlite3_mutex_leave() routine exits a mutex that was
5933+** previously entered by the same thread. ^(The behavior
5934+** is undefined if the mutex is not currently entered by the
5935+** calling thread or is not currently allocated. SQLite will
5936+** never do either.)^
5937+**
5938+** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
5939+** sqlite3_mutex_leave() is a NULL pointer, then all three routines
5940+** behave as no-ops.
5941+**
5942+** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
5943+*/
5944+SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
5945+SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
5946+SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
5947+SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
5948+SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
5949+
5950+/*
5951+** CAPI3REF: Mutex Methods Object
5952+**
5953+** An instance of this structure defines the low-level routines
5954+** used to allocate and use mutexes.
5955+**
5956+** Usually, the default mutex implementations provided by SQLite are
5957+** sufficient, however the user has the option of substituting a custom
5958+** implementation for specialized deployments or systems for which SQLite
5959+** does not provide a suitable implementation. In this case, the user
5960+** creates and populates an instance of this structure to pass
5961+** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option.
5962+** Additionally, an instance of this structure can be used as an
5963+** output variable when querying the system for the current mutex
5964+** implementation, using the [SQLITE_CONFIG_GETMUTEX] option.
5965+**
5966+** ^The xMutexInit method defined by this structure is invoked as
5967+** part of system initialization by the sqlite3_initialize() function.
5968+** ^The xMutexInit routine is called by SQLite exactly once for each
5969+** effective call to [sqlite3_initialize()].
5970+**
5971+** ^The xMutexEnd method defined by this structure is invoked as
5972+** part of system shutdown by the sqlite3_shutdown() function. The
5973+** implementation of this method is expected to release all outstanding
5974+** resources obtained by the mutex methods implementation, especially
5975+** those obtained by the xMutexInit method. ^The xMutexEnd()
5976+** interface is invoked exactly once for each call to [sqlite3_shutdown()].
5977+**
5978+** ^(The remaining seven methods defined by this structure (xMutexAlloc,
5979+** xMutexFree, xMutexEnter, xMutexTry, xMutexLeave, xMutexHeld and
5980+** xMutexNotheld) implement the following interfaces (respectively):
5981+**
5982+** <ul>
5983+** <li> [sqlite3_mutex_alloc()] </li>
5984+** <li> [sqlite3_mutex_free()] </li>
5985+** <li> [sqlite3_mutex_enter()] </li>
5986+** <li> [sqlite3_mutex_try()] </li>
5987+** <li> [sqlite3_mutex_leave()] </li>
5988+** <li> [sqlite3_mutex_held()] </li>
5989+** <li> [sqlite3_mutex_notheld()] </li>
5990+** </ul>)^
5991+**
5992+** The only difference is that the public sqlite3_XXX functions enumerated
5993+** above silently ignore any invocations that pass a NULL pointer instead
5994+** of a valid mutex handle. The implementations of the methods defined
5995+** by this structure are not required to handle this case, the results
5996+** of passing a NULL pointer instead of a valid mutex handle are undefined
5997+** (i.e. it is acceptable to provide an implementation that segfaults if
5998+** it is passed a NULL pointer).
5999+**
6000+** The xMutexInit() method must be threadsafe. ^It must be harmless to
6001+** invoke xMutexInit() multiple times within the same process and without
6002+** intervening calls to xMutexEnd(). Second and subsequent calls to
6003+** xMutexInit() must be no-ops.
6004+**
6005+** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
6006+** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory
6007+** allocation for a static mutex. ^However xMutexAlloc() may use SQLite
6008+** memory allocation for a fast or recursive mutex.
6009+**
6010+** ^SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is
6011+** called, but only if the prior call to xMutexInit returned SQLITE_OK.
6012+** If xMutexInit fails in any way, it is expected to clean up after itself
6013+** prior to returning.
6014+*/
6015+typedef struct sqlite3_mutex_methods sqlite3_mutex_methods;
6016+struct sqlite3_mutex_methods {
6017+ int (*xMutexInit)(void);
6018+ int (*xMutexEnd)(void);
6019+ sqlite3_mutex *(*xMutexAlloc)(int);
6020+ void (*xMutexFree)(sqlite3_mutex *);
6021+ void (*xMutexEnter)(sqlite3_mutex *);
6022+ int (*xMutexTry)(sqlite3_mutex *);
6023+ void (*xMutexLeave)(sqlite3_mutex *);
6024+ int (*xMutexHeld)(sqlite3_mutex *);
6025+ int (*xMutexNotheld)(sqlite3_mutex *);
6026+};
6027+
6028+/*
6029+** CAPI3REF: Mutex Verification Routines
6030+**
6031+** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
6032+** are intended for use inside assert() statements. ^The SQLite core
6033+** never uses these routines except inside an assert() and applications
6034+** are advised to follow the lead of the core. ^The SQLite core only
6035+** provides implementations for these routines when it is compiled
6036+** with the SQLITE_DEBUG flag. ^External mutex implementations
6037+** are only required to provide these routines if SQLITE_DEBUG is
6038+** defined and if NDEBUG is not defined.
6039+**
6040+** ^These routines should return true if the mutex in their argument
6041+** is held or not held, respectively, by the calling thread.
6042+**
6043+** ^The implementation is not required to provided versions of these
6044+** routines that actually work. If the implementation does not provide working
6045+** versions of these routines, it should at least provide stubs that always
6046+** return true so that one does not get spurious assertion failures.
6047+**
6048+** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
6049+** the routine should return 1. This seems counter-intuitive since
6050+** clearly the mutex cannot be held if it does not exist. But
6051+** the reason the mutex does not exist is because the build is not
6052+** using mutexes. And we do not want the assert() containing the
6053+** call to sqlite3_mutex_held() to fail, so a non-zero return is
6054+** the appropriate thing to do. ^The sqlite3_mutex_notheld()
6055+** interface should also return 1 when given a NULL pointer.
6056+*/
6057+#ifndef NDEBUG
6058+SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
6059+SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
6060+#endif
6061+
6062+/*
6063+** CAPI3REF: Mutex Types
6064+**
6065+** The [sqlite3_mutex_alloc()] interface takes a single argument
6066+** which is one of these integer constants.
6067+**
6068+** The set of static mutexes may change from one SQLite release to the
6069+** next. Applications that override the built-in mutex logic must be
6070+** prepared to accommodate additional static mutexes.
6071+*/
6072+#define SQLITE_MUTEX_FAST 0
6073+#define SQLITE_MUTEX_RECURSIVE 1
6074+#define SQLITE_MUTEX_STATIC_MASTER 2
6075+#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
6076+#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
6077+#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
6078+#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
6079+#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
6080+#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
6081+#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
6082+
6083+/*
6084+** CAPI3REF: Retrieve the mutex for a database connection
6085+**
6086+** ^This interface returns a pointer the [sqlite3_mutex] object that
6087+** serializes access to the [database connection] given in the argument
6088+** when the [threading mode] is Serialized.
6089+** ^If the [threading mode] is Single-thread or Multi-thread then this
6090+** routine returns a NULL pointer.
6091+*/
6092+SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
6093+
6094+/*
6095+** CAPI3REF: Low-Level Control Of Database Files
6096+**
6097+** ^The [sqlite3_file_control()] interface makes a direct call to the
6098+** xFileControl method for the [sqlite3_io_methods] object associated
6099+** with a particular database identified by the second argument. ^The
6100+** name of the database is "main" for the main database or "temp" for the
6101+** TEMP database, or the name that appears after the AS keyword for
6102+** databases that are added using the [ATTACH] SQL command.
6103+** ^A NULL pointer can be used in place of "main" to refer to the
6104+** main database file.
6105+** ^The third and fourth parameters to this routine
6106+** are passed directly through to the second and third parameters of
6107+** the xFileControl method. ^The return value of the xFileControl
6108+** method becomes the return value of this routine.
6109+**
6110+** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
6111+** a pointer to the underlying [sqlite3_file] object to be written into
6112+** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER
6113+** case is a short-circuit path which does not actually invoke the
6114+** underlying sqlite3_io_methods.xFileCont

Part of diff was cut off due to size limit. Use your local client to view the full diff.