/* -*- 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); }