You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by ma...@apache.org on 2015/07/15 11:42:45 UTC
[12/14] incubator-kylin git commit: add odbc driver to maven
repository
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/d1dcfd15/odbc/Driver/KO_CONN.CPP
----------------------------------------------------------------------
diff --git a/odbc/Driver/KO_CONN.CPP b/odbc/Driver/KO_CONN.CPP
new file mode 100644
index 0000000..2a5233b
--- /dev/null
+++ b/odbc/Driver/KO_CONN.CPP
@@ -0,0 +1,1010 @@
+// ----------------------------------------------------------------------------
+//
+// File: KO_CONN.CPP
+//
+// Purpose: Contains the main connection functions more
+// specifically SQLDriverConnect.
+//
+// Only SQLDriverConnect with DSN specified is supported now.
+// The DSN must have been set properly with ODBCAD.exe
+//
+// Most functions in this file either to support the dialog box or
+// help in manipulation or parsing of key-value pairs
+//
+// Exported functions:
+// SQLDriverConnect
+// SQLConnect
+// SQLBrowseConnect
+//
+// ----------------------------------------------------------------------------
+#include "stdafx.h"
+
+#include <stdio.h>
+#include <resource.h>
+
+#include "REST.h"
+
+// ------------------------------ local defines -------------------------------
+#define MAX_KEYS_STR_LEN 1024 // arbitray for loading keys from DSN file
+#define MAX_CONN_STR_LEN 2048 // arbitray for building key-values from DSN
+#define KV_BLOCK_SIZE 5 // arbitray size for a set of key-value pairs
+
+// ------------------------ local callback functions -------------------------
+INT_PTR CALLBACK DlgDSNCfg1Proc ( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
+
+// ----------------------------- local functions ------------------------------
+static eGoodBad CreateAndSetConnProp ( pODBCConn pConn, Word pPropID, void* pPropValue );
+
+static eGoodBad PutDataToDlgDSNCfg1 ( pODBCConn pConn, HWND hDlg );
+
+static eGoodBad GetDataFromDlgDSNCfg1 ( HWND hDlg, pODBCConn pConn );
+
+static Word PromptForConnInfo ( SQLHDBC pConn );
+
+static eGoodBad LoadKeyValuesfromFileDSN ( pODBCConn pConn, CStrPtr pDSNName, Word* pNumPair,
+ struct ODBCKV** pKV );
+
+static bool AddKVToConnStr ( StrPtr pKey, StrPtr pValue, Word* iPos, StrPtr pStrConn, Word pMaxLen );
+static bool BuildConnStr ( char* pStrConn, Word pMaxLen, pODBCConn pConn, struct ODBCKV* KVInput,
+ Word iKVInputPairs, struct ODBCKV* KVFileDSN, Word iKVFileDSNPairs );
+
+
+
+// -----------------------------------------------------------------------
+// to set a specified property in the connection structure
+// -----------------------------------------------------------------------
+
+eGoodBad SetConnProp ( pODBCConn pConn, Word pPropID, void* pPropValue ) {
+ // note
+ // this function does not create a copy of char data
+ // it just transfers the pointer
+ // numeric data is assumed to be a pointer
+
+ // check property
+ switch ( pPropID ) {
+ case CONN_PROP_SERVER:
+
+ // check if a new value has to be put
+ if ( pPropValue ) {
+ copyTrimmed ( & ( ( char* ) pConn->Server ), ( char* ) pPropValue );
+ }
+
+ if ( pConn->Server == NULL || strlen ( pConn->Server ) == 0 ) {
+ __ODBCPopMsg ( "Server cannot be empty" );
+ return BAD;
+ }
+
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The server is set to %s", pConn->Server ) );
+ break;
+
+ case CONN_PROP_PORT:
+
+ // numeric values are passed as pointer to value
+ if ( pPropValue )
+ { pConn->ServerPort = * ( ( ULong* ) pPropValue ); }
+
+ if ( pConn->ServerPort == 0 ) {
+ __ODBCPopMsg ( "ServerPort cannot be 0" );
+ return BAD;
+ }
+
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The port is set to %d", pConn->ServerPort ) );
+ break;
+
+ case CONN_PROP_UID:
+
+ // check if a new value has to be put
+ if ( pPropValue )
+ { copyTrimmed ( & ( ( char* ) pConn->UserName ), ( char* ) pPropValue ); }
+
+ if ( pConn->UserName == NULL || strlen ( pConn->UserName ) == 0 ) {
+ __ODBCPopMsg ( "UserName cannot be empty" );
+ return BAD;
+ }
+
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The uid is set to %s", pConn->UserName ) );
+ break;
+
+ case CONN_PROP_PWD:
+
+ // check if a new value has to be put
+ if ( pPropValue )
+ { copyTrimmed ( & ( ( char* ) pConn->Password ), ( char* ) pPropValue ); }
+
+ if ( pConn->Password == NULL || strlen ( pConn->Password ) == 0 ) {
+ __ODBCPopMsg ( "Password cannot be empty" );
+ return BAD;
+ }
+
+ break;
+
+ case CONN_PROP_PROJECT:
+
+ // check if a new value has to be put
+ if ( pPropValue )
+ { copyTrimmed ( & ( ( char* ) pConn->Project ), ( char* ) pPropValue ); }
+
+ if ( pConn->Project == NULL || strlen ( pConn->Project ) == 0 ) {
+ __ODBCPopMsg ( "Project cannot be empty" );
+ return BAD;
+ }
+
+ break;
+
+ default:
+ __ODBCPOPMSG ( _ODBCPopMsg ( "Bad connection property" ) );
+ return BAD;
+ }
+
+ return GOOD;
+}
+
+
+// -----------------------------------------------------------------------
+// to create copy of a value and then set it in the struct
+// -----------------------------------------------------------------------
+
+static eGoodBad CreateAndSetConnProp ( pODBCConn pConn, Word pPropID, void* pPropValue ) {
+ bool IsPropStr;
+
+ // precaution
+ if ( !pConn )
+ { return BAD; }
+
+ // determine the prop type
+ switch ( pPropID ) {
+ case CONN_PROP_PORT: // port is stored as a number
+ IsPropStr = FALSE;
+ break;
+
+ default:
+ IsPropStr = TRUE;
+ break;
+ }
+
+ // check property type
+ if ( IsPropStr ) {
+ Word x;
+ unique_ptr<char[]> s = NULL;
+ // find length of property
+ x = pPropValue ? strlen ( ( StrPtr ) pPropValue ) : 0;
+
+ // check if something
+ if ( x > 0 ) {
+ // create copy of property
+ s = make_unique_str ( x );
+ // store
+ strcpy ( s.get(), ( StrPtr ) pPropValue );
+ }
+
+ // now set the property
+ return SetConnProp ( pConn, pPropID, s.get() );
+ }
+
+ else {
+ Long v;
+ // convert value to integer
+ v = ( pPropValue ) ? atoi ( ( StrPtr ) pPropValue ) : 0;
+ // now set the property
+ return SetConnProp ( pConn, pPropID, &v );
+ }
+}
+
+// -----------------------------------------------------------------------
+// to provide the default data to DSN config dialog 1
+// -----------------------------------------------------------------------
+
+static eGoodBad PutDataToDlgDSNCfg1 ( pODBCConn pConn, HWND hDlg ) {
+ BOOL x;
+
+ // precaution
+ if ( !pConn || !hDlg ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "PutDataToDlgDSNCfg1 - Bad params" ) );
+ return BAD;
+ }
+
+ // server name/IP
+ if ( pConn->Server )
+ { x = SetDlgItemText ( hDlg, IDC_SERVER, pConn->Server ); }
+
+ else
+ { x = SetDlgItemText ( hDlg, IDC_SERVER, "" ); }
+
+ if ( !x ) { return BAD; }
+
+ // server port
+ if ( pConn->ServerPort )
+ { x = SetDlgItemInt ( hDlg, IDC_PORT, pConn->ServerPort, FALSE ); }
+
+ else
+ { x = SetDlgItemInt ( hDlg, IDC_PORT, DEFAULT_PORT, FALSE ); }
+
+ if ( !x ) { return BAD; }
+
+ // user name
+ if ( pConn->UserName )
+ { x = SetDlgItemText ( hDlg, IDC_UID, pConn->UserName ); }
+
+ else
+ { x = SetDlgItemText ( hDlg, IDC_UID, "" ); }
+
+ if ( !x ) { return BAD; }
+
+ // password
+ if ( pConn->Password )
+ { x = SetDlgItemText ( hDlg, IDC_PWD, pConn->Password ); }
+
+ else
+ { x = SetDlgItemText ( hDlg, IDC_PWD, "" ); }
+
+ if ( !x ) { return BAD; }
+
+ return GOOD;
+}
+
+
+
+// -----------------------------------------------------------------------
+// to fetch the data from the dialog 1 into the conn-struct
+// -----------------------------------------------------------------------
+
+static eGoodBad GetDataFromDlgDSNCfg1 ( HWND hDlg, pODBCConn pConn ) {
+ Long x;
+ std::unique_ptr<char[]> n = NULL;
+ eGoodBad status;
+
+ // note
+ // no error handling is currently being done for
+ // GetDlgItemText/GetDlgItemInt/SetConnProp
+ // generally should not be a problem
+
+ // precaution
+ if ( !pConn || !hDlg ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "GetDataFromDlgDSNCfg1 - Bad params" ) );
+ return BAD;
+ }
+
+ ////// server name/IP
+ // get length of input text
+ x = SendDlgItemMessage ( hDlg, IDC_SERVER, EM_LINELENGTH, 0, 0 );
+
+ if ( x > 0 ) {
+ n = make_unique_str ( x ); // allocate space for holding the text
+ GetDlgItemText ( hDlg, IDC_SERVER, n.get(), x + 1 ); // get text from dialog
+ }
+
+ else
+ { n = NULL; } // no input
+
+ // set value in struct
+ status = SetConnProp ( pConn, CONN_PROP_SERVER, n.get() );
+
+ if ( status == BAD ) { return BAD; }
+
+ ///// Port
+ // get value
+ x = GetDlgItemInt ( hDlg, IDC_PORT, NULL, FALSE );
+ // set value in struct
+ status = SetConnProp ( pConn, CONN_PROP_PORT, &x );
+
+ if ( status == BAD ) { return BAD; }
+
+ ////// User name
+ // get length
+ x = SendDlgItemMessage ( hDlg, IDC_UID, EM_LINELENGTH, 0, 0 );
+
+ if ( x > 0 ) {
+ // allocate space
+ n = make_unique_str ( x ); // allocate space for holding the text
+ GetDlgItemText ( hDlg, IDC_UID, n.get(), x + 1 );
+ }
+
+ else
+ { n = NULL; }
+
+ // set value in struct
+ status = SetConnProp ( pConn, CONN_PROP_UID, n.get() );
+
+ if ( status == BAD ) { return BAD; }
+
+ ////// Password
+ // get length
+ x = SendDlgItemMessage ( hDlg, IDC_PWD, EM_LINELENGTH, 0, 0 );
+
+ if ( x > 0 ) {
+ // allocate space
+ n = make_unique_str ( x ); // allocate space for holding the text
+ GetDlgItemText ( hDlg, IDC_PWD, n.get(), x + 1 );
+ }
+
+ else
+ { n = NULL; }
+
+ // set value in struct
+ status = SetConnProp ( pConn, CONN_PROP_PWD, n.get() );
+
+ if ( status == BAD ) { return BAD; }
+
+ return GOOD;
+}
+
+
+// --------------------------------------------------------------------------
+// call back for DSN config dialog 1
+// --------------------------------------------------------------------------
+
+INT_PTR CALLBACK DlgDSNCfg1Proc ( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
+ pODBCConn pgConn = NULL;
+ eGoodBad status = GOOD;
+ RETCODE ret = SQL_SUCCESS;
+
+ switch ( uMsg ) {
+ case WM_INITDIALOG:
+ // store the structure for future use
+ SetWindowLongPtr ( hDlg, DWLP_USER, lParam );
+ // initialize the dialog with data from conn struct
+ PutDataToDlgDSNCfg1 ( ( pODBCConn ) lParam, hDlg );
+ // set focus automatically
+ return TRUE;
+
+ case WM_COMMAND:
+ switch ( LOWORD ( wParam ) ) {
+ case IDC_CONNECT: {
+ HWND hwndCombo = GetDlgItem ( hDlg, IDC_COMBO1 );
+ HWND hwndOK = GetDlgItem ( hDlg, IDOK );
+ // fetch all information from controls & feed to struct
+ pgConn = ( pODBCConn ) GetWindowLongPtr ( hDlg, DWLP_USER );
+ status = GetDataFromDlgDSNCfg1 ( hDlg, pgConn );
+
+ if ( status == BAD ) {
+ //Blank input, already popped message
+ return FALSE;
+ }
+
+ ret = TryAuthenticate ( pgConn );
+
+ if ( ret == SQL_ERROR ) {
+ //validation of data & other prompts goes here
+ __ODBCPopMsg ( "Username/Password not authorized, or server out of service." );
+ return FALSE;
+ }
+
+ //passed verification
+ EnableWindow ( hwndCombo, TRUE );
+
+ try {
+ std::vector<string> projects;
+ restListProjects ( pgConn->Server, pgConn->ServerPort, pgConn->UserName, pgConn->Password, projects );
+
+ for ( unsigned int i = 0 ; i < projects.size(); ++i ) {
+ SendMessage ( hwndCombo, ( UINT ) CB_ADDSTRING, ( WPARAM ) 0, ( LPARAM ) projects.at ( i ).c_str() );
+ }
+
+ SendMessage ( hwndCombo, CB_SETCURSEL, ( WPARAM ) 0, ( LPARAM ) 0 );
+ }
+
+ catch ( exception& e ) {
+ __ODBCPopMsg ( e.what() );
+ return FALSE;
+ }
+
+ EnableWindow ( hwndOK, TRUE );
+ return TRUE;
+ }
+
+ case IDOK: {
+ pgConn = ( pODBCConn ) GetWindowLongPtr ( hDlg, DWLP_USER );
+ HWND hwndCombo = GetDlgItem ( hDlg, IDC_COMBO1 );
+ int ItemIndex = SendMessage ( ( HWND ) hwndCombo, ( UINT ) CB_GETCURSEL,
+ ( WPARAM ) 0, ( LPARAM ) 0 );
+ TCHAR projectName[256];
+ ( TCHAR ) SendMessage ( ( HWND ) hwndCombo, ( UINT ) CB_GETLBTEXT,
+ ( WPARAM ) ItemIndex, ( LPARAM ) projectName );
+ SetConnProp ( pgConn, CONN_PROP_PROJECT, projectName );
+ //last trial with project given
+ ret = TryFetchMetadata ( pgConn );
+
+ if ( ret == SQL_ERROR ) {
+ //validation of data & other prompts goes here
+ __ODBCPopMsg ( "Something went wrong with your selected project" );
+ return FALSE;
+ }
+
+ EndDialog ( hDlg, wParam );
+ return TRUE;
+ }
+
+ // Fall through, do not break or return
+ case IDCANCEL:
+ // indicate end with control id as return value
+ EndDialog ( hDlg, wParam );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+// -----------------------------------------------------------------------
+// to get connection info from user
+// -----------------------------------------------------------------------
+
+static Word PromptForConnInfo ( SQLHDBC pConn ) {
+ int i;
+ // invoke dialog to fetch info
+ i = DialogBoxParam ( ghInstDLL, MAKEINTRESOURCE ( IDD_DSN_CFG1 ), NULL, DlgDSNCfg1Proc, ( LPARAM ) pConn );
+
+ // check status
+ switch ( i ) {
+ case IDOK:
+ return 1; // complete
+
+ default:
+ return 0; // user-cancelled
+ }
+}
+
+
+// -----------------------------------------------------------------------
+// to split a given string into key value pairs separated with semi-colon
+// -----------------------------------------------------------------------
+
+eGoodBad CvtStrToKeyValues ( CStrPtr pStr, Word pMaxLen, Word* pNumPair, struct ODBCKV** pKV ) {
+ bool flgError;
+ Word x;
+ Word pairs;
+ Word i, len;
+ struct ODBCKV* kvtemp;
+ struct ODBCKV* kv;
+ // caller safe
+ *pNumPair = 0;
+ *pKV = NULL;
+ // local initializations
+ kvtemp = NULL;
+ kv = NULL;
+
+ // main loop to split the strings into key values
+ for ( pairs = 0, i = 0, len = ( pMaxLen > 0 ) ? pMaxLen : strlen ( pStr ), flgError = FALSE; i < len &&
+ !flgError; pairs ++ ) {
+ // find the length of key
+ for ( x = 0; pStr[i] != '=' && i < len; x ++, i ++ );
+
+ // check if a valid key found
+ if ( x <= 0 ) {
+ flgError = TRUE; // error condition
+ continue;
+ }
+
+ // allocate a new record ie key-value if required
+ if ( kv == NULL || pairs % KV_BLOCK_SIZE == 0 ) {
+ // allocate more records
+ kvtemp = new struct ODBCKV[pairs + KV_BLOCK_SIZE];
+ memset ( kvtemp, 0, sizeof ( struct ODBCKV ) * ( pairs + KV_BLOCK_SIZE ) );
+
+ // transfer the old ones into this new one
+ if ( kv ) {
+ memcpy ( kvtemp, kv, sizeof ( struct ODBCKV ) *pairs );
+ delete[] kv;
+ kv = NULL;
+ }
+
+ // now start using the new one
+ kv = kvtemp;
+ kvtemp = NULL;
+ }
+
+ // create key in current row
+ kv[pairs].key = new Char[x + 1];
+ // put key
+ strncpy ( kv[pairs].key, pStr + ( i - x ), x );
+ kv[pairs].key[x] = 0;
+ // move ahead to ignore equals sign
+ ++ i;
+
+ // find the length of value
+ if ( strcmp ( kv[pairs].key, "PWD" ) != 0 ) {
+ for ( x = 0; pStr[i] != ';' && i < len; x ++, i ++ ) ;
+ }
+
+ else {
+ //There may exist ; in PWD
+ for ( x = 0; i < len; x ++, i ++ ) {
+ if ( strncmp ( &pStr[i], ";SERVER=", 8 ) == 0 )
+ { break; }
+ }
+ }
+
+ // check if a non-empty value found
+ if ( x > 0 ) {
+ // create value in current row
+ kv[pairs].value = new Char[x + 1];
+ // put value
+ strncpy ( kv[pairs].value, pStr + ( i - x ), x );
+ kv[pairs].value[x] = 0;
+ }
+
+ // move ahead to ignore the semi-colon at end of key-value
+ ++ i;
+ }
+
+ // check for error condition
+ if ( flgError ) {
+ // clean up
+ if ( kv ) {
+ delete[] kv;
+ kv = NULL;
+ }
+
+ return BAD; // error condition
+ }
+
+ else {
+ *pNumPair = pairs;
+ *pKV = kv;
+ return GOOD;
+ }
+}
+
+void FreeGenODBCKeyValues ( ODBCKV* keyvalues, int pairs ) {
+ for ( int i = 0 ; i < pairs; ++i ) {
+ if ( keyvalues[i].key )
+ { delete[] keyvalues[i].key ; }
+
+ if ( keyvalues[i].value )
+ { delete[] keyvalues[i].value; }
+ }
+}
+
+
+// -----------------------------------------------------------------------
+// to find a particular key and/or value in key-value pair list
+// -----------------------------------------------------------------------
+
+bool FindInKeyValues ( CStrPtr pKey, CStrPtr pValue, struct ODBCKV* pKV, Word pItems, Word* pPosition ) {
+ Word i;
+ bool flgMatch;
+
+ // loop to traverse the list
+ for ( i = 0, flgMatch = FALSE; i < pItems; i ++ ) {
+ // match key
+ flgMatch = ( pKey && _stricmp ( pKey, pKV[i].key ) == 0 );
+
+ // match value
+ if ( pValue && pKV[i].value )
+ { flgMatch = ( _stricmp ( pValue, pKV[i].value ) == 0 ); }
+
+ // break if match
+ if ( flgMatch ) { break; }
+ }
+
+ // check if found
+ if ( flgMatch ) {
+ if ( pPosition ) { *pPosition = i; }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+// -----------------------------------------------------------------------
+// to load key value pairs from a File DSN
+// -----------------------------------------------------------------------
+
+static eGoodBad LoadKeyValuesfromFileDSN ( pODBCConn pConn, CStrPtr pDSNName, Word* pNumPair,
+ struct ODBCKV** pKV ) {
+ //Never called
+ throw - 1;
+}
+
+
+// -----------------------------------------------------------------------
+// to add a key-value pair to specified conn string
+// -----------------------------------------------------------------------
+
+static bool AddKVToConnStr ( StrPtr pKey, StrPtr pValue, Word* iPos, StrPtr pStrConn, Word pMaxLen ) {
+ Word i, j;
+
+ // precaution
+ if ( !pKey )
+ { return FALSE; }
+
+ // get length of key and value
+ i = strlen ( pKey );
+ j = ( pValue ) ? strlen ( pValue ) : 0;
+
+ // check if both can be added along with equal sign & semi-colon
+ if ( *iPos + i + j + 2 <= pMaxLen ) {
+ strcat ( pStrConn, pKey );
+ strcat ( pStrConn, "=" );
+
+ if ( pValue )
+ { strcat ( pStrConn, pValue ); }
+
+ strcat ( pStrConn, ";" );
+ ( *iPos ) = ( *iPos ) + i + j + 2; // re-position
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+// -----------------------------------------------------------------------
+// to build the out-connection string
+// -----------------------------------------------------------------------
+
+static bool BuildConnStr ( char* pStrConn, Word pMaxLen, pODBCConn pConn, struct ODBCKV* KVInput,
+ Word iKVInputPairs, struct ODBCKV* KVFileDSN, Word iKVFileDSNPairs ) {
+ Word iPos = 0;
+ Char p[32]; // arbitary for string port number as string
+ // initializations
+ memset ( pStrConn, 0, pMaxLen );
+ // convert port number to string
+ _itoa ( pConn->ServerPort, p, 10 );
+
+ // transfer all strings from struct
+ if ( !AddKVToConnStr ( "DRIVER", "{KylinODBCDriver}", &iPos, pStrConn, pMaxLen ) ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "AddKVToConnStr failed in %s", "Driver" ) );
+ return FALSE;
+ }
+
+ if ( !AddKVToConnStr ( "SERVER", pConn->Server, &iPos, pStrConn, pMaxLen ) ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "AddKVToConnStr failed in %s", "Server" ) );
+ return FALSE;
+ }
+
+ if ( !AddKVToConnStr ( "PROJECT", pConn->Project, &iPos, pStrConn, pMaxLen ) ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "AddKVToConnStr failed in %s", "Project" ) );
+ return FALSE;
+ }
+
+ if ( !AddKVToConnStr ( "PORT", p, &iPos, pStrConn, pMaxLen ) ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "AddKVToConnStr failed in %s", "Port" ) );
+ return FALSE;
+ }
+
+ if ( !AddKVToConnStr ( "UID", pConn->UserName, &iPos, pStrConn, pMaxLen ) ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "AddKVToConnStr failed in %s", "Uid" ) );
+ return FALSE;
+ }
+
+ if ( !AddKVToConnStr ( "PWD", pConn->Password, &iPos, pStrConn, pMaxLen ) ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "AddKVToConnStr failed in %s", "Pwd" ) );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+// to connect to the driver
+// -----------------------------------------------------------------------
+RETCODE SQL_API SQLDriverConnectW ( SQLHDBC hdbc,
+ SQLHWND hwnd,
+ SQLWCHAR* szConnStrIn,
+ SQLSMALLINT cchConnStrIn,
+ SQLWCHAR* szConnStrOut,
+ SQLSMALLINT cchConnStrOutMax,
+ SQLSMALLINT* pcchConnStrOut,
+ SQLUSMALLINT fDriverCompletion ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLDriverConnectW called, cchConnStrIn %d, cchConnStrOutMax %d, wcslen %d",
+ cchConnStrIn, cchConnStrOutMax, wcslen ( szConnStrIn ) ) );
+ int inStrLength = wcslen ( szConnStrIn ) + 1;
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The inStr Length is : %d", inStrLength ) );
+ unique_ptr<char[]> pInStr ( new char[inStrLength] );
+ unique_ptr<char[]> pOutStr ( new char[cchConnStrOutMax + 1] );
+ wchar2char ( szConnStrIn, pInStr.get(), inStrLength );
+ //__ODBCLOG(_ODBCLogMsg(LogLevel_DEBUG,"The inStr is : %s",pInStr.get()));
+ SQLSMALLINT outStrLength = 0 ;
+ RETCODE code = SQLDriverConnect ( hdbc, hwnd, ( SQLCHAR* ) pInStr.get(), cchConnStrIn, ( SQLCHAR* ) pOutStr.get(),
+ cchConnStrOutMax, &outStrLength, fDriverCompletion );
+
+ if ( code == SQL_ERROR ) {
+ return code;
+ }
+
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "pcchConnStrOut null? %d, cchConnStrOutMax > 0 ? %d, szConnStrOut null? %d",
+ pcchConnStrOut == NULL, cchConnStrOutMax > 0 , szConnStrOut == NULL ) );
+
+ if ( cchConnStrOutMax > 0 && pcchConnStrOut && szConnStrOut ) {
+ char2wchar ( pOutStr.get(), szConnStrOut, ( int ) cchConnStrOutMax );
+ *pcchConnStrOut = wcslen ( szConnStrOut );
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "(W)The Length of Out Conn Str is %d", *pcchConnStrOut ) );
+ }
+
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "the ret code is %d", code ) );
+ return code;
+}
+
+RETCODE SQL_API SQLDriverConnect ( SQLHDBC pConn,
+ SQLHWND pWndHandle,
+ SQLCHAR* pInConnStr,
+ SQLSMALLINT pInConnStrLen,
+ SQLCHAR* pOutConnStr,
+ SQLSMALLINT pOutConnStrLen,
+ SQLSMALLINT* pOutConnStrLenPtr,
+ SQLUSMALLINT pDriverCompletion ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The window handle is %d, the driver completion flag is %d", pWndHandle,
+ pDriverCompletion ) );
+ pODBCConn pgConn = ( pODBCConn ) pConn;
+ bool f;
+ bool flgDriver, flgDSN; // flags for knowing if these key present in string
+ bool flgServer, flgPort, flgUID, flgPWD, flgProj; // flags for knowing if these key present in string
+ Word i, n;
+ Word iKVInputPairs; // no of key value pairs as input
+ Word iDriverPos, iDSNPos; // ??? can be eliminated by optimization of code
+ Word iServerPos, iPortPos, iUIDPos, iPWDPos, iProjPos; // ??? can be eliminated by optimization of code
+ struct ODBCKV* KVInput; // key value as input via function param
+ struct ODBCKV* KV; // generic, temp
+
+ if ( !pInConnStr ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLDriverConnect: pInConnStr is required" ) );
+ return SQL_ERROR;
+ }
+
+ else {
+ //__ODBCLOG(_ODBCLogMsg(LogLevel_DEBUG,"The passed-in Connection Str is %s",(char*)pInConnStr));
+ }
+
+ __CHK_HANDLE ( pConn, SQL_HANDLE_DBC, SQL_ERROR );
+ _SQLFreeDiag ( _DIAGCONN ( pConn ) );
+
+ // caller safe
+ if ( pOutConnStr ) { *pOutConnStr = 0; }
+
+ if ( pOutConnStrLenPtr ) { *pOutConnStrLenPtr = 0; }
+
+ // initializations
+ KVInput = NULL;
+ flgServer = FALSE;
+ flgPort = FALSE;
+ flgUID = FALSE;
+ flgPWD = FALSE;
+ flgProj = FALSE;
+
+ // check if an in-string has been specified
+ if ( pInConnStr ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Parsing the in str" ) );
+
+ // split into key-value pairs
+ if ( CvtStrToKeyValues ( ( StrPtr ) pInConnStr, pInConnStrLen, &iKVInputPairs, &KVInput ) != GOOD ) {
+ return SQL_ERROR;
+ }
+
+ // first check if dsn keyword is present
+ flgDSN = FindInKeyValues ( "DSN", NULL, KVInput, iKVInputPairs, &iDSNPos );
+ // look for driver only if DSN is absent else Driver is always ignored
+ flgDriver = ( flgDSN ) ? FALSE : FindInKeyValues ( "DRIVER", NULL, KVInput, iKVInputPairs, &iDriverPos );
+
+ // if DSN is to be used, fetch its set of key values
+ if ( flgDSN ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The in str is a dsn string" ) );
+ //connect by dsn
+ SetCurrentDSN ( ( char* ) pInConnStr, "SQLDriverConnect" );
+
+ if ( LoadODBCINIDataToConn ( pgConn ) != GOOD ) {
+ return SQL_ERROR;
+ }
+ }
+
+ else if ( flgDriver ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The in str is a driver string" ) );
+ /************* debug
+ for ( i = 0, n = iKVInputPairs, KV = KVInput; i < n; i++ )
+ fprintf ( stderr, "Index: %d, Key: %s, Value: %s\n", i, KV[i].key ? KV[i].key : "(nokey)", KV[i].value ? KV[i].value : "(no value)" );
+ *********/
+
+ // loop to parse both input key-values and DSN key-values & feed into struct
+ for ( i = 0, n = iKVInputPairs, KV = KVInput; i < n; i++ ) {
+ if ( !flgServer ) {
+ flgServer = FindInKeyValues ( "SERVER", NULL, KV, n, &iServerPos );
+
+ if ( flgServer ) { CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_SERVER, KV[iServerPos].value ); }
+ }
+
+ if ( !flgPort ) {
+ flgPort = FindInKeyValues ( "PORT", NULL, KV, n, &iPortPos );
+
+ if ( flgPort ) { CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_PORT, KV[iPortPos].value ); }
+ }
+
+ if ( !flgUID ) {
+ flgUID = FindInKeyValues ( "UID", NULL, KV, n, &iUIDPos );
+
+ if ( flgUID ) {
+ CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_UID, KV[iUIDPos].value );
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "Log in as User : %s ", KV[iUIDPos].value ) );
+ }
+ }
+
+ if ( !flgPWD ) {
+ flgPWD = FindInKeyValues ( "PWD", NULL, KV, n, &iPWDPos );
+
+ if ( flgPWD ) { CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_PWD, KV[iPWDPos].value ); }
+ }
+
+ if ( !flgProj ) {
+ flgProj = FindInKeyValues ( "PROJECT", NULL, KV, n, &iProjPos );
+
+ if ( flgProj ) { CreateAndSetConnProp ( ( pODBCConn ) pConn, CONN_PROP_PROJECT, KV[iProjPos].value ); }
+ }
+ }
+ }
+
+ else {
+ _SQLPutDiagRow ( SQL_HANDLE_DBC, pConn, "SQLDriverConnectW", "HY000", 1045, "Only DSN or driver connect is allowed" );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "Only DSN or driver connect is allowed, instead of %s", pInConnStr ) );
+ return SQL_ERROR;
+ }
+
+ FreeGenODBCKeyValues ( KVInput, iKVInputPairs );
+ delete[] KVInput;
+ }
+
+ else if ( pDriverCompletion == SQL_DRIVER_NOPROMPT ) { // check if no-prompt forced
+ __ODBCPOPMSG ( _ODBCPopMsg ( "No connection string && no prompt specified" ) );
+ _SQLPutDiagRow ( SQL_HANDLE_DBC, pConn, "SQLDriverConnectW", "HY000", 1045,
+ "Access denied. (using UID: NO , using password: NO)" );
+ return SQL_ERROR;
+ }
+
+ RETCODE ret;
+
+ // check if prompt required ie any info is missing
+ if ( flgDriver && ( !flgServer || !flgPort || !flgUID || !flgPWD || !flgProj ) ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "Connection info imcomplete, prompt for input..." ) );
+
+ if ( flgUID && !flgPWD && pDriverCompletion == SQL_DRIVER_NOPROMPT ) {
+ _SQLPutDiagRow ( SQL_HANDLE_DBC, pConn, "SQLDriverConnectW", "HY000", 1045,
+ "Access denied for user 'root'@'kylin-tableau-clean.com' (using password: NO)" );
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR,
+ "UID present but PWD absent, guessing it's on Tableau Server, return SQL ERROR" ) );
+ return SQL_ERROR;
+ }
+
+ //connect by driver
+ // fetch entire connection information thru dialogs
+ switch ( PromptForConnInfo ( pConn ) ) {
+ case 0: // user-cancelled
+ return SQL_NO_DATA_FOUND;
+
+ default:
+ break;
+ }
+
+ ret = SQL_SUCCESS;
+ }
+
+ else {
+ ret = TryFetchMetadata ( pgConn ) ;
+
+ if ( ret == SQL_ERROR ) {
+ return ret;
+ }
+ }
+
+ // OUT CONN STRING
+ // build the out-connection string if required
+ if ( pOutConnStr && pOutConnStrLen > 0 && pOutConnStrLenPtr ) {
+ if ( flgDriver ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Building out str..." ) );
+ // build the out conn string using key value pairs
+ f = BuildConnStr ( ( StrPtr ) pOutConnStr, pOutConnStrLen, ( pODBCConn ) pConn, NULL, 0, NULL, 0 );
+
+ if ( !f ) {
+ _SQLPutDiagRow ( SQL_HANDLE_DBC, pConn, "SQLDriverConnectW", "HY000", 1045, "Out connection string not complete" );
+ }
+ }
+
+ else {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Copy in str to out str" ) );
+ strcpy ( ( char* ) pOutConnStr, ( char* ) pInConnStr );
+ }
+
+ *pOutConnStrLenPtr = strlen ( ( StrPtr ) pOutConnStr );
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "The Length of Out Conn Str is %d", *pOutConnStrLenPtr ) );
+ }
+
+ else {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "skip writing to the out put string" ) );
+ }
+
+ return ret;
+}
+
+
+RETCODE TryFetchMetadata ( pODBCConn pgConn ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "start loading metadata..." ) );
+
+ try {
+ pgConn->meta = std::move ( restGetMeta ( pgConn->Server, pgConn->ServerPort, pgConn->UserName, pgConn->Password,
+ pgConn->Project ) );
+ }
+
+ catch ( const exception& e ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, "The REST request failed to get metadata" ) );
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, e.what() ) );
+ _SQLPutDiagRow ( SQL_HANDLE_DBC, pgConn, "SQLDriverConnect", "HY000", 1045, "Access denied. (using password: NO)" );
+ return SQL_ERROR;
+ }
+
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "End loading metadata" ) );
+ return SQL_SUCCESS;
+}
+
+RETCODE TryAuthenticate ( pODBCConn pgConn ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Start authenticating.." ) );
+
+ try {
+ bool authenticated = restAuthenticate ( pgConn->Server, pgConn->ServerPort, pgConn->UserName, pgConn->Password );
+
+ if ( !authenticated )
+ { throw exception ( "Username/Password incorrect." ); }
+ }
+
+ catch ( const exception& e ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, "The REST request failed to authenticate." ) );
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_ERROR, e.what() ) );
+ _SQLPutDiagRow ( SQL_HANDLE_DBC, pgConn, "SQLDriverConnect", "HY000", 1045, "Access denied. (using password: NO)" );
+ return SQL_ERROR;
+ }
+
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "End authenticating" ) );
+ return SQL_SUCCESS;
+}
+
+// -----------------------------------------------------------------------
+// to connect to the server using standard parameters
+// -----------------------------------------------------------------------
+
+RETCODE SQL_API SQLConnect ( SQLHDBC pConn,
+ SQLCHAR* pServerName,
+ SQLSMALLINT pServerNameLen,
+ SQLCHAR* pUserName,
+ SQLSMALLINT pUserNameLen,
+ SQLCHAR* pPassword,
+ SQLSMALLINT pPasswordLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLConnect called" ) );
+ __CHK_HANDLE ( pConn, SQL_HANDLE_DBC, SQL_ERROR );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLConnect - not implemented, use SQLDriverConnect" ) );
+ return SQL_ERROR;
+ _SQLFreeDiag ( _DIAGCONN ( pConn ) );
+ return ( SQL_SUCCESS );
+}
+
+SQLRETURN SQL_API SQLConnectW ( SQLHDBC hdbc,
+ SQLWCHAR* szDSN,
+ SQLSMALLINT cchDSN,
+ SQLWCHAR* szUID,
+ SQLSMALLINT cchUID,
+ SQLWCHAR* szAuthStr,
+ SQLSMALLINT cchAuthStr
+ ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLConnectW called" ) );
+ __CHK_HANDLE ( hdbc, SQL_HANDLE_DBC, SQL_ERROR );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLConnectW - not implemented, use SQLDriverConnectW" ) );
+ return SQL_ERROR;
+ _SQLFreeDiag ( _DIAGCONN ( hdbc ) );
+ return ( SQL_SUCCESS );
+}
+
+
+
+// -----------------------------------------------------------------------
+// to connect in multiple iterations
+// -----------------------------------------------------------------------
+
+RETCODE SQL_API SQLBrowseConnect ( SQLHDBC pConn,
+ SQLCHAR* InConnectionString,
+ SQLSMALLINT StringLength1,
+ SQLCHAR* OutConnectionString,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT* StringLength2Ptr ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLBrowseConnect called" ) );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLBrowseConnect - not implemented, use SQLDriverConnect" ) );
+ return SQL_ERROR;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/d1dcfd15/odbc/Driver/KO_CTLG.CPP
----------------------------------------------------------------------
diff --git a/odbc/Driver/KO_CTLG.CPP b/odbc/Driver/KO_CTLG.CPP
new file mode 100644
index 0000000..0170428
--- /dev/null
+++ b/odbc/Driver/KO_CTLG.CPP
@@ -0,0 +1,341 @@
+// ----------------------------------------------------------------------------
+//
+// File: KO_CTLG.CPP
+//
+// Purpose: Contains catalog functions
+// Functions that allow collection of metadata/information
+// about the database are termed as catalog functions.
+// For example SQLTables allows you to get all the
+// databases, users on the server or tables in database.
+// Similarly SQLColumns allows you to get all the cols
+// in a table.
+//
+// Exported functions:
+// SQLTables
+// SQLColumns
+// SQLSpecialColumns
+// SQLStatistics
+// SQLPrimaryKeys
+// SQLForeignKeys
+// SQLTablePrivileges
+// SQLColumnPrivileges
+// SQLProcedures
+// SQLProcedureColumns
+//
+// ----------------------------------------------------------------------------
+
+#include "stdafx.h"
+
+
+
+// -----------------------------------------------------------------------
+// to get list of catalog(database), schema(users), tables(tables)
+// ------------------------------------------------------------------------
+
+RETCODE SQL_API SQLTablesW ( SQLHSTMT pStmt,
+ SQLWCHAR* pCatalogName,
+ SQLSMALLINT pCatalogNameSize,
+ SQLWCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameSize,
+ SQLWCHAR* pTableName,
+ SQLSMALLINT pTableNameSize,
+ SQLWCHAR* pTableType,
+ SQLSMALLINT pTableTypeSize ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLTablesW is called " ) );
+ unique_ptr<char[]> p1 ( wchar2char ( pCatalogName ) );
+ unique_ptr<char[]> p2 ( wchar2char ( pSchemaName ) );
+ unique_ptr<char[]> p3 ( wchar2char ( pTableName ) );
+ unique_ptr<char[]> p4 ( wchar2char ( pTableType ) );
+ return SQLTables ( pStmt, ( SQLCHAR* ) p1.get(), pCatalogNameSize, ( SQLCHAR* ) p2.get(), pSchemaNameSize,
+ ( SQLCHAR* ) p3.get(), pTableNameSize, ( SQLCHAR* ) p4.get(), pTableTypeSize );
+}
+
+RETCODE SQL_API SQLTables ( SQLHSTMT pStmt,
+ SQLCHAR* pCatalogName,
+ SQLSMALLINT pCatalogNameSize,
+ SQLCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameSize,
+ SQLCHAR* pTableName,
+ SQLSMALLINT pTableNameSize,
+ SQLCHAR* pTableType,
+ SQLSMALLINT pTableTypeSize ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLTables: Ctlg: %s, %d, Schema: %s, %d, Table: %s,%d, Type: %s, %d",
+ pCatalogName, pCatalogNameSize, pSchemaName, pSchemaNameSize, pTableName, pTableNameSize, pTableType,
+ pTableTypeSize ) );
+ __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR );
+ _SQLFreeDiag ( _DIAGSTMT ( pStmt ) );
+ std::unique_ptr<SQLResponse> p = SQLResponse::MakeResp4SQLTables ( ( ( pODBCStmt ) pStmt )->Conn->meta.get() );
+
+ if ( PutRespToStmt ( ( pODBCStmt ) pStmt, std::move ( p ) ) != GOOD ) {
+ return SQL_ERROR;
+ }
+
+ return SQL_SUCCESS;
+}
+
+// -----------------------------------------------------------------------
+// to get the list of column names in specified tables
+// ------------------------------------------------------------------------
+
+RETCODE SQL_API SQLColumnsW ( SQLHSTMT pStmt,
+ SQLWCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLWCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLWCHAR* pTableName,
+ SQLSMALLINT pTableNameLen,
+ SQLWCHAR* pColumnName,
+ SQLSMALLINT pColumnNameLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLColumnsW is called" ) );
+ unique_ptr<char[]> p1 ( wchar2char ( pCtlgName ) );
+ unique_ptr<char[]> p2 ( wchar2char ( pSchemaName ) );
+ unique_ptr<char[]> p3 ( wchar2char ( pTableName ) );
+ unique_ptr<char[]> p4 ( wchar2char ( pColumnName ) );
+ return SQLColumns ( pStmt, ( SQLCHAR* ) p1.get(), pCtlgNameLen, ( SQLCHAR* ) p2.get(), pSchemaNameLen,
+ ( SQLCHAR* ) p3.get(), pTableNameLen, ( SQLCHAR* ) p4.get(), pColumnNameLen );
+}
+
+RETCODE SQL_API SQLColumns ( SQLHSTMT pStmt,
+ SQLCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLCHAR* pTableName,
+ SQLSMALLINT pTableNameLen,
+ SQLCHAR* pColumnName,
+ SQLSMALLINT pColumnNameLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLColumns called, Ctlg: %s, %d. Schema: %s, %d, Table: %s, %d, Col: %s, %d",
+ pCtlgName, pCtlgNameLen, pSchemaName, pSchemaNameLen, pTableName, pTableNameLen, pColumnName, pColumnNameLen ) );
+ __CHK_HANDLE ( pStmt, SQL_HANDLE_STMT, SQL_ERROR );
+ _SQLFreeDiag ( _DIAGSTMT ( pStmt ) );
+ // feed stmt structure with response
+ std::unique_ptr<SQLResponse> p = SQLResponse::MakeResp4SQLColumns ( ( ( pODBCStmt ) pStmt )->Conn->meta.get(),
+ ( char* ) pTableName, ( char* ) pColumnName );
+
+ if ( PutRespToStmt ( ( pODBCStmt ) pStmt, std::move ( p ) ) != GOOD ) {
+ return SQL_ERROR;
+ }
+
+ return SQL_SUCCESS;
+}
+
+
+// -----------------------------------------------------------------------
+// to get the list of column names which make a row unqiue or r updateable
+// ------------------------------------------------------------------------
+
+SQLRETURN SQL_API SQLSpecialColumns ( SQLHSTMT pStmt,
+ SQLUSMALLINT pIdentifierType,
+ SQLCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLCHAR* pTableName,
+ SQLSMALLINT pTableNameLen,
+ SQLUSMALLINT pScope,
+ SQLUSMALLINT pNullable )
+
+{
+ // note
+ // possible values for pIdentifierType are
+ // SQL_BEST_ROWID ----- primary key columns
+ // SQL_ROWVER --------- all updateable columns
+ //
+ // possible values for pScope are
+ // SQL_SCOPE_CURROW
+ // SQL_SCOPE_TRANSACTION
+ // SQL_SCOPE_SESSION
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLSpecialColumns called, Ctlg: %s, %d. Schema: %s, %d, Table: %s, %d",
+ pCtlgName, pCtlgNameLen, pSchemaName, pSchemaNameLen, pTableName, pTableNameLen ) );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLSpecialColumns not implemented" ) );
+ return SQL_ERROR;
+}
+
+// -----------------------------------------------------------------------
+// to get table and/or index statistics
+// ------------------------------------------------------------------------
+
+RETCODE SQL_API SQLStatistics ( SQLHSTMT pStmt,
+ SQLCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLCHAR* pTableName,
+ SQLSMALLINT pTableNameLen,
+ SQLUSMALLINT pUnique,
+ SQLUSMALLINT pReserved ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLStatistics called" ) );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLStatistics not implemented" ) );
+ return SQL_ERROR;
+}
+
+// -----------------------------------------------------------------------
+// to get columns which make up the p-keys
+// ------------------------------------------------------------------------
+RETCODE SQL_API SQLPrimaryKeysW ( SQLHSTMT pStmt,
+ SQLWCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLWCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLWCHAR* pTableName,
+ SQLSMALLINT pTableNameLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLPrimaryKeysW called" ) );
+ return SQLPrimaryKeys ( pStmt, NULL, NULL, NULL, NULL, NULL, NULL );
+}
+
+
+RETCODE SQL_API SQLPrimaryKeys ( SQLHSTMT pStmt,
+ SQLCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLCHAR* pTableName,
+ SQLSMALLINT pTableNameLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLPrimaryKeys called" ) );
+ std::unique_ptr<SQLResponse> p ( new SQLResponse() );
+
+ if ( PutRespToStmt ( ( pODBCStmt ) pStmt, std::move ( p ) ) != GOOD ) {
+ return SQL_ERROR;
+ }
+
+ return SQL_SUCCESS;
+}
+
+// -----------------------------------------------------------------------
+// to get foreign key information
+// ------------------------------------------------------------------------
+RETCODE SQL_API SQLForeignKeysW ( SQLHSTMT pStmt,
+ SQLWCHAR* pPKCtlgName,
+ SQLSMALLINT pPKCtlgNameLen,
+ SQLWCHAR* pPKSchemaName,
+ SQLSMALLINT pPKSchemaNameLen,
+ SQLWCHAR* pPKTableName,
+ SQLSMALLINT pPKTableNameLen,
+ SQLWCHAR* pFKCtlgName,
+ SQLSMALLINT pFKCtlgNameLen,
+ SQLWCHAR* pFKSchemaName,
+ SQLSMALLINT pFKSchemaNameLen,
+ SQLWCHAR* pFKTableName,
+ SQLSMALLINT pFKTableNameLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLForeignKeysW called" ) );
+ unique_ptr<char[]> p1 ( wchar2char ( pPKCtlgName ) );
+ unique_ptr<char[]> p2 ( wchar2char ( pPKSchemaName ) );
+ unique_ptr<char[]> p3 ( wchar2char ( pPKTableName ) );
+ unique_ptr<char[]> p4 ( wchar2char ( pFKCtlgName ) );
+ unique_ptr<char[]> p5 ( wchar2char ( pFKSchemaName ) );
+ unique_ptr<char[]> p6 ( wchar2char ( pFKTableName ) );
+ return SQLForeignKeys ( pStmt,
+ ( SQLCHAR* ) p1.get(),
+ pPKCtlgNameLen,
+ ( SQLCHAR* ) p2.get(),
+ pPKSchemaNameLen,
+ ( SQLCHAR* ) p3.get(),
+ pPKTableNameLen,
+ ( SQLCHAR* ) p4.get(),
+ pFKCtlgNameLen,
+ ( SQLCHAR* ) p5.get(),
+ pFKSchemaNameLen,
+ ( SQLCHAR* ) p6.get(),
+ pFKTableNameLen );
+}
+
+RETCODE SQL_API SQLForeignKeys ( SQLHSTMT pStmt,
+ SQLCHAR* pPKCtlgName,
+ SQLSMALLINT pPKCtlgNameLen,
+ SQLCHAR* pPKSchemaName,
+ SQLSMALLINT pPKSchemaNameLen,
+ SQLCHAR* pPKTableName,
+ SQLSMALLINT pPKTableNameLen,
+ SQLCHAR* pFKCtlgName,
+ SQLSMALLINT pFKCtlgNameLen,
+ SQLCHAR* pFKSchemaName,
+ SQLSMALLINT pFKSchemaNameLen,
+ SQLCHAR* pFKTableName,
+ SQLSMALLINT pFKTableNameLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG,
+ "SQLForeignKeys called pPKCtlgName: %s, pPKSchemaName : %s, pPKTableName: %s, pFKCtlgName: %s, pFKSchemaName: %s, pFKTableName: %s",
+ pPKCtlgName, pPKSchemaName, pPKTableName, pFKCtlgName, pFKSchemaName, pFKTableName ) );
+ std::unique_ptr<SQLResponse> p ( new SQLResponse() );
+
+ if ( PutRespToStmt ( ( pODBCStmt ) pStmt, std::move ( p ) ) != GOOD ) {
+ return SQL_ERROR;
+ }
+
+ return SQL_SUCCESS;
+}
+
+
+// -----------------------------------------------------------------------
+// to get a list of tables and the privileges associated with each table
+// ------------------------------------------------------------------------
+
+RETCODE SQL_API SQLTablePrivileges ( SQLHSTMT pStmt,
+ SQLCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLCHAR* pTableName,
+ SQLSMALLINT pTableNameLen )
+
+{
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLTablePrivileges called" ) );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLTablePrivileges not implemented" ) );
+ return SQL_ERROR;
+}
+
+// -----------------------------------------------------------------------
+// to get a list of columns and associated privileges for the specified table
+// ------------------------------------------------------------------------
+
+RETCODE SQL_API SQLColumnPrivileges ( SQLHSTMT pStmt,
+ SQLCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLCHAR* pTableName,
+ SQLSMALLINT pTableNameLen,
+ SQLCHAR* pColumnName,
+ SQLSMALLINT pColumnNameLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLColumnPrivileges called" ) );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLColumnPrivileges not implemented" ) );
+ return SQL_ERROR;
+}
+
+
+// -----------------------------------------------------------------------
+// to get a list of procedure names stored in a specific data source
+// ------------------------------------------------------------------------
+
+
+RETCODE SQL_API SQLProcedures ( SQLHSTMT pStmt,
+ SQLCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLCHAR* pProcName,
+ SQLSMALLINT pProcNameLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLProcedures called" ) );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLProcedures not implemented" ) );
+ return SQL_ERROR;
+}
+
+
+// -----------------------------------------------------------------------
+// to get a list of procedure names stored in a specific data source
+// ------------------------------------------------------------------------
+
+RETCODE SQL_API SQLProcedureColumns ( SQLHSTMT pStmt,
+ SQLCHAR* pCtlgName,
+ SQLSMALLINT pCtlgNameLen,
+ SQLCHAR* pSchemaName,
+ SQLSMALLINT pSchemaNameLen,
+ SQLCHAR* pProcName,
+ SQLSMALLINT pProcNameLen,
+ SQLCHAR* pColumnName,
+ SQLSMALLINT pColumnNameLen ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "SQLProceduresColumns called" ) );
+ __ODBCPOPMSG ( _ODBCPopMsg ( "SQLProceduresColumns not implemented" ) );
+ return SQL_ERROR;
+}
+
+
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/d1dcfd15/odbc/Driver/KO_Config.cpp
----------------------------------------------------------------------
diff --git a/odbc/Driver/KO_Config.cpp b/odbc/Driver/KO_Config.cpp
new file mode 100644
index 0000000..4fa2773
--- /dev/null
+++ b/odbc/Driver/KO_Config.cpp
@@ -0,0 +1,677 @@
+#include "stdafx.h"
+
+#include "StringUtils.h"
+
+#include <stdio.h>
+#include <resource.h>
+#include <REST.h>
+
+#define SERVERKEY "SERVER"
+#define PORTKEY "PORT"
+#define UIDKEY "UID"
+#define PWDKEY "PWD"
+#define PROJECTKEY "PROJECT"
+
+#define BUFFERSIZE 256
+
+#define INITFILE "ODBC.INI"
+#define INSTINIFILE "ODBCINST.INI"
+
+#define DRIVER_NAME "KylinODBCDriver"
+#define DRIVER_DEFAULT_LOCATION "C:\\Program Files (x86)\\kylinolap\\KylinODBCDriver\\driver.dll"
+
+static char currentDSN[BUFFERSIZE];
+
+static int GetValueFromODBCINI ( char* section, char* key, char* defaultValue, char* buffer, int bufferSize,
+ char* initFileName ) {
+ return SQLGetPrivateProfileString ( section, key, defaultValue, buffer, bufferSize, initFileName );
+}
+
+static BOOL SetValueInODBCINI ( char* section, char* key, char* newValue, char* initFileName ) {
+ return SQLWritePrivateProfileString ( section, key, newValue, initFileName );
+}
+
+static BOOL AddDSN ( char* dsnName ) {
+ return SQLWritePrivateProfileString ( "ODBC Data Sources", dsnName, "KylinODBCDriver", INITFILE );
+}
+
+static BOOL RemoveDSN ( char* dsnName ) {
+ BOOL temp = true;
+ temp = SQLWritePrivateProfileString ( dsnName, NULL, NULL, INITFILE );
+ return SQLWritePrivateProfileString ( "ODBC Data Sources", dsnName, NULL, INITFILE ) && temp;
+}
+
+void SetCurrentDSN ( char* connStr, char* logFunc ) {
+ currentDSN[0] = '\0';
+ Word pairCount = 0;
+ Word index = 0 ;
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "%s : lparam: %s", logFunc, connStr ) );
+ ODBCKV* pKV = NULL;
+
+ if ( connStr == NULL || CvtStrToKeyValues ( connStr, -1, &pairCount, &pKV ) != GOOD ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "%s: failed to parse the attribute string %s", logFunc, connStr ) );
+ }
+
+ else {
+ if ( FindInKeyValues ( "DSN", NULL, pKV, pairCount, &index ) != true ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "%s: failed to find the DSN attribute in %s", logFunc, connStr ) );
+ }
+
+ else {
+ strcpy ( currentDSN, pKV[index].value );
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "%s: success to set the currentDSN: %s", logFunc, currentDSN ) );
+ }
+
+ FreeGenODBCKeyValues ( pKV, pairCount );
+ delete[] pKV;
+ }
+}
+
+static eGoodBad LoadODBCINIDataToDlgDSNCfg2 ( HWND hDlg ) {
+ BOOL x;
+ char buffer[BUFFERSIZE];
+
+ // precaution
+ if ( !hDlg ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "LoadODBCINIDataToDlgDSNCfg2 - Bad params: hDlg is NULL" ) );
+ return BAD;
+ }
+
+ // DSN name
+ x = SetDlgItemText ( hDlg, IDC_DSNNAME, currentDSN );
+
+ if ( !x ) { return BAD; }
+
+ // server name/IP
+ GetValueFromODBCINI ( currentDSN, SERVERKEY, "", buffer, BUFFERSIZE, INITFILE );
+ x = SetDlgItemText ( hDlg, IDC_SERVER, buffer );
+
+ if ( !x ) { return BAD; }
+
+ // server port
+ GetValueFromODBCINI ( currentDSN, PORTKEY, "443", buffer, BUFFERSIZE, INITFILE );
+ int portTemp = atoi ( buffer );
+
+ if ( portTemp == 0 )
+ { portTemp = 443; }
+
+ x = SetDlgItemInt ( hDlg, IDC_PORT, portTemp, FALSE );
+
+ if ( !x ) { return BAD; }
+
+ // user name
+ GetValueFromODBCINI ( currentDSN, UIDKEY, "", buffer, BUFFERSIZE, INITFILE );
+ x = SetDlgItemText ( hDlg, IDC_UID, buffer );
+
+ if ( !x ) { return BAD; }
+
+ // password
+ GetValueFromODBCINI ( currentDSN, PWDKEY, "", buffer, BUFFERSIZE, INITFILE );
+ x = SetDlgItemText ( hDlg, IDC_PWD, buffer );
+
+ if ( !x ) { return BAD; }
+
+ return GOOD;
+}
+
+static eGoodBad RetriveDlgData ( HWND hDlg, char* newDSN, char* serverStr, char* uidStr, char* pwdStr, long* port ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Start retrieving the configs..." ) );
+ Long x;
+
+ if ( !hDlg ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "RetriveDlgData - Bad params: hDlg is NULL" ) );
+ return BAD;
+ }
+
+ x = SendDlgItemMessage ( hDlg, IDC_DSNNAME, EM_LINELENGTH, 0, 0 ); // get text from dialog
+
+ if ( x > 0 ) {
+ GetDlgItemText ( hDlg, IDC_DSNNAME, newDSN, BUFFERSIZE ); // get text from dialog
+ }
+
+ else {
+ newDSN[0] = '\0';
+ }
+
+ ////// server name/IP
+ // get length of input text
+ x = SendDlgItemMessage ( hDlg, IDC_SERVER, EM_LINELENGTH, 0, 0 );
+
+ if ( x > 0 ) {
+ GetDlgItemText ( hDlg, IDC_SERVER, serverStr, BUFFERSIZE ); // get text from dialog
+ }
+
+ else {
+ serverStr[0] = '\0';
+ }
+
+ ///// Port
+ // get value
+ *port = GetDlgItemInt ( hDlg, IDC_PORT, NULL, FALSE );
+ ////// User name
+ // get length
+ x = SendDlgItemMessage ( hDlg, IDC_UID, EM_LINELENGTH, 0, 0 );
+
+ if ( x > 0 ) {
+ // allocate space
+ GetDlgItemText ( hDlg, IDC_UID, uidStr, BUFFERSIZE );
+ }
+
+ else {
+ uidStr[0] = '\0';
+ }
+
+ ////// Password
+ // get length
+ x = SendDlgItemMessage ( hDlg, IDC_PWD, EM_LINELENGTH, 0, 0 );
+
+ if ( x > 0 ) {
+ GetDlgItemText ( hDlg, IDC_PWD, pwdStr, BUFFERSIZE );
+ }
+
+ else {
+ pwdStr[0] = '\0';
+ }
+
+ trimwhitespace ( newDSN );
+ trimwhitespace ( serverStr );
+ trimwhitespace ( uidStr );
+ trimwhitespace ( pwdStr );
+
+ if ( strlen ( newDSN ) == 0 ) {
+ __ODBCPopMsg ( "DSN name cannot be empty" );
+ return BAD;
+ }
+
+ if ( strlen ( serverStr ) == 0 ) {
+ __ODBCPopMsg ( "Server cannot be empty" );
+ return BAD;
+ }
+
+ if ( strlen ( uidStr ) == 0 ) {
+ __ODBCPopMsg ( "Username cannot be empty" );
+ return BAD;
+ }
+
+ if ( strlen ( pwdStr ) == 0 ) {
+ __ODBCPopMsg ( "Password cannot be empty" );
+ return BAD;
+ }
+
+ if ( port == 0 ) {
+ __ODBCPopMsg ( "Port cannot be 0" );
+ return BAD;
+ }
+
+ return GOOD;
+}
+
+static pODBCConn createConn() {
+ pODBCConn conn;
+ // allocate a conn
+ conn = new ODBCConn;
+ // clear the conn attributes
+ memset ( conn, 0, sizeof ( ODBCConn ) );
+ // set the handle signature
+ ( ( pODBCConn ) conn )->Sign = SQL_HANDLE_DBC;
+ // default values
+ ( ( pODBCConn ) conn )->AccessMode = SQL_MODE_READ_ONLY;
+ ( ( pODBCConn ) conn )->AutoIPD = SQL_FALSE;
+ ( ( pODBCConn ) conn )->AsyncEnable = SQL_ASYNC_ENABLE_OFF;
+ ( ( pODBCConn ) conn )->AutoCommit = SQL_AUTOCOMMIT_ON;
+ ( ( pODBCConn ) conn )->TimeOut = 0;
+ ( ( pODBCConn ) conn )->LoginTimeOut = 0;
+ ( ( pODBCConn ) conn )->MetaDataID = SQL_FALSE;
+ ( ( pODBCConn ) conn )->ODBCCursors = SQL_CUR_USE_DRIVER;
+ ( ( pODBCConn ) conn )->Window = NULL;
+ ( ( pODBCConn ) conn )->TxnIsolation = 0;
+ ( ( pODBCConn ) conn )->MaxRows = 0;
+ ( ( pODBCConn ) conn )->QueryTimeout = 0;
+ ( ( pODBCConn ) conn )->Server = new char[BUFFERSIZE];
+ ( ( pODBCConn ) conn )->UserName = new char[BUFFERSIZE];
+ ( ( pODBCConn ) conn )->Password = new char[BUFFERSIZE];
+ ( ( pODBCConn ) conn )->Project = new char[BUFFERSIZE];
+ return conn;
+}
+
+static eGoodBad testGetMetadata ( char* serverStr, char* uidStr, char* pwdStr, long port, char* project ) {
+ pODBCConn conn = createConn();
+ strcpy ( ( ( pODBCConn ) conn )->Server, serverStr );
+ strcpy ( ( ( pODBCConn ) conn )->UserName, uidStr );
+ strcpy ( ( ( pODBCConn ) conn )->Password, pwdStr );
+ strcpy ( ( ( pODBCConn ) conn )->Project, project );
+ ( ( pODBCConn ) conn )->ServerPort = port;
+ RETCODE ret = TryFetchMetadata ( conn );
+ _SQLFreeDiag ( _DIAGCONN ( conn ) );
+ // disconnect
+ _SQLDisconnect ( conn );
+ // now free the structure itself
+ delete conn;
+
+ if ( ret == SQL_ERROR ) {
+ //validation of data & other prompts goes here
+ __ODBCPopMsg ( "Username/Password not authorized, or server out of service." );
+ return BAD;
+ }
+
+ return GOOD;
+}
+
+static eGoodBad testConnection ( char* serverStr, char* uidStr, char* pwdStr, long port ) {
+ pODBCConn conn = createConn();
+ strcpy ( ( ( pODBCConn ) conn )->Server, serverStr );
+ strcpy ( ( ( pODBCConn ) conn )->UserName, uidStr );
+ strcpy ( ( ( pODBCConn ) conn )->Password, pwdStr );
+ ( ( pODBCConn ) conn )->ServerPort = port;
+ RETCODE ret = TryAuthenticate ( conn );
+ _SQLFreeDiag ( _DIAGCONN ( conn ) );
+ // disconnect
+ _SQLDisconnect ( conn );
+ // now free the structure itself
+ delete conn;
+
+ if ( ret == SQL_ERROR ) {
+ //validation of data & other prompts goes here
+ __ODBCPopMsg ( "Username/Password not authorized, or server out of service." );
+ return BAD;
+ }
+
+ return GOOD;
+}
+
+static eGoodBad SaveConfigToODBCINI ( char* newDSN, char* serverStr, char* uidStr, char* pwdStr, long port,
+ char* projectStr ) {
+ char portStrBuffer[BUFFERSIZE];
+ SetValueInODBCINI ( newDSN, SERVERKEY, serverStr, INITFILE );
+ SetValueInODBCINI ( newDSN, PORTKEY, _itoa ( port, portStrBuffer, 10 ), INITFILE );
+ SetValueInODBCINI ( newDSN, UIDKEY, uidStr, INITFILE );
+ SetValueInODBCINI ( newDSN, PWDKEY, pwdStr, INITFILE );
+ SetValueInODBCINI ( newDSN, PROJECTKEY, projectStr, INITFILE );
+
+ //If a new dsn name comes, add a new entry in regedit
+ if ( _stricmp ( newDSN, currentDSN ) != 0 ) {
+ AddDSN ( newDSN );
+
+ //it is a dsn renaming
+ if ( strlen ( currentDSN ) != 0 ) {
+ RemoveDSN ( currentDSN );
+ }
+ }
+
+ strcpy ( currentDSN, newDSN );
+ char temp[BUFFERSIZE];
+ GetValueFromODBCINI ( DRIVER_NAME, "Driver", DRIVER_DEFAULT_LOCATION, temp, BUFFERSIZE, INSTINIFILE );
+ SetValueInODBCINI ( currentDSN, "Driver", temp, INITFILE );
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Finish saving the configurations to ODBC INI" ) );
+ return GOOD;
+}
+
+static eGoodBad RetriveDlgDataToODBCINI ( HWND hDlg, bool onlyTest ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Start retrieving the configurations to ODBC INI" ) );
+ Long x, port;
+ char newDSN[BUFFERSIZE];
+ char serverStr[BUFFERSIZE];
+ char uidStr[BUFFERSIZE];
+ char pwdStr[BUFFERSIZE];
+ char portStrBuffer[BUFFERSIZE];
+
+ if ( !hDlg ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "RetriveDlgDataToODBCINI - Bad params: hDlg is NULL" ) );
+ return BAD;
+ }
+
+ x = SendDlgItemMessage ( hDlg, IDC_DSNNAME, EM_LINELENGTH, 0, 0 ); // get text from dialog
+
+ if ( x > 0 ) {
+ GetDlgItemText ( hDlg, IDC_DSNNAME, newDSN, BUFFERSIZE ); // get text from dialog
+ }
+
+ else {
+ newDSN[0] = '\0';
+ }
+
+ ////// server name/IP
+ // get length of input text
+ x = SendDlgItemMessage ( hDlg, IDC_SERVER, EM_LINELENGTH, 0, 0 );
+
+ if ( x > 0 ) {
+ GetDlgItemText ( hDlg, IDC_SERVER, serverStr, BUFFERSIZE ); // get text from dialog
+ }
+
+ else {
+ serverStr[0] = '\0';
+ }
+
+ ///// Port
+ // get value
+ port = GetDlgItemInt ( hDlg, IDC_PORT, NULL, FALSE );
+ ////// User name
+ // get length
+ x = SendDlgItemMessage ( hDlg, IDC_UID, EM_LINELENGTH, 0, 0 );
+
+ if ( x > 0 ) {
+ // allocate space
+ GetDlgItemText ( hDlg, IDC_UID, uidStr, BUFFERSIZE );
+ }
+
+ else {
+ uidStr[0] = '\0';
+ }
+
+ ////// Password
+ // get length
+ x = SendDlgItemMessage ( hDlg, IDC_PWD, EM_LINELENGTH, 0, 0 );
+
+ if ( x > 0 ) {
+ GetDlgItemText ( hDlg, IDC_PWD, pwdStr, BUFFERSIZE );
+ }
+
+ else {
+ pwdStr[0] = '\0';
+ }
+
+ trimwhitespace ( newDSN );
+ trimwhitespace ( serverStr );
+ trimwhitespace ( uidStr );
+ trimwhitespace ( pwdStr );
+
+ if ( strlen ( newDSN ) == 0 ) {
+ __ODBCPopMsg ( "DSN name cannot be empty" );
+ return BAD;
+ }
+
+ if ( strlen ( serverStr ) == 0 ) {
+ __ODBCPopMsg ( "Server cannot be empty" );
+ return BAD;
+ }
+
+ if ( strlen ( uidStr ) == 0 ) {
+ __ODBCPopMsg ( "Username cannot be empty" );
+ return BAD;
+ }
+
+ if ( strlen ( pwdStr ) == 0 ) {
+ __ODBCPopMsg ( "Password cannot be empty" );
+ return BAD;
+ }
+
+ if ( port == 0 ) {
+ __ODBCPopMsg ( "Port cannot be 0" );
+ return BAD;
+ }
+
+ if ( onlyTest ) {
+ pODBCConn conn;
+ // allocate a conn
+ conn = new ODBCConn;
+ // clear the conn attributes
+ memset ( conn, 0, sizeof ( ODBCConn ) );
+ // set the handle signature
+ ( ( pODBCConn ) conn )->Sign = SQL_HANDLE_DBC;
+ // default values
+ ( ( pODBCConn ) conn )->AccessMode = SQL_MODE_READ_ONLY;
+ ( ( pODBCConn ) conn )->AutoIPD = SQL_FALSE;
+ ( ( pODBCConn ) conn )->AsyncEnable = SQL_ASYNC_ENABLE_OFF;
+ ( ( pODBCConn ) conn )->AutoCommit = SQL_AUTOCOMMIT_ON;
+ ( ( pODBCConn ) conn )->TimeOut = 0;
+ ( ( pODBCConn ) conn )->LoginTimeOut = 0;
+ ( ( pODBCConn ) conn )->MetaDataID = SQL_FALSE;
+ ( ( pODBCConn ) conn )->ODBCCursors = SQL_CUR_USE_DRIVER;
+ ( ( pODBCConn ) conn )->Window = NULL;
+ ( ( pODBCConn ) conn )->TxnIsolation = 0;
+ ( ( pODBCConn ) conn )->MaxRows = 0;
+ ( ( pODBCConn ) conn )->QueryTimeout = 0;
+ ( ( pODBCConn ) conn )->Server = new char[BUFFERSIZE];
+ ( ( pODBCConn ) conn )->UserName = new char[BUFFERSIZE];
+ ( ( pODBCConn ) conn )->Password = new char[BUFFERSIZE];
+ strcpy ( ( ( pODBCConn ) conn )->Server, serverStr );
+ strcpy ( ( ( pODBCConn ) conn )->UserName, uidStr );
+ strcpy ( ( ( pODBCConn ) conn )->Password, pwdStr );
+ ( ( pODBCConn ) conn )->ServerPort = port;
+ RETCODE ret = TryAuthenticate ( conn );
+ _SQLFreeDiag ( _DIAGCONN ( conn ) );
+ // disconnect
+ _SQLDisconnect ( conn );
+ // now free the structure itself
+ delete conn;
+
+ if ( ret == SQL_ERROR ) {
+ //validation of data & other prompts goes here
+ __ODBCPopMsg ( "Username/Password not authorized, or server out of service." );
+ return BAD;
+ }
+
+ return GOOD;
+ }
+
+ SetValueInODBCINI ( newDSN, SERVERKEY, serverStr, INITFILE );
+ SetValueInODBCINI ( newDSN, PORTKEY, _itoa ( port, portStrBuffer, 10 ), INITFILE );
+ SetValueInODBCINI ( newDSN, UIDKEY, uidStr, INITFILE );
+ SetValueInODBCINI ( newDSN, PWDKEY, pwdStr, INITFILE );
+
+ //If a new dsn name comes, add a new entry in regedit
+ if ( _stricmp ( newDSN, currentDSN ) != 0 ) {
+ AddDSN ( newDSN );
+
+ //it is a dsn renaming
+ if ( strlen ( currentDSN ) != 0 ) {
+ RemoveDSN ( currentDSN );
+ }
+ }
+
+ strcpy ( currentDSN, newDSN );
+ char temp[BUFFERSIZE];
+ GetValueFromODBCINI ( DRIVER_NAME, "Driver", DRIVER_DEFAULT_LOCATION, temp, BUFFERSIZE, INSTINIFILE );
+ SetValueInODBCINI ( currentDSN, "Driver", temp, INITFILE );
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "Finish saving the configurations to ODBC INI" ) );
+ return GOOD;
+}
+
+
+eGoodBad LoadODBCINIDataToConn ( pODBCConn pConn ) {
+ Long x;
+ char buffer[BUFFERSIZE];
+ int c;
+
+ // note
+ // no error handling is currently being done for
+ // GetDlgItemText/GetDlgItemInt/SetConnProp
+ // generally should not be a problem
+
+ // precaution
+ if ( !pConn ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "GetDataFromDlgDSNCfg1 - Bad params: pConn is NULL" ) );
+ return BAD;
+ }
+
+ ////// server name/IP
+ c = GetValueFromODBCINI ( currentDSN, SERVERKEY, "", buffer, BUFFERSIZE, INITFILE );
+
+ if ( c <= 0 ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "Please config the Kylin DSN in odbcad.exe before using it." ) );
+ return BAD;
+ }
+
+ // set value in struct
+ SetConnProp ( pConn, CONN_PROP_SERVER, buffer );
+ ///// Port
+ c = GetValueFromODBCINI ( currentDSN, PORTKEY, "", buffer, BUFFERSIZE, INITFILE );
+
+ if ( c <= 0 ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "Please config the Kylin DSN in odbcad.exe before using it." ) );
+ return BAD;
+ }
+
+ x = atoi ( buffer );
+ // set value in struct
+ SetConnProp ( pConn, CONN_PROP_PORT, &x );
+ ////// User name
+ c = GetValueFromODBCINI ( currentDSN, UIDKEY, "", buffer, BUFFERSIZE, INITFILE );
+
+ if ( c <= 0 ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "Please config the Kylin DSN in odbcad.exe before using it." ) );
+ return BAD;
+ }
+
+ // set value in struct
+ SetConnProp ( pConn, CONN_PROP_UID, buffer );
+ ////// Password
+ c = GetValueFromODBCINI ( currentDSN, PWDKEY, "", buffer, BUFFERSIZE, INITFILE );
+
+ if ( c <= 0 ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "Please config the Kylin DSN in odbcad.exe before using it." ) );
+ return BAD;
+ }
+
+ // set value in struct
+ SetConnProp ( pConn, CONN_PROP_PWD, buffer );
+ ////// Project
+ c = GetValueFromODBCINI ( currentDSN, PROJECTKEY, "", buffer, BUFFERSIZE, INITFILE );
+
+ if ( c <= 0 ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "Please config the Kylin DSN in odbcad.exe before using it." ) );
+ return BAD;
+ }
+
+ // set value in struct
+ SetConnProp ( pConn, CONN_PROP_PROJECT, buffer );
+ return GOOD;
+}
+
+INT_PTR CALLBACK DlgDSNCfg2Proc ( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
+ char* attributes = ( char* ) lParam;
+ Long port;
+ char newDSN[BUFFERSIZE];
+ char serverStr[BUFFERSIZE];
+ char uidStr[BUFFERSIZE];
+ char pwdStr[BUFFERSIZE];
+
+ switch ( uMsg ) {
+ case WM_INITDIALOG:
+ SetCurrentDSN ( attributes, "DlgDSNCfg2Proc" );
+ // store the structure for future use
+ SetWindowLongPtr ( hDlg, DWLP_USER, lParam );
+
+ // initialize the dialog with data from REGEDIT
+ if ( LoadODBCINIDataToDlgDSNCfg2 ( hDlg ) != GOOD )
+ { return false; }
+
+ // set focus automatically
+ return TRUE;
+
+ case WM_COMMAND:
+ switch ( LOWORD ( wParam ) ) {
+ case IDC_BTEST: {
+ if ( RetriveDlgData ( hDlg, newDSN, serverStr, uidStr, pwdStr, &port ) == GOOD ) {
+ if ( testConnection ( serverStr, uidStr, pwdStr, port ) == GOOD ) {
+ HWND hwndCombo = GetDlgItem ( hDlg, IDC_COMBO1 );
+ HWND hwndOK = GetDlgItem ( hDlg, IDOK );
+ //passed verification
+ EnableWindow ( hwndCombo, TRUE );
+
+ try {
+ std::vector<string> projects;
+ restListProjects ( serverStr, port, uidStr, pwdStr, projects );
+
+ for ( unsigned int i = 0 ; i < projects.size(); ++i ) {
+ SendMessage ( hwndCombo, ( UINT ) CB_ADDSTRING, ( WPARAM ) 0, ( LPARAM ) projects.at ( i ).c_str() );
+ }
+
+ SendMessage ( hwndCombo, CB_SETCURSEL, ( WPARAM ) 0, ( LPARAM ) 0 );
+ }
+
+ catch ( exception& e ) {
+ stringstream ss;
+ ss << "Getting project list failed with error: " << e.what();
+ __ODBCPopMsg ( ss.str().c_str() );
+ return FALSE;
+ }
+
+ EnableWindow ( hwndOK, TRUE );
+ return TRUE;
+ }
+
+ else {
+ __ODBCPopMsg ( "testConnection failed." );
+ }
+ }
+
+ else {
+ __ODBCPopMsg ( "RetriveDlgData failed." );
+ }
+
+ return FALSE;
+ }
+
+ case IDOK: {
+ HWND hwndCombo = GetDlgItem ( hDlg, IDC_COMBO1 );
+ int ItemIndex = SendMessage ( ( HWND ) hwndCombo, ( UINT ) CB_GETCURSEL,
+ ( WPARAM ) 0, ( LPARAM ) 0 );
+ TCHAR projectName[256];
+ ( TCHAR ) SendMessage ( ( HWND ) hwndCombo, ( UINT ) CB_GETLBTEXT,
+ ( WPARAM ) ItemIndex, ( LPARAM ) projectName );
+
+ if ( RetriveDlgData ( hDlg, newDSN, serverStr, uidStr, pwdStr, &port ) == GOOD ) {
+ if ( testGetMetadata ( serverStr, uidStr, pwdStr, port, projectName ) == GOOD ) {
+ SaveConfigToODBCINI ( newDSN, serverStr, uidStr, pwdStr, port, projectName );
+ EndDialog ( hDlg, wParam );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ case IDCANCEL:
+ // indicate end with control id as return value
+ EndDialog ( hDlg, wParam );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+BOOL INSTAPI ConfigDSN ( HWND hwndParent, WORD fRequest, LPCSTR lpszDriver, LPCSTR lpszAttributes ) {
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_DEBUG, "ConfigDSN %s is called %s, the fRequest is: %d", lpszDriver, lpszAttributes,
+ fRequest ) );
+
+ if ( fRequest == ODBC_REMOVE_DSN ) {
+ SetCurrentDSN ( ( char* ) lpszAttributes, "ConfigDSN" );
+
+ if ( strlen ( currentDSN ) <= 0 ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "The DSN name is not defined in the connection string!" ) );
+ return false;
+ }
+
+ BOOL ret = TRUE;
+ ret = RemoveDSN ( currentDSN );
+
+ if ( !ret ) {
+ __ODBCPOPMSG ( _ODBCPopMsg ( "The DSN is not found, removal failed!" ) );
+ return false;
+ }
+
+ return true;
+ }
+
+ //else is ODBC_CONFIG_DSN or ODBC_ADD_DSN
+ int i;
+ i = DialogBoxParam ( ghInstDLL, MAKEINTRESOURCE ( IDD_DSN_CFG2 ), NULL, DlgDSNCfg2Proc, ( LPARAM ) lpszAttributes );
+
+ // check status
+ switch ( i ) {
+ case IDOK:
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "User click OK button on DSN config" ) );
+ return true; // complete
+
+ default:
+ __ODBCLOG ( _ODBCLogMsg ( LogLevel_INFO, "User click Cancel button on DSN config" ) );
+ return false; // user-cancelled
+ }
+
+ return true;
+}
+
+