//	////////////////////////////////////////////////////////////////////////////
SQLSMALLINT GetDiagRecordNumberCount(SQLSMALLINT handle_type,
                                     SQLHANDLE handle_value)
{
    SQLINTEGER record_number;

    try {
        GetDiagField_SQLINTEGER(handle_type, handle_value, 0, SQL_DIAG_NUMBER,
                                record_number);
        if (record_number < 0)
            throw OdbcException("Invocation of '::SQLGetDiagField()' with a "
                                "diagnostic identifier of 'SQL_DIAG_NUMBER' resulted in a value "
                                "of 0, which is invalid.");
        else if (record_number > std::numeric_limits<SQLSMALLINT>::max())
            throw OdbcException("Invocation of '::SQLGetDiagField()' with a "
                                "diagnostic identifier of 'SQL_DIAG_NUMBER' resulted in a value "
                                "of " + MLB::Utility::AnyToString(record_number) + ", which is "
                                "greater than the maximum permissible for a value of type '"
                                "SQLSMALLINT' (" + MLB::Utility::AnyToString(
                                    std::numeric_limits<SQLSMALLINT>::max()) + ").");
    }
    catch (const std::exception &except) {
        MLB::Utility::Rethrow(except, "Attempt to retrieve the count of "
                              "diagnostic records for handle type " +
                              MLB::Utility::AnyToString(handle_type) + ", handle value " +
                              MLB::Utility::AnyToString(handle_value) + " failed: " +
                              std::string(except.what()));
    }

    return(static_cast<SQLSMALLINT>(record_number));
}
Beispiel #2
0
// ////////////////////////////////////////////////////////////////////////////
SQLRETURN GetAttrForHandle(SQLHANDLE Handle, SQLINTEGER Attribute,
	std::string &ValuePtr, const char *odbc_function_name,
	HandleGetAttrFunc get_attr_function, OdbcThrowFlags::Flags throw_flags)
{
	CheckStringArgInLengthDomain<SQLINTEGER>(ValuePtr, "ValuePtr",
		odbc_function_name);

	SQLRETURN                                      return_code;
	MLB::Utility::IncrementalBuffer<SQLCHAR, 4096> buffer;

	throw_flags = MLB::Utility::EnumFlagAnd(throw_flags,
		static_cast<OdbcThrowFlags::Flags>(~(OdbcThrowFlags::SuccessWithInfo)));

	for ( ; ; ) {
		SQLINTEGER actual_len;
		return_code = get_attr_function(Handle, Attribute,
			reinterpret_cast<SQLPOINTER>(buffer.GetPtr()),
			buffer.GetAllocationCountAsType<SQLINTEGER>(), &actual_len,
			throw_flags);
		if (return_code == SQL_SUCCESS) {
			std::string(reinterpret_cast<const char *>(buffer.GetPtr()),
				actual_len).swap(ValuePtr);
			break;
		}
		else if (return_code == SQL_SUCCESS_WITH_INFO) {
			if (!buffer.SetCount(actual_len, false))
				throw OdbcException("Call to '" + std::string(odbc_function_name) +
					"' returned 'SQL_SUCCESS_WITH_INFO', but no returned lengths "
					"qualified for that return code.");
		}
	}

	return(return_code);
}
Beispiel #3
0
    bool OdbcConnection::TryReadRow()
    {
        if (executionState != FetchRow)
        {
            throw OdbcException("The connection is in an invalid state");
        }

        SQLRETURN ret = SQLFetch(statement);
        if (ret == SQL_STILL_EXECUTING) 
        { 
            return false; 
        }
        if (ret == SQL_NO_DATA) 
        { 
            resultset->moreRows = false;
            statement.Free();
            executionState = Idle;
            return true;
        }
        else 
        {
            resultset->moreRows = true;
        }
        if (!SQL_SUCCEEDED(ret)) 
        { 
            statement.Throw();
        }

        return true;
    }
