/* odbc-test-05.c: How to get some status information etc
 * This program compiled and run, without changes, on:
 *   Red Hat Linux 8.0, gcc 3.2, unixODBC 2.2.2
 *     ("gcc -Wall odbc-test-05.c -o odbc-test-05 -lodbc")
 *   Windows 2000 Professional, Microsoft Visual C++ 6.0
 *   Windows 2000 Professional, Borland C++ Builder 5.0
 * All of those with Mimer 9.1.3, and Mimer ODBC driver 9.something
 * Thomas Padron-McCarthy (Thomas.Padron-McCarthy@tech.oru.se)
 * October 7, 2003
 */

#include <stdlib.h>
#include <stdio.h>
#if defined(_MSDOS) || defined(_WIN32)
#include <windows.h>
#endif
#include "sqlext.h"

/*------------------------------------------------------------*/

void list_data_sources(SQLHENV eh) {
  SQLCHAR source_name[SQL_MAX_DSN_LENGTH + 1];
  SQLSMALLINT sn_length;
  SQLCHAR driver_name[SQL_MAX_DSN_LENGTH + 1];
  SQLSMALLINT dn_length;
  SQLRETURN result;

  printf("Följande datakällor finns:\n");

  /* List all system data sources */
  result = SQLDataSources(eh,
			  SQL_FETCH_FIRST_SYSTEM,
			  source_name,
			  sizeof source_name,
			  &sn_length,
			  driver_name,
			  sizeof driver_name,
			  &dn_length);

  printf("  System-datakällor:\n");
  while (SQL_SUCCEEDED(result)) {
    printf("    Namn = '%s', drivrutin = '%s'\n",
	   source_name, driver_name);

    result = SQLDataSources(eh,
			    SQL_FETCH_NEXT,
			    source_name,
			    sizeof source_name,
			    &sn_length,
			    driver_name,
			    sizeof driver_name,
			    &dn_length);
  } // while

  /* List all user data sources, for this user */
  result = SQLDataSources(eh,
			  SQL_FETCH_FIRST_USER,
			  source_name,
			  sizeof source_name,
			  &sn_length,
			  driver_name,
			  sizeof driver_name,
			  &dn_length);

  printf("  Användar-datakällor:\n");
  while (SQL_SUCCEEDED(result)) {
    printf("    Namn = '%s', drivrutin = '%s'\n",
	   source_name, driver_name);

    result = SQLDataSources(eh,
			    SQL_FETCH_NEXT,
			    source_name,
			    sizeof source_name,
			    &sn_length,
			    driver_name,
			    sizeof driver_name,
			    &dn_length);
  } // while

  printf("Slut på datakällor.\n");
} /* list_data_sources */

/*------------------------------------------------------------*/

void show_dbms_info(SQLHDBC ch) {
  char str_value[100 + 1];
  SQLSMALLINT length;
  SQLSMALLINT int_value;

  printf("Information om den databashanterare vi anslutit till:\n");

  if (SQLGetInfo(ch, SQL_DBMS_NAME, (SQLPOINTER)&str_value,
		 sizeof str_value, &length) != SQL_SUCCESS) {
    fprintf(stderr, "SQLGetInfo misslyckades.\n");
    exit(EXIT_FAILURE);
  }
  printf("  Databashanterarens namn: %s\n", str_value);

  if (SQLGetInfo(ch, SQL_DBMS_VER, (SQLPOINTER)&str_value,
		 sizeof str_value, &length) != SQL_SUCCESS) {
    fprintf(stderr, "SQLGetInfo misslyckades.\n");
    exit(EXIT_FAILURE);
  }
  printf("  Databashanterarens version: %s\n", str_value);
 
  /* Get SQL conformance level */
  if (SQLGetInfo(ch, SQL_SQL_CONFORMANCE, (SQLPOINTER)&int_value,
		 sizeof int_value, NULL) != SQL_SUCCESS) {
    fprintf(stderr, "SQLGetInfo misslyckades.\n");
    exit(EXIT_FAILURE);
  }

  printf("  SQL conformance: Entry level SQL-92: %s\n",
	 (int_value & SQL_SC_SQL92_ENTRY) ? "Ja" : "Nej");
  printf("  SQL conformance: FIPS 127-2 transitional level: %s\n",
	 (int_value & SQL_SC_FIPS127_2_TRANSITIONAL) ? "Ja" : "Nej");
  printf("  SQL conformance: Intermediate level SQL-92: %s\n",
	 (int_value & SQL_SC_SQL92_INTERMEDIATE) ? "Ja" : "Nej");
  printf("  SQL conformance: Full level SQL-92: %s\n",
	 (int_value & SQL_SC_SQL92_FULL) ? "Ja" : "Nej");

  /* One of many things we can query the DBMS about:
   * max column name length
   */
  if (SQLGetInfo(ch, SQL_MAX_COLUMN_NAME_LEN, (SQLPOINTER)&int_value,
		 sizeof int_value, &length) != SQL_SUCCESS) {
    fprintf(stderr, "SQLGetInfo misslyckades.\n");
    exit(EXIT_FAILURE);
  }
  printf("  Största tillåtna längd på ett kolumnnamn: %d\n", int_value);
} /* show_dbms_info */

