/*
 * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
 */

#include "h2odbc.h"

SQLRETURN  SQL_API SQLAllocHandle(SQLSMALLINT HandleType,
           SQLHANDLE InputHandle, SQLHANDLE* OutputHandle) {
    trace("SQLAllocHandle");
    if(OutputHandle==0) {
        return SQL_ERROR;
    }
    switch(HandleType) {
    case SQL_HANDLE_ENV:
        trace(" SQL_HANDLE_ENV");
        *OutputHandle=new Environment();
        break;
    case SQL_HANDLE_DBC: {
        trace(" SQL_HANDLE_DBC");
        Environment* env=Environment::cast(InputHandle);
        if(env==0) {
            return SQL_INVALID_HANDLE;
        }
        env->setError(0);
        Connection* conn = env->createConnection();
        *OutputHandle = conn;
//        trace(" use ODBC cursor library if possible");
//        SQLSetConnectAttr(conn, SQL_ATTR_ODBC_CURSORS, (void*)SQL_CUR_USE_ODBC);
        break;
    }
    case SQL_HANDLE_STMT: {
        trace(" SQL_HANDLE_STMT");
        Connection* conn = Connection::cast(InputHandle);
        if(conn==0) {
            return SQL_INVALID_HANDLE;
        }
        conn->setError(0);
        if(conn->isClosed()) {
            conn->setError(E_08003);
            return SQL_ERROR;
        }
        *OutputHandle=new Statement(conn);
        break;
    }
    case SQL_HANDLE_DESC: {
        trace(" SQL_HANDLE_DESC");
        Connection* conn = Connection::cast(InputHandle);
        if(conn==0) {
            return SQL_INVALID_HANDLE;
        }
        conn->setError(0);
        if(conn->isClosed()) {
            conn->setError(E_08003);
            return SQL_ERROR;
        }        
        *OutputHandle=new Descriptor(conn);
        break;
    }
    default:
        trace(" ? %d TODO ", HandleType);
        return SQL_ERROR;
    }
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLBindCol(SQLHSTMT StatementHandle, 
           SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, 
           SQLPOINTER TargetValue, SQLINTEGER BufferLength, 
           SQLINTEGER* StrLen_or_Ind) {
    trace("SQLBindCol");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);
    trace(" getAppRowDesc");
    Descriptor* desc = stat->getAppRowDesc();
    if(desc == 0) {
        trace(" desc=null");
        return SQL_ERROR;
    }        
    ColumnNumber--;
    trace(" ColumnNumber=%d", ColumnNumber);
    if(ColumnNumber > stat->getColumnCount()) {
        trace(" columnCount=%d", stat->getColumnCount());
        return SQL_ERROR;
    }
    trace(" getRecord");
    if(ColumnNumber >= desc->getRecordCount()) {
        trace(" wrong column; cols=%d", desc->getRecordCount());
    }
    DescriptorRecord* rec = desc->getRecord(ColumnNumber);
    if(rec == 0) {
        trace(" rec out of range");
        return SQL_ERROR;
    }    
    trace(" setTargetDataType");
    rec->setCDataType(TargetType);
    trace(" setTargetPointer");
    rec->setTargetPointer(TargetValue);
    trace(" setTargetBufferLength");
    rec->setTargetBufferLength(BufferLength);
    trace(" setTargetStatusPointer");
    rec->setTargetStatusPointer(StrLen_or_Ind);
    return SQL_SUCCESS;
}

