1290fcaa2Sdrh /*
2290fcaa2Sdrh ** 2016-06-07
3290fcaa2Sdrh **
4290fcaa2Sdrh ** The author disclaims copyright to this source code. In place of
5290fcaa2Sdrh ** a legal notice, here is a blessing:
6290fcaa2Sdrh **
7290fcaa2Sdrh ** May you do good and not evil.
8290fcaa2Sdrh ** May you find forgiveness for yourself and forgive others.
9290fcaa2Sdrh ** May you share freely, never taking more than you give.
10290fcaa2Sdrh **
11290fcaa2Sdrh *************************************************************************
12290fcaa2Sdrh **
137c4942cbSdrh ** This is a utility program that computes an SHA1 hash on the content
14290fcaa2Sdrh ** of an SQLite database.
15290fcaa2Sdrh **
16290fcaa2Sdrh ** The hash is computed over just the content of the database. Free
17290fcaa2Sdrh ** space inside of the database file, and alternative on-disk representations
18290fcaa2Sdrh ** of the same content (ex: UTF8 vs UTF16) do not affect the hash. So,
19290fcaa2Sdrh ** for example, the database file page size, encoding, and auto_vacuum setting
20290fcaa2Sdrh ** can all be changed without changing the hash.
21290fcaa2Sdrh */
22290fcaa2Sdrh #include <stdio.h>
23290fcaa2Sdrh #include <stdlib.h>
24290fcaa2Sdrh #include <stdarg.h>
25290fcaa2Sdrh #include <ctype.h>
26290fcaa2Sdrh #include <string.h>
27290fcaa2Sdrh #include <assert.h>
28290fcaa2Sdrh #include "sqlite3.h"
29290fcaa2Sdrh
30290fcaa2Sdrh /* Context for the SHA1 hash */
31290fcaa2Sdrh typedef struct SHA1Context SHA1Context;
32290fcaa2Sdrh struct SHA1Context {
33290fcaa2Sdrh unsigned int state[5];
34290fcaa2Sdrh unsigned int count[2];
35290fcaa2Sdrh unsigned char buffer[64];
36290fcaa2Sdrh };
37290fcaa2Sdrh
38290fcaa2Sdrh /*
39290fcaa2Sdrh ** All global variables are gathered into the "g" singleton.
40290fcaa2Sdrh */
41290fcaa2Sdrh struct GlobalVars {
42290fcaa2Sdrh const char *zArgv0; /* Name of program */
43290fcaa2Sdrh unsigned fDebug; /* Debug flags */
44290fcaa2Sdrh sqlite3 *db; /* The database connection */
45290fcaa2Sdrh SHA1Context cx; /* SHA1 hash context */
46290fcaa2Sdrh } g;
47290fcaa2Sdrh
487c4942cbSdrh /*
497c4942cbSdrh ** Debugging flags
507c4942cbSdrh */
517c4942cbSdrh #define DEBUG_FULLTRACE 0x00000001 /* Trace hash to stderr */
527c4942cbSdrh
53290fcaa2Sdrh /******************************************************************************
54290fcaa2Sdrh ** The Hash Engine
55290fcaa2Sdrh **
56290fcaa2Sdrh ** Modify these routines (and appropriate state fields in global variable 'g')
57290fcaa2Sdrh ** in order to compute a different (better?) hash of the database.
58290fcaa2Sdrh */
59290fcaa2Sdrh /*
60290fcaa2Sdrh * blk0() and blk() perform the initial expand.
61290fcaa2Sdrh * I got the idea of expanding during the round function from SSLeay
62290fcaa2Sdrh *
63290fcaa2Sdrh * blk0le() for little-endian and blk0be() for big-endian.
64290fcaa2Sdrh */
65290fcaa2Sdrh #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
66290fcaa2Sdrh #define rol(x,k) SHA_ROT(x,k,32-(k))
67290fcaa2Sdrh #define ror(x,k) SHA_ROT(x,32-(k),k)
68290fcaa2Sdrh
69290fcaa2Sdrh #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
70290fcaa2Sdrh |(rol(block[i],8)&0x00FF00FF))
71290fcaa2Sdrh #define blk0be(i) block[i]
72290fcaa2Sdrh #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
73290fcaa2Sdrh ^block[(i+2)&15]^block[i&15],1))
74290fcaa2Sdrh
75290fcaa2Sdrh /*
76290fcaa2Sdrh * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
77290fcaa2Sdrh *
78290fcaa2Sdrh * Rl0() for little-endian and Rb0() for big-endian. Endianness is
79290fcaa2Sdrh * determined at run-time.
80290fcaa2Sdrh */
81290fcaa2Sdrh #define Rl0(v,w,x,y,z,i) \
82290fcaa2Sdrh z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
83290fcaa2Sdrh #define Rb0(v,w,x,y,z,i) \
84290fcaa2Sdrh z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
85290fcaa2Sdrh #define R1(v,w,x,y,z,i) \
86290fcaa2Sdrh z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
87290fcaa2Sdrh #define R2(v,w,x,y,z,i) \
88290fcaa2Sdrh z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
89290fcaa2Sdrh #define R3(v,w,x,y,z,i) \
90290fcaa2Sdrh z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
91290fcaa2Sdrh #define R4(v,w,x,y,z,i) \
92290fcaa2Sdrh z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
93290fcaa2Sdrh
94290fcaa2Sdrh /*
95290fcaa2Sdrh * Hash a single 512-bit block. This is the core of the algorithm.
96290fcaa2Sdrh */
97290fcaa2Sdrh #define a qq[0]
98290fcaa2Sdrh #define b qq[1]
99290fcaa2Sdrh #define c qq[2]
100290fcaa2Sdrh #define d qq[3]
101290fcaa2Sdrh #define e qq[4]
102290fcaa2Sdrh
SHA1Transform(unsigned int state[5],const unsigned char buffer[64])103290fcaa2Sdrh void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
104290fcaa2Sdrh unsigned int qq[5]; /* a, b, c, d, e; */
105290fcaa2Sdrh static int one = 1;
106290fcaa2Sdrh unsigned int block[16];
107290fcaa2Sdrh memcpy(block, buffer, 64);
108290fcaa2Sdrh memcpy(qq,state,5*sizeof(unsigned int));
109290fcaa2Sdrh
110290fcaa2Sdrh /* Copy g.cx.state[] to working vars */
111290fcaa2Sdrh /*
112290fcaa2Sdrh a = state[0];
113290fcaa2Sdrh b = state[1];
114290fcaa2Sdrh c = state[2];
115290fcaa2Sdrh d = state[3];
116290fcaa2Sdrh e = state[4];
117290fcaa2Sdrh */
118290fcaa2Sdrh
119290fcaa2Sdrh /* 4 rounds of 20 operations each. Loop unrolled. */
120290fcaa2Sdrh if( 1 == *(unsigned char*)&one ){
121290fcaa2Sdrh Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
122290fcaa2Sdrh Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
123290fcaa2Sdrh Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
124290fcaa2Sdrh Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
125290fcaa2Sdrh }else{
126290fcaa2Sdrh Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
127290fcaa2Sdrh Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
128290fcaa2Sdrh Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
129290fcaa2Sdrh Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
130290fcaa2Sdrh }
131290fcaa2Sdrh R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
132290fcaa2Sdrh R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
133290fcaa2Sdrh R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
134290fcaa2Sdrh R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
135290fcaa2Sdrh R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
136290fcaa2Sdrh R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
137290fcaa2Sdrh R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
138290fcaa2Sdrh R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
139290fcaa2Sdrh R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
140290fcaa2Sdrh R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
141290fcaa2Sdrh R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
142290fcaa2Sdrh R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
143290fcaa2Sdrh R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
144290fcaa2Sdrh R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
145290fcaa2Sdrh R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
146290fcaa2Sdrh R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
147290fcaa2Sdrh
148290fcaa2Sdrh /* Add the working vars back into context.state[] */
149290fcaa2Sdrh state[0] += a;
150290fcaa2Sdrh state[1] += b;
151290fcaa2Sdrh state[2] += c;
152290fcaa2Sdrh state[3] += d;
153290fcaa2Sdrh state[4] += e;
154290fcaa2Sdrh }
155290fcaa2Sdrh
156290fcaa2Sdrh
157290fcaa2Sdrh /* Initialize the SHA1 hash */
hash_init(void)158290fcaa2Sdrh static void hash_init(void){
159290fcaa2Sdrh /* SHA1 initialization constants */
160290fcaa2Sdrh g.cx.state[0] = 0x67452301;
161290fcaa2Sdrh g.cx.state[1] = 0xEFCDAB89;
162290fcaa2Sdrh g.cx.state[2] = 0x98BADCFE;
163290fcaa2Sdrh g.cx.state[3] = 0x10325476;
164290fcaa2Sdrh g.cx.state[4] = 0xC3D2E1F0;
165290fcaa2Sdrh g.cx.count[0] = g.cx.count[1] = 0;
166290fcaa2Sdrh }
167290fcaa2Sdrh
168290fcaa2Sdrh /* Add new content to the SHA1 hash */
hash_step(const unsigned char * data,unsigned int len)169290fcaa2Sdrh static void hash_step(const unsigned char *data, unsigned int len){
170290fcaa2Sdrh unsigned int i, j;
171290fcaa2Sdrh
172290fcaa2Sdrh j = g.cx.count[0];
173290fcaa2Sdrh if( (g.cx.count[0] += len << 3) < j ){
174290fcaa2Sdrh g.cx.count[1] += (len>>29)+1;
175290fcaa2Sdrh }
176290fcaa2Sdrh j = (j >> 3) & 63;
177290fcaa2Sdrh if( (j + len) > 63 ){
178290fcaa2Sdrh (void)memcpy(&g.cx.buffer[j], data, (i = 64-j));
179290fcaa2Sdrh SHA1Transform(g.cx.state, g.cx.buffer);
180290fcaa2Sdrh for(; i + 63 < len; i += 64){
181290fcaa2Sdrh SHA1Transform(g.cx.state, &data[i]);
182290fcaa2Sdrh }
183290fcaa2Sdrh j = 0;
184290fcaa2Sdrh }else{
185290fcaa2Sdrh i = 0;
186290fcaa2Sdrh }
187290fcaa2Sdrh (void)memcpy(&g.cx.buffer[j], &data[i], len - i);
188290fcaa2Sdrh }
189290fcaa2Sdrh
190290fcaa2Sdrh
191290fcaa2Sdrh /* Add padding and compute and output the message digest. */
hash_finish(const char * zName)1927c4942cbSdrh static void hash_finish(const char *zName){
193290fcaa2Sdrh unsigned int i;
194290fcaa2Sdrh unsigned char finalcount[8];
195290fcaa2Sdrh unsigned char digest[20];
196290fcaa2Sdrh static const char zEncode[] = "0123456789abcdef";
1971d5721a7Sdrh char zOut[41];
198290fcaa2Sdrh
199290fcaa2Sdrh for (i = 0; i < 8; i++){
200290fcaa2Sdrh finalcount[i] = (unsigned char)((g.cx.count[(i >= 4 ? 0 : 1)]
201290fcaa2Sdrh >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
202290fcaa2Sdrh }
203290fcaa2Sdrh hash_step((const unsigned char *)"\200", 1);
204290fcaa2Sdrh while ((g.cx.count[0] & 504) != 448){
205290fcaa2Sdrh hash_step((const unsigned char *)"\0", 1);
206290fcaa2Sdrh }
207290fcaa2Sdrh hash_step(finalcount, 8); /* Should cause a SHA1Transform() */
208290fcaa2Sdrh for (i = 0; i < 20; i++){
209290fcaa2Sdrh digest[i] = (unsigned char)((g.cx.state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
210290fcaa2Sdrh }
211290fcaa2Sdrh for(i=0; i<20; i++){
212290fcaa2Sdrh zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
213290fcaa2Sdrh zOut[i*2+1] = zEncode[digest[i] & 0xf];
214290fcaa2Sdrh }
215290fcaa2Sdrh zOut[i*2]= 0;
2167c4942cbSdrh printf("%s %s\n", zOut, zName);
217290fcaa2Sdrh }
218290fcaa2Sdrh /* End of the hashing logic
219290fcaa2Sdrh *******************************************************************************/
220290fcaa2Sdrh
221290fcaa2Sdrh /*
222290fcaa2Sdrh ** Print an error resulting from faulting command-line arguments and
223290fcaa2Sdrh ** abort the program.
224290fcaa2Sdrh */
cmdlineError(const char * zFormat,...)225290fcaa2Sdrh static void cmdlineError(const char *zFormat, ...){
226290fcaa2Sdrh va_list ap;
227290fcaa2Sdrh fprintf(stderr, "%s: ", g.zArgv0);
228290fcaa2Sdrh va_start(ap, zFormat);
229290fcaa2Sdrh vfprintf(stderr, zFormat, ap);
230290fcaa2Sdrh va_end(ap);
231290fcaa2Sdrh fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0);
232290fcaa2Sdrh exit(1);
233290fcaa2Sdrh }
234290fcaa2Sdrh
235290fcaa2Sdrh /*
236290fcaa2Sdrh ** Print an error message for an error that occurs at runtime, then
237290fcaa2Sdrh ** abort the program.
238290fcaa2Sdrh */
runtimeError(const char * zFormat,...)239290fcaa2Sdrh static void runtimeError(const char *zFormat, ...){
240290fcaa2Sdrh va_list ap;
241290fcaa2Sdrh fprintf(stderr, "%s: ", g.zArgv0);
242290fcaa2Sdrh va_start(ap, zFormat);
243290fcaa2Sdrh vfprintf(stderr, zFormat, ap);
244290fcaa2Sdrh va_end(ap);
245290fcaa2Sdrh fprintf(stderr, "\n");
246290fcaa2Sdrh exit(1);
247290fcaa2Sdrh }
248290fcaa2Sdrh
249290fcaa2Sdrh /*
250290fcaa2Sdrh ** Prepare a new SQL statement. Print an error and abort if anything
251290fcaa2Sdrh ** goes wrong.
252290fcaa2Sdrh */
db_vprepare(const char * zFormat,va_list ap)253290fcaa2Sdrh static sqlite3_stmt *db_vprepare(const char *zFormat, va_list ap){
254290fcaa2Sdrh char *zSql;
255290fcaa2Sdrh int rc;
256290fcaa2Sdrh sqlite3_stmt *pStmt;
257290fcaa2Sdrh
258290fcaa2Sdrh zSql = sqlite3_vmprintf(zFormat, ap);
259290fcaa2Sdrh if( zSql==0 ) runtimeError("out of memory");
260290fcaa2Sdrh rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0);
261290fcaa2Sdrh if( rc ){
262290fcaa2Sdrh runtimeError("SQL statement error: %s\n\"%s\"", sqlite3_errmsg(g.db),
263290fcaa2Sdrh zSql);
264290fcaa2Sdrh }
265290fcaa2Sdrh sqlite3_free(zSql);
266290fcaa2Sdrh return pStmt;
267290fcaa2Sdrh }
db_prepare(const char * zFormat,...)268290fcaa2Sdrh static sqlite3_stmt *db_prepare(const char *zFormat, ...){
269290fcaa2Sdrh va_list ap;
270290fcaa2Sdrh sqlite3_stmt *pStmt;
271290fcaa2Sdrh va_start(ap, zFormat);
272290fcaa2Sdrh pStmt = db_vprepare(zFormat, ap);
273290fcaa2Sdrh va_end(ap);
274290fcaa2Sdrh return pStmt;
275290fcaa2Sdrh }
276290fcaa2Sdrh
277290fcaa2Sdrh /*
2787c4942cbSdrh ** Compute the hash for all rows of the query formed from the printf-style
2797c4942cbSdrh ** zFormat and its argument.
280290fcaa2Sdrh */
hash_one_query(const char * zFormat,...)2817c4942cbSdrh static void hash_one_query(const char *zFormat, ...){
2827c4942cbSdrh va_list ap;
2837c4942cbSdrh sqlite3_stmt *pStmt; /* The query defined by zFormat and "..." */
2847c4942cbSdrh int nCol; /* Number of columns in the result set */
2857c4942cbSdrh int i; /* Loop counter */
2867c4942cbSdrh
2877c4942cbSdrh /* Prepare the query defined by zFormat and "..." */
2887c4942cbSdrh va_start(ap, zFormat);
2897c4942cbSdrh pStmt = db_vprepare(zFormat, ap);
2907c4942cbSdrh va_end(ap);
291290fcaa2Sdrh nCol = sqlite3_column_count(pStmt);
2927c4942cbSdrh
2937c4942cbSdrh /* Compute a hash over the result of the query */
294290fcaa2Sdrh while( SQLITE_ROW==sqlite3_step(pStmt) ){
295290fcaa2Sdrh for(i=0; i<nCol; i++){
296290fcaa2Sdrh switch( sqlite3_column_type(pStmt,i) ){
297290fcaa2Sdrh case SQLITE_NULL: {
298290fcaa2Sdrh hash_step((const unsigned char*)"0",1);
2997c4942cbSdrh if( g.fDebug & DEBUG_FULLTRACE ) fprintf(stderr, "NULL\n");
300290fcaa2Sdrh break;
301290fcaa2Sdrh }
302290fcaa2Sdrh case SQLITE_INTEGER: {
303290fcaa2Sdrh sqlite3_uint64 u;
304290fcaa2Sdrh int j;
305290fcaa2Sdrh unsigned char x[8];
306290fcaa2Sdrh sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
307290fcaa2Sdrh memcpy(&u, &v, 8);
308290fcaa2Sdrh for(j=7; j>=0; j--){
309290fcaa2Sdrh x[j] = u & 0xff;
310290fcaa2Sdrh u >>= 8;
311290fcaa2Sdrh }
312290fcaa2Sdrh hash_step((const unsigned char*)"1",1);
313290fcaa2Sdrh hash_step(x,8);
3147c4942cbSdrh if( g.fDebug & DEBUG_FULLTRACE ){
3157c4942cbSdrh fprintf(stderr, "INT %s\n", sqlite3_column_text(pStmt,i));
3167c4942cbSdrh }
317290fcaa2Sdrh break;
318290fcaa2Sdrh }
319290fcaa2Sdrh case SQLITE_FLOAT: {
320290fcaa2Sdrh sqlite3_uint64 u;
321290fcaa2Sdrh int j;
322290fcaa2Sdrh unsigned char x[8];
323290fcaa2Sdrh double r = sqlite3_column_double(pStmt,i);
324290fcaa2Sdrh memcpy(&u, &r, 8);
325290fcaa2Sdrh for(j=7; j>=0; j--){
326290fcaa2Sdrh x[j] = u & 0xff;
327290fcaa2Sdrh u >>= 8;
328290fcaa2Sdrh }
329290fcaa2Sdrh hash_step((const unsigned char*)"2",1);
330290fcaa2Sdrh hash_step(x,8);
3317c4942cbSdrh if( g.fDebug & DEBUG_FULLTRACE ){
3327c4942cbSdrh fprintf(stderr, "FLOAT %s\n", sqlite3_column_text(pStmt,i));
3337c4942cbSdrh }
334290fcaa2Sdrh break;
335290fcaa2Sdrh }
336290fcaa2Sdrh case SQLITE_TEXT: {
337290fcaa2Sdrh int n = sqlite3_column_bytes(pStmt, i);
338290fcaa2Sdrh const unsigned char *z = sqlite3_column_text(pStmt, i);
339290fcaa2Sdrh hash_step((const unsigned char*)"3", 1);
340290fcaa2Sdrh hash_step(z, n);
3417c4942cbSdrh if( g.fDebug & DEBUG_FULLTRACE ){
3427c4942cbSdrh fprintf(stderr, "TEXT '%s'\n", sqlite3_column_text(pStmt,i));
3437c4942cbSdrh }
344290fcaa2Sdrh break;
345290fcaa2Sdrh }
346290fcaa2Sdrh case SQLITE_BLOB: {
347290fcaa2Sdrh int n = sqlite3_column_bytes(pStmt, i);
348290fcaa2Sdrh const unsigned char *z = sqlite3_column_blob(pStmt, i);
349290fcaa2Sdrh hash_step((const unsigned char*)"4", 1);
350290fcaa2Sdrh hash_step(z, n);
3517c4942cbSdrh if( g.fDebug & DEBUG_FULLTRACE ){
3527c4942cbSdrh fprintf(stderr, "BLOB (%d bytes)\n", n);
3537c4942cbSdrh }
354290fcaa2Sdrh break;
355290fcaa2Sdrh }
356290fcaa2Sdrh }
357290fcaa2Sdrh }
358290fcaa2Sdrh }
359290fcaa2Sdrh sqlite3_finalize(pStmt);
360290fcaa2Sdrh }
361290fcaa2Sdrh
362290fcaa2Sdrh
363290fcaa2Sdrh /*
364290fcaa2Sdrh ** Print sketchy documentation for this utility program
365290fcaa2Sdrh */
showHelp(void)366290fcaa2Sdrh static void showHelp(void){
3677c4942cbSdrh printf("Usage: %s [options] FILE ...\n", g.zArgv0);
368290fcaa2Sdrh printf(
3697c4942cbSdrh "Compute a SHA1 hash on the content of database FILE. System tables such as\n"
3707c4942cbSdrh "sqlite_stat1, sqlite_stat4, and sqlite_sequence are omitted from the hash.\n"
3717c4942cbSdrh "Options:\n"
3727c4942cbSdrh " --debug N Set debugging flags to N (experts only)\n"
3737c4942cbSdrh " --like PATTERN Only hash tables whose name is LIKE the pattern\n"
3747c4942cbSdrh " --schema-only Only hash the schema - omit table content\n"
3757c4942cbSdrh " --without-schema Only hash table content - omit the schema\n"
376290fcaa2Sdrh );
377290fcaa2Sdrh }
378290fcaa2Sdrh
main(int argc,char ** argv)379290fcaa2Sdrh int main(int argc, char **argv){
3807c4942cbSdrh const char *zDb = 0; /* Name of the database currently being hashed */
3817c4942cbSdrh int i; /* Loop counter */
3827c4942cbSdrh int rc; /* Subroutine return code */
3837c4942cbSdrh char *zErrMsg; /* Error message when opening database */
3847c4942cbSdrh sqlite3_stmt *pStmt; /* An SQLite query */
3857c4942cbSdrh const char *zLike = 0; /* LIKE pattern of tables to hash */
3867c4942cbSdrh int omitSchema = 0; /* True to compute hash on content only */
3877c4942cbSdrh int omitContent = 0; /* True to compute hash on schema only */
3887c4942cbSdrh int nFile = 0; /* Number of input filenames seen */
389290fcaa2Sdrh
390290fcaa2Sdrh g.zArgv0 = argv[0];
391290fcaa2Sdrh sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
392290fcaa2Sdrh for(i=1; i<argc; i++){
393290fcaa2Sdrh const char *z = argv[i];
394290fcaa2Sdrh if( z[0]=='-' ){
395290fcaa2Sdrh z++;
396290fcaa2Sdrh if( z[0]=='-' ) z++;
397290fcaa2Sdrh if( strcmp(z,"debug")==0 ){
398290fcaa2Sdrh if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]);
399290fcaa2Sdrh g.fDebug = strtol(argv[++i], 0, 0);
400290fcaa2Sdrh }else
401290fcaa2Sdrh if( strcmp(z,"help")==0 ){
402290fcaa2Sdrh showHelp();
403290fcaa2Sdrh return 0;
404290fcaa2Sdrh }else
4057c4942cbSdrh if( strcmp(z,"like")==0 ){
4067c4942cbSdrh if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]);
4077c4942cbSdrh if( zLike!=0 ) cmdlineError("only one --like allowed");
4087c4942cbSdrh zLike = argv[++i];
4097c4942cbSdrh }else
4107c4942cbSdrh if( strcmp(z,"schema-only")==0 ){
4117c4942cbSdrh omitContent = 1;
4127c4942cbSdrh }else
4137c4942cbSdrh if( strcmp(z,"without-schema")==0 ){
4147c4942cbSdrh omitSchema = 1;
415290fcaa2Sdrh }else
416290fcaa2Sdrh {
417290fcaa2Sdrh cmdlineError("unknown option: %s", argv[i]);
418290fcaa2Sdrh }
419290fcaa2Sdrh }else{
4207c4942cbSdrh nFile++;
4217c4942cbSdrh if( nFile<i ) argv[nFile] = argv[i];
422290fcaa2Sdrh }
423290fcaa2Sdrh }
4247c4942cbSdrh if( nFile==0 ){
4257c4942cbSdrh cmdlineError("no input files specified - nothing to do");
426290fcaa2Sdrh }
4277c4942cbSdrh if( omitSchema && omitContent ){
4287c4942cbSdrh cmdlineError("only one of --without-schema and --omit-schema allowed");
4297c4942cbSdrh }
4307c4942cbSdrh if( zLike==0 ) zLike = "%";
4317c4942cbSdrh
4327c4942cbSdrh for(i=1; i<=nFile; i++){
4337c4942cbSdrh static const int openFlags =
4347c4942cbSdrh SQLITE_OPEN_READWRITE | /* Read/write so hot journals can recover */
4357c4942cbSdrh SQLITE_OPEN_URI
4367c4942cbSdrh ;
4377c4942cbSdrh zDb = argv[i];
4387c4942cbSdrh rc = sqlite3_open_v2(zDb, &g.db, openFlags, 0);
439290fcaa2Sdrh if( rc ){
4407c4942cbSdrh fprintf(stderr, "cannot open database file '%s'\n", zDb);
4417c4942cbSdrh continue;
442290fcaa2Sdrh }
443*067b92baSdrh rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_schema", 0, 0, &zErrMsg);
444290fcaa2Sdrh if( rc || zErrMsg ){
4457c4942cbSdrh sqlite3_close(g.db);
4467c4942cbSdrh g.db = 0;
4477c4942cbSdrh fprintf(stderr, "'%s' is not a valid SQLite database\n", zDb);
4487c4942cbSdrh continue;
449290fcaa2Sdrh }
450290fcaa2Sdrh
4517c4942cbSdrh /* Start the hash */
4527c4942cbSdrh hash_init();
4537c4942cbSdrh
4547c4942cbSdrh /* Hash table content */
4557c4942cbSdrh if( !omitContent ){
456290fcaa2Sdrh pStmt = db_prepare(
457*067b92baSdrh "SELECT name FROM sqlite_schema\n"
458290fcaa2Sdrh " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
4597c4942cbSdrh " AND name NOT LIKE 'sqlite_%%'\n"
4607c4942cbSdrh " AND name LIKE '%q'\n"
4617c4942cbSdrh " ORDER BY name COLLATE nocase;\n",
4627c4942cbSdrh zLike
463290fcaa2Sdrh );
464290fcaa2Sdrh while( SQLITE_ROW==sqlite3_step(pStmt) ){
4657c4942cbSdrh /* We want rows of the table to be hashed in PRIMARY KEY order.
4667c4942cbSdrh ** Technically, an ORDER BY clause is required to guarantee that
4677c4942cbSdrh ** order. However, though not guaranteed by the documentation, every
4687c4942cbSdrh ** historical version of SQLite has always output rows in PRIMARY KEY
4697c4942cbSdrh ** order when there is no WHERE or GROUP BY clause, so the ORDER BY
4707c4942cbSdrh ** can be safely omitted. */
4717c4942cbSdrh hash_one_query("SELECT * FROM \"%w\"", sqlite3_column_text(pStmt,0));
472290fcaa2Sdrh }
4737c4942cbSdrh sqlite3_finalize(pStmt);
4747c4942cbSdrh }
475290fcaa2Sdrh
4767c4942cbSdrh /* Hash the database schema */
4777c4942cbSdrh if( !omitSchema ){
4787c4942cbSdrh hash_one_query(
479*067b92baSdrh "SELECT type, name, tbl_name, sql FROM sqlite_schema\n"
4807c4942cbSdrh " WHERE tbl_name LIKE '%q'\n"
4817c4942cbSdrh " ORDER BY name COLLATE nocase;\n",
4827c4942cbSdrh zLike
4837c4942cbSdrh );
4847c4942cbSdrh }
4857c4942cbSdrh
4867c4942cbSdrh /* Finish and output the hash and close the database connection. */
4877c4942cbSdrh hash_finish(zDb);
488290fcaa2Sdrh sqlite3_close(g.db);
4897c4942cbSdrh }
490290fcaa2Sdrh return 0;
491290fcaa2Sdrh }
492