xref: /sqlite-3.40.0/test/startup.c (revision 33e1ec22)
1*33e1ec22Sdrh /*
2*33e1ec22Sdrh ** 2021-01-01
3*33e1ec22Sdrh **
4*33e1ec22Sdrh ** The author disclaims copyright to this source code.  In place of
5*33e1ec22Sdrh ** a legal notice, here is a blessing:
6*33e1ec22Sdrh **
7*33e1ec22Sdrh **    May you do good and not evil.
8*33e1ec22Sdrh **    May you find forgiveness for yourself and forgive others.
9*33e1ec22Sdrh **    May you share freely, never taking more than you give.
10*33e1ec22Sdrh **
11*33e1ec22Sdrh *************************************************************************
12*33e1ec22Sdrh **
13*33e1ec22Sdrh ** This file implements a program used to measure the start-up performance
14*33e1ec22Sdrh ** of SQLite.
15*33e1ec22Sdrh **
16*33e1ec22Sdrh ** To use:
17*33e1ec22Sdrh **
18*33e1ec22Sdrh **     ./startup init
19*33e1ec22Sdrh **     valgrind --tool=cachegrind ./startup run
20*33e1ec22Sdrh **
21*33e1ec22Sdrh **
22*33e1ec22Sdrh ** The "./startup init" command creates the test database file named
23*33e1ec22Sdrh ** "startup.db".  The performance test is run by the "./startup run"
24*33e1ec22Sdrh ** command.  That command does nothing but open the database file and
25*33e1ec22Sdrh ** parse the entire schema.
26*33e1ec22Sdrh */
27*33e1ec22Sdrh #include <stdio.h>
28*33e1ec22Sdrh #include <unistd.h>
29*33e1ec22Sdrh #include <string.h>
30*33e1ec22Sdrh #include <stdlib.h>
31*33e1ec22Sdrh #include <ctype.h>
32*33e1ec22Sdrh #include "sqlite3.h"
33*33e1ec22Sdrh 
34*33e1ec22Sdrh static const char zHelp[] =
35*33e1ec22Sdrh   "Usage: %s COMMAND\n"
36*33e1ec22Sdrh   "Commands:\n"
37*33e1ec22Sdrh   "  init                Initialized the startup.db database file\n"
38*33e1ec22Sdrh   "  run                 Run the startup performance test\n"
39*33e1ec22Sdrh   "Options:\n"
40*33e1ec22Sdrh   "  --dbname NAME       Set the name of the test database file\n"
41*33e1ec22Sdrh   "  --heap SZ MIN       Memory allocator uses SZ bytes & min allocation MIN\n"
42*33e1ec22Sdrh   "  --stats             Show statistics at the end\n"
43*33e1ec22Sdrh /* TBD
44*33e1ec22Sdrh   "  --journal M         Set the journal_mode to M\n"
45*33e1ec22Sdrh   "  --lookaside N SZ    Configure lookaside for N slots of SZ bytes each\n"
46*33e1ec22Sdrh   "  --mmap SZ           MMAP the first SZ bytes of the database file\n"
47*33e1ec22Sdrh   "  --multithread       Set multithreaded mode\n"
48*33e1ec22Sdrh   "  --nomemstat         Disable memory statistics\n"
49*33e1ec22Sdrh   "  --pagesize N        Set the page size to N\n"
50*33e1ec22Sdrh   "  --pcache N SZ       Configure N pages of pagecache each of size SZ bytes\n"
51*33e1ec22Sdrh   "  --serialized        Set serialized threading mode\n"
52*33e1ec22Sdrh   "  --singlethread      Set single-threaded mode - disables all mutexing\n"
53*33e1ec22Sdrh   "  --utf16be           Set text encoding to UTF-16BE\n"
54*33e1ec22Sdrh   "  --utf16le           Set text encoding to UTF-16LE\n"
55*33e1ec22Sdrh   "  --utf8              Set text encoding to UTF-8\n"
56*33e1ec22Sdrh */
57*33e1ec22Sdrh ;
58*33e1ec22Sdrh 
usage(const char * argv0)59*33e1ec22Sdrh static void usage(const char *argv0){
60*33e1ec22Sdrh   printf(zHelp, argv0);
61*33e1ec22Sdrh   exit(1);
62*33e1ec22Sdrh }
63*33e1ec22Sdrh 
64*33e1ec22Sdrh /*
65*33e1ec22Sdrh ** The test schema is derived from the Fossil repository for SQLite itself.
66*33e1ec22Sdrh ** The schema covers the repository, the local checkout database, and
67*33e1ec22Sdrh ** the global configuration database.
68*33e1ec22Sdrh */
69*33e1ec22Sdrh static const char zTestSchema[] =
70*33e1ec22Sdrh   "CREATE TABLE repo_blob(\n"
71*33e1ec22Sdrh   "  rid INTEGER PRIMARY KEY,\n"
72*33e1ec22Sdrh   "  rcvid INTEGER,\n"
73*33e1ec22Sdrh   "  size INTEGER,\n"
74*33e1ec22Sdrh   "  uuid TEXT UNIQUE NOT NULL,\n"
75*33e1ec22Sdrh   "  content BLOB,\n"
76*33e1ec22Sdrh   "  CHECK( length(uuid)>=40 AND rid>0 )\n"
77*33e1ec22Sdrh   ");\n"
78*33e1ec22Sdrh   "CREATE TABLE repo_delta(\n"
79*33e1ec22Sdrh   "  rid INTEGER PRIMARY KEY,\n"
80*33e1ec22Sdrh   "  srcid INTEGER NOT NULL REFERENCES blob\n"
81*33e1ec22Sdrh   ");\n"
82*33e1ec22Sdrh   "CREATE TABLE repo_rcvfrom(\n"
83*33e1ec22Sdrh   "  rcvid INTEGER PRIMARY KEY,\n"
84*33e1ec22Sdrh   "  uid INTEGER REFERENCES user,\n"
85*33e1ec22Sdrh   "  mtime DATETIME,\n"
86*33e1ec22Sdrh   "  nonce TEXT UNIQUE,\n"
87*33e1ec22Sdrh   "  ipaddr TEXT\n"
88*33e1ec22Sdrh   ");\n"
89*33e1ec22Sdrh   "CREATE TABLE repo_private(rid INTEGER PRIMARY KEY);\n"
90*33e1ec22Sdrh   "CREATE TABLE repo_accesslog(\n"
91*33e1ec22Sdrh   "  uname TEXT,\n"
92*33e1ec22Sdrh   "  ipaddr TEXT,\n"
93*33e1ec22Sdrh   "  success BOOLEAN,\n"
94*33e1ec22Sdrh   "  mtime TIMESTAMP);\n"
95*33e1ec22Sdrh   "CREATE TABLE repo_user(\n"
96*33e1ec22Sdrh   "  uid INTEGER PRIMARY KEY,\n"
97*33e1ec22Sdrh   "  login TEXT UNIQUE,\n"
98*33e1ec22Sdrh   "  pw TEXT,\n"
99*33e1ec22Sdrh   "  cap TEXT,\n"
100*33e1ec22Sdrh   "  cookie TEXT,\n"
101*33e1ec22Sdrh   "  ipaddr TEXT,\n"
102*33e1ec22Sdrh   "  cexpire DATETIME,\n"
103*33e1ec22Sdrh   "  info TEXT,\n"
104*33e1ec22Sdrh   "  mtime DATE,\n"
105*33e1ec22Sdrh   "  photo BLOB\n"
106*33e1ec22Sdrh   ");\n"
107*33e1ec22Sdrh   "CREATE TABLE repo_reportfmt(\n"
108*33e1ec22Sdrh   "   rn INTEGER PRIMARY KEY,\n"
109*33e1ec22Sdrh   "   owner TEXT,\n"
110*33e1ec22Sdrh   "   title TEXT UNIQUE,\n"
111*33e1ec22Sdrh   "   mtime INTEGER,\n"
112*33e1ec22Sdrh   "   cols TEXT,\n"
113*33e1ec22Sdrh   "   sqlcode TEXT\n"
114*33e1ec22Sdrh   ");\n"
115*33e1ec22Sdrh   "CREATE TABLE repo_sqlite_stat2(tbl,idx,sampleno,sample);\n"
116*33e1ec22Sdrh   "CREATE TABLE repo_sqlite_stat1(tbl,idx,stat);\n"
117*33e1ec22Sdrh   "CREATE TABLE repo_sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample);\n"
118*33e1ec22Sdrh   "CREATE TABLE repo_config(\n"
119*33e1ec22Sdrh   "  name TEXT PRIMARY KEY NOT NULL,\n"
120*33e1ec22Sdrh   "  value CLOB, mtime INTEGER,\n"
121*33e1ec22Sdrh   "  CHECK( typeof(name)='text' AND length(name)>=1 )\n"
122*33e1ec22Sdrh   ") WITHOUT ROWID;\n"
123*33e1ec22Sdrh   "CREATE TABLE repo_shun(uuid PRIMARY KEY,\n"
124*33e1ec22Sdrh   "  mtime INTEGER,\n"
125*33e1ec22Sdrh   "  scom TEXT) WITHOUT ROWID;\n"
126*33e1ec22Sdrh   "CREATE TABLE repo_concealed(\n"
127*33e1ec22Sdrh   "  hash TEXT PRIMARY KEY,\n"
128*33e1ec22Sdrh   "  content TEXT\n"
129*33e1ec22Sdrh   ", mtime INTEGER) WITHOUT ROWID;\n"
130*33e1ec22Sdrh   "CREATE TABLE repo_admin_log(\n"
131*33e1ec22Sdrh   " id INTEGER PRIMARY KEY,\n"
132*33e1ec22Sdrh   " time INTEGER, -- Seconds since 1970\n"
133*33e1ec22Sdrh   " page TEXT,    -- path of page\n"
134*33e1ec22Sdrh   " who TEXT,     -- User who made the change\n"
135*33e1ec22Sdrh   "  what TEXT     -- What changed\n"
136*33e1ec22Sdrh   ");\n"
137*33e1ec22Sdrh   "CREATE TABLE repo_unversioned(\n"
138*33e1ec22Sdrh   "  name TEXT PRIMARY KEY,\n"
139*33e1ec22Sdrh   "  rcvid INTEGER,\n"
140*33e1ec22Sdrh   "  mtime DATETIME,\n"
141*33e1ec22Sdrh   "  hash TEXT,\n"
142*33e1ec22Sdrh   "  sz INTEGER,\n"
143*33e1ec22Sdrh   "  encoding INT,\n"
144*33e1ec22Sdrh   "  content BLOB\n"
145*33e1ec22Sdrh   ") WITHOUT ROWID;\n"
146*33e1ec22Sdrh   "CREATE TABLE repo_subscriber(\n"
147*33e1ec22Sdrh   "  subscriberId INTEGER PRIMARY KEY,\n"
148*33e1ec22Sdrh   "  subscriberCode BLOB DEFAULT (randomblob(32)) UNIQUE,\n"
149*33e1ec22Sdrh   "  semail TEXT UNIQUE COLLATE nocase,\n"
150*33e1ec22Sdrh   "  suname TEXT,\n"
151*33e1ec22Sdrh   "  sverified BOOLEAN DEFAULT true,\n"
152*33e1ec22Sdrh   "  sdonotcall BOOLEAN,\n"
153*33e1ec22Sdrh   "  sdigest BOOLEAN,\n"
154*33e1ec22Sdrh   "  ssub TEXT,\n"
155*33e1ec22Sdrh   "  sctime INTDATE,\n"
156*33e1ec22Sdrh   "  mtime INTDATE,\n"
157*33e1ec22Sdrh   "  smip TEXT\n"
158*33e1ec22Sdrh   ");\n"
159*33e1ec22Sdrh   "CREATE TABLE repo_pending_alert(\n"
160*33e1ec22Sdrh   "  eventid TEXT PRIMARY KEY,\n"
161*33e1ec22Sdrh   "  sentSep BOOLEAN DEFAULT false,\n"
162*33e1ec22Sdrh   "  sentDigest BOOLEAN DEFAULT false\n"
163*33e1ec22Sdrh   ", sentMod BOOLEAN DEFAULT false) WITHOUT ROWID;\n"
164*33e1ec22Sdrh   "CREATE INDEX repo_delta_i1 ON repo_delta(srcid);\n"
165*33e1ec22Sdrh   "CREATE INDEX repo_blob_rcvid ON repo_blob(rcvid);\n"
166*33e1ec22Sdrh   "CREATE INDEX repo_subscriberUname\n"
167*33e1ec22Sdrh   "  ON repo_subscriber(suname) WHERE suname IS NOT NULL;\n"
168*33e1ec22Sdrh   "CREATE VIEW repo_artifact(rid,rcvid,size,atype,srcid,hash,content) AS\n"
169*33e1ec22Sdrh   "     SELECT blob.rid,rcvid,size,1,srcid,uuid,content\n"
170*33e1ec22Sdrh   "       FROM repo_blob LEFT JOIN repo_delta ON (blob.rid=delta.rid);\n"
171*33e1ec22Sdrh   "CREATE TABLE repo_filename(\n"
172*33e1ec22Sdrh   "  fnid INTEGER PRIMARY KEY,\n"
173*33e1ec22Sdrh   "  name TEXT UNIQUE\n"
174*33e1ec22Sdrh   ");\n"
175*33e1ec22Sdrh   "CREATE TABLE repo_mlink(\n"
176*33e1ec22Sdrh   "  mid INTEGER,\n"
177*33e1ec22Sdrh   "  fid INTEGER,\n"
178*33e1ec22Sdrh   "  pmid INTEGER,\n"
179*33e1ec22Sdrh   "  pid INTEGER,\n"
180*33e1ec22Sdrh   "  fnid INTEGER REFERENCES filename,\n"
181*33e1ec22Sdrh   "  pfnid INTEGER,\n"
182*33e1ec22Sdrh   "  mperm INTEGER,\n"
183*33e1ec22Sdrh   "  isaux BOOLEAN DEFAULT 0\n"
184*33e1ec22Sdrh   ");\n"
185*33e1ec22Sdrh   "CREATE INDEX repo_mlink_i1 ON repo_mlink(mid);\n"
186*33e1ec22Sdrh   "CREATE INDEX repo_mlink_i2 ON repo_mlink(fnid);\n"
187*33e1ec22Sdrh   "CREATE INDEX repo_mlink_i3 ON repo_mlink(fid);\n"
188*33e1ec22Sdrh   "CREATE INDEX repo_mlink_i4 ON repo_mlink(pid);\n"
189*33e1ec22Sdrh   "CREATE TABLE repo_plink(\n"
190*33e1ec22Sdrh   "  pid INTEGER REFERENCES blob,\n"
191*33e1ec22Sdrh   "  cid INTEGER REFERENCES blob,\n"
192*33e1ec22Sdrh   "  isprim BOOLEAN,\n"
193*33e1ec22Sdrh   "  mtime DATETIME,\n"
194*33e1ec22Sdrh   "  baseid INTEGER REFERENCES blob,\n"
195*33e1ec22Sdrh   "  UNIQUE(pid, cid)\n"
196*33e1ec22Sdrh   ");\n"
197*33e1ec22Sdrh   "CREATE INDEX repo_plink_i2 ON repo_plink(cid,pid);\n"
198*33e1ec22Sdrh   "CREATE TABLE repo_leaf(rid INTEGER PRIMARY KEY);\n"
199*33e1ec22Sdrh   "CREATE TABLE repo_event(\n"
200*33e1ec22Sdrh   "  type TEXT,\n"
201*33e1ec22Sdrh   "  mtime DATETIME,\n"
202*33e1ec22Sdrh   "  objid INTEGER PRIMARY KEY,\n"
203*33e1ec22Sdrh   "  tagid INTEGER,\n"
204*33e1ec22Sdrh   "  uid INTEGER REFERENCES user,\n"
205*33e1ec22Sdrh   "  bgcolor TEXT,\n"
206*33e1ec22Sdrh   "  euser TEXT,\n"
207*33e1ec22Sdrh   "  user TEXT,\n"
208*33e1ec22Sdrh   "  ecomment TEXT,\n"
209*33e1ec22Sdrh   "  comment TEXT,\n"
210*33e1ec22Sdrh   "  brief TEXT,\n"
211*33e1ec22Sdrh   "  omtime DATETIME\n"
212*33e1ec22Sdrh   ");\n"
213*33e1ec22Sdrh   "CREATE INDEX repo_event_i1 ON repo_event(mtime);\n"
214*33e1ec22Sdrh   "CREATE TABLE repo_phantom(\n"
215*33e1ec22Sdrh   "  rid INTEGER PRIMARY KEY\n"
216*33e1ec22Sdrh   ");\n"
217*33e1ec22Sdrh   "CREATE TABLE repo_orphan(\n"
218*33e1ec22Sdrh   "  rid INTEGER PRIMARY KEY,\n"
219*33e1ec22Sdrh   "  baseline INTEGER\n"
220*33e1ec22Sdrh   ");\n"
221*33e1ec22Sdrh   "CREATE INDEX repo_orphan_baseline ON repo_orphan(baseline);\n"
222*33e1ec22Sdrh   "CREATE TABLE repo_unclustered(\n"
223*33e1ec22Sdrh   "  rid INTEGER PRIMARY KEY\n"
224*33e1ec22Sdrh   ");\n"
225*33e1ec22Sdrh   "CREATE TABLE repo_unsent(\n"
226*33e1ec22Sdrh   "  rid INTEGER PRIMARY KEY\n"
227*33e1ec22Sdrh   ");\n"
228*33e1ec22Sdrh   "CREATE TABLE repo_tag(\n"
229*33e1ec22Sdrh   "  tagid INTEGER PRIMARY KEY,\n"
230*33e1ec22Sdrh   "  tagname TEXT UNIQUE\n"
231*33e1ec22Sdrh   ");\n"
232*33e1ec22Sdrh   "CREATE TABLE repo_tagxref(\n"
233*33e1ec22Sdrh   "  tagid INTEGER REFERENCES tag,\n"
234*33e1ec22Sdrh   "  tagtype INTEGER,\n"
235*33e1ec22Sdrh   "  srcid INTEGER REFERENCES blob,\n"
236*33e1ec22Sdrh   "  origid INTEGER REFERENCES blob,\n"
237*33e1ec22Sdrh   "  value TEXT,\n"
238*33e1ec22Sdrh   "  mtime TIMESTAMP,\n"
239*33e1ec22Sdrh   "  rid INTEGER REFERENCE blob,\n"
240*33e1ec22Sdrh   "  UNIQUE(rid, tagid)\n"
241*33e1ec22Sdrh   ");\n"
242*33e1ec22Sdrh   "CREATE INDEX repo_tagxref_i1 ON repo_tagxref(tagid, mtime);\n"
243*33e1ec22Sdrh   "CREATE TABLE repo_backlink(\n"
244*33e1ec22Sdrh   "  target TEXT,\n"
245*33e1ec22Sdrh   "  srctype INT,\n"
246*33e1ec22Sdrh   "  srcid INT,\n"
247*33e1ec22Sdrh   "  mtime TIMESTAMP,\n"
248*33e1ec22Sdrh   "  UNIQUE(target, srctype, srcid)\n"
249*33e1ec22Sdrh   ");\n"
250*33e1ec22Sdrh   "CREATE INDEX repo_backlink_src ON repo_backlink(srcid, srctype);\n"
251*33e1ec22Sdrh   "CREATE TABLE repo_attachment(\n"
252*33e1ec22Sdrh   "  attachid INTEGER PRIMARY KEY,\n"
253*33e1ec22Sdrh   "  isLatest BOOLEAN DEFAULT 0,\n"
254*33e1ec22Sdrh   "  mtime TIMESTAMP,\n"
255*33e1ec22Sdrh   "  src TEXT,\n"
256*33e1ec22Sdrh   "  target TEXT,\n"
257*33e1ec22Sdrh   "  filename TEXT,\n"
258*33e1ec22Sdrh   "  comment TEXT,\n"
259*33e1ec22Sdrh   "  user TEXT\n"
260*33e1ec22Sdrh   ");\n"
261*33e1ec22Sdrh   "CREATE INDEX repo_attachment_idx1\n"
262*33e1ec22Sdrh   " ON repo_attachment(target, filename, mtime);\n"
263*33e1ec22Sdrh   "CREATE INDEX repo_attachment_idx2 ON repo_attachment(src);\n"
264*33e1ec22Sdrh   "CREATE TABLE repo_cherrypick(\n"
265*33e1ec22Sdrh   "  parentid INT,\n"
266*33e1ec22Sdrh   "  childid INT,\n"
267*33e1ec22Sdrh   "  isExclude BOOLEAN DEFAULT false,\n"
268*33e1ec22Sdrh   "  PRIMARY KEY(parentid, childid)\n"
269*33e1ec22Sdrh   ") WITHOUT ROWID;\n"
270*33e1ec22Sdrh   "CREATE INDEX repo_cherrypick_cid ON repo_cherrypick(childid);\n"
271*33e1ec22Sdrh   "CREATE TABLE repo_ticket(\n"
272*33e1ec22Sdrh   "  -- Do not change any column that begins with tkt_\n"
273*33e1ec22Sdrh   "  tkt_id INTEGER PRIMARY KEY,\n"
274*33e1ec22Sdrh   "  tkt_uuid TEXT UNIQUE,\n"
275*33e1ec22Sdrh   "  tkt_mtime DATE,\n"
276*33e1ec22Sdrh   "  tkt_ctime DATE,\n"
277*33e1ec22Sdrh   "  -- Add as many fields as required below this line\n"
278*33e1ec22Sdrh   "  type TEXT,\n"
279*33e1ec22Sdrh   "  status TEXT,\n"
280*33e1ec22Sdrh   "  subsystem TEXT,\n"
281*33e1ec22Sdrh   "  priority TEXT,\n"
282*33e1ec22Sdrh   "  severity TEXT,\n"
283*33e1ec22Sdrh   "  foundin TEXT,\n"
284*33e1ec22Sdrh   "  private_contact TEXT,\n"
285*33e1ec22Sdrh   "  resolution TEXT,\n"
286*33e1ec22Sdrh   "  title TEXT,\n"
287*33e1ec22Sdrh   "  comment TEXT\n"
288*33e1ec22Sdrh   ");\n"
289*33e1ec22Sdrh   "CREATE TABLE repo_ticketchng(\n"
290*33e1ec22Sdrh   "  -- Do not change any column that begins with tkt_\n"
291*33e1ec22Sdrh   "  tkt_id INTEGER REFERENCES ticket,\n"
292*33e1ec22Sdrh   "  tkt_rid INTEGER REFERENCES blob,\n"
293*33e1ec22Sdrh   "  tkt_mtime DATE,\n"
294*33e1ec22Sdrh   "  -- Add as many fields as required below this line\n"
295*33e1ec22Sdrh   "  login TEXT,\n"
296*33e1ec22Sdrh   "  username TEXT,\n"
297*33e1ec22Sdrh   "  mimetype TEXT,\n"
298*33e1ec22Sdrh   "  icomment TEXT\n"
299*33e1ec22Sdrh   ");\n"
300*33e1ec22Sdrh   "CREATE INDEX repo_ticketchng_idx1 ON repo_ticketchng(tkt_id, tkt_mtime);\n"
301*33e1ec22Sdrh   "CREATE TRIGGER repo_alert_trigger1\n"
302*33e1ec22Sdrh   "AFTER INSERT ON repo_event BEGIN\n"
303*33e1ec22Sdrh   "  INSERT INTO repo_pending_alert(eventid)\n"
304*33e1ec22Sdrh   "    SELECT printf('%.1c%d',new.type,new.objid) WHERE true\n"
305*33e1ec22Sdrh   "    ON CONFLICT(eventId) DO NOTHING;\n"
306*33e1ec22Sdrh   "END;\n"
307*33e1ec22Sdrh   "CREATE TABLE repo_vcache(\n"
308*33e1ec22Sdrh   "  vid INTEGER,         -- check-in ID\n"
309*33e1ec22Sdrh   "  fname TEXT,          -- filename\n"
310*33e1ec22Sdrh   "  rid INTEGER,         -- artifact ID\n"
311*33e1ec22Sdrh   "  PRIMARY KEY(vid,fname)\n"
312*33e1ec22Sdrh   ") WITHOUT ROWID;\n"
313*33e1ec22Sdrh   "CREATE TABLE localdb_vvar(\n"
314*33e1ec22Sdrh   "  name TEXT PRIMARY KEY NOT NULL,\n"
315*33e1ec22Sdrh   "  value CLOB,\n"
316*33e1ec22Sdrh   "  CHECK( typeof(name)='text' AND length(name)>=1 )\n"
317*33e1ec22Sdrh   ");\n"
318*33e1ec22Sdrh   "CREATE TABLE localdb_vfile(\n"
319*33e1ec22Sdrh   "  id INTEGER PRIMARY KEY,\n"
320*33e1ec22Sdrh   "  vid INTEGER REFERENCES blob,\n"
321*33e1ec22Sdrh   "  chnged INT DEFAULT 0,\n"
322*33e1ec22Sdrh   "  deleted BOOLEAN DEFAULT 0,\n"
323*33e1ec22Sdrh   "  isexe BOOLEAN,\n"
324*33e1ec22Sdrh   "  islink BOOLEAN,\n"
325*33e1ec22Sdrh   "  rid INTEGER,\n"
326*33e1ec22Sdrh   "  mrid INTEGER,\n"
327*33e1ec22Sdrh   "  mtime INTEGER,\n"
328*33e1ec22Sdrh   "  pathname TEXT,\n"
329*33e1ec22Sdrh   "  origname TEXT, mhash,\n"
330*33e1ec22Sdrh   "  UNIQUE(pathname,vid)\n"
331*33e1ec22Sdrh   ");\n"
332*33e1ec22Sdrh   "CREATE TABLE localdb_sqlite_stat1(tbl,idx,stat);\n"
333*33e1ec22Sdrh   "CREATE TABLE localdb_vcache(\n"
334*33e1ec22Sdrh   "  vid INTEGER,         -- check-in ID\n"
335*33e1ec22Sdrh   "  fname TEXT,          -- filename\n"
336*33e1ec22Sdrh   "  rid INTEGER,         -- artifact ID\n"
337*33e1ec22Sdrh   "  PRIMARY KEY(vid,fname)\n"
338*33e1ec22Sdrh   ") WITHOUT ROWID;\n"
339*33e1ec22Sdrh   "CREATE TABLE localdb_stash(\n"
340*33e1ec22Sdrh   "  stashid INTEGER PRIMARY KEY,\n"
341*33e1ec22Sdrh   "  vid INTEGER,\n"
342*33e1ec22Sdrh   "  hash TEXT,\n"
343*33e1ec22Sdrh   "  comment TEXT,\n"
344*33e1ec22Sdrh   "  ctime TIMESTAMP\n"
345*33e1ec22Sdrh   ");\n"
346*33e1ec22Sdrh   "CREATE TABLE localdb_stashfile(\n"
347*33e1ec22Sdrh   "  stashid INTEGER REFERENCES stash,\n"
348*33e1ec22Sdrh   "  isAdded BOOLEAN,\n"
349*33e1ec22Sdrh   "  isRemoved BOOLEAN,\n"
350*33e1ec22Sdrh   "  isExec BOOLEAN,\n"
351*33e1ec22Sdrh   "  isLink BOOLEAN,\n"
352*33e1ec22Sdrh   "  rid INTEGER,\n"
353*33e1ec22Sdrh   "  hash TEXT,\n"
354*33e1ec22Sdrh   "  origname TEXT,\n"
355*33e1ec22Sdrh   "  newname TEXT,\n"
356*33e1ec22Sdrh   "  delta BLOB,\n"
357*33e1ec22Sdrh   "  PRIMARY KEY(newname, stashid)\n"
358*33e1ec22Sdrh   ");\n"
359*33e1ec22Sdrh   "CREATE TABLE localdb_vmerge(\n"
360*33e1ec22Sdrh   "  id INTEGER REFERENCES vfile,\n"
361*33e1ec22Sdrh   "  merge INTEGER,\n"
362*33e1ec22Sdrh   "  mhash TEXT\n"
363*33e1ec22Sdrh   ");\n"
364*33e1ec22Sdrh   "CREATE UNIQUE INDEX localdb_vmergex1 ON localdb_vmerge(id,mhash);\n"
365*33e1ec22Sdrh   "CREATE TRIGGER localdb_vmerge_ck1 AFTER INSERT ON localdb_vmerge\n"
366*33e1ec22Sdrh   "WHEN new.mhash IS NULL BEGIN\n"
367*33e1ec22Sdrh   "  SELECT raise(FAIL,\n"
368*33e1ec22Sdrh   "  'trying to update a newer checkout with an older version of Fossil');\n"
369*33e1ec22Sdrh   "END;\n"
370*33e1ec22Sdrh   "CREATE TABLE configdb_global_config(\n"
371*33e1ec22Sdrh   "  name TEXT PRIMARY KEY,\n"
372*33e1ec22Sdrh   "  value TEXT\n"
373*33e1ec22Sdrh   ");\n"
374*33e1ec22Sdrh   "CREATE TABLE configdb_sqlite_stat1(tbl,idx,stat);\n"
375*33e1ec22Sdrh ;
376*33e1ec22Sdrh 
377*33e1ec22Sdrh #ifdef __linux__
378*33e1ec22Sdrh #include <sys/types.h>
379*33e1ec22Sdrh #include <unistd.h>
380*33e1ec22Sdrh 
381*33e1ec22Sdrh /*
382*33e1ec22Sdrh ** Attempt to display I/O stats on Linux using /proc/PID/io
383*33e1ec22Sdrh */
displayLinuxIoStats(FILE * out)384*33e1ec22Sdrh static void displayLinuxIoStats(FILE *out){
385*33e1ec22Sdrh   FILE *in;
386*33e1ec22Sdrh   char z[200];
387*33e1ec22Sdrh   sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
388*33e1ec22Sdrh   in = fopen(z, "rb");
389*33e1ec22Sdrh   if( in==0 ) return;
390*33e1ec22Sdrh   while( fgets(z, sizeof(z), in)!=0 ){
391*33e1ec22Sdrh     static const struct {
392*33e1ec22Sdrh       const char *zPattern;
393*33e1ec22Sdrh       const char *zDesc;
394*33e1ec22Sdrh     } aTrans[] = {
395*33e1ec22Sdrh       { "rchar: ",                  "Bytes received by read():" },
396*33e1ec22Sdrh       { "wchar: ",                  "Bytes sent to write():"    },
397*33e1ec22Sdrh       { "syscr: ",                  "Read() system calls:"      },
398*33e1ec22Sdrh       { "syscw: ",                  "Write() system calls:"     },
399*33e1ec22Sdrh       { "read_bytes: ",             "Bytes rcvd from storage:"  },
400*33e1ec22Sdrh       { "write_bytes: ",            "Bytes sent to storage:"    },
401*33e1ec22Sdrh       { "cancelled_write_bytes: ",  "Cancelled write bytes:"    },
402*33e1ec22Sdrh     };
403*33e1ec22Sdrh     int i;
404*33e1ec22Sdrh     for(i=0; i<sizeof(aTrans)/sizeof(aTrans[0]); i++){
405*33e1ec22Sdrh       int n = (int)strlen(aTrans[i].zPattern);
406*33e1ec22Sdrh       if( strncmp(aTrans[i].zPattern, z, n)==0 ){
407*33e1ec22Sdrh         fprintf(out, "-- %-28s %s", aTrans[i].zDesc, &z[n]);
408*33e1ec22Sdrh         break;
409*33e1ec22Sdrh       }
410*33e1ec22Sdrh     }
411*33e1ec22Sdrh   }
412*33e1ec22Sdrh   fclose(in);
413*33e1ec22Sdrh }
414*33e1ec22Sdrh #endif
415*33e1ec22Sdrh 
416*33e1ec22Sdrh /*
417*33e1ec22Sdrh ** Return the value of a hexadecimal digit.  Return -1 if the input
418*33e1ec22Sdrh ** is not a hex digit.
419*33e1ec22Sdrh */
hexDigitValue(char c)420*33e1ec22Sdrh static int hexDigitValue(char c){
421*33e1ec22Sdrh   if( c>='0' && c<='9' ) return c - '0';
422*33e1ec22Sdrh   if( c>='a' && c<='f' ) return c - 'a' + 10;
423*33e1ec22Sdrh   if( c>='A' && c<='F' ) return c - 'A' + 10;
424*33e1ec22Sdrh   return -1;
425*33e1ec22Sdrh }
426*33e1ec22Sdrh 
427*33e1ec22Sdrh /*
428*33e1ec22Sdrh ** Interpret zArg as an integer value, possibly with suffixes.
429*33e1ec22Sdrh */
integerValue(const char * zArg)430*33e1ec22Sdrh static int integerValue(const char *zArg){
431*33e1ec22Sdrh   sqlite3_int64 v = 0;
432*33e1ec22Sdrh   static const struct { char *zSuffix; int iMult; } aMult[] = {
433*33e1ec22Sdrh     { "KiB", 1024 },
434*33e1ec22Sdrh     { "MiB", 1024*1024 },
435*33e1ec22Sdrh     { "GiB", 1024*1024*1024 },
436*33e1ec22Sdrh     { "KB",  1000 },
437*33e1ec22Sdrh     { "MB",  1000000 },
438*33e1ec22Sdrh     { "GB",  1000000000 },
439*33e1ec22Sdrh     { "K",   1000 },
440*33e1ec22Sdrh     { "M",   1000000 },
441*33e1ec22Sdrh     { "G",   1000000000 },
442*33e1ec22Sdrh   };
443*33e1ec22Sdrh   int i;
444*33e1ec22Sdrh   int isNeg = 0;
445*33e1ec22Sdrh   if( zArg[0]=='-' ){
446*33e1ec22Sdrh     isNeg = 1;
447*33e1ec22Sdrh     zArg++;
448*33e1ec22Sdrh   }else if( zArg[0]=='+' ){
449*33e1ec22Sdrh     zArg++;
450*33e1ec22Sdrh   }
451*33e1ec22Sdrh   if( zArg[0]=='0' && zArg[1]=='x' ){
452*33e1ec22Sdrh     int x;
453*33e1ec22Sdrh     zArg += 2;
454*33e1ec22Sdrh     while( (x = hexDigitValue(zArg[0]))>=0 ){
455*33e1ec22Sdrh       v = (v<<4) + x;
456*33e1ec22Sdrh       zArg++;
457*33e1ec22Sdrh     }
458*33e1ec22Sdrh   }else{
459*33e1ec22Sdrh     while( isdigit(zArg[0]) ){
460*33e1ec22Sdrh       v = v*10 + zArg[0] - '0';
461*33e1ec22Sdrh       zArg++;
462*33e1ec22Sdrh     }
463*33e1ec22Sdrh   }
464*33e1ec22Sdrh   for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
465*33e1ec22Sdrh     if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
466*33e1ec22Sdrh       v *= aMult[i].iMult;
467*33e1ec22Sdrh       break;
468*33e1ec22Sdrh     }
469*33e1ec22Sdrh   }
470*33e1ec22Sdrh   if( v>0x7fffffff ){
471*33e1ec22Sdrh     printf("ERROR: parameter too large - max 2147483648\n");
472*33e1ec22Sdrh     exit(1);
473*33e1ec22Sdrh   }
474*33e1ec22Sdrh   return (int)(isNeg? -v : v);
475*33e1ec22Sdrh }
476*33e1ec22Sdrh 
477*33e1ec22Sdrh 
main(int argc,char ** argv)478*33e1ec22Sdrh int main(int argc, char **argv){
479*33e1ec22Sdrh   const char *zCmd = 0;
480*33e1ec22Sdrh   int i;
481*33e1ec22Sdrh   int bAutovac = 0;
482*33e1ec22Sdrh   int showStats = 0;
483*33e1ec22Sdrh   const char *zDbName = "./startup.db";
484*33e1ec22Sdrh   int nHeap = 0;
485*33e1ec22Sdrh   int mnHeap = 0;
486*33e1ec22Sdrh 
487*33e1ec22Sdrh   for(i=1; i<argc; i++){
488*33e1ec22Sdrh     const char *z = argv[i];
489*33e1ec22Sdrh     if( z[0]!='-' ){
490*33e1ec22Sdrh       if( zCmd ){
491*33e1ec22Sdrh         usage(argv[0]);
492*33e1ec22Sdrh       }
493*33e1ec22Sdrh       zCmd = z;
494*33e1ec22Sdrh       continue;
495*33e1ec22Sdrh     }
496*33e1ec22Sdrh     if( z[1]=='-' ) z++;
497*33e1ec22Sdrh     if( strcmp(z, "-autovacuum")==0 ){
498*33e1ec22Sdrh       bAutovac = 1;
499*33e1ec22Sdrh     }else
500*33e1ec22Sdrh     if( strcmp(z, "-dbname")==0 ){
501*33e1ec22Sdrh       if( i==argc-1 ){
502*33e1ec22Sdrh         printf("ERROR: missing argument on \"%s\"\n", argv[0]);
503*33e1ec22Sdrh         exit(1);
504*33e1ec22Sdrh       }
505*33e1ec22Sdrh       zDbName = argv[++i];
506*33e1ec22Sdrh     }else
507*33e1ec22Sdrh     if( strcmp(z,"-heap")==0 ){
508*33e1ec22Sdrh       if( i>=argc-2 ){
509*33e1ec22Sdrh         printf("ERROR: missing arguments on %s\n", argv[i]);
510*33e1ec22Sdrh         exit(1);
511*33e1ec22Sdrh       }
512*33e1ec22Sdrh       nHeap = integerValue(argv[i+1]);
513*33e1ec22Sdrh       mnHeap = integerValue(argv[i+2]);
514*33e1ec22Sdrh       i += 2;
515*33e1ec22Sdrh     }else
516*33e1ec22Sdrh     if( strcmp(z,"-stats")==0 ){
517*33e1ec22Sdrh        showStats = 1;
518*33e1ec22Sdrh     }else
519*33e1ec22Sdrh     {
520*33e1ec22Sdrh       printf("ERROR: unknown option \"%s\"\n", argv[i]);
521*33e1ec22Sdrh       usage(argv[0]);
522*33e1ec22Sdrh     }
523*33e1ec22Sdrh   }
524*33e1ec22Sdrh   if( zCmd==0 ){
525*33e1ec22Sdrh     printf("ERROR: no COMMAND specified\n");
526*33e1ec22Sdrh     usage(argv[0]);
527*33e1ec22Sdrh   }
528*33e1ec22Sdrh   if( strcmp(zCmd, "run")==0 ){
529*33e1ec22Sdrh     sqlite3 *db;
530*33e1ec22Sdrh     int rc;
531*33e1ec22Sdrh     char *zErr = 0;
532*33e1ec22Sdrh     void *pHeap = 0;
533*33e1ec22Sdrh     if( nHeap>0 ){
534*33e1ec22Sdrh       pHeap = malloc( nHeap );
535*33e1ec22Sdrh       if( pHeap==0 ){
536*33e1ec22Sdrh         printf("ERROR: cannot allocate %d-byte heap\n", nHeap);
537*33e1ec22Sdrh         exit(1);
538*33e1ec22Sdrh       }
539*33e1ec22Sdrh       rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap);
540*33e1ec22Sdrh       if( rc ){
541*33e1ec22Sdrh         printf("ERROR: heap configuration failed: %d\n", rc);
542*33e1ec22Sdrh         exit(1);
543*33e1ec22Sdrh       }
544*33e1ec22Sdrh     }
545*33e1ec22Sdrh     rc = sqlite3_open(zDbName, &db);
546*33e1ec22Sdrh     if( rc ){
547*33e1ec22Sdrh       printf("SQLite error: %s\n", sqlite3_errmsg(db));
548*33e1ec22Sdrh     }else{
549*33e1ec22Sdrh       sqlite3_exec(db, "PRAGMA synchronous", 0, 0, &zErr);
550*33e1ec22Sdrh     }
551*33e1ec22Sdrh     if( zErr ){
552*33e1ec22Sdrh       printf("ERROR: %s\n", zErr);
553*33e1ec22Sdrh       sqlite3_free(zErr);
554*33e1ec22Sdrh     }
555*33e1ec22Sdrh     if( showStats ){
556*33e1ec22Sdrh       int iCur, iHi;
557*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHi, 0);
558*33e1ec22Sdrh       printf("-- Lookaside Slots Used:        %d (max %d)\n", iCur,iHi);
559*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHi, 0);
560*33e1ec22Sdrh       printf("-- Successful lookasides:       %d\n", iHi);
561*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur,&iHi,0);
562*33e1ec22Sdrh       printf("-- Lookaside size faults:       %d\n", iHi);
563*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur,&iHi,0);
564*33e1ec22Sdrh       printf("-- Lookaside OOM faults:        %d\n", iHi);
565*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHi, 0);
566*33e1ec22Sdrh       printf("-- Pager Heap Usage:            %d bytes\n", iCur);
567*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHi, 1);
568*33e1ec22Sdrh       printf("-- Page cache hits:             %d\n", iCur);
569*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHi, 1);
570*33e1ec22Sdrh       printf("-- Page cache misses:           %d\n", iCur);
571*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHi, 1);
572*33e1ec22Sdrh       printf("-- Page cache writes:           %d\n", iCur);
573*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHi, 0);
574*33e1ec22Sdrh       printf("-- Schema Heap Usage:           %d bytes\n", iCur);
575*33e1ec22Sdrh       sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHi, 0);
576*33e1ec22Sdrh       printf("-- Statement Heap Usage:        %d bytes\n", iCur);
577*33e1ec22Sdrh     }
578*33e1ec22Sdrh     sqlite3_close(db);
579*33e1ec22Sdrh     free(pHeap);
580*33e1ec22Sdrh     /* Global memory usage statistics printed after the database connection
581*33e1ec22Sdrh     ** has closed.  Memory usage should be zero at this point. */
582*33e1ec22Sdrh     if( showStats ){
583*33e1ec22Sdrh       int iCur, iHi;
584*33e1ec22Sdrh       sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHi, 0);
585*33e1ec22Sdrh       printf("-- Memory Used (bytes):         %d (max %d)\n", iCur,iHi);
586*33e1ec22Sdrh       sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHi, 0);
587*33e1ec22Sdrh       printf("-- Outstanding Allocations:     %d (max %d)\n", iCur,iHi);
588*33e1ec22Sdrh       sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHi, 0);
589*33e1ec22Sdrh       printf("-- Pcache Overflow Bytes:       %d (max %d)\n", iCur,iHi);
590*33e1ec22Sdrh       sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHi, 0);
591*33e1ec22Sdrh       printf("-- Largest Allocation:          %d bytes\n",iHi);
592*33e1ec22Sdrh       sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHi, 0);
593*33e1ec22Sdrh       printf("-- Largest Pcache Allocation:   %d bytes\n",iHi);
594*33e1ec22Sdrh #ifdef __linux__
595*33e1ec22Sdrh       displayLinuxIoStats(stdout);
596*33e1ec22Sdrh #endif
597*33e1ec22Sdrh     }
598*33e1ec22Sdrh     return 0;
599*33e1ec22Sdrh   }
600*33e1ec22Sdrh   if( strcmp(zCmd, "init")==0 ){
601*33e1ec22Sdrh     sqlite3 *db;
602*33e1ec22Sdrh     char *zAux;
603*33e1ec22Sdrh     char *zErr = 0;
604*33e1ec22Sdrh     int rc;
605*33e1ec22Sdrh     unlink(zDbName);
606*33e1ec22Sdrh     zAux = sqlite3_mprintf("%s-journal", zDbName);
607*33e1ec22Sdrh     unlink(zAux);
608*33e1ec22Sdrh     sqlite3_free(zAux);
609*33e1ec22Sdrh     zAux = sqlite3_mprintf("%s-wal", zDbName);
610*33e1ec22Sdrh     unlink(zAux);
611*33e1ec22Sdrh     sqlite3_free(zAux);
612*33e1ec22Sdrh     rc = sqlite3_open(zDbName, &db);
613*33e1ec22Sdrh     if( rc ){
614*33e1ec22Sdrh       printf("SQLite error: %s\n", sqlite3_errmsg(db));
615*33e1ec22Sdrh     }else{
616*33e1ec22Sdrh       sqlite3_exec(db, "BEGIN", 0, 0, 0);
617*33e1ec22Sdrh       sqlite3_exec(db, zTestSchema, 0, 0, &zErr);
618*33e1ec22Sdrh       sqlite3_exec(db, "COMMIT", 0, 0, 0);
619*33e1ec22Sdrh     }
620*33e1ec22Sdrh     if( zErr ){
621*33e1ec22Sdrh       printf("ERROR: %s\n", zErr);
622*33e1ec22Sdrh       sqlite3_free(zErr);
623*33e1ec22Sdrh     }
624*33e1ec22Sdrh     sqlite3_close(db);
625*33e1ec22Sdrh     return 0;
626*33e1ec22Sdrh 
627*33e1ec22Sdrh   }
628*33e1ec22Sdrh }
629