Files @ 3d604507d726
Branch filter:

Location: DA/protocols/pmodbc.c

Mark Raasveldt
Add pmodbc.c and add new protocol tests to vldb-protocols.py.

#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqlext.h>
#include <string.h>
#include <assert.h>

// compilation: gcc -g pmodbc.c -lodbc -o pmodbc

static void list_drivers();
static void query_db(char* dsn, char* query, int csv);
void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type);

int main(int argc, char** argv) {
    if (argc < 4) {
        printf("Incorrect number of arguments.\n\n");
        printf("Arguments:\n");
        printf("pmodbc [dsn] [query] [csv={0,1}]\n\n");
        printf("DSN List:\n");
        list_drivers();
    } else {
        query_db(argv[1], argv[2], *argv[3] == '1');
    }
}


static void list_drivers() {
    SQLHENV env;
    char dsn[256];
    char desc[256];
    SQLSMALLINT dsn_ret;
    SQLSMALLINT desc_ret;
    SQLUSMALLINT direction;
    SQLRETURN ret;

    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
    SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);

    direction = SQL_FETCH_FIRST;
    while(SQL_SUCCEEDED(ret = SQLDataSources(env, direction, dsn, sizeof(dsn), &dsn_ret, desc, sizeof(desc), &desc_ret))) {
        direction = SQL_FETCH_NEXT;
        printf("%s - %s\n", dsn, desc);
        if (ret == SQL_SUCCESS_WITH_INFO) printf("\tdata truncation\n");
    }
}


static void query_db(char* dsn_str, char* query, int csv) {
    SQLHENV env;
    SQLHDBC dbc;
    SQLHSTMT stmt;
    SQLRETURN ret; /* ODBC API return status */
    SQLSMALLINT columns; /* number of columns in result-set */
    int row = 0;
    char dsn[1000];
    snprintf(dsn, 1000, "DSN=%s;", dsn_str);

    /* Allocate an environment handle */
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
    /* We want ODBC 3 support */
    SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
    /* Allocate a connection handle */
    ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
    if (!SQL_SUCCEEDED(ret)) {
      extract_error("SQLAllocHandle for dbc", env, SQL_HANDLE_ENV);
      exit(1);
    }
    /* Connect to the DSN mydsn */
    /* You will need to change mydsn to one you have created and tested */
    SQLDriverConnect(dbc, NULL, dsn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
    /* Allocate a statement handle */
    SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
    /* Retrieve a list of tables */
    //SQLTables(stmt, NULL, 0, NULL, 0, NULL, 0, "TABLE", SQL_NTS);
    ret = SQLExecDirect(stmt, query, SQL_NTS);
    if (!SQL_SUCCEEDED(ret)) {
        extract_error("SQLExecuteDirect for dbc", stmt, SQL_HANDLE_STMT);
        exit(1);
    }
    /* How many columns are there */
    SQLNumResultCols(stmt, &columns);
    if (csv == 0) {
        while (SQL_SUCCEEDED(ret = SQLFetch(stmt))) {
        }
    } else {
        char csvbuf[1000];
        /* Loop through the rows in the result-set */
        while (SQL_SUCCEEDED(ret = SQLFetch(stmt))) {
            SQLUSMALLINT i;
            SQLLEN curlen = 0;
            SQLLEN indicator;
            /* Loop through the columns */
            for (i = 1; i <= columns; i++) {
                /* retrieve column data as a string */
                ret = SQLGetData(stmt, i, SQL_C_CHAR, csvbuf + curlen, sizeof(csvbuf) - curlen, &indicator);
                if (!SQL_SUCCEEDED(ret)) {
                    extract_error("SQLExecuteDirect for dbc", stmt, SQL_HANDLE_STMT);
                    exit(1);    
                }
                curlen += indicator;
                if (i != columns) 
                    csvbuf[curlen++] = ',';
            }
            puts(csvbuf);
        }
    }
    extract_error("SQLStmt for dbc", stmt, SQL_HANDLE_STMT);
    exit(1);
}

void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type)
{
    SQLINTEGER   i = 0;
    SQLINTEGER   native;
    SQLCHAR  state[ 7 ];
    SQLCHAR  text[256];
    SQLSMALLINT  len;
    SQLRETURN    ret;

    fprintf(stderr,
            "\n"
            "The driver reported the following diagnostics whilst running "
            "%s\n\n",
            fn);

    do
    {
        ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
                            sizeof(text), &len );
        if (SQL_SUCCEEDED(ret))
            printf("%s:%d:%d:%s\n", state, i, native, text);
    }
    while( ret == SQL_SUCCESS );
}