/*
 *
 * Much of this code was adopted from easysoft tutorials
 *   http://www.easysoft.com/developer/languages/c/odbc_tutorial.html
 *   http://www.easysoft.com/developer/languages/c/odbc-tutorial-fetching-results.html
 */

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

/* This routine is taken from the easysoft tutorials */
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:%ld:%ld:%s\n", state, i, native, text);
      }
    while( ret == SQL_SUCCESS );
}

SQLCHAR *connectionString = 
  "DRIVER={MySQL};"                   /* defined in /etc/odbcinst.ini */
  "Server=joe.cs.unca.edu;"
  "Port=3306;"                        /* not needed */
  "Database=socialDB;"
  "UID=csci343;" ;

SQLCHAR *sqlDBquery =
  "SELECT A.name, B.name "
  "FROM Highschooler A, Highschooler B, Friend F "
  "WHERE A.ID = F.ID1 AND B.ID = F.ID2 AND A.name < B.name ;" ;

/* This is modification of the easysoft example */
int main(int argc, char *argv[]) {
  SQLHENV env;             /* Environment handle */
  SQLHDBC dbc;             /* Database connection */
  SQLHSTMT stmt;           /* Statement for execution */
  SQLRETURN ret;           /* ODBC API return status */
  SQLSMALLINT columns;     /* number of columns in result-set */
  SQLCHAR outstr[1024];
  SQLSMALLINT outstrlen;
  int row = 0 ;

  /* 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 */
  SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
  ret = SQLDriverConnect(dbc, NULL, 
			 connectionString, SQL_NTS,
			 outstr, sizeof(outstr), &outstrlen,
			 SQL_DRIVER_COMPLETE);
  if (!SQL_SUCCEEDED(ret)) {
    fprintf(stderr, "Failed to connect\n");
    extract_error("SQLDriverConnect", dbc, SQL_HANDLE_DBC);
  }

  /* Allocate a statement handle */
  SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);

  /* Prepare for execution */
  ret = SQLPrepare(stmt, sqlDBquery, SQL_NTS) ;
  if (!SQL_SUCCEEDED(ret)) {
    fprintf(stderr, "Failed to prepare\n");
    extract_error("SQLprepare", dbc, SQL_HANDLE_DBC);
  }

  /* Do it */
  ret = SQLExecute(stmt) ;
  if (!SQL_SUCCEEDED(ret)) {
    fprintf(stderr, "Failed to execute\n");
    extract_error("SQLexecute", dbc, SQL_HANDLE_DBC);
  }

  SQLNumResultCols(stmt, &columns);

  /* Loop through the rows in the result-set */
  while (SQL_SUCCEEDED(ret = SQLFetch(stmt))) {
    SQLUSMALLINT i;
    char friend[2][512] ;
    /* Loop through the columns -- better be only 2 */
    for (i = 1; i <= columns; i++) {
      SQLLEN indicator;
      ret = SQLGetData(stmt, i, SQL_C_CHAR,
		       friend[i-1], sizeof(friend[0]), &indicator);
      if (SQL_SUCCEEDED(ret)) {
	/* Handle null columns */
	if (indicator == SQL_NULL_DATA) strcpy(friend[i-1], "NULL");
      }
    }
    fprintf(stdout, "Friends:   %-10s & %-10s\n", friend[0], friend[1]) ;
  }
}
