
/****************************************************************************
 *
 * MODULE:       db.execute
 * AUTHOR(S):    Radim Blazek <radim.blazek gmail.com> (original contributor)
 *               Huidae Cho <grass4u gmail.com>, Glynn Clements <glynn gclements.plus.com>, Hamish Bowman <hamish_b yahoo.com>, Markus Neteler <neteler itc.it>, Stephan Holl
 * PURPOSE:      process one non-select sql statement
 * COPYRIGHT:    (C) 2002-2006, 2010 by the GRASS Development Team
 *
 *               This program is free software under the GNU General Public
 *               License (>=v2). Read the file COPYING that comes with GRASS
 *               for details.
 *
 *****************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <grass/gis.h>
#include <grass/dbmi.h>
#include <grass/codes.h>
#include <grass/glocale.h>


struct
{
    char *driver, *database, *input;
    int i;
} parms;


/* function prototypes */
static void parse_command_line(int, char **);
static int get_stmt(FILE *, dbString *);
static int stmt_is_empty(dbString *);


int main(int argc, char **argv)
{
    dbString stmt;
    dbDriver *driver;
    dbHandle handle;
    int ret;
    FILE *fd;
    const char *schema;
    int error = 0;

    parse_command_line(argc, argv);

    if (parms.input && strcmp(parms.input,"-") != 0) {
	fd = fopen(parms.input, "r");
	if (fd == NULL) {
	    perror(parms.input);
	    exit(EXIT_FAILURE);
	}
    }
    else
	fd = stdin;

    driver = db_start_driver(parms.driver);
    if (driver == NULL) {
	G_fatal_error(_("Unable to start driver <%s>"), parms.driver);
    }

    db_init_handle(&handle);
    schema = db_get_default_schema_name();
    db_set_handle(&handle, parms.database, schema);
    if (db_open_database(driver, &handle) != DB_OK)
	G_fatal_error(_("Unable to open database <%s>"), parms.database);

    while (get_stmt(fd, &stmt)) {
	if (!stmt_is_empty(&stmt)) {
	    G_debug(3, "sql: %s", db_get_string(&stmt));

	    ret = db_execute_immediate(driver, &stmt);

	    if (ret != DB_OK) {
		if (parms.i) {	/* ignore SQL errors */
		    G_warning(_("Error while executing: '%s'"),
			      db_get_string(&stmt));
		    error++;
		}
		else {
		    db_close_database(driver);
		    db_shutdown_driver(driver);
		    
		    G_fatal_error(_("Error while executing: '%s'"),
				  db_get_string(&stmt));
		}
	    }
	}
    }

    db_close_database(driver);
    db_shutdown_driver(driver);

    exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
}


static void parse_command_line(int argc, char **argv)
{
    struct Option *driver, *database, *input;
    struct Flag *i;
    struct GModule *module;
    const char *drv, *db;

    /* Initialize the GIS calls */
    G_gisinit(argv[0]);

    /* Set description */
    module = G_define_module();
    module->keywords = _("database, attribute table, SQL");
    module->description = _("Executes any SQL statement.");

    input = G_define_standard_option(G_OPT_F_INPUT);
    input->required = NO;
    input->label = _("Name of file containing SQL statements");
    input->guisection = _("Query");
    input->description = _("If not given or '-' read from standard input");
    
    driver = G_define_standard_option(G_OPT_DRIVER);
    driver->options = db_list_drivers();
    driver->guisection = _("Connection");
    if ((drv = db_get_default_driver_name()))
	driver->answer = (char *) drv;

    database = G_define_standard_option(G_OPT_DATABASE);
    database->guisection = _("Connection");
    if ((db = db_get_default_database_name()))
	database->answer = (char *) db;

    i = G_define_flag();
    i->key = 'i';
    i->description = _("Ignore SQL errors and continue");

    if (G_parser(argc, argv))
	exit(EXIT_SUCCESS);

    parms.driver = driver->answer;
    parms.database = database->answer;
    parms.input = input->answer;
    parms.i = i->answer;
}


static int get_stmt(FILE * fd, dbString * stmt)
{
    char buf[4000], buf2[4000];
    int len, row = 0;

    db_init_string(stmt);

    while (fgets(buf, 4000, fd) != NULL) {
	strcpy(buf2, buf);
	G_chop(buf2);
	len = strlen(buf2);

	if (buf2[len - 1] == ';') {	/* end of statement */
	    buf2[len - 1] = 0;	/* truncate ';' */
	    db_append_string(stmt, buf2);	/* append truncated */
	    return 1;
	}
	else {
	    db_append_string(stmt, buf);	/* append not truncated string (\n may be part of value) */
	}
	row++;
    }

    if (row > 0)
	return 1;

    return 0;
}


static int stmt_is_empty(dbString * stmt)
{
    char dummy[2];

    return (sscanf(db_get_string(stmt), "%1s", dummy) != 1);
}
