#include "tap.h"

/* Columns order num for SQLColumns */
#define TABLE_CAT	   1
#define TABLE_SCHEM	   2
#define TABLE_NAME	   3
#define COLUMN_NAME	   4
#define DATA_TYPE          5
#define TYPE_NAME	   6
#define COLUMN_SIZE        7
#define BUFFER_LENGTH      8
#define DECIMAL_DIGITS     9
#define NUM_PREC_RADIX    10
#define NULLABLE          11
#define REMARKS		  12
#define COLUMN_DEF	  13
#define SQL_DATA_TYPE     14
#define SQL_DATETIME_SUB  15
#define CHAR_OCTET_LENGTH 16
#define ORDINAL_POSITION  17
#define IS_NULLABLE	  18

#define DEBUG_DESCRIBE_COL 1
#define DEBUG_DATA	   0

#define PROBLEM 1

ODBC_TEST(odbc152)
{
    char table_cat[64];
    int table_cat_valuesize = sizeof(table_cat);
    SQLLEN table_cat_ind;
    
    char table_schem[64];
    int table_schem_valuesize = sizeof(table_schem);
    SQLLEN table_schem_ind;
    
    char table_name[64];
    int table_name_valuesize = sizeof(table_name);
    SQLLEN table_name_ind;
    
    char column_name[64];
    int column_name_valuesize = sizeof(column_name);
    SQLLEN column_name_ind;
    
    short data_type;
    int data_type_valuesize = sizeof(short);
    SQLLEN data_type_ind;
    
    SQLBIGINT column_size;
    int column_size_valuesize = sizeof(SQLBIGINT);
    SQLLEN column_size_ind;
    
    SQLBIGINT buffer_length;
    int buffer_length_valuesize = sizeof(SQLBIGINT);
    SQLLEN buffer_length_ind;
    
    short decimal_digits;
    int decimal_digits_valuesize = sizeof(short);
    SQLLEN decimal_digits_ind;
    
    short num_prec_radix;
    int num_prec_radix_valuesize = sizeof(short);
    SQLLEN num_prec_radix_ind;

    short nullable;
    int nullable_valuesize = sizeof(short);
    SQLLEN nullable_ind;

    char remarks[1024];
    int remarks_valuesize = sizeof(remarks);
    SQLLEN remarks_ind;
    
    char column_def[1024*1024];
    int column_def_valuesize = sizeof(column_def);
    SQLLEN column_def_ind;

    short sql_data_type;
    int sql_data_type_valuesize = sizeof(short);
    SQLLEN sql_data_type_ind;

    short sql_datetime_sub;
    int sql_datetime_sub_valuesize = sizeof(short);
    SQLLEN sql_datetime_sub_ind;

    SQLBIGINT char_octet_length;
    int char_octet_length_valuesize = sizeof(SQLBIGINT);
    SQLLEN char_octet_length_ind;

    SQLBIGINT ordinal_position;
    int ordinal_position_valuesize = sizeof(SQLBIGINT);
    SQLLEN ordinal_position_ind;

    char is_nullable[3];
    int is_nullable_valuesize = sizeof(is_nullable);
    SQLLEN is_nullable_ind;
    
    int fetchmode;
    SQLSMALLINT column_count;
    
    OK_SIMPLE_STMT(Stmt, "drop table if exists t_odbc152");
    OK_SIMPLE_STMT(Stmt, "create table t_odbc152("
		   "`Revision` bigint(20) unsigned NOT NULL DEFAULT '0',"
		   "`Datum` date NOT NULL DEFAULT '0000-00-00',"
		   "`Uhrzeit` time NOT NULL DEFAULT '00:00:00',"
		   "`User_ID` int(10) unsigned NOT NULL DEFAULT '0',"
		   "`Projekt_ID` bigint(20) unsigned NOT NULL,"
		   "`Beschreibung` longtext CHARACTER SET latin1,"
		   "`Kunde_ID` int(10) unsigned DEFAULT NULL,"
		   "`Handbuch` smallint(5) unsigned NOT NULL,"
		   "`FehlerNr` bigint(20) unsigned DEFAULT NULL,"
		   "`TextChecked` tinyint(3) unsigned DEFAULT '0',"
		   "`Prio` smallint(1) unsigned DEFAULT '0') ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin");
    
    CHECK_STMT_RC(Stmt, SQLColumns(Stmt, NULL, SQL_NTS, NULL, SQL_NTS,
				   (SQLCHAR *)"t_odbc152", SQL_NTS, NULL, 0));
    
    CHECK_STMT_RC(Stmt, SQLNumResultCols(Stmt, &column_count));
    is_num( column_count, 18 );
	
#if DEBUG_DESCRIBE_COL
    {
	SQLSMALLINT column_nr;
	
	for (column_nr = 1; column_nr <= column_count; column_nr++) {
	    
	    char column_name[256];
	    SQLLEN is_unsigned;
	    SQLULEN size;
	    SQLSMALLINT column_name_len, typecode, scale, nullable;
	    
	    CHECK_STMT_RC(Stmt, SQLDescribeCol( Stmt, column_nr, column_name, sizeof(column_name), &column_name_len, &typecode, &size, &scale, &nullable ));
	    
	    CHECK_STMT_RC(Stmt, SQLColAttribute( Stmt, column_nr, SQL_DESC_UNSIGNED, NULL, 0, NULL, &is_unsigned));
	    
	    printf("    DESC [%02d] column_name '%s' typecode=%d size=%d scale=%d nullable=%d is_unsigned=%d\n", column_nr, column_name, typecode, size, scale, nullable, is_unsigned );
        }
    }
#endif
    
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, TABLE_CAT, SQL_C_CHAR, &table_cat, table_cat_valuesize, &table_cat_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, TABLE_SCHEM, SQL_C_CHAR, &table_schem, table_schem_valuesize, &table_schem_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, TABLE_NAME, SQL_C_CHAR, &table_name, table_name_valuesize, &table_name_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, COLUMN_NAME, SQL_C_CHAR, &column_name, column_name_valuesize, &column_name_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, DATA_TYPE, SQL_C_SSHORT, &data_type, data_type_valuesize, &data_type_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, COLUMN_SIZE, SQL_C_SBIGINT, &column_size, column_size_valuesize, &column_size_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, BUFFER_LENGTH, SQL_C_SBIGINT, &buffer_length, buffer_length_valuesize, &buffer_length_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, DECIMAL_DIGITS, SQL_C_SSHORT, &decimal_digits, decimal_digits_valuesize, &decimal_digits_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, NUM_PREC_RADIX, SQL_C_SSHORT, &num_prec_radix, num_prec_radix_valuesize, &num_prec_radix_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, NULLABLE, SQL_C_SSHORT, &nullable, nullable_valuesize, &nullable_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, REMARKS, SQL_C_CHAR, &column_def, column_def_valuesize, &column_def_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, COLUMN_DEF, SQL_C_CHAR, &column_def, column_def_valuesize, &column_def_ind ));
#if PROBLEM
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, SQL_DATA_TYPE, SQL_C_SSHORT, &sql_data_type, sql_data_type_valuesize, &sql_data_type_ind ));
#endif
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, SQL_DATETIME_SUB, SQL_C_SSHORT, &sql_datetime_sub, sql_datetime_sub_valuesize, &sql_datetime_sub_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, CHAR_OCTET_LENGTH, SQL_C_SBIGINT, &char_octet_length, char_octet_length_valuesize, &char_octet_length_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, ORDINAL_POSITION, SQL_C_SBIGINT, &ordinal_position, ordinal_position_valuesize, &ordinal_position_ind ));
    CHECK_STMT_RC(Stmt, SQLBindCol( Stmt, IS_NULLABLE, SQL_C_CHAR, &is_nullable, is_nullable_valuesize, &is_nullable_ind ));
    
    CHECK_STMT_RC(Stmt, SQLSetStmtAttr( Stmt, SQL_ATTR_ROW_ARRAY_SIZE,
					(SQLPOINTER) 1,
					SQL_IS_UINTEGER ));
    
    fetchmode = SQL_FETCH_FIRST;
    EXPECT_STMT( Stmt, SQLFetchScroll(Stmt, fetchmode, 0), SQL_SUCCESS );

    {
	SQLLEN type_name_len;
	char type_name[100];
	
	CHECK_STMT_RC(Stmt, SQLGetData( Stmt, TYPE_NAME, SQL_CHAR, type_name, sizeof(type_name), &type_name_len ));
	
	
	
	printf("    DATA [%s][%s][%s][%s] (data_type %d/%d) (type_name %d [%s]) (columnsize %d/%lld) (buffer_length %d/%lld) (decimal_digits %d/%lld) (num_prec_radix %d/%lld) (nullable %d/%lld) (remarks %d [%s]) (column_def %d [%s]) (sql_data_type %d/%lld) (sql_datetime_sub %d/%lld) (char_octet_length %d/%lld) (ordinal_position %d/%lld) (is_nullable %d [%s])\n",
	       table_cat_ind < 0 ? "" : table_cat,
	       table_schem_ind < 0 ? "" : table_schem,
	       table_name_ind < 0 ? "" : table_name,
	       column_name,
	       data_type_ind, data_type,
	       type_name_len, type_name,
	       column_size_ind, column_size,
	       buffer_length_ind, buffer_length,
	       decimal_digits_ind, decimal_digits,
	       num_prec_radix_ind, num_prec_radix,
	       nullable_ind, nullable,
	       remarks_ind, remarks,
	       column_def_ind, column_def,
	       sql_data_type_ind, sql_data_type,
	       sql_datetime_sub_ind, sql_datetime_sub,
	       char_octet_length_ind, char_octet_length,
	       ordinal_position_ind, ordinal_position,
	       is_nullable_ind, is_nullable );
	
	fetchmode = SQL_FETCH_NEXT;
    }
    
    
    while (SQLFetchScroll(Stmt, fetchmode, 0) != SQL_NO_DATA) {
	
	SQLLEN type_name_len;
	char type_name[100];
	
	fetchmode = SQL_FETCH_NEXT;
	
	CHECK_STMT_RC(Stmt, SQLGetData( Stmt, TYPE_NAME, SQL_CHAR, type_name, sizeof(type_name), &type_name_len ));

#if DEBUG_DATA	
	printf("    DATA [%s][%s][%s][%s] (data_type %d/%d) (type_name %d [%s]) (columnsize %d/%lld) (buffer_length %d/%lld) (decimal_digits %d/%lld) (num_prec_radix %d/%lld) (nullable %d/%lld) (remarks %d [%s]) (column_def %d [%s]) (sql_data_type %d/%lld) (sql_datetime_sub %d/%lld) (char_octet_length %d/%lld) (ordinal_position %d/%lld) (is_nullable %d [%s])\n",
	       table_cat_ind < 0 ? "" : table_cat,
	       table_schem_ind < 0 ? "" : table_schem,
	       table_name_ind < 0 ? "" : table_name,
	       column_name,
	       data_type_ind, data_type,
	       type_name_len, type_name,
	       column_size_ind, column_size,
	       buffer_length_ind, buffer_length,
	       decimal_digits_ind, decimal_digits,
	       num_prec_radix_ind, num_prec_radix,
	       nullable_ind, nullable,
	       remarks_ind, remarks,
	       column_def_ind, column_def,
	       sql_data_type_ind, sql_data_type,
	       sql_datetime_sub_ind, sql_datetime_sub,
	       char_octet_length_ind, char_octet_length,
	       ordinal_position_ind, ordinal_position,
	       is_nullable_ind, is_nullable );
#endif
    }
    
    CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_CLOSE));
    
    OK_SIMPLE_STMT(Stmt, "DROP TABLE t_odbc152");
    
    return OK;
}

MA_ODBC_TESTS my_tests[]=
{
  {odbc152, "odbc152",      NORMAL},
  {NULL, NULL}
};


int main(int argc, char **argv)
{
  int tests= sizeof(my_tests)/sizeof(MA_ODBC_TESTS) - 1;
  int result;

  get_options(argc, argv);
  plan(tests);

  result= run_tests(my_tests);
  /* Now one more run as ODBC2 app */
  OdbcVer= SQL_OV_ODBC2;

  return run_tests(my_tests) || result;
}
