#include <iostream>
#include <vector>
#include <stdexcept>
#include <sys/timeb.h>    	// _ftime(), time_t and struct timeb
#include <ctime>          	// localtime()
#include <cstdarg>			// for: va_list va_start va_end vsprintf
							// They do not seem to be in the namespace std: ?

#include <windows.h>
#include <sql.h>
#include <sqlext.h>

#define CHECK_RC( txt,htype, hndl, SQLRC) \
	if(SQLRC != SQL_SUCCESS) \
	{ \
			std::cerr << txt << GetErrorString(htype, hndl,SQLRC) << std::endl; \
	}

std::string GetErrorString(	SQLSMALLINT htype,		/* handle type identifier SQL_HANDLE_ENV | SQL_HANDLE_DBC | SQL_HANDLE_STMT | SQL_HANDLE_DESC */
							SQLHANDLE   hndl,		/* handle used by the SQL...func. */
							SQLRETURN   sqlrc);	/* ret. code of the SQL... func. */
std::string GetDiagnostics(	SQLSMALLINT htype, 		/* handle type identifier : */
							SQLHANDLE   hndl);  	/* handle */


HENV	henv;
HDBC	hdbc;
HSTMT	hstmt;
SQLRETURN rc;

int main(int argc, char *argv[], char *envp[])
{
	std::cerr << "+ int main(int argc, char *argv[], char *envp[])\n";
	
	// Initialize ODBC environment
	rc = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE, &henv);
	CHECK_RC( "SQLAllocHandle(henv): ", SQL_HANDLE_ENV, henv, rc);
	SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3,0);
	
	// Get a connection
	rc = SQLAllocHandle( SQL_HANDLE_DBC,henv, &hdbc);
	CHECK_RC( "SQLAllocHandle(hdbc): ", SQL_HANDLE_ENV, henv, rc);
	
	rc = SQLConnect(hdbc, 					// SQLHDBC     	ConnectionHandle,
     				(SQLCHAR*)"TestDB",		// SQLCHAR *   	ServerName,
					SQL_NTS, 				// SQLSMALLINT 	NameLength1,
					(SQLCHAR*)"postgres",	// SQLCHAR *   	UserName,
     				SQL_NTS,				// SQLSMALLINT 	NameLength2,
     				(SQLCHAR*)"",			// SQLCHAR *   	Authentication,
					SQL_NTS);				// SQLSMALLINT 	NameLength3);
	CHECK_RC( "SQLConnect: ", SQL_HANDLE_DBC, hdbc, rc);						

	// Get a statement handle
	rc = SQLAllocHandle(	SQL_HANDLE_STMT,hdbc, &hstmt ) ;
	CHECK_RC( "SQLAllocHandle(hstmt)", SQL_HANDLE_DBC, hstmt, rc);

	std::string sqlStatement = "select * from getobjectid()";							
	rc = SQLPrepare(hstmt , (SQLCHAR*)sqlStatement.c_str(), SQL_NTS);
	CHECK_RC( "SQLPrepare: ", SQL_HANDLE_DBC, hdbc, rc);
	
	short numberOfColumns = 0;
	rc = SQLNumResultCols (hstmt , (SQLSMALLINT*)&numberOfColumns);
	CHECK_RC( "SQLNumResultCols: ", SQL_HANDLE_STMT, hstmt, rc);
	
	std::cout << "SQLNumResultCols: " << numberOfColumns << std::endl;
								
	rc = SQLExecute(hstmt);
	CHECK_RC( "SQLExecute: ", SQL_HANDLE_STMT, hstmt, rc);

	rc = SQLDisconnect(hdbc);
	rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
	rc = SQLFreeHandle(SQL_HANDLE_ENV, henv);
	
	std::cerr<< "- int main(int argc, char *argv[], char *envp[])\n";
	return 0;
}

std::string GetErrorString(	SQLSMALLINT htype,  /* handle type identifier SQL_HANDLE_ENV | SQL_HANDLE_DBC | SQL_HANDLE_STMT | SQL_HANDLE_DESC */
							SQLHANDLE   hndl,   /* handle used by the SQL...func. */
							SQLRETURN   sqlrc)  /* ret. code of the SQL... func. */
{
	std::string errorString;

	switch ( sqlrc )
	{
		case SQL_SUCCESS:
		break ;
		case SQL_INVALID_HANDLE:
			errorString = "SQL_INVALID_HANDLE";
			break ;
		case SQL_ERROR:	
			errorString = "SQL_ERROR:\n";
			errorString += GetDiagnostics( htype, hndl);
			break ;
		case SQL_SUCCESS_WITH_INFO:
			errorString = "SQL_SUCCESS_WITH_INFO";
			errorString += GetDiagnostics( htype, hndl);
			break ;
		case SQL_STILL_EXECUTING :
			errorString = "SQL_STILL_EXECUTING";
			break ;
		case SQL_NEED_DATA :
			errorString = "SQL_NEED_DATA";
			break ;
		case SQL_NO_DATA_FOUND:
			errorString = "SQL_NO_DATA_FOUND\n";
			break ;
		default:
			errorString = "Default";
		break ;
	}
	return errorString;
}

std::string GetDiagnostics(	SQLSMALLINT htype, 	/* handle type identifier : */
							SQLHANDLE   hndl)  	/* handle */
{
	SQLCHAR     message[SQL_MAX_MESSAGE_LENGTH + 1] ;
	SQLCHAR     SQLSTATE[SQL_SQLSTATE_SIZE + 1] ;
	SQLINTEGER  sqlcode ;
	SQLSMALLINT length, i ;

	std::string diagnostics ;

	i = 1 ;

	while ( SQLGetDiagRec(	htype,
							hndl,
							i,
							SQLSTATE,
							&sqlcode,
							message,
							SQL_MAX_MESSAGE_LENGTH + 1,
							&length
						) == SQL_SUCCESS )
	{
			diagnostics += (std::string("\nSQLSTATE = ") + std::string((const char*)SQLSTATE));
//			diagnostics += (std::string("\nNative rc Code = ")+ itoa( sqlcode ));
			diagnostics += (std::string("\nMessage: ") + std::string((const char*)message));
			i++ ;
   	}
   	if(i==1)
   	{
 		diagnostics = "No diagnostics available";
	}
	return diagnostics;
}
	