//	////////////////////////////////////////////////////////////////////////////
SQLSMALLINT CheckIsValidDiagRecordNumber(SQLSMALLINT handle_type,
        SQLHANDLE handle_value, SQLSMALLINT record_number)
{
    if (record_number < 1)
        throw OdbcException("A diagnostic record number of 0 is invalid ("
                            "diagnostic records are numbered from 1).");

    SQLSMALLINT record_number_count =
        GetDiagRecordNumberCount(handle_type, handle_value);

    if (record_number > record_number_count)
        throw OdbcException("The specified diagnostic record number of " +
                            MLB::Utility::AnyToString(record_number) + "handle type " +
                            MLB::Utility::AnyToString(handle_type) + ", handle value " +
                            MLB::Utility::AnyToString(handle_value) + " is invalid --- "
                            "the maximum available diagnostic record number is " +
                            MLB::Utility::AnyToString(record_number_count) + ".");

    return(record_number_count);
}
// ////////////////////////////////////////////////////////////////////////////
const GetInfoTypeDatumRaw *GetInfoTypeDatumRaw::GetInfoTypeDatumPtrChecked(
	SQLUSMALLINT info_type)
{
	const GetInfoTypeDatumRaw *found_ptr = GetInfoTypeDatumPtr(info_type);

	if (found_ptr == NULL)
		throw OdbcException("Unable to locate the '::SQLGetInfo()' information "
			"type descriptor entry for " + MLB::Utility::AnyToString(info_type) +
			".");

	return(found_ptr);
}
Beispiel #6
0
    void OdbcConnection::InitializeEnvironment()
    {
        SQLRETURN ret = SQLSetEnvAttr(NULL, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)SQL_CP_ONE_PER_HENV, 0);
        if (!SQL_SUCCEEDED(ret)) { throw OdbcException("Unable to initialize ODBC connection pooling"); }

        environment.Alloc();

        ret = SQLSetEnvAttr(environment, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
        if (!SQL_SUCCEEDED(ret)) { throw OdbcException::Create(SQL_HANDLE_ENV, environment); }
        ret = SQLSetEnvAttr(environment, SQL_ATTR_CP_MATCH, (SQLPOINTER)SQL_CP_RELAXED_MATCH, 0);
        if (!SQL_SUCCEEDED(ret)) { throw OdbcException::Create(SQL_HANDLE_ENV, environment); }
    }
