/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*
Copyright (c) 2013 D. Richard Hipp
This program is free software; you can redistribute it and/or
modify it under the terms of the Simplified BSD License (also
known as the "2-Clause License" or "FreeBSD License".)
This program is distributed in the hope that it will be useful,
but without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
Author contact information:
drh@hwaci.com
http://www.hwaci.com/drh/
*****************************************************************************
This file implements a basic 'ls' for in-repo content
(not yet filesystem-level).
*/
#include "fossil-scm/fossil-cli.h" /* Fossil App mini-framework */
/* #include "fossil-scm/fossil-internal.h" */
static void fcli_local_help(){
printf("Usage:\n\t%s [options] "
"-e SQL_CODE|FILE [-e SQL_CODE|FILE ...]\n\n", fcli.appName);
puts("Executes SQL against fossil repo/checkout databases. "
"When executing \"fetching\" queries (SELECT and friends) "
"the results are dumped to the fcli output "
"channel. Options:\n");
puts("\t--dry-run|-n forces a rollback of the implicit transaction "
"at completion.\n");
puts("\t--no-header|-h disables the display of the "
"column headers for fetching queries.\n");
puts("\t--no-transaction|-t disables automatic creation of a transaction. "
"Needed when ATTACH is used in script files.\n");
puts("\t--separator|-s=STRING sets the separator string for "
"result columns. Default=TAB. Use \\t and \\n for "
"TAB and NEWLINE, respectively.\n");
}
static struct {
char showHeaders;
char * separator;
} QueryApp = {
1/*showHeaders*/,
NULL/*separator*/
};
static int fsl_stmt_each_f_row( fsl_stmt * stmt, void * state ){
int i;
char const * sep = QueryApp.separator
? QueryApp.separator : "\t";
if('\\'==*sep){
/* Translate client-provided \t and \n */
switch(*(sep+1)){
case 't': sep = "\t"; break;
case 'n': sep = "\n"; break;
}
}
if((1==stmt->rowCount) && QueryApp.showHeaders){
for( i = 0; i < stmt->colCount; ++i){
f_out("%s%s", fsl_stmt_col_name(stmt, i),
(i<(stmt->colCount-1)) ? sep : "\n");
}
}
for( i = 0; i < stmt->colCount; ++i){
char const * col = fsl_stmt_g_text(stmt, i, NULL);
f_out("%s%s", col ? col : "NULL",
(i<(stmt->colCount-1)) ? sep : "\n");
}
return 0;
}
int main(int argc, char * const * argv ){
int rc = 0;
char * fname = NULL;
char * sql = NULL;
fsl_cx * f;
fsl_db * db;
char qCount = 0;
fsl_buffer scriptBuf = fsl_buffer_empty;
char noTransaction = 0;
fcli.appHelp = fcli_local_help;
rc = fcli_setup(argc, argv);
if(FSL_RC_BREAK==rc) /* --help */ return 0;
else if(rc) goto end;
/* Set up/validate args... */
f = fcli.f;
db = fsl_cx_db(f);
if(!db){
rc = fcli_err_set(FSL_RC_NOT_A_REPO,
"Requires an opened database. See --help.");
goto end;
}
noTransaction = fcli_flag2("t", "no-transaction", NULL);
QueryApp.showHeaders = !fcli_flag2("h", "no-header", NULL);
fcli_flag2("s", "separator", &QueryApp.separator);
if(!fcli.fDryRun){
fcli.fDryRun = fcli_flag("n", NULL);
}
rc = noTransaction ? 0 : fsl_db_transaction_begin(db);
while(!rc && fcli_flag("e", &sql)){
fsl_stmt st = fsl_stmt_empty;
fsl_buffer_reset(&scriptBuf);
if(0==fsl_file_access(sql,0)){
rc = fsl_buffer_fill_from_filename(&scriptBuf, sql);
if(rc){
fcli_err_set(rc, "Error %d (%s) loading SQL from file [%s]",
rc, fsl_rc_cstr(rc), sql);
fsl_free(sql);
sql = NULL;
goto end;
}
fsl_free(sql);
sql = (char *)scriptBuf.mem;
scriptBuf = fsl_buffer_empty /* xfer ownership to sql */;
}
++qCount;
rc = fsl_db_prepare(db, &st, "%s", sql);
fsl_free(sql);
sql = NULL;
if(!rc){
if(st.colCount){ /* SELECT-style query */
rc = fsl_stmt_each( &st, fsl_stmt_each_f_row, NULL );
}else{
rc = fsl_stmt_step(&st);
if(FSL_RC_STEP_ROW==rc || FSL_RC_STEP_DONE==rc) rc = 0;
}
}
fsl_stmt_finalize(&st);
if(rc) fsl_cx_uplift_db_error(f, db);
}
if(db->beginCount>0){
assert(!noTransaction);
if(rc || fcli.fDryRun){
FCLI_V(("Rolling back transaction.\n"));
fsl_db_transaction_rollback(db);
}else{
FCLI_V(("Committing transaction.\n"));
rc = fsl_db_transaction_commit(db);
if(rc) fsl_cx_uplift_db_error(f, db);
}
}
if(!qCount){
fcli_help();
rc = FSL_RC_MISUSE;
goto end;
}
end:
fsl_buffer_clear(&scriptBuf);
fsl_free(QueryApp.separator);
fsl_free(fname);
return fcli_end_of_main(rc);
}