| ︙ | | | ︙ | |
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
** and located at the root of the local copy of the source tree.
**
*/
#include "config.h"
#if ! defined(_WIN32)
# include <pwd.h>
#endif
#include <sqlite3.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include "db.h"
#if INTERFACE
/*
** An single SQL statement is represented as an instance of the following
** structure.
*/
struct Stmt {
Blob sql; /* The SQL for this statement */
sqlite3_stmt *pStmt; /* The results of sqlite3_prepare() */
Stmt *pNext, *pPrev; /* List of all unfinalized statements */
int nStep; /* Number of sqlite3_step() calls */
};
/*
** Copy this to initialize a Stmt object to a clean/empty state. This
** is useful to help avoid assertions when performing cleanup in some
** error handling cases.
*/
|
|
|
|
|
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
** and located at the root of the local copy of the source tree.
**
*/
#include "config.h"
#if ! defined(_WIN32)
# include <pwd.h>
#endif
#include <sqlite4.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include "db.h"
#if INTERFACE
/*
** An single SQL statement is represented as an instance of the following
** structure.
*/
struct Stmt {
Blob sql; /* The SQL for this statement */
sqlite4_stmt *pStmt; /* The results of sqlite4_prepare() */
Stmt *pNext, *pPrev; /* List of all unfinalized statements */
int nStep; /* Number of sqlite4_step() calls */
};
/*
** Copy this to initialize a Stmt object to a clean/empty state. This
** is useful to help avoid assertions when performing cleanup in some
** error handling cases.
*/
|
| ︙ | | | ︙ | |
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
** the following structure.
*/
static struct DbLocalData {
int nBegin; /* Nesting depth of BEGIN */
int doRollback; /* True to force a rollback */
int nCommitHook; /* Number of commit hooks */
Stmt *pAllStmt; /* List of all unfinalized statements */
int nPrepare; /* Number of calls to sqlite3_prepare() */
int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
struct sCommitHook {
int (*xHook)(void); /* Functions to call at db_end_transaction() */
int sequence; /* Call functions in sequence order */
} aHook[5];
char *azDeleteOnFail[3]; /* Files to delete on a failure */
char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
int nBeforeCommit; /* Number of entries in azBeforeCommit */
int nPriorChanges; /* sqlite3_total_changes() at transaction start */
} db = {0, 0, 0, 0, 0, 0, };
/*
** Arrange for the given file to be deleted on a failure.
*/
void db_delete_on_failure(const char *zFilename){
assert( db.nDeleteOnFail<count(db.azDeleteOnFail) );
|
|
|
|
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
** the following structure.
*/
static struct DbLocalData {
int nBegin; /* Nesting depth of BEGIN */
int doRollback; /* True to force a rollback */
int nCommitHook; /* Number of commit hooks */
Stmt *pAllStmt; /* List of all unfinalized statements */
int nPrepare; /* Number of calls to sqlite4_prepare() */
int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
struct sCommitHook {
int (*xHook)(void); /* Functions to call at db_end_transaction() */
int sequence; /* Call functions in sequence order */
} aHook[5];
char *azDeleteOnFail[3]; /* Files to delete on a failure */
char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
int nBeforeCommit; /* Number of entries in azBeforeCommit */
int nPriorChanges; /* sqlite4_total_changes() at transaction start */
} db = {0, 0, 0, 0, 0, 0, };
/*
** Arrange for the given file to be deleted on a failure.
*/
void db_delete_on_failure(const char *zFilename){
assert( db.nDeleteOnFail<count(db.azDeleteOnFail) );
|
| ︙ | | | ︙ | |
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
/*
** Begin and end a nested transaction
*/
void db_begin_transaction(void){
if( db.nBegin==0 ){
db_multi_exec("BEGIN");
sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
db.nPriorChanges = sqlite3_total_changes(g.db);
}
db.nBegin++;
}
void db_end_transaction(int rollbackFlag){
if( g.db==0 ) return;
if( db.nBegin<=0 ) return;
if( rollbackFlag ) db.doRollback = 1;
db.nBegin--;
if( db.nBegin==0 ){
int i;
if( db.doRollback==0 && db.nPriorChanges<sqlite3_total_changes(g.db) ){
while( db.nBeforeCommit ){
db.nBeforeCommit--;
sqlite3_exec(g.db, db.azBeforeCommit[db.nBeforeCommit], 0, 0, 0);
sqlite3_free(db.azBeforeCommit[db.nBeforeCommit]);
}
leaf_do_pending_checks();
}
for(i=0; db.doRollback==0 && i<db.nCommitHook; i++){
db.doRollback |= db.aHook[i].xHook();
}
while( db.pAllStmt ){
db_finalize(db.pAllStmt);
}
db_multi_exec(db.doRollback ? "ROLLBACK" : "COMMIT");
db.doRollback = 0;
}
}
/*
** Force a rollback and shutdown the database
*/
void db_force_rollback(void){
int i;
static int busy = 0;
sqlite3_stmt *pStmt = 0;
if( busy || g.db==0 ) return;
busy = 1;
undo_rollback();
while( (pStmt = sqlite3_next_stmt(g.db,pStmt))!=0 ){
sqlite3_reset(pStmt);
}
while( db.pAllStmt ){
db_finalize(db.pAllStmt);
}
if( db.nBegin ){
sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0);
db.nBegin = 0;
}
busy = 0;
db_close(0);
for(i=0; i<db.nDeleteOnFail; i++){
file_delete(db.azDeleteOnFail[i]);
}
|
|
|
|
|
|
|
|
|
|
|
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
/*
** Begin and end a nested transaction
*/
void db_begin_transaction(void){
if( db.nBegin==0 ){
db_multi_exec("BEGIN");
/* sqlite3_commit_hook(g.db, db_verify_at_commit, 0); */
db.nPriorChanges = sqlite4_total_changes(g.db);
}
db.nBegin++;
}
void db_end_transaction(int rollbackFlag){
if( g.db==0 ) return;
if( db.nBegin<=0 ) return;
if( rollbackFlag ) db.doRollback = 1;
db.nBegin--;
if( db.nBegin==0 ){
int i;
if( db.doRollback==0 && db.nPriorChanges<sqlite4_total_changes(g.db) ){
while( db.nBeforeCommit ){
db.nBeforeCommit--;
sqlite4_exec(g.db, db.azBeforeCommit[db.nBeforeCommit], 0, 0, 0);
sqlite4_free(0, db.azBeforeCommit[db.nBeforeCommit]);
}
leaf_do_pending_checks();
}
for(i=0; db.doRollback==0 && i<db.nCommitHook; i++){
db.doRollback |= db.aHook[i].xHook();
}
while( db.pAllStmt ){
db_finalize(db.pAllStmt);
}
db_multi_exec(db.doRollback ? "ROLLBACK" : "COMMIT");
db.doRollback = 0;
}
}
/*
** Force a rollback and shutdown the database
*/
void db_force_rollback(void){
int i;
static int busy = 0;
sqlite4_stmt *pStmt = 0;
if( busy || g.db==0 ) return;
busy = 1;
undo_rollback();
while( (pStmt = sqlite4_next_stmt(g.db,pStmt))!=0 ){
sqlite4_reset(pStmt);
}
while( db.pAllStmt ){
db_finalize(db.pAllStmt);
}
if( db.nBegin ){
sqlite4_exec(g.db, "ROLLBACK", 0, 0, 0);
db.nBegin = 0;
}
busy = 0;
db_close(0);
for(i=0; i<db.nDeleteOnFail; i++){
file_delete(db.azDeleteOnFail[i]);
}
|
| ︙ | | | ︙ | |
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
int rc;
char *zSql;
blob_zero(&pStmt->sql);
blob_vappendf(&pStmt->sql, zFormat, ap);
va_end(ap);
zSql = blob_str(&pStmt->sql);
db.nPrepare++;
rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
if( rc!=0 && !errOk ){
db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
}
pStmt->pNext = pStmt->pPrev = 0;
pStmt->nStep = 0;
return rc;
}
int db_prepare(Stmt *pStmt, const char *zFormat, ...){
int rc;
|
|
|
|
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
int rc;
char *zSql;
blob_zero(&pStmt->sql);
blob_vappendf(&pStmt->sql, zFormat, ap);
va_end(ap);
zSql = blob_str(&pStmt->sql);
db.nPrepare++;
rc = sqlite4_prepare(g.db, zSql, -1, &pStmt->pStmt, 0);
if( rc!=0 && !errOk ){
db_err("%s\n%s", sqlite4_errmsg(g.db), zSql);
}
pStmt->pNext = pStmt->pPrev = 0;
pStmt->nStep = 0;
return rc;
}
int db_prepare(Stmt *pStmt, const char *zFormat, ...){
int rc;
|
| ︙ | | | ︙ | |
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
|
return rc;
}
/*
** Return the index of a bind parameter
*/
static int paramIdx(Stmt *pStmt, const char *zParamName){
int i = sqlite3_bind_parameter_index(pStmt->pStmt, zParamName);
if( i==0 ){
db_err("no such bind parameter: %s\nSQL: %b", zParamName, &pStmt->sql);
}
return i;
}
/*
** Bind an integer, string, or Blob value to a named parameter.
*/
int db_bind_int(Stmt *pStmt, const char *zParamName, int iValue){
return sqlite3_bind_int(pStmt->pStmt, paramIdx(pStmt, zParamName), iValue);
}
int db_bind_int64(Stmt *pStmt, const char *zParamName, i64 iValue){
return sqlite3_bind_int64(pStmt->pStmt, paramIdx(pStmt, zParamName), iValue);
}
int db_bind_double(Stmt *pStmt, const char *zParamName, double rValue){
return sqlite3_bind_double(pStmt->pStmt, paramIdx(pStmt, zParamName), rValue);
}
int db_bind_text(Stmt *pStmt, const char *zParamName, const char *zValue){
return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue,
-1, SQLITE_STATIC);
}
int db_bind_null(Stmt *pStmt, const char *zParamName){
return sqlite3_bind_null(pStmt->pStmt, paramIdx(pStmt, zParamName));
}
int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){
return sqlite3_bind_blob(pStmt->pStmt, paramIdx(pStmt, zParamName),
blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
}
/* bind_str() treats a Blob object like a TEXT string and binds it
** to the SQL variable. Constrast this to bind_blob() which treats
** the Blob object like an SQL BLOB.
*/
int db_bind_str(Stmt *pStmt, const char *zParamName, Blob *pBlob){
return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName),
blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
}
/*
** Step the SQL statement. Return either SQLITE_ROW or an error code
** or SQLITE_OK if the statement finishes successfully.
*/
int db_step(Stmt *pStmt){
int rc;
rc = sqlite3_step(pStmt->pStmt);
pStmt->nStep++;
return rc;
}
/*
** Print warnings if a query is inefficient.
*/
static void db_stats(Stmt *pStmt){
#ifdef FOSSIL_DEBUG
int c1, c2, c3;
const char *zSql = sqlite3_sql(pStmt->pStmt);
if( zSql==0 ) return;
c1 = sqlite3_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1);
c2 = sqlite3_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, 1);
c3 = sqlite3_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_SORT, 1);
if( c1>pStmt->nStep*4 && strstr(zSql,"/*scan*/")==0 ){
fossil_warning("%d scan steps for %d rows in [%s]", c1, pStmt->nStep, zSql);
}else if( c2 ){
fossil_warning("%d automatic index rows in [%s]", c2, zSql);
}else if( c3 && strstr(zSql,"/*sort*/")==0 && strstr(zSql,"/*scan*/")==0 ){
fossil_warning("sort w/o index in [%s]", zSql);
}
pStmt->nStep = 0;
#endif
}
/*
** Reset or finalize a statement.
*/
int db_reset(Stmt *pStmt){
int rc;
db_stats(pStmt);
rc = sqlite3_reset(pStmt->pStmt);
db_check_result(rc);
return rc;
}
int db_finalize(Stmt *pStmt){
int rc;
db_stats(pStmt);
blob_reset(&pStmt->sql);
rc = sqlite3_finalize(pStmt->pStmt);
db_check_result(rc);
pStmt->pStmt = 0;
if( pStmt->pNext ){
pStmt->pNext->pPrev = pStmt->pPrev;
}
if( pStmt->pPrev ){
pStmt->pPrev->pNext = pStmt->pNext;
}else if( db.pAllStmt==pStmt ){
db.pAllStmt = pStmt->pNext;
}
pStmt->pNext = 0;
pStmt->pPrev = 0;
return rc;
}
/*
** Return the rowid of the most recent insert
*/
i64 db_last_insert_rowid(void){
return sqlite3_last_insert_rowid(g.db);
}
/*
** Return the number of rows that were changed by the most recent
** INSERT, UPDATE, or DELETE. Auxiliary changes caused by triggers
** or other side effects are not counted.
*/
int db_changes(void){
return sqlite3_changes(g.db);
}
/*
** Extract text, integer, or blob values from the N-th column of the
** current row.
*/
int db_column_bytes(Stmt *pStmt, int N){
return sqlite3_column_bytes(pStmt->pStmt, N);
}
int db_column_int(Stmt *pStmt, int N){
return sqlite3_column_int(pStmt->pStmt, N);
}
i64 db_column_int64(Stmt *pStmt, int N){
return sqlite3_column_int64(pStmt->pStmt, N);
}
double db_column_double(Stmt *pStmt, int N){
return sqlite3_column_double(pStmt->pStmt, N);
}
const char *db_column_text(Stmt *pStmt, int N){
return (char*)sqlite3_column_text(pStmt->pStmt, N);
}
const char *db_column_raw(Stmt *pStmt, int N){
return (const char*)sqlite3_column_blob(pStmt->pStmt, N);
}
const char *db_column_name(Stmt *pStmt, int N){
return (char*)sqlite3_column_name(pStmt->pStmt, N);
}
int db_column_count(Stmt *pStmt){
return sqlite3_column_count(pStmt->pStmt);
}
char *db_column_malloc(Stmt *pStmt, int N){
return mprintf("%s", db_column_text(pStmt, N));
}
void db_column_blob(Stmt *pStmt, int N, Blob *pBlob){
blob_append(pBlob, sqlite3_column_blob(pStmt->pStmt, N),
sqlite3_column_bytes(pStmt->pStmt, N));
}
/*
** Initialize a blob to an ephermeral copy of the content of a
** column in the current row. The data in the blob will become
** invalid when the statement is stepped or reset.
*/
void db_ephemeral_blob(Stmt *pStmt, int N, Blob *pBlob){
blob_init(pBlob, sqlite3_column_blob(pStmt->pStmt, N),
sqlite3_column_bytes(pStmt->pStmt, N));
}
/*
** Check a result code. If it is not SQLITE_OK, print the
** corresponding error message and exit.
*/
void db_check_result(int rc){
if( rc!=SQLITE_OK ){
db_err("SQL error: %s", sqlite3_errmsg(g.db));
}
}
/*
** Execute a single prepared statement until it finishes.
*/
int db_exec(Stmt *pStmt){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
|
return rc;
}
/*
** Return the index of a bind parameter
*/
static int paramIdx(Stmt *pStmt, const char *zParamName){
int i = sqlite4_bind_parameter_index(pStmt->pStmt, zParamName);
if( i==0 ){
db_err("no such bind parameter: %s\nSQL: %b", zParamName, &pStmt->sql);
}
return i;
}
/*
** Bind an integer, string, or Blob value to a named parameter.
*/
int db_bind_int(Stmt *pStmt, const char *zParamName, int iValue){
return sqlite4_bind_int(pStmt->pStmt, paramIdx(pStmt, zParamName), iValue);
}
int db_bind_int64(Stmt *pStmt, const char *zParamName, i64 iValue){
return sqlite4_bind_int64(pStmt->pStmt, paramIdx(pStmt, zParamName), iValue);
}
int db_bind_double(Stmt *pStmt, const char *zParamName, double rValue){
return sqlite4_bind_double(pStmt->pStmt, paramIdx(pStmt, zParamName), rValue);
}
int db_bind_text(Stmt *pStmt, const char *zParamName, const char *zValue){
return sqlite4_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue,
-1, SQLITE_STATIC);
}
int db_bind_null(Stmt *pStmt, const char *zParamName){
return sqlite4_bind_null(pStmt->pStmt, paramIdx(pStmt, zParamName));
}
int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){
return sqlite4_bind_blob(pStmt->pStmt, paramIdx(pStmt, zParamName),
blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
}
/* bind_str() treats a Blob object like a TEXT string and binds it
** to the SQL variable. Constrast this to bind_blob() which treats
** the Blob object like an SQL BLOB.
*/
int db_bind_str(Stmt *pStmt, const char *zParamName, Blob *pBlob){
return sqlite4_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName),
blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
}
/*
** Step the SQL statement. Return either SQLITE_ROW or an error code
** or SQLITE_OK if the statement finishes successfully.
*/
int db_step(Stmt *pStmt){
int rc;
rc = sqlite4_step(pStmt->pStmt);
pStmt->nStep++;
return rc;
}
/*
** Print warnings if a query is inefficient.
*/
static void db_stats(Stmt *pStmt){
#ifdef FOSSIL_DEBUG
int c1, c2, c3;
const char *zSql = sqlite4_sql(pStmt->pStmt);
if( zSql==0 ) return;
c1 = sqlite4_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1);
c2 = sqlite4_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, 1);
c3 = sqlite4_stmt_status(pStmt->pStmt, SQLITE_STMTSTATUS_SORT, 1);
if( c1>pStmt->nStep*4 && strstr(zSql,"/*scan*/")==0 ){
fossil_warning("%d scan steps for %d rows in [%s]", c1, pStmt->nStep, zSql);
}else if( c2 ){
fossil_warning("%d automatic index rows in [%s]", c2, zSql);
}else if( c3 && strstr(zSql,"/*sort*/")==0 && strstr(zSql,"/*scan*/")==0 ){
fossil_warning("sort w/o index in [%s]", zSql);
}
pStmt->nStep = 0;
#endif
}
/*
** Reset or finalize a statement.
*/
int db_reset(Stmt *pStmt){
int rc;
db_stats(pStmt);
rc = sqlite4_reset(pStmt->pStmt);
db_check_result(rc);
return rc;
}
int db_finalize(Stmt *pStmt){
int rc;
db_stats(pStmt);
blob_reset(&pStmt->sql);
rc = sqlite4_finalize(pStmt->pStmt);
db_check_result(rc);
pStmt->pStmt = 0;
if( pStmt->pNext ){
pStmt->pNext->pPrev = pStmt->pPrev;
}
if( pStmt->pPrev ){
pStmt->pPrev->pNext = pStmt->pNext;
}else if( db.pAllStmt==pStmt ){
db.pAllStmt = pStmt->pNext;
}
pStmt->pNext = 0;
pStmt->pPrev = 0;
return rc;
}
/*
** Return the rowid of the most recent insert
*/
i64 db_last_insert_rowid(void){
return sqlite4_last_insert_rowid(g.db);
}
/*
** Return the number of rows that were changed by the most recent
** INSERT, UPDATE, or DELETE. Auxiliary changes caused by triggers
** or other side effects are not counted.
*/
int db_changes(void){
return sqlite4_changes(g.db);
}
/*
** Extract text, integer, or blob values from the N-th column of the
** current row.
*/
int db_column_bytes(Stmt *pStmt, int N){
return sqlite4_column_bytes(pStmt->pStmt, N);
}
int db_column_int(Stmt *pStmt, int N){
return sqlite4_column_int(pStmt->pStmt, N);
}
i64 db_column_int64(Stmt *pStmt, int N){
return sqlite4_column_int64(pStmt->pStmt, N);
}
double db_column_double(Stmt *pStmt, int N){
return sqlite4_column_double(pStmt->pStmt, N);
}
const char *db_column_text(Stmt *pStmt, int N){
return (char*)sqlite4_column_text(pStmt->pStmt, N);
}
const char *db_column_raw(Stmt *pStmt, int N){
return (const char*)sqlite4_column_blob(pStmt->pStmt, N);
}
const char *db_column_name(Stmt *pStmt, int N){
return (char*)sqlite4_column_name(pStmt->pStmt, N);
}
int db_column_count(Stmt *pStmt){
return sqlite4_column_count(pStmt->pStmt);
}
char *db_column_malloc(Stmt *pStmt, int N){
return mprintf("%s", db_column_text(pStmt, N));
}
void db_column_blob(Stmt *pStmt, int N, Blob *pBlob){
blob_append(pBlob, sqlite4_column_blob(pStmt->pStmt, N),
sqlite4_column_bytes(pStmt->pStmt, N));
}
/*
** Initialize a blob to an ephermeral copy of the content of a
** column in the current row. The data in the blob will become
** invalid when the statement is stepped or reset.
*/
void db_ephemeral_blob(Stmt *pStmt, int N, Blob *pBlob){
blob_init(pBlob, sqlite4_column_blob(pStmt->pStmt, N),
sqlite4_column_bytes(pStmt->pStmt, N));
}
/*
** Check a result code. If it is not SQLITE_OK, print the
** corresponding error message and exit.
*/
void db_check_result(int rc){
if( rc!=SQLITE_OK ){
db_err("SQL error: %s", sqlite4_errmsg(g.db));
}
}
/*
** Execute a single prepared statement until it finishes.
*/
int db_exec(Stmt *pStmt){
|
| ︙ | | | ︙ | |
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
|
int rc;
va_list ap;
char *zErr = 0;
blob_init(&sql, 0, 0);
va_start(ap, zSql);
blob_vappendf(&sql, zSql, ap);
va_end(ap);
rc = sqlite3_exec(g.db, blob_buffer(&sql), 0, 0, &zErr);
if( rc!=SQLITE_OK ){
db_err("%s\n%s", zErr, blob_buffer(&sql));
}
blob_reset(&sql);
return rc;
}
/*
** Optionally make the following changes to the database if feasible and
** convenient. Do not start a transaction for these changes, but only
** make these changes if other changes are also being made.
*/
void db_optional_sql(const char *zDb, const char *zSql, ...){
if( db_is_writeable(zDb) && db.nBeforeCommit < count(db.azBeforeCommit) ){
va_list ap;
va_start(ap, zSql);
db.azBeforeCommit[db.nBeforeCommit++] = sqlite3_vmprintf(zSql, ap);
va_end(ap);
}
}
/*
** Execute a query and return a single integer value.
*/
|
|
|
|
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
|
int rc;
va_list ap;
char *zErr = 0;
blob_init(&sql, 0, 0);
va_start(ap, zSql);
blob_vappendf(&sql, zSql, ap);
va_end(ap);
rc = sqlite4_exec(g.db, blob_buffer(&sql), 0, 0, &zErr);
if( rc!=SQLITE_OK ){
db_err("%s\n%s", zErr, blob_buffer(&sql));
}
blob_reset(&sql);
return rc;
}
/*
** Optionally make the following changes to the database if feasible and
** convenient. Do not start a transaction for these changes, but only
** make these changes if other changes are also being made.
*/
void db_optional_sql(const char *zDb, const char *zSql, ...){
if( db_is_writeable(zDb) && db.nBeforeCommit < count(db.azBeforeCommit) ){
va_list ap;
va_start(ap, zSql);
db.azBeforeCommit[db.nBeforeCommit++] = sqlite4_vmprintf(0, zSql, ap);
va_end(ap);
}
}
/*
** Execute a query and return a single integer value.
*/
|
| ︙ | | | ︙ | |
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
|
void db_blob(Blob *pResult, const char *zSql, ...){
va_list ap;
Stmt s;
va_start(ap, zSql);
db_vprepare(&s, 0, zSql, ap);
va_end(ap);
if( db_step(&s)==SQLITE_ROW ){
blob_append(pResult, sqlite3_column_blob(s.pStmt, 0),
sqlite3_column_bytes(s.pStmt, 0));
}
db_finalize(&s);
}
/*
** Execute a query. Return the first column of the first row
** of the result set as a string. Space to hold the string is
** obtained from malloc(). If the result set is empty, return
** zDefault instead.
*/
char *db_text(char const *zDefault, const char *zSql, ...){
va_list ap;
Stmt s;
char *z;
va_start(ap, zSql);
db_vprepare(&s, 0, zSql, ap);
va_end(ap);
if( db_step(&s)==SQLITE_ROW ){
z = mprintf("%s", sqlite3_column_text(s.pStmt, 0));
}else if( zDefault ){
z = mprintf("%s", zDefault);
}else{
z = 0;
}
db_finalize(&s);
return z;
}
/*
** Initialize a new database file with the given schema. If anything
** goes wrong, call db_err() to exit.
*/
void db_init_database(
const char *zFileName, /* Name of database file to create */
const char *zSchema, /* First part of schema */
... /* Additional SQL to run. Terminate with NULL. */
){
sqlite3 *db;
int rc;
const char *zSql;
va_list ap;
rc = sqlite3_open(zFileName, &db);
if( rc!=SQLITE_OK ){
db_err(sqlite3_errmsg(db));
}
sqlite3_busy_timeout(db, 5000);
sqlite3_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
rc = sqlite3_exec(db, zSchema, 0, 0, 0);
if( rc!=SQLITE_OK ){
db_err(sqlite3_errmsg(db));
}
va_start(ap, zSchema);
while( (zSql = va_arg(ap, const char*))!=0 ){
rc = sqlite3_exec(db, zSql, 0, 0, 0);
if( rc!=SQLITE_OK ){
db_err(sqlite3_errmsg(db));
}
}
va_end(ap);
sqlite3_exec(db, "COMMIT", 0, 0, 0);
sqlite3_close(db);
}
/*
** Function to return the number of seconds since 1970. This is
** the same as strftime('%s','now') but is more compact.
*/
void db_now_function(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3_result_int64(context, time(0));
}
/*
** Open a database file. Return a pointer to the new database
** connection. An error results in process abort.
*/
static sqlite3 *openDatabase(const char *zDbName){
int rc;
const char *zVfs;
sqlite3 *db;
zVfs = fossil_getenv("FOSSIL_VFS");
rc = sqlite3_open_v2(
zDbName, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
zVfs
);
if( rc!=SQLITE_OK ){
db_err(sqlite3_errmsg(db));
}
sqlite3_busy_timeout(db, 5000);
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
return db;
}
/*
** zDbName is the name of a database file. If no other database
** file is open, then open this one. If another database file is
|
|
|
|
|
|
>
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|
<
<
|
|
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
|
void db_blob(Blob *pResult, const char *zSql, ...){
va_list ap;
Stmt s;
va_start(ap, zSql);
db_vprepare(&s, 0, zSql, ap);
va_end(ap);
if( db_step(&s)==SQLITE_ROW ){
blob_append(pResult, sqlite4_column_blob(s.pStmt, 0),
sqlite4_column_bytes(s.pStmt, 0));
}
db_finalize(&s);
}
/*
** Execute a query. Return the first column of the first row
** of the result set as a string. Space to hold the string is
** obtained from malloc(). If the result set is empty, return
** zDefault instead.
*/
char *db_text(char const *zDefault, const char *zSql, ...){
va_list ap;
Stmt s;
char *z;
va_start(ap, zSql);
db_vprepare(&s, 0, zSql, ap);
va_end(ap);
if( db_step(&s)==SQLITE_ROW ){
z = mprintf("%s", sqlite4_column_text(s.pStmt, 0));
}else if( zDefault ){
z = mprintf("%s", zDefault);
}else{
z = 0;
}
db_finalize(&s);
return z;
}
/*
** Initialize a new database file with the given schema. If anything
** goes wrong, call db_err() to exit.
*/
void db_init_database(
const char *zFileName, /* Name of database file to create */
const char *zSchema, /* First part of schema */
... /* Additional SQL to run. Terminate with NULL. */
){
sqlite4 *db;
int rc;
const char *zSql;
va_list ap;
rc = sqlite4_open(0, zFileName, &db,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
if( rc!=SQLITE_OK ){
db_err(sqlite4_errmsg(db));
}
sqlite4_exec(db, "BEGIN EXCLUSIVE", 0, 0, 0);
rc = sqlite4_exec(db, zSchema, 0, 0, 0);
if( rc!=SQLITE_OK ){
db_err(sqlite4_errmsg(db));
}
va_start(ap, zSchema);
while( (zSql = va_arg(ap, const char*))!=0 ){
rc = sqlite4_exec(db, zSql, 0, 0, 0);
if( rc!=SQLITE_OK ){
db_err(sqlite4_errmsg(db));
}
}
va_end(ap);
sqlite4_exec(db, "COMMIT", 0, 0, 0);
sqlite4_close(db);
}
/*
** Function to return the number of seconds since 1970. This is
** the same as strftime('%s','now') but is more compact.
*/
void db_now_function(
sqlite4_context *context,
int argc,
sqlite4_value **argv
){
sqlite4_result_int64(context, time(0));
}
/*
** Open a database file. Return a pointer to the new database
** connection. An error results in process abort.
*/
static sqlite4 *openDatabase(const char *zDbName){
int rc;
const char *zVfs;
sqlite4 *db;
zVfs = fossil_getenv("FOSSIL_VFS");
rc = sqlite4_open(0,
zDbName, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
);
if( rc!=SQLITE_OK ){
db_err(sqlite4_errmsg(db));
}
sqlite4_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
return db;
}
/*
** zDbName is the name of a database file. If no other database
** file is open, then open this one. If another database file is
|
| ︙ | | | ︙ | |
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
|
if( g.localOpen) return 1;
file_getcwd(zPwd, sizeof(zPwd)-20);
n = strlen(zPwd);
if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
while( n>0 ){
if( file_access(zPwd, W_OK) ) break;
for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){
sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "%s", aDbName[i]);
if( isValidLocalDb(zPwd) ){
/* Found a valid checkout database file */
zPwd[n] = 0;
while( n>1 && zPwd[n-1]=='/' ){
n--;
zPwd[n] = 0;
}
|
|
|
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
|
if( g.localOpen) return 1;
file_getcwd(zPwd, sizeof(zPwd)-20);
n = strlen(zPwd);
if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
while( n>0 ){
if( file_access(zPwd, W_OK) ) break;
for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){
sqlite4_snprintf(zPwd+n, sizeof(zPwd)-n, "%s", aDbName[i]);
if( isValidLocalDb(zPwd) ){
/* Found a valid checkout database file */
zPwd[n] = 0;
while( n>1 && zPwd[n-1]=='/' ){
n--;
zPwd[n] = 0;
}
|
| ︙ | | | ︙ | |
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
|
" AND value<>'%s'", AUX_SCHEMA);
}
/*
** Return true if the database is writeable
*/
int db_is_writeable(const char *zName){
return !sqlite3_db_readonly(g.db, db_name(zName));
}
/*
** Verify that the repository schema is correct. If it is not correct,
** issue a fatal error and die.
*/
void db_verify_schema(void){
|
|
|
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
|
" AND value<>'%s'", AUX_SCHEMA);
}
/*
** Return true if the database is writeable
*/
int db_is_writeable(const char *zName){
return 1; /* !sqlite4_db_readonly(g.db, db_name(zName)); */
}
/*
** Verify that the repository schema is correct. If it is not correct,
** issue a fatal error and die.
*/
void db_verify_schema(void){
|
| ︙ | | | ︙ | |
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
|
/*
** Close the database connection.
**
** Check for unfinalized statements and report errors if the reportErrors
** argument is true. Ignore unfinalized statements when false.
*/
void db_close(int reportErrors){
sqlite3_stmt *pStmt;
if( g.db==0 ) return;
if( g.fSqlStats ){
int cur, hiwtr;
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
fprintf(stderr, "-- LOOKASIDE_HIT %10d\n", hiwtr);
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &cur,&hiwtr,0);
fprintf(stderr, "-- LOOKASIDE_MISS_SIZE %10d\n", hiwtr);
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &cur,&hiwtr,0);
fprintf(stderr, "-- LOOKASIDE_MISS_FULL %10d\n", hiwtr);
sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- CACHE_USED %10d\n", cur);
sqlite3_db_status(g.db, SQLITE_DBSTATUS_SCHEMA_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- SCHEMA_USED %10d\n", cur);
sqlite3_db_status(g.db, SQLITE_DBSTATUS_STMT_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- STMT_USED %10d\n", cur);
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- MEMORY_USED %10d %10d\n", cur, hiwtr);
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &cur, &hiwtr, 0);
fprintf(stderr, "-- MALLOC_SIZE %10d\n", hiwtr);
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &cur, &hiwtr, 0);
fprintf(stderr, "-- MALLOC_COUNT %10d %10d\n", cur, hiwtr);
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &cur, &hiwtr, 0);
fprintf(stderr, "-- PCACHE_OVFLOW %10d %10d\n", cur, hiwtr);
fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
}
while( db.pAllStmt ){
db_finalize(db.pAllStmt);
}
db_end_transaction(1);
pStmt = 0;
if( reportErrors ){
while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
}
}
g.repositoryOpen = 0;
g.localOpen = 0;
g.configOpen = 0;
sqlite3_wal_checkpoint(g.db, 0);
sqlite3_close(g.db);
g.db = 0;
if( g.dbConfig ){
sqlite3_close(g.dbConfig);
g.dbConfig = 0;
}
}
/*
** Create a new empty repository database with the given name.
|
|
|
|
|
|
|
|
|
|
|
|
<
<
|
|
<
|
|
|
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
|
/*
** Close the database connection.
**
** Check for unfinalized statements and report errors if the reportErrors
** argument is true. Ignore unfinalized statements when false.
*/
void db_close(int reportErrors){
sqlite4_stmt *pStmt;
if( g.db==0 ) return;
if( g.fSqlStats ){
int cur, hiwtr;
sqlite4_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- LOOKASIDE_USED %10d %10d\n", cur, hiwtr);
sqlite4_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &cur, &hiwtr, 0);
fprintf(stderr, "-- LOOKASIDE_HIT %10d\n", hiwtr);
sqlite4_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &cur,&hiwtr,0);
fprintf(stderr, "-- LOOKASIDE_MISS_SIZE %10d\n", hiwtr);
sqlite4_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &cur,&hiwtr,0);
fprintf(stderr, "-- LOOKASIDE_MISS_FULL %10d\n", hiwtr);
sqlite4_db_status(g.db, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- CACHE_USED %10d\n", cur);
sqlite4_db_status(g.db, SQLITE_DBSTATUS_SCHEMA_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- SCHEMA_USED %10d\n", cur);
sqlite4_db_status(g.db, SQLITE_DBSTATUS_STMT_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- STMT_USED %10d\n", cur);
sqlite4_env_status(0, SQLITE_ENVSTATUS_MEMORY_USED, &cur, &hiwtr, 0);
fprintf(stderr, "-- MEMORY_USED %10d %10d\n", cur, hiwtr);
sqlite4_env_status(0, SQLITE_ENVSTATUS_MALLOC_SIZE, &cur, &hiwtr, 0);
fprintf(stderr, "-- MALLOC_SIZE %10d\n", hiwtr);
sqlite4_env_status(0, SQLITE_ENVSTATUS_MALLOC_COUNT, &cur, &hiwtr, 0);
fprintf(stderr, "-- MALLOC_COUNT %10d %10d\n", cur, hiwtr);
fprintf(stderr, "-- prepared statements %10d\n", db.nPrepare);
}
while( db.pAllStmt ){
db_finalize(db.pAllStmt);
}
db_end_transaction(1);
pStmt = 0;
if( reportErrors ){
while( (pStmt = sqlite4_next_stmt(g.db, pStmt))!=0 ){
fossil_warning("unfinalized SQL statement: [%s]", sqlite4_sql(pStmt));
}
}
g.repositoryOpen = 0;
g.localOpen = 0;
g.configOpen = 0;
sqlite4_close(g.db);
g.db = 0;
if( g.dbConfig ){
sqlite4_close(g.dbConfig);
g.dbConfig = 0;
}
}
/*
** Create a new empty repository database with the given name.
|
| ︙ | | | ︙ | |
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
|
/*
** SQL functions for debugging.
**
** The print() function writes its arguments on stdout, but only
** if the -sqlprint command-line option is turned on.
*/
static void db_sql_print(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int i;
if( g.fSqlPrint ){
for(i=0; i<argc; i++){
char c = i==argc-1 ? '\n' : ' ';
fossil_print("%s%c", sqlite3_value_text(argv[i]), c);
}
}
}
static void db_sql_trace(void *notUsed, const char *zSql){
int n = strlen(zSql);
char *zMsg = mprintf("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
fossil_puts(zMsg, 1);
fossil_free(zMsg);
}
/*
** Implement the user() SQL function. user() takes no arguments and
** returns the user ID of the current user.
*/
static void db_sql_user(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
if( g.zLogin!=0 ){
sqlite3_result_text(context, g.zLogin, -1, SQLITE_STATIC);
}
}
/*
** Implement the cgi() SQL function. cgi() takes a an argument which is
** a name of CGI query parameter. The value of that parameter is returned,
** if available. optional second argument will be returned if the first
** doesn't exist as a CGI parameter.
*/
static void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
const char* zP;
if( argc!=1 && argc!=2 ) return;
zP = P((const char*)sqlite3_value_text(argv[0]));
if( zP ){
sqlite3_result_text(context, zP, -1, SQLITE_STATIC);
}else if( argc==2 ){
zP = (const char*)sqlite3_value_text(argv[1]);
if( zP ) sqlite3_result_text(context, zP, -1, SQLITE_TRANSIENT);
}
}
/*
** This is used by the [commit] command.
**
** Return true if either:
**
** a) Global.aCommitFile is NULL, or
** b) Global.aCommitFile contains the integer passed as an argument.
**
** Otherwise return false.
*/
static void file_is_selected(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
assert(argc==1);
if( g.aCommitFile ){
int iId = sqlite3_value_int(argv[0]);
int ii;
for(ii=0; g.aCommitFile[ii]; ii++){
if( iId==g.aCommitFile[ii] ){
sqlite3_result_int(context, 1);
return;
}
}
sqlite3_result_int(context, 0);
}else{
sqlite3_result_int(context, 1);
}
}
/*
** Convert the input string into an SHA1. Make a notation in the
** CONCEALED table so that the hash can be undo using the db_reveal()
** function at some later time.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
|
/*
** SQL functions for debugging.
**
** The print() function writes its arguments on stdout, but only
** if the -sqlprint command-line option is turned on.
*/
static void db_sql_print(
sqlite4_context *context,
int argc,
sqlite4_value **argv
){
int i;
if( g.fSqlPrint ){
for(i=0; i<argc; i++){
char c = i==argc-1 ? '\n' : ' ';
fossil_print("%s%c", sqlite4_value_text(argv[i]), c);
}
}
}
static void db_sql_trace(void *notUsed, const char *zSql){
int n = strlen(zSql);
char *zMsg = mprintf("%s%s\n", zSql, (n>0 && zSql[n-1]==';') ? "" : ";");
fossil_puts(zMsg, 1);
fossil_free(zMsg);
}
/*
** Implement the user() SQL function. user() takes no arguments and
** returns the user ID of the current user.
*/
static void db_sql_user(
sqlite4_context *context,
int argc,
sqlite4_value **argv
){
if( g.zLogin!=0 ){
sqlite4_result_text(context, g.zLogin, -1, SQLITE_STATIC);
}
}
/*
** Implement the cgi() SQL function. cgi() takes a an argument which is
** a name of CGI query parameter. The value of that parameter is returned,
** if available. optional second argument will be returned if the first
** doesn't exist as a CGI parameter.
*/
static void db_sql_cgi(sqlite4_context *context, int argc, sqlite4_value **argv){
const char* zP;
if( argc!=1 && argc!=2 ) return;
zP = P((const char*)sqlite4_value_text(argv[0]));
if( zP ){
sqlite4_result_text(context, zP, -1, SQLITE_STATIC);
}else if( argc==2 ){
zP = (const char*)sqlite4_value_text(argv[1]);
if( zP ) sqlite4_result_text(context, zP, -1, SQLITE_TRANSIENT);
}
}
/*
** This is used by the [commit] command.
**
** Return true if either:
**
** a) Global.aCommitFile is NULL, or
** b) Global.aCommitFile contains the integer passed as an argument.
**
** Otherwise return false.
*/
static void file_is_selected(
sqlite4_context *context,
int argc,
sqlite4_value **argv
){
assert(argc==1);
if( g.aCommitFile ){
int iId = sqlite4_value_int(argv[0]);
int ii;
for(ii=0; g.aCommitFile[ii]; ii++){
if( iId==g.aCommitFile[ii] ){
sqlite4_result_int(context, 1);
return;
}
}
sqlite4_result_int(context, 0);
}else{
sqlite4_result_int(context, 1);
}
}
/*
** Convert the input string into an SHA1. Make a notation in the
** CONCEALED table so that the hash can be undo using the db_reveal()
** function at some later time.
|
| ︙ | | | ︙ | |
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
|
Blob out;
if( n==40 && validate16(zContent, n) ){
memcpy(zHash, zContent, n);
zHash[n] = 0;
}else{
sha1sum_step_text(zContent, n);
sha1sum_finish(&out);
sqlite3_snprintf(sizeof(zHash), zHash, "%s", blob_str(&out));
blob_reset(&out);
db_multi_exec(
"INSERT OR IGNORE INTO concealed(hash,content,mtime)"
" VALUES(%Q,%#Q,now())",
zHash, n, zContent
);
}
|
|
|
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
|
Blob out;
if( n==40 && validate16(zContent, n) ){
memcpy(zHash, zContent, n);
zHash[n] = 0;
}else{
sha1sum_step_text(zContent, n);
sha1sum_finish(&out);
sqlite4_snprintf(zHash, sizeof(zHash), "%s", blob_str(&out));
blob_reset(&out);
db_multi_exec(
"INSERT OR IGNORE INTO concealed(hash,content,mtime)"
" VALUES(%Q,%#Q,now())",
zHash, n, zContent
);
}
|
| ︙ | | | ︙ | |
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
|
}
/*
** This function registers auxiliary functions when the SQLite
** database connection is first established.
*/
LOCAL void db_connection_init(void){
sqlite3_exec(g.db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
sqlite3_create_function(g.db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
sqlite3_create_function(g.db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
sqlite3_create_function(g.db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
sqlite3_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
sqlite3_create_function(
g.db, "file_is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
);
if( g.fSqlTrace ){
sqlite3_trace(g.db, db_sql_trace, 0);
}
}
/*
** Return true if the string zVal represents "true" (or "false").
*/
int is_truth(const char *zVal){
|
|
|
|
|
|
|
|
|
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
|
}
/*
** This function registers auxiliary functions when the SQLite
** database connection is first established.
*/
LOCAL void db_connection_init(void){
sqlite4_exec(g.db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
sqlite4_create_function(g.db, "user", 0, SQLITE_ANY, 0, db_sql_user, 0, 0);
sqlite4_create_function(g.db, "cgi", 1, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
sqlite4_create_function(g.db, "cgi", 2, SQLITE_ANY, 0, db_sql_cgi, 0, 0);
sqlite4_create_function(g.db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
sqlite4_create_function(
g.db, "file_is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
);
if( g.fSqlTrace ){
sqlite4_trace(g.db, db_sql_trace, 0);
}
}
/*
** Return true if the string zVal represents "true" (or "false").
*/
int is_truth(const char *zVal){
|
| ︙ | | | ︙ | |
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
|
**
** If g.useAttach that means the ~/.fossil database was opened with
** the useAttach flag set to 1. In that case no connection swap is required
** so this routine is a no-op.
*/
void db_swap_connections(void){
if( !g.useAttach ){
sqlite3 *dbTemp = g.db;
g.db = g.dbConfig;
g.dbConfig = dbTemp;
}
}
/*
** Logic for reading potentially versioned settings from
|
|
|
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
|
**
** If g.useAttach that means the ~/.fossil database was opened with
** the useAttach flag set to 1. In that case no connection swap is required
** so this routine is a no-op.
*/
void db_swap_connections(void){
if( !g.useAttach ){
sqlite4 *dbTemp = g.db;
g.db = g.dbConfig;
g.dbConfig = dbTemp;
}
}
/*
** Logic for reading potentially versioned settings from
|
| ︙ | | | ︙ | |
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
|
** describes that timespan in units of seconds, minutes, hours, days,
** or years, depending on its duration.
*/
char *db_timespan_name(double rSpan){
if( rSpan<0 ) rSpan = -rSpan;
rSpan *= 24.0*3600.0; /* Convert units to seconds */
if( rSpan<120.0 ){
return sqlite3_mprintf("%.1f seconds", rSpan);
}
rSpan /= 60.0; /* Convert units to minutes */
if( rSpan<90.0 ){
return sqlite3_mprintf("%.1f minutes", rSpan);
}
rSpan /= 60.0; /* Convert units to hours */
if( rSpan<=48.0 ){
return sqlite3_mprintf("%.1f hours", rSpan);
}
rSpan /= 24.0; /* Convert units to days */
if( rSpan<=365.0 ){
return sqlite3_mprintf("%.1f days", rSpan);
}
rSpan /= 356.24; /* Convert units to years */
return sqlite3_mprintf("%.1f years", rSpan);
}
/*
** COMMAND: test-timespan
** %fossil test-timespan TIMESTAMP
**
** Print the approximate span of time from now to TIMESTAMP.
*/
void test_timespan_cmd(void){
double rDiff;
if( g.argc!=3 ) usage("TIMESTAMP");
sqlite3_open(":memory:", &g.db);
rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]);
fossil_print("Time differences: %s\n", db_timespan_name(rDiff));
sqlite3_close(g.db);
g.db = 0;
}
|
|
|
|
|
|
|
|
|
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
|
** describes that timespan in units of seconds, minutes, hours, days,
** or years, depending on its duration.
*/
char *db_timespan_name(double rSpan){
if( rSpan<0 ) rSpan = -rSpan;
rSpan *= 24.0*3600.0; /* Convert units to seconds */
if( rSpan<120.0 ){
return sqlite4_mprintf(0, "%.1f seconds", rSpan);
}
rSpan /= 60.0; /* Convert units to minutes */
if( rSpan<90.0 ){
return sqlite4_mprintf(0, "%.1f minutes", rSpan);
}
rSpan /= 60.0; /* Convert units to hours */
if( rSpan<=48.0 ){
return sqlite4_mprintf(0, "%.1f hours", rSpan);
}
rSpan /= 24.0; /* Convert units to days */
if( rSpan<=365.0 ){
return sqlite4_mprintf(0, "%.1f days", rSpan);
}
rSpan /= 356.24; /* Convert units to years */
return sqlite4_mprintf(0, "%.1f years", rSpan);
}
/*
** COMMAND: test-timespan
** %fossil test-timespan TIMESTAMP
**
** Print the approximate span of time from now to TIMESTAMP.
*/
void test_timespan_cmd(void){
double rDiff;
if( g.argc!=3 ) usage("TIMESTAMP");
sqlite4_open(0, ":memory:", &g.db, SQLITE_OPEN_READWRITE);
rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]);
fossil_print("Time differences: %s\n", db_timespan_name(rDiff));
sqlite4_close(g.db);
g.db = 0;
}
|