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;
+}
+
+