Beispiel #7
0
void COdbcEnvironment::InitializeEnvironment( )
{
	SetEnvAttr( SQL_ATTR_CONNECTION_POOLING, ( SQLPOINTER )SQL_CP_DRIVER_AWARE );

	if( !Alloc( ) )
	{
		throw OdbcException( GetSqlError( ) );
	}

	if( !SetEnvAttr( SQL_ATTR_ODBC_VERSION, ( SQLPOINTER )SQL_OV_ODBC3_80 ) )
	{
		if( !SetEnvAttr( SQL_ATTR_ODBC_VERSION, ( SQLPOINTER )SQL_OV_ODBC3 ) )
		{
			throw OdbcException( GetSqlError( ) );
		}
	}
	
	if( !SetEnvAttr( SQL_ATTR_CP_MATCH, ( SQLPOINTER )SQL_CP_RELAXED_MATCH ) )
	{
		throw OdbcException( GetSqlError( ) );
	}
}
Beispiel #8
0
// ////////////////////////////////////////////////////////////////////////////
SQLRETURN DescribeCol(SQLHSTMT StatementHandle, SQLSMALLINT ColumnNumber,
	std::string &ColumnName, SQLSMALLINT *DataTypePtr,
	SQLUINTEGER *ColumnSizePtr, SQLSMALLINT *DecimalDigitsPtr,
	SQLSMALLINT *NullablePtr, OdbcThrowFlags::Flags throw_flags)
{
	SQLRETURN                                     return_code;
	MLB::Utility::IncrementalBuffer<SQLCHAR, 256> buffer;
	OdbcThrowFlags::Flags                         tmp_throw_flags;

	tmp_throw_flags = MLB::Utility::EnumFlagAnd(throw_flags,
		static_cast<OdbcThrowFlags::Flags>(~(OdbcThrowFlags::SuccessWithInfo)));

	for ( ; ; ) {
		SQLSMALLINT actual_len;
		return_code = DescribeCol(StatementHandle, ColumnNumber,
			reinterpret_cast<SQLCHAR *>(buffer.GetPtr()),
			buffer.GetAllocationCountAsType<SQLSMALLINT>(), &actual_len,
         DataTypePtr, ColumnSizePtr, DecimalDigitsPtr, NullablePtr,
			tmp_throw_flags);
		if (return_code == SQL_SUCCESS) {
			std::string(reinterpret_cast<const char *>(buffer.GetPtr()),
				actual_len).swap(ColumnName);
			break;
		}
		else if (return_code == SQL_SUCCESS_WITH_INFO) {
			if (!buffer.SetCount(actual_len, false)) {
				std::string(reinterpret_cast<const char *>(buffer.GetPtr()),
					actual_len).swap(ColumnName);
				if (throw_flags & OdbcThrowFlags::SuccessWithInfo)
					throw OdbcException("Call to '::SQLDescribeCol()' returned "
						"'SQL_SUCCESS_WITH_INFO', but no returned lengths qualified "
						"for that return code.");
				break;
			}
		}
	}

	return(return_code);
}
Beispiel #9
0
    bool OdbcConnection::TryOpen(const wstring& connectionString)
    {
        SQLRETURN ret;

        if (connectionState == Closed)
        {
            OdbcConnectionHandle localConnection;

            localConnection.Alloc(environment);

            this->connection = std::move(localConnection);

            // TODO: determine async open support correctly
            // SQLSetConnectAttr(connection, SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, (SQLPOINTER)SQL_ASYNC_DBC_ENABLE_ON, 0);

            connectionState = Opening;
        }

        if (connectionState == Opening)
        {
            ret = SQLDriverConnect(connection, NULL, const_cast<wchar_t*>(connectionString.c_str()), connectionString.length(), NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
            if (ret == SQL_STILL_EXECUTING) 
            { 
                return false; 
            }
            if (!SQL_SUCCEEDED(ret)) 
            { 
                connection.Throw();  
            }

            connectionState = Open;
            return true;
        }

        throw OdbcException("Attempt to open a connection that is not closed");
    }
Beispiel #10
0
    bool OdbcConnection::TryExecute(const wstring& query)
    {
        if (connectionState != Open)
        {
            throw OdbcException("Unable to execute a query on a connection that is not open");
        }

        if (executionState == Idle)
        {
            statement.Alloc(connection);
            
            // ignore failure - optional attribute
            SQLSetStmtAttr(statement, SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_ON, 0);

            executionState = Executing;
        }

        if (executionState == Executing)
        {
            SQLRETURN ret = SQLExecDirect(statement, const_cast<wchar_t*>(query.c_str()), query.length());
            if (ret == SQL_STILL_EXECUTING) 
            { 
                return false; 
            }
            if (!SQL_SUCCEEDED(ret)) 
            { 
                statement.Throw();  
            }

            executionState = CountingColumns;
        }

        if (executionState == CountingColumns)
        {
            SQLSMALLINT columns;
            SQLRETURN ret = SQLNumResultCols(statement, &columns);
            if (ret == SQL_STILL_EXECUTING) 
            { 
                return false; 
            }
            if (!SQL_SUCCEEDED(ret)) 
            { 
                statement.Throw();  
            }        

            executionState = Metadata;
            column = 0;
            resultset = make_shared<ResultSet>(columns);

        }

        if (executionState == Metadata)
        {
            while (column < resultset->GetColumns())
            {
                SQLSMALLINT nameLength;
                SQLRETURN ret = SQLDescribeCol(statement, column + 1, nullptr, 0, &nameLength, nullptr, nullptr, nullptr, nullptr);
                if (ret == SQL_STILL_EXECUTING) 
                { 
                    return false; 
                }
                if (!SQL_SUCCEEDED(ret)) 
                { 
                    statement.Throw();  
                }
                ResultSet::ColumnDefinition& current = resultset->GetMetadata(column);
                vector<wchar_t> buffer(nameLength+1);
                ret = SQLDescribeCol(statement, column + 1, buffer.data(), nameLength+1, &nameLength, &current.dataType, &current.columnSize, &current.decimalDigits, &current.nullable);
                if (ret == SQL_STILL_EXECUTING) 
                { 
                    return false; 
                }
                if (!SQL_SUCCEEDED(ret)) 
                { 
                    statement.Throw();  
                }
                current.name = wstring(buffer.data(), nameLength);

                column++;
            }

            executionState = CountRows;
        }

        if (executionState == CountRows)
        {
            SQLLEN rowcount;
            SQLRETURN ret = SQLRowCount(statement, &rowcount);
            if (!SQL_SUCCEEDED(ret)) 
            { 
                statement.Throw();  
            }
            resultset->rowcount = rowcount;

            if (resultset->GetColumns() > 0)
            {
                executionState = FetchRow;
            }
            else {
                statement.Free();
                executionState = Idle;
            }
            return true;
        }

        throw OdbcException("The connection is in an invalid state");
    }
Beispiel #11
0
    bool OdbcConnection::TryReadColumn(int column)
    {
        if (executionState != FetchRow)
        {
            throw OdbcException("The connection is in an invalid state");
        }

        if (column < 0 || column >= resultset->GetColumns())
        {
            // TODO report an error
            return true;
        }

        SQLLEN strLen_or_IndPtr;
        const ResultSet::ColumnDefinition& definition = resultset->GetMetadata(column);
        switch (definition.dataType)
        {
        case SQL_CHAR:
        case SQL_VARCHAR:
        case SQL_LONGVARCHAR:
        case SQL_WCHAR:
        case SQL_WVARCHAR:
        case SQL_WLONGVARCHAR:
            {
                bool more = false;
                wchar_t buffer[2048+1] = {0};
                SQLRETURN ret = SQLGetData(statement, column + 1, SQL_C_WCHAR, buffer, sizeof(buffer)-sizeof(wchar_t), &strLen_or_IndPtr);
                if (ret == SQL_STILL_EXECUTING) 
                { 
                    return false; 
                }
                if (!SQL_SUCCEEDED(ret)) 
                { 
                    statement.Throw();  
                }
                if (strLen_or_IndPtr == SQL_NULL_DATA) 
                {
                    resultset->SetColumn(make_shared<NullColumn>());
                }
                else 
                {
                    SQLWCHAR SQLState[6];
                    SQLINTEGER nativeError;
                    SQLSMALLINT textLength;
                    if (ret == SQL_SUCCESS_WITH_INFO)
                    {
                        ret = SQLGetDiagRec(SQL_HANDLE_STMT, statement, 1, SQLState, &nativeError, NULL, 0, &textLength);
                        if (!SQL_SUCCEEDED(ret)) 
                        { 
                            statement.Throw();  
                        }
                        more = wcsncmp(SQLState, L"01004", 6) == 0;
                    }

                    resultset->SetColumn(make_shared<StringColumn>(buffer, more));
                }
            }
            break;
        case SQL_SMALLINT:
        case SQL_BIT:
        case SQL_TINYINT:
        case SQL_INTEGER:
            {
                long val;
                SQLRETURN ret = SQLGetData(statement, column + 1, SQL_C_SLONG, &val, sizeof(val), &strLen_or_IndPtr);
                if (ret == SQL_STILL_EXECUTING) 
                { 
                    return false; 
                }
                if (!SQL_SUCCEEDED(ret)) 
                { 
                    statement.Throw();  
                }
                if (strLen_or_IndPtr == SQL_NULL_DATA) 
                {
                    resultset->SetColumn(make_shared<NullColumn>());
                }
                else 
                {
                    resultset->SetColumn(make_shared<IntColumn>(val));
                }
            }
            break;
        case SQL_DECIMAL:
        case SQL_NUMERIC:
        case SQL_REAL:
        case SQL_FLOAT:
        case SQL_DOUBLE:
        case SQL_BIGINT:
            {
                double val;
                SQLRETURN ret = SQLGetData(statement, column + 1, SQL_C_DOUBLE, &val, sizeof(val), &strLen_or_IndPtr);
                if (ret == SQL_STILL_EXECUTING) 
                { 
                    return false; 
                }
                if (!SQL_SUCCEEDED(ret)) 
                { 
                    statement.Throw();  
                }
                if (strLen_or_IndPtr == SQL_NULL_DATA) 
                {
                    resultset->SetColumn(make_shared<NullColumn>());
                }
                else 
                {
                    resultset->SetColumn(make_shared<NumberColumn>(val));
                }
            }
            break;
        case SQL_BINARY:
        case SQL_VARBINARY:
        case SQL_LONGVARBINARY:
            {
                bool more = false;
                vector<char> buffer(2048);
                SQLRETURN ret = SQLGetData(statement, column + 1, SQL_C_BINARY, buffer.data(), buffer.size(), &strLen_or_IndPtr);
                if (ret == SQL_STILL_EXECUTING) 
                { 
                    return false; 
                }
                if (!SQL_SUCCEEDED(ret)) 
                { 
                    statement.Throw();  
                }
                if (strLen_or_IndPtr == SQL_NULL_DATA) 
                {
                    resultset->SetColumn(make_shared<NullColumn>());
                }
                else 
                {
                    assert(strLen_or_IndPtr != SQL_NO_TOTAL); // per http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx

                    SQLWCHAR SQLState[6];
                    SQLINTEGER nativeError;
                    SQLSMALLINT textLength;
                    if (ret == SQL_SUCCESS_WITH_INFO)
                    {
                        ret = SQLGetDiagRec(SQL_HANDLE_STMT, statement, 1, SQLState, &nativeError, NULL, 0, &textLength);
                        if (!SQL_SUCCEEDED(ret)) 
                        { 
                            statement.Throw();  
                        }
                        more = wcsncmp(SQLState, L"01004", 6) == 0;
                    }

					int amount = strLen_or_IndPtr;
					if (more) {
						amount = buffer.size();
					}

                    vector<char> trimmed(amount);
                    memcpy(trimmed.data(), buffer.data(), amount);
                    resultset->SetColumn(make_shared<BinaryColumn>(trimmed, more));
                }
            }
            break;
        // use text format form time/date/etc.. for now
        // INTERVAL TYPES? 
        case SQL_GUID:
        case SQL_TYPE_TIME:
        case SQL_TYPE_TIMESTAMP:
        case SQL_TYPE_DATE:
        default:
            {
                // TODO: how to figure out the size?
                vector<wchar_t> buffer(8192+1);
                SQLRETURN ret = SQLGetData(statement, column + 1, SQL_C_WCHAR, buffer.data(), 8192*sizeof(wchar_t), &strLen_or_IndPtr);
                if (ret == SQL_STILL_EXECUTING) 
                { 
                    return false; 
                }
                if (!SQL_SUCCEEDED(ret)) 
                { 
                    statement.Throw();  
                }
                                
                resultset->SetColumn(make_shared<StringColumn>(buffer.data(), false));
            }
            break;
        }

        return true;
    }