/*------------------------------------------------------------*/

void show_odbc_diagnostics(SQLHSTMT sh) {
  SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH + 1];
  SQLCHAR sqlstate[5 + 1];
  SQLSMALLINT msglen, msgno;
  SQLINTEGER nativeerror;
 
  printf("Felmeddelande (eller felmeddelanden) från ODBC:\n");
  msgno = 0;
  while (SQLGetDiagRec(SQL_HANDLE_STMT,
                       sh,
                       ++msgno,
                       sqlstate,
                       &nativeerror,
                       msg,
                       sizeof msg,
                       &msglen) == SQL_SUCCESS) {
    msg[msglen] = '\0';
    fflush(stdout);
    fflush(stderr);
    printf("  Diagnostiskt ODBC-meddelande nummer %d:\n", (int)msgno);
    printf("    SQLSTATE: '%s'\n", sqlstate);
    printf("    Native error: %d\n", (int)nativeerror);
    printf("    Message: '%s'\n", msg);
  } /* while more messages */
} /* show_odbc_diagnostics */

/*------------------------------------------------------------*/

int main(void) {
  SQLHENV eh;
  SQLHDBC ch;
  SQLHSTMT sh;

  /* Allocate environment handle. */
  if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &eh) != SQL_SUCCESS) {
    fprintf(stderr, "Kunde inte allokera en ODBC-omgivning.\n");
    return EXIT_FAILURE;
  }

  /* Set the ODBC version attribute,
   * so ODBC knows which ODBC version this application was written for.
   */
  if (SQLSetEnvAttr(eh,
		    SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,
		    SQL_IS_INTEGER) != SQL_SUCCESS) {
    fprintf(stderr, "Failed to set ODBC version to SQL_OV_ODBC3.\n");
    return EXIT_FAILURE;
  }

  list_data_sources(eh);

  /* Allocate connection handle */
  if (SQLAllocHandle(SQL_HANDLE_DBC, eh, &ch) != SQL_SUCCESS) {
    fprintf(stderr, "Kunde inte allokera ett anslutningsobjekt.\n");
    return EXIT_FAILURE;
  }

  /* Connect: data source, user name, password */
  if (SQLConnect(ch, (SQLCHAR*)"demobasen", SQL_NTS,
		 (SQLCHAR*)"demouser", SQL_NTS,
		 (SQLCHAR*)"fnord", SQL_NTS) != SQL_SUCCESS) {
    fprintf(stderr, "Kunde inte ansluta till datakällan 'demobasen'.\n");
    return EXIT_FAILURE;
  }

  show_dbms_info(ch);

  /* Allocate statement handle */
  if (SQLAllocHandle(SQL_HANDLE_STMT, ch, &sh) != SQL_SUCCESS) {
    fprintf(stderr, "Kunde inte allokera ett statement handle.\n");
    return EXIT_FAILURE;
  }

  printf("Nu försöker vi köra en fråga som kommer att misslyckas.\n");

  /* This query is supposed to fail! */
  if (SQLExecDirect(sh, (SQLCHAR*)"select Flim, Flam from Person", SQL_NTS)
      == SQL_SUCCESS) {
    fprintf(stderr, "Kunde köra frågan. Det hade vi inte väntat oss.\n");
    return EXIT_FAILURE;
  }

  show_odbc_diagnostics(sh);

  return EXIT_SUCCESS;
} /* main */

