Fossil SCM

fossil-scm / src / sqlcmd.c
Blame History Raw 435 lines
1
/*
2
** Copyright (c) 2010 D. Richard Hipp
3
**
4
** This program is free software; you can redistribute it and/or
5
** modify it under the terms of the Simplified BSD License (also
6
** known as the "2-Clause License" or "FreeBSD License".)
7
8
** This program is distributed in the hope that it will be useful,
9
** but without any warranty; without even the implied warranty of
10
** merchantability or fitness for a particular purpose.
11
**
12
** Author contact information:
13
** [email protected]
14
** http://www.hwaci.com/drh/
15
**
16
*******************************************************************************
17
**
18
** This module contains the code that initializes the "sqlite3" command-line
19
** shell against the repository database. The command-line shell itself
20
** is a copy of the "shell.c" code from SQLite. This file contains logic
21
** to initialize the code in shell.c.
22
*/
23
#include "config.h"
24
#include "sqlcmd.h"
25
#include <stdlib.h> /* atexit() */
26
#include <zlib.h>
27
#ifndef _WIN32
28
# include "linenoise.h"
29
#endif
30
31
/*
32
** True if the "fossil sql" command has the --test flag. False otherwise.
33
*/
34
static int local_bSqlCmdTest = 0;
35
36
/*
37
** Implementation of the "content(X)" SQL function. Return the complete
38
** content of artifact identified by X as a blob.
39
*/
40
static void sqlcmd_content(
41
sqlite3_context *context,
42
int argc,
43
sqlite3_value **argv
44
){
45
int rid;
46
Blob cx;
47
const char *zName;
48
assert( argc==1 );
49
zName = (const char*)sqlite3_value_text(argv[0]);
50
if( zName==0 ) return;
51
g.db = sqlite3_context_db_handle(context);
52
g.repositoryOpen = 1;
53
rid = name_to_rid(zName);
54
if( rid==0 ) return;
55
if( content_get(rid, &cx) ){
56
sqlite3_result_blob(context, blob_buffer(&cx), blob_size(&cx),
57
SQLITE_TRANSIENT);
58
blob_reset(&cx);
59
}
60
}
61
62
/*
63
** Implementation of the "compress(X)" SQL function. The input X is
64
** compressed using zLib and the output is returned.
65
*/
66
static void sqlcmd_compress(
67
sqlite3_context *context,
68
int argc,
69
sqlite3_value **argv
70
){
71
const unsigned char *pIn;
72
unsigned char *pOut;
73
unsigned int nIn;
74
unsigned long int nOut;
75
int rc;
76
77
pIn = sqlite3_value_blob(argv[0]);
78
nIn = sqlite3_value_bytes(argv[0]);
79
nOut = 13 + nIn + (nIn+999)/1000;
80
pOut = sqlite3_malloc( nOut+4 );
81
pOut[0] = nIn>>24 & 0xff;
82
pOut[1] = nIn>>16 & 0xff;
83
pOut[2] = nIn>>8 & 0xff;
84
pOut[3] = nIn & 0xff;
85
rc = compress(&pOut[4], &nOut, pIn, nIn);
86
if( rc==Z_OK ){
87
sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free);
88
}else if( rc==Z_MEM_ERROR ){
89
sqlite3_free(pOut);
90
sqlite3_result_error_nomem(context);
91
}else{
92
sqlite3_free(pOut);
93
sqlite3_result_error(context, "input cannot be zlib compressed", -1);
94
}
95
}
96
97
/*
98
** Implementation of the "decompress(X)" SQL function. The argument X
99
** is a blob which was obtained from compress(Y). The output will be
100
** the value Y.
101
*/
102
static void sqlcmd_decompress(
103
sqlite3_context *context,
104
int argc,
105
sqlite3_value **argv
106
){
107
const unsigned char *pIn;
108
unsigned char *pOut;
109
unsigned int nIn;
110
unsigned long int nOut;
111
int rc;
112
113
pIn = sqlite3_value_blob(argv[0]);
114
if( pIn==0 ) return;
115
nIn = sqlite3_value_bytes(argv[0]);
116
if( nIn<4 ) return;
117
nOut = (pIn[0]<<24) + (pIn[1]<<16) + (pIn[2]<<8) + pIn[3];
118
pOut = sqlite3_malloc( nOut+1 );
119
rc = uncompress(pOut, &nOut, &pIn[4], nIn-4);
120
if( rc==Z_OK ){
121
sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
122
}else if( rc==Z_MEM_ERROR ){
123
sqlite3_free(pOut);
124
sqlite3_result_error_nomem(context);
125
}else{
126
sqlite3_free(pOut);
127
sqlite3_result_error(context, "input is not zlib compressed", -1);
128
}
129
}
130
131
/*
132
** Implementation of the "gather_artifact_stats(X)" SQL function.
133
** That function merely calls the gather_artifact_stats() function
134
** in stat.c to populate the ARTSTAT temporary table.
135
*/
136
static void sqlcmd_gather_artifact_stats(
137
sqlite3_context *context,
138
int argc,
139
sqlite3_value **argv
140
){
141
gather_artifact_stats(1);
142
}
143
144
/*
145
** Add the content(), compress(), decompress(), and
146
** gather_artifact_stats() SQL functions to database connection db.
147
*/
148
int add_content_sql_commands(sqlite3 *db){
149
sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
150
sqlcmd_content, 0, 0);
151
sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
152
sqlcmd_compress, 0, 0);
153
sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0,
154
sqlcmd_decompress, 0, 0);
155
sqlite3_create_function(db, "gather_artifact_stats", 0, SQLITE_UTF8, 0,
156
sqlcmd_gather_artifact_stats, 0, 0);
157
return SQLITE_OK;
158
}
159
160
/*
161
** Undocumented test SQL functions:
162
**
163
** db_protect(X)
164
** db_protect_pop(X)
165
**
166
** These invoke the corresponding C routines.
167
**
168
** WARNING:
169
** Do not instantiate these functions for any Fossil webpage or command
170
** method other than the "fossil sql" command. If an attacker gains access
171
** to these functions, he will be able to disable other defense mechanisms.
172
**
173
** This routines are for interactive testing only. They are experimental
174
** and undocumented (apart from this comments) and might go away or change
175
** in future releases.
176
**
177
** 2020-11-29: These functions are now only available if the "fossil sql"
178
** command is started with the --test option.
179
*/
180
static void sqlcmd_db_protect(
181
sqlite3_context *context,
182
int argc,
183
sqlite3_value **argv
184
){
185
unsigned mask = 0;
186
const char *z = (const char*)sqlite3_value_text(argv[0]);
187
if( z!=0 && local_bSqlCmdTest ){
188
if( sqlite3_stricmp(z,"user")==0 ) mask |= PROTECT_USER;
189
if( sqlite3_stricmp(z,"config")==0 ) mask |= PROTECT_CONFIG;
190
if( sqlite3_stricmp(z,"sensitive")==0 ) mask |= PROTECT_SENSITIVE;
191
if( sqlite3_stricmp(z,"readonly")==0 ) mask |= PROTECT_READONLY;
192
if( sqlite3_stricmp(z,"all")==0 ) mask |= PROTECT_ALL;
193
db_protect(mask);
194
}
195
}
196
static void sqlcmd_db_protect_pop(
197
sqlite3_context *context,
198
int argc,
199
sqlite3_value **argv
200
){
201
if( !local_bSqlCmdTest ) db_protect_pop();
202
}
203
204
/*
205
** This is the "automatic extension" initializer that runs right after
206
** the connection to the repository database is opened. Set up the
207
** database connection to be more useful to the human operator.
208
*/
209
static int sqlcmd_autoinit(
210
sqlite3 *db,
211
const char **pzErrMsg,
212
const void *notUsed
213
){
214
int mTrace = SQLITE_TRACE_CLOSE;
215
add_content_sql_commands(db);
216
db_add_aux_functions(db);
217
re_add_sql_func(db);
218
search_sql_setup(db);
219
foci_register(db);
220
deltafunc_init(db);
221
helptext_vtab_register(db);
222
builtin_vtab_register(db);
223
g.repositoryOpen = 1;
224
g.db = db;
225
sqlite3_busy_timeout(db, 10000);
226
if( g.zRepositoryName ){
227
sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "repository");
228
db_maybe_set_encryption_key(db, g.zRepositoryName);
229
}
230
if( g.zLocalDbName ){
231
char *zSql = sqlite3_mprintf("ATTACH %Q AS 'localdb' KEY ''",
232
g.zLocalDbName);
233
sqlite3_exec(db, zSql, 0, 0, 0);
234
sqlite3_free(zSql);
235
}
236
if( g.zConfigDbName ){
237
char *zSql = sqlite3_mprintf("ATTACH %Q AS 'configdb' KEY ''",
238
g.zConfigDbName);
239
sqlite3_exec(db, zSql, 0, 0, 0);
240
sqlite3_free(zSql);
241
}
242
(void)timeline_query_for_tty(); /* Registers wiki_to_text() as side-effect */
243
/* Arrange to trace close operations so that static prepared statements
244
** will get cleaned up when the shell closes the database connection */
245
if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE;
246
sqlite3_trace_v2(db, mTrace, db_sql_trace, 0);
247
if( g.zRepositoryName ){
248
db_protect_only(PROTECT_NONE);
249
sqlite3_set_authorizer(db, db_top_authorizer, db);
250
if( local_bSqlCmdTest ){
251
sqlite3_create_function(db, "db_protect", 1, SQLITE_UTF8, 0,
252
sqlcmd_db_protect, 0, 0);
253
sqlite3_create_function(db, "db_protect_pop", 0, SQLITE_UTF8, 0,
254
sqlcmd_db_protect_pop, 0, 0);
255
sqlite3_create_function(db, "shared_secret", 2, SQLITE_UTF8, 0,
256
sha1_shared_secret_sql_function, 0, 0);
257
}
258
}
259
return SQLITE_OK;
260
}
261
262
/*
263
** atexit() handler that cleans up global state modified by this module.
264
*/
265
static void sqlcmd_atexit(void) {
266
g.zConfigDbName = 0; /* prevent panic */
267
}
268
269
/*
270
** This routine is called by the sqlite3 command-line shell to
271
** to load the name the Fossil repository database.
272
*/
273
void sqlcmd_get_dbname(const char **pzRepoName){
274
*pzRepoName = g.zRepositoryName;
275
}
276
277
/*
278
** This routine is called by the sqlite3 command-line shell to do
279
** extra initialization prior to starting up the shell.
280
*/
281
void sqlcmd_init_proc(void){
282
sqlite3_initialize();
283
sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit);
284
}
285
286
#if USE_SEE
287
/*
288
** This routine is called by the patched sqlite3 command-line shell in order
289
** to load the encryption key for the open Fossil database. The memory that
290
** is pointed to by the value placed in pzKey must be obtained from malloc.
291
*/
292
void fossil_key(const char **pzKey, int *pnKey){
293
char *zSavedKey = db_get_saved_encryption_key();
294
char *zKey;
295
size_t savedKeySize = db_get_saved_encryption_key_size();
296
297
if( !db_is_valid_saved_encryption_key(zSavedKey, savedKeySize) ) return;
298
zKey = (char*)malloc( savedKeySize );
299
if( zKey ){
300
memcpy(zKey, zSavedKey, savedKeySize);
301
*pzKey = zKey;
302
if( fossil_getenv("FOSSIL_USE_SEE_TEXTKEY")==0 ){
303
*pnKey = (int)strlen(zKey);
304
}else{
305
*pnKey = -1;
306
}
307
}else{
308
fossil_fatal("failed to allocate %u bytes for key", savedKeySize);
309
}
310
}
311
#endif
312
313
/*
314
** This routine closes the Fossil databases and/or invalidates the global
315
** state variables that keep track of them.
316
*/
317
static void fossil_close(int bDb, int noRepository){
318
if( bDb ) db_close(1);
319
if( noRepository ) g.zRepositoryName = 0;
320
g.db = 0;
321
g.repositoryOpen = 0;
322
g.localOpen = 0;
323
}
324
325
/*
326
** COMMAND: sql
327
** COMMAND: sqlite3*
328
**
329
** Usage: %fossil sql ?OPTIONS?
330
**
331
** Run the sqlite3 command-line shell on the Fossil repository
332
** identified by the -R option, or on the current repository.
333
** See https://www.sqlite.org/cli.html for additional information about
334
** the sqlite3 command-line shell.
335
**
336
** WARNING: Careless use of this command can corrupt a Fossil repository
337
** in ways that are unrecoverable. Be sure you know what you are doing before
338
** running any SQL commands that modify the repository database. Use the
339
** --readonly option to prevent accidental damage to the repository.
340
**
341
** Options:
342
** --no-repository Skip opening the repository database
343
** --readonly Open the repository read-only. No changes
344
** are allowed. This is a recommended safety
345
** precaution to prevent repository damage.
346
** -R REPOSITORY Use REPOSITORY as the repository database
347
** --test Enable some testing and analysis features
348
** that are normally disabled.
349
**
350
** All of the standard sqlite3 command-line shell options should also
351
** work.
352
**
353
** The following SQL extensions are provided with this Fossil-enhanced
354
** version of the sqlite3 command-line shell:
355
**
356
** builtin A virtual table that contains one row for
357
** each datafile that is built into the Fossil
358
** binary.
359
**
360
** checkin_mtime(X,Y) Return the mtime for the file Y (a BLOB.RID)
361
** found in check-in X (another BLOB.RID value).
362
**
363
** compress(X) Compress text X with the same algorithm used
364
** to compress artifacts in the BLOB table.
365
**
366
** content(X) Return the content of artifact X. X can be an
367
** artifact hash or hash prefix or a tag. Artifacts
368
** are stored compressed and deltaed. This function
369
** does all necessary decompression and undeltaing.
370
**
371
** decompress(X) Decompress text X. Undoes the work of
372
** compress(X).
373
**
374
** delta_apply(X,D) Apply delta D to source blob X and return
375
** the result.
376
**
377
** delta_create(X,Y) Create and return a delta that will convert
378
** X into Y.
379
**
380
** delta_output_size(D) Return the number of bytes of output to expect
381
** when applying delta D
382
**
383
** delta_parse(D) A table-valued function that deconstructs
384
** delta D and returns rows for each element of
385
** that delta.
386
**
387
** files_of_checkin(X) A table-valued function that returns info on
388
** all files contained in check-in X. Example:
389
**
390
** SELECT * FROM files_of_checkin('trunk');
391
**
392
** helptext A virtual table with one row for each command,
393
** webpage, and setting together with the built-in
394
** help text.
395
**
396
** now() Return the number of seconds since 1970.
397
**
398
** obscure(T) Obfuscate the text password T so that its
399
** original value is not readily visible. Fossil
400
** uses this same algorithm when storing passwords
401
** of remote URLs.
402
**
403
** regexp The REGEXP operator works, unlike in
404
** standard SQLite.
405
**
406
** symbolic_name_to_rid(X) Return the BLOB.RID corresponding to symbolic
407
** name X.
408
*/
409
void cmd_sqlite3(void){
410
int noRepository;
411
char *zConfigDb;
412
extern int sqlite3_shell(int, char**);
413
#ifdef FOSSIL_ENABLE_TH1_HOOKS
414
g.fNoThHook = 1;
415
#endif
416
noRepository = find_option("no-repository", 0, 0)!=0;
417
local_bSqlCmdTest = find_option("test",0,0)!=0;
418
if( !noRepository ){
419
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
420
}
421
db_open_config(1,0);
422
zConfigDb = fossil_strdup(g.zConfigDbName);
423
fossil_close(1, noRepository);
424
sqlite3_shutdown();
425
#ifndef _WIN32
426
linenoiseSetMultiLine(1);
427
#endif
428
atexit(sqlcmd_atexit);
429
g.zConfigDbName = zConfigDb;
430
g.argv[1] = "--noinit";
431
sqlite3_shell(g.argc, g.argv);
432
sqlite3_cancel_auto_extension((void(*)(void))sqlcmd_autoinit);
433
fossil_close(0, noRepository);
434
}
435

Keyboard Shortcuts

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