SQLRETURN SQL_API SQLBindParameter(
    SQLHSTMT StatementHandle,
    SQLUSMALLINT ParameterNumber,
    SQLSMALLINT InputOutputType,
    SQLSMALLINT ValueType,
    SQLSMALLINT ParameterType,
    SQLUINTEGER ColumnSize,
    SQLSMALLINT DecimalDigits,
    SQLPOINTER ParameterValuePtr,
    SQLINTEGER BufferLength,
    SQLINTEGER* StrLen_or_IndPtr) {
    trace("SQLBindParameter");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);
    switch(InputOutputType) {
    case SQL_PARAM_INPUT:
        trace(" SQL_PARAM_INPUT");
        break;
    case SQL_PARAM_INPUT_OUTPUT:
        trace(" SQL_PARAM_INPUT_OUTPUT");
        break;
    case SQL_PARAM_OUTPUT:
        trace(" SQL_PARAM_OUTPUT");
        break;
    default:
        trace(" ? %d TODO ", InputOutputType);
        return SQL_ERROR;
    }
    Descriptor* desc = stat->getAppParamDesc();
    ParameterNumber--;
    while(desc->getRecordCount() <= ParameterNumber) {
        stat->addParameter();
    }
    DescriptorRecord* rec = desc->getRecord(ParameterNumber);
    if(rec==0) {
        trace("  rec=0 TODO");
    }
    if(ValueType == SQL_C_DEFAULT) {
        trace("  SQL_C_DEFAULT");
        ValueType = getDefaultCType(ParameterType);
    }
    trace("  ValueType=%d, ParameterType=%d", ValueType, ParameterType);
    rec->setSqlDataType(ParameterType);
    rec->setCDataType(ValueType);
    rec->setTargetPointer(ParameterValuePtr);
    rec->setTargetBufferLength(ColumnSize);
    rec->setTargetStatusPointer(StrLen_or_IndPtr);    
    return SQL_SUCCESS;
}                        

SQLRETURN  SQL_API SQLCancel(SQLHSTMT StatementHandle) {
    trace("SQLCancel TODO");
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLCloseCursor(SQLHSTMT StatementHandle) {
    trace("SQLCloseCursor");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);
    stat->closeCursor();
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLDriverConnect(
           SQLHDBC ConnectionHandle,
           SQLHWND WindowHandle,
           SQLCHAR* InConnectionString,
           SQLSMALLINT StringLength1,
           SQLCHAR* OutConnectionString,
           SQLSMALLINT BufferLength,
           SQLSMALLINT* StringLength2Ptr,
           SQLUSMALLINT DriverCompletion) {
    trace("SQLDriverConnect");
    Connection* conn=Connection::cast(ConnectionHandle);
    if(conn==0) {
        return SQL_INVALID_HANDLE;
    }
    conn->setError(0);
    
    char connect[1024];
    char url[1024];
    char user[1024];
    char password[1024];
    strcpy(url, "");
    strcpy(user, "");
    strcpy(password, "");
    setString(connect,sizeof(connect),InConnectionString,StringLength1);
    char* start = strstr(connect, "DSN=");
    if(start != 0) {
        char dns[1024];
        strncpy(dns, start+4, strlen(start+4));
        char* end = strstr(dns, ";");
        if(end != 0) {
            *end = 0;
        }
        conn->setDataSourceName(dns);
        SQLGetPrivateProfileString(
            dns, 
            "URL", "", url, MAX_STRING_LEN,
            "ODBC.INI");
        SQLGetPrivateProfileString(
            dns, 
            "User", "", user, MAX_STRING_LEN,
            "ODBC.INI");
        SQLGetPrivateProfileString(
            dns, 
            "Password", "", password, MAX_STRING_LEN,
            "ODBC.INI");
    }
    trace(" url=%s user=%s password=%s", url, user, password);
    trace(" connect=%s DSN=<%s>", connect, conn->getDataSourceName().data());
    strcat(connect,"UID=sa;PWD=;DRIVER=h2odbc");
    
    conn->open(url, user, password);
    if(conn->getError() != 0) {
        return SQL_ERROR;
    }

    returnString(OutConnectionString,BufferLength,StringLength2Ptr,connect);
    trace(" %s",connect);
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLConnect(SQLHDBC ConnectionHandle,
           SQLCHAR* ServerName, SQLSMALLINT NameLength1,
           SQLCHAR* UserName, SQLSMALLINT NameLength2,
           SQLCHAR* Authentication, SQLSMALLINT NameLength3) {
    trace("SQLConnect");
    Connection* conn = Connection::cast(ConnectionHandle);
    if(conn==0) {
        return SQL_INVALID_HANDLE;
    }
    conn->setError(0);        
    char name[512];
    char user[512];
    char password[512];
    setString(name,sizeof(name),ServerName,NameLength1);
    setString(user,sizeof(user),UserName,NameLength2);
    setString(password,sizeof(password),Authentication,NameLength3);
    trace(" dns=%s user=%s", name, user);
    conn->setDataSourceName(name);
    conn->open(name,user,password);
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLCopyDesc(SQLHDESC SourceDescHandle,
           SQLHDESC TargetDescHandle) {
    trace("SQLCopyDesc TODO");
    return SQL_ERROR;
}

SQLRETURN  SQL_API SQLDescribeCol(SQLHSTMT StatementHandle,
           SQLUSMALLINT ColumnNumber, SQLCHAR* ColumnName,
           SQLSMALLINT BufferLength, SQLSMALLINT* NameLengthPtr,
           SQLSMALLINT* DataTypePtr, SQLUINTEGER* ColumnSizePtr,
           SQLSMALLINT* DecimalDigitsPtr, SQLSMALLINT* NullablePtr) {
    trace("SQLDescribeCol");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);  
    Descriptor* desc = stat->getImpRowDesc();
    ColumnNumber--;
    if(ColumnNumber >= desc->getRecordCount()) {
        trace("SQLDescribeCol E_07009 %d", ColumnNumber);
        stat->setError(E_07009);
        return SQL_ERROR;
    }
    trace("  column %d", ColumnNumber);
    DescriptorRecord* rec = desc->getRecord(ColumnNumber);
    returnString((SQLCHAR*)ColumnName, BufferLength, NameLengthPtr, rec->getColumnName().data());
    trace("   =%s", (SQLCHAR*)ColumnName);
    returnSmall(DataTypePtr, (SQLINTEGER*)0, rec->getSqlDataType());
    returnInt(ColumnSizePtr, rec->getDisplaySize());
    trace("   =%d", rec->getDisplaySize());
    returnSmall(DecimalDigitsPtr, (SQLINTEGER*)0, 0);
    returnSmall(NullablePtr, (SQLINTEGER*)0, SQL_NULLABLE_UNKNOWN);
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLDisconnect(SQLHDBC ConnectionHandle) {
    trace("SQLDisconnect");
    Connection* conn = Connection::cast(ConnectionHandle);
    if(conn==0) {
        return SQL_INVALID_HANDLE;
    }
    conn->setError(0);
    conn->close();
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLEndTran(SQLSMALLINT HandleType, SQLHANDLE Handle,
           SQLSMALLINT CompletionType) {
    trace("SQLEndTran");
    switch(HandleType) {
    case SQL_HANDLE_ENV: {
        trace(" SQL_HANDLE_ENV TODO");
        Environment* env = Environment::cast(Handle);
        if(env==0) {
            return SQL_INVALID_HANDLE;   
        }
        env->setError(0);
        break;
    }
    case SQL_HANDLE_DBC: {
        trace(" SQL_HANDLE_DBC");
        Connection* conn = Connection::cast(Handle);
        if(conn==0) {
            return SQL_INVALID_HANDLE;
        }
        conn->setError(0);    
           switch(CompletionType) {
        case SQL_COMMIT:
            trace("  SQL_COMMIT"); 
            conn->commit();
            break;
        case SQL_ROLLBACK:
            trace("  SQL_ROLLBACK"); 
            conn->rollback();
            break;
        default:
            conn->setError(E_HY012);
            return SQL_ERROR;
            break;
        }
        break;
    }    
    default:
        trace(" ? %d TODO ", HandleType);
        return SQL_ERROR;
    }
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLExecDirect(SQLHSTMT StatementHandle,
           SQLCHAR* StatementText, SQLINTEGER TextLength) {
    trace("SQLExecDirect");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);        
    char sql[512];
    setString(sql,sizeof(sql),StatementText,TextLength);
    trace(" %s", sql);
    if(stat->execute(sql)) {
        return SQL_SUCCESS;
    } else {
        return SQL_ERROR;
    }
}

SQLRETURN  SQL_API SQLExecute(SQLHSTMT StatementHandle) {
    trace("SQLExecute");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);
    if(stat->executePrepared()) {
        return SQL_SUCCESS;
    } else {
        return SQL_ERROR;
    }
}

SQLRETURN  SQL_API SQLFetch(SQLHSTMT StatementHandle) {
    trace("SQLFetch");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);
    if(!stat->next()) {
        trace(" SQL_NO_DATA");
        return SQL_NO_DATA;
    } else {
        trace(" SQL_SUCCESS");
        return SQL_SUCCESS;
    }
}

SQLRETURN  SQL_API SQLFetchScroll(SQLHSTMT StatementHandle,
           SQLSMALLINT FetchOrientation, SQLINTEGER FetchOffset) {
    trace("SQLFetchScroll");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);
    switch(FetchOrientation) {
    case SQL_FETCH_NEXT: {
        trace(" SQL_FETCH_NEXT");
        if(stat->next()) {
            return SQL_SUCCESS;
        }
        return SQL_NO_DATA;
    }
    case SQL_FETCH_PRIOR:
        trace(" SQL_FETCH_PRIOR TODO");
        return SQL_ERROR;
        break;
    case SQL_FETCH_RELATIVE:
        trace(" SQL_FETCH_RELATIVE TODO");
        return SQL_ERROR;        
        break;
    case SQL_FETCH_ABSOLUTE:
        trace(" SQL_FETCH_ABSOLUTE TODO");
        return SQL_ERROR;        
        break;
    case SQL_FETCH_FIRST:
        trace(" SQL_FETCH_FIRST TODO");
        return SQL_ERROR;        
        break;
    case SQL_FETCH_LAST:
        trace(" SQL_FETCH_LAST TODO");
        return SQL_ERROR;        
        break;
    case SQL_FETCH_BOOKMARK:
        trace(" SQL_FETCH_BOOKMARK TODO");
        return SQL_ERROR;        
        break;
    default:
        trace(" ? %d", FetchOrientation);
        return SQL_ERROR;        
        break;
    }
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle) {
    trace("SQLFreeHandle");
    switch(HandleType) {
    case SQL_HANDLE_ENV: {
        trace(" SQL_HANDLE_ENV");
        Environment* env=Environment::cast(Handle);
        if(env==0) {
            return SQL_INVALID_HANDLE;
        }
        env->setError(0);        
        if(env->getOpenConnectionCount()>0) {
            return SQL_ERROR;
        }
        delete env;
        break;
    }
    case SQL_HANDLE_DBC: {
        trace(" SQL_HANDLE_DBC");
        Connection* conn=Connection::cast(Handle);
        if(conn==0) {
            return SQL_INVALID_HANDLE;
        }
        conn->setError(0);    
        if(!conn->isClosed()) {
            return SQL_ERROR;
        }
        Environment* env=conn->getEnvironment();
        env->closeConnection(conn);
        break;
    }
    case SQL_HANDLE_STMT: {
        trace(" SQL_HANDLE_STMT");
        Statement* stat=Statement::cast(Handle);
        if(stat==0) {
            return SQL_INVALID_HANDLE;
        }
        stat->setError(0);            
        delete stat;
        break;
    }
    case SQL_HANDLE_DESC: {
        trace(" SQL_HANDLE_DESC");
        Descriptor* desc=Descriptor::cast(Handle);
        if(desc==0) {
            return SQL_INVALID_HANDLE;
        }
        desc->setError(0);            
        delete desc;
        break;
    }
    default:
        trace(" ? %d TODO", HandleType);
        return SQL_INVALID_HANDLE;
    }
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLFreeStmt(SQLHSTMT StatementHandle,
           SQLUSMALLINT Option) {
    trace("SQLFreeStmt");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);        
    switch(Option) {
    case SQL_CLOSE:
        trace(" SQL_CLOSE");
        stat->closeCursor();
        break;
    case SQL_UNBIND:
        trace(" SQL_UNBIND TODO");
        break;
    case SQL_RESET_PARAMS:
        trace(" SQL_RESET_PARAMS TODO");
        break;
    default:
        trace("%d TODO",Option);
        return SQL_ERROR;
    }
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLGetCursorName(SQLHSTMT StatementHandle,
           SQLCHAR* CursorName, SQLSMALLINT BufferLength,
           SQLSMALLINT* NameLength) {
    trace("SQLGetCursorName TODO");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(E_IM001);        
    return SQL_ERROR;
}

SQLRETURN  SQL_API SQLGetData(SQLHSTMT StatementHandle,
           SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType,
           SQLPOINTER TargetValue, SQLINTEGER BufferLength,
           SQLINTEGER* StrLen_or_Ind) {
    trace("SQLGetData col=%d", ColumnNumber, TargetType);
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }
    stat->setError(0);
    Descriptor* desc = stat->getImpRowDesc();
    ColumnNumber--;
    if(ColumnNumber > stat->getColumnCount()) {
        trace(" columnCount=%d", stat->getColumnCount());
        return SQL_ERROR;
    }
    DescriptorRecord* rec = desc->getRecord(ColumnNumber);
    if(rec->wasNull()) {
        if(StrLen_or_Ind==0) {
            trace(" wasNull error");       
            stat->setError(E_22002);
            return SQL_ERROR;
        }
        trace(" wasNull");
        *StrLen_or_Ind=SQL_NULL_DATA;
        return SQL_SUCCESS;
    }
    if(TargetType == SQL_C_DEFAULT) {
        TargetType = getDefaultCType(rec->getSqlDataType());
        trace("  SQL_C_DEFAULT set to %d", TargetType); 
    }
    switch(TargetType) {
    case SQL_CHAR:
    case SQL_VARCHAR:
        trace("  SQL_CHAR / SQL_VARCHAR"); 
        returnString((SQLCHAR*)TargetValue, BufferLength, StrLen_or_Ind, rec->getString());
        break;
    case SQL_INTEGER:
        trace("  SQL_INTEGER"); 
        returnInt(TargetValue, StrLen_or_Ind, rec->getInt());
        break;
    case SQL_SMALLINT:
        trace("  SQL_SMALLINT");         
        returnSmall((SQLSMALLINT*)TargetValue, StrLen_or_Ind, rec->getInt());
        break;
    default:
        trace("  type=%d TODO", TargetType);
    }
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLGetDescField(SQLHDESC DescriptorHandle,
           SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
           SQLPOINTER Value, SQLINTEGER BufferLength,
           SQLINTEGER* StringLength) {
    trace("SQLGetDescField TODO");
    Descriptor* desc = Descriptor::cast(DescriptorHandle);
    if(desc==0) {
        return SQL_INVALID_HANDLE;
    }    
    desc->setError(0);    
    RecNumber--;
    if(RecNumber < 0 || desc->getRecordCount() >= RecNumber) {
        desc->setError(E_07009);
        return SQL_ERROR;
    }
 
    return SQL_ERROR;
}

SQLRETURN  SQL_API SQLGetDescRec(SQLHDESC DescriptorHandle,
           SQLSMALLINT RecNumber, SQLCHAR* Name,
           SQLSMALLINT BufferLength, SQLSMALLINT* StringLength,
           SQLSMALLINT* Type, SQLSMALLINT* SubType, 
           SQLINTEGER* Length, SQLSMALLINT* Precision, 
           SQLSMALLINT* Scale, SQLSMALLINT* Nullable) {
    trace("SQLGetDescRec TODO");
    return SQL_ERROR;
}

SQLRETURN  SQL_API SQLGetEnvAttr(SQLHENV EnvironmentHandle,
           SQLINTEGER Attribute, SQLPOINTER Value,
           SQLINTEGER BufferLength, SQLINTEGER* StringLength) {
    trace("SQLGetEnvAttr %d",Attribute);
    Environment* env=Environment::cast(EnvironmentHandle);
    if(env==0) {
        return SQL_INVALID_HANDLE;
    }    
    env->setError(0);    
    switch(Attribute) {
    case SQL_ATTR_ODBC_VERSION:
        trace(" SQL_ATTR_ODBC_VERSION");
        returnInt(Value,StringLength,env->getBehavior());
        break;
    case SQL_ATTR_CONNECTION_POOLING:
        trace(" SQL_ATTR_CONNECTION_POOLING");
        break;
    case SQL_ATTR_CP_MATCH:
        trace(" SQL_ATTR_CP_MATCH");
        break;
    case SQL_ATTR_OUTPUT_NTS:
        trace(" SQL_ATTR_OUTPUT_NTS");
        returnInt(Value,StringLength,SQL_TRUE);
        break;
    default:
        trace(" %d",Attribute);
        return SQL_ERROR;
    }
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLNumResultCols(SQLHSTMT StatementHandle,
           SQLSMALLINT* ColumnCount) {
    trace("SQLNumResultCols");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }    
    stat->setError(0);    
    int count = stat->getColumnCount();
    returnInt(ColumnCount, count);
    trace(" %d", count);
    return SQL_SUCCESS;
}

SQLRETURN SQL_API SQLNativeSql(
    SQLHDBC ConnectionHandle,
    SQLCHAR* InStatementText,
    SQLINTEGER TextLength1,
    SQLCHAR* OutStatementText,
    SQLINTEGER BufferLength,
    SQLINTEGER* TextLength2Ptr) {
    trace("SQLNativeSql");
    Connection* conn=Connection::cast(ConnectionHandle);
    if(conn==0) {
        return SQL_INVALID_HANDLE;
    }    
    conn->setError(0);        
    char sql[512];
    setString(sql,sizeof(sql),InStatementText,TextLength1);
    string translated = conn->getNativeSQL(sql);
    returnString(OutStatementText,BufferLength,TextLength2Ptr,translated.data());
    return SQL_SUCCESS;
}

SQLRETURN SQL_API SQLNumParams(
    SQLHSTMT StatementHandle,
    SQLSMALLINT* ParameterCountPtr ) {
    trace("SQLNumParams");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }    
    stat->setError(0);
    int params = stat->getParametersCount();
    returnInt(ParameterCountPtr, params);
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLParamData(SQLHSTMT StatementHandle,
           SQLPOINTER* Value) {
    trace("SQLParamData TODO");
    return SQL_ERROR;
}

SQLRETURN  SQL_API SQLPrepare(SQLHSTMT StatementHandle,
           SQLCHAR* StatementText, SQLINTEGER TextLength) {
    trace("SQLPrepare");
    // TODO should support longer statements
    char sql[512];
    setString(sql,sizeof(sql),StatementText,TextLength);
    trace(" %s", sql);
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }    
    stat->setError(0);        
    if(stat->prepare(sql)) {
        return SQL_SUCCESS;
    } else {
        return SQL_ERROR;
    }
}

SQLRETURN  SQL_API SQLPutData(SQLHSTMT StatementHandle,
           SQLPOINTER Data, SQLINTEGER StrLen_or_Ind) {
    trace("SQLPutData TODO");
    return SQL_ERROR;
}

SQLRETURN  SQL_API SQLRowCount(SQLHSTMT StatementHandle, 
           SQLINTEGER* RowCount) {
    trace("SQLRowCount");
    Statement* stat=Statement::cast(StatementHandle);
    if(stat==0) {
        return SQL_INVALID_HANDLE;
    }    
    stat->setError(0);    
    trace(" %d", stat->getUpdateCount());
    returnInt(RowCount, (SQLINTEGER*)0, stat->getUpdateCount());
    return SQL_SUCCESS;
}

SQLRETURN  SQL_API SQLSetCursorName(SQLHSTMT StatementHandle,
           SQLCHAR* CursorName, SQLSMALLINT NameLength) {
    trace("SQLSetCursorName TODO");
    return SQL_ERROR;
}

SQLRETURN  SQL_API SQLSetDescField(SQLHDESC DescriptorHandle,
           SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier,
           SQLPOINTER Value, SQLINTEGER BufferLength) {
    trace("SQLSetDescField TODO");
    return SQL_ERROR;
}

SQLRETURN  SQL_API SQLSetDescRec(SQLHDESC DescriptorHandle,
           SQLSMALLINT RecNumber, SQLSMALLINT Type,
           SQLSMALLINT SubType, SQLINTEGER Length,
           SQLSMALLINT Precision, SQLSMALLINT Scale,
           SQLPOINTER Data, SQLINTEGER* StringLength,
           SQLINTEGER* Indicator) {
    trace("SQLSetDescRec TODO");
    return SQL_ERROR;
}

SQLRETURN  SQL_API SQLSetEnvAttr(SQLHENV EnvironmentHandle,
           SQLINTEGER Attribute, SQLPOINTER Value,
           SQLINTEGER StringLength) {
    trace("SQLSetEnvAttr");
    Environment* env=Environment::cast(EnvironmentHandle);
    if(env==0) {
        return SQL_INVALID_HANDLE;
    }    
    env->setError(0);        
    switch(Attribute) {
    case SQL_ATTR_ODBC_VERSION:
        env->setBehavior((int)Value);
        trace(" SQL_ATTR_ODBC_VERSION");
        return SQL_SUCCESS;
    case SQL_ATTR_CONNECTION_POOLING:
        trace(" SQL_ATTR_CONNECTION_POOLING TODO");
    case SQL_ATTR_CP_MATCH:
        trace(" SQL_ATTR_CP_MATCH TODO");
    case SQL_ATTR_OUTPUT_NTS:
        trace(" SQL_ATTR_OUTPUT_NTS TODO");
        if((int)Value==SQL_TRUE) {
            return SQL_ERROR;
        } else {
            return SQL_ERROR;
        }
    default:
        trace(" ? %d TODO",Attribute);
        return SQL_ERROR;
    }
}