/*
 *    Program type:  API Interface
 *
 *    Description:
 *        This program performs a multi-database transaction
 *        with a two-phase commit.  A 'currency' field is updated
 *        in database 1 for table country, and corresponding
 *        'from_currency' or 'to_currency' fields are updated in
 *        database 2 for table cross_rate.  The transaction is
 *        committed only if all instances of the string are
 *        changed successfully in both databases.
 */

#include <stdlib.h>
#include <string.h>
#include <ibase.h>
#include <stdio.h>
#include "example.h"

#define BUFLEN        512
#define CURRENLEN    10

char    *sel_str1 =
    "SELECT currency FROM country WHERE country = 'Canada'";


int main (ARG(int, argc), ARG(char **, argv))
ARGLIST(int argc)
ARGLIST(char **argv)
{
    char                *country = "Canada";        /* passed as a parameter */
    char                *new_name = "CdnDollar";    /* passed as a parameter */
    char                orig_name[CURRENLEN + 1];
    char                buf[BUFLEN + 1];
    isc_db_handle       db1 = NULL,        /* handle for database 1 */
                        db2 = NULL;        /* handle for database 2 */
    isc_tr_handle       trans1 = NULL;     /* transaction handle */
    long                status[20];
    XSQLDA ISC_FAR *    sel_sqlda;
    isc_stmt_handle     stmt = NULL;
    long                stat1, stat2, stat3;
    char                empdb[128], empdb2[128];

    if (argc > 1)
        strcpy(empdb, argv[1]);
    else
        strcpy(empdb, "employee.gdb");
    if (argc > 2)
        strcpy(empdb2, argv[2]);
    else
        strcpy(empdb2, "employe2.gdb");


    /* Open database 1. */
    printf("Attaching to database %s\n", empdb);
    if (isc_attach_database(status, 0, empdb, &db1, 0, NULL))
    {
        ERREXIT(status, 1)
    }

    /* Open database 2. */
    printf ("Attaching to database %s\n", empdb2);
    if (isc_attach_database(status, 0, empdb2, &db2, 0, NULL))
    {
        ERREXIT(status, 1)
    }

    /* Start a two-database transaction. */
    if (isc_start_transaction(status, &trans1, 2, &db1, 0, NULL, &db2, 0, NULL))
    {
        ERREXIT(status, 1)
    }          

    /*
     *  Get the string, which is to be globally changed.
     */

    sprintf(buf, "SELECT currency FROM country WHERE country = '%s'", country);

    sel_sqlda = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH(1));
    sel_sqlda->sqln = 1;
    sel_sqlda->version = 1;
 
    if (isc_dsql_allocate_statement(status, &db1, &stmt))
    {
        ERREXIT(status, 1)
    }
    if (isc_dsql_prepare(status, &trans1, &stmt, 0, sel_str1, 1, sel_sqlda))
    {
        ERREXIT(status, 1)
    }
 
    sel_sqlda->sqlvar[0].sqldata = orig_name;
    sel_sqlda->sqlvar[0].sqltype = SQL_TEXT;
    sel_sqlda->sqlvar[0].sqllen = CURRENLEN;
 
    if (isc_dsql_execute(status, &trans1, &stmt, 1, NULL))
    {
        ERREXIT(status, 1)
    }
    if (isc_dsql_fetch(status, &stmt, 1, sel_sqlda))
    {
        ERREXIT(status, 1)
    }

    orig_name[CURRENLEN] = '\0';
    printf("Modifying currency string:  %s\n", orig_name);
                   
    /*
     *  Change the string in database 1.
     */

    sprintf(buf, "UPDATE country SET currency = '%s' WHERE country = 'Canada'",
            new_name);

    stat1 = 0L;
    if (isc_dsql_execute_immediate(status, &db1, &trans1, 0, buf, 1, NULL))
    {
        isc_print_status(status);
        stat1 = isc_sqlcode(status);
    }       

    /*
     *  Change all corresponding occurences of the string in database 2.
     */

    sprintf(buf, "UPDATE cross_rate SET from_currency = '%s' WHERE \
            from_currency = '%s'", new_name, orig_name);

    stat2 = 0L;
    if (isc_dsql_execute_immediate(status, &db2, &trans1, 0, buf, 1, NULL))
    {
        isc_print_status(status);
        stat2 = isc_sqlcode(status);
    }
    
    sprintf(buf, "UPDATE cross_rate SET to_currency = '%s' WHERE \
            to_currency = '%s'", new_name, orig_name);

    stat3 = 0L;
    if (isc_dsql_execute_immediate(status, &db2, &trans1, 0, buf, 1, NULL))
    {
        isc_print_status(status);
        stat3 = isc_sqlcode(status);
    }

    if (isc_dsql_free_statement(status, &stmt, DSQL_close))
        isc_print_status(status);

    /*
     *    If all statements executed successfully, commit the transaction.
     *    Otherwise, undo all work.
     */
    if (!stat1 && !stat2 && !stat3)
    {
        if (isc_commit_transaction (status, &trans1))
            isc_print_status(status);
        printf("Changes committed.\n");
    }
    else
    {
        printf("update1:  %d\n", stat1);
        printf("update2:  %d\n", stat2);
        printf("update3:  %d\n", stat3);
        if (isc_rollback_transaction(status, &trans1))
            isc_print_status(status);
        printf("Changes undone.\n");
    }

    /* Close database 1. */
    if (isc_detach_database(status, &db1))
        isc_print_status(status);

    /* Close database 2. */
    if (isc_detach_database(status, &db2))
        isc_print_status(status);
    
    free(sel_sqlda);

    return 0;
}
