odbc.cpp
来自「Shorthand是一个强大的脚本语言」· C++ 代码 · 共 300 行
CPP
300 行
#ifdef WIN32
#include <windows.h>
#else
#include <stdlib.h>
#include <stdio.h>
#endif
#include <sql.h>
#include <sqlext.h>
#include "dbdriver.h"
#include "except.h"
class OdbcErrorContainer
{
public:
SQLTCHAR* m_szMessage;
SQLTCHAR* m_szState;
SQLINTEGER m_nNativeError;
SQLSMALLINT m_cbMessage;
OdbcErrorContainer(HENV env, SQLHDBC connection = 0, SQLHSTMT statement = 0)
{
m_szMessage = (SQLTCHAR*) malloc(sizeof(SQLTCHAR)*SQL_MAX_MESSAGE_LENGTH);
m_szState = (SQLTCHAR*) malloc(sizeof(SQLTCHAR)*SQL_MAX_MESSAGE_LENGTH);
m_szMessage[0] = '\0';
m_szState[0] = '\0';
m_cbMessage = SQL_MAX_MESSAGE_LENGTH-1;
populate(env, connection, statement);
}
void populate(HENV env, SQLHDBC connection = 0, SQLHSTMT statement = 0)
{
SQLError(env, connection, statement, m_szState, &m_nNativeError, m_szMessage,
SQL_MAX_MESSAGE_LENGTH-1, &m_cbMessage );
}
const char* getErrorMessage() const { return (const char*) m_szMessage; }
int getErrorCode() const { return m_nNativeError; }
const char* getOdbcState() const { return (const char*) m_szState; }
~OdbcErrorContainer()
{
if (m_szMessage != NULL) free(m_szMessage);
if (m_szState != NULL) free(m_szState);
}
};
class OdbcDriver : public ShhDbDriver
{
private:
HENV m_env;
public:
OdbcDriver()
{
m_env = NULL;
}
void throwSQL(int code, const char* format, ...)
{
va_list args; va_start(args, format);
throw new ShhObjectException(format, args);
}
void check_odbc_status(SQLRETURN code, SQLHDBC connection = 0, SQLHSTMT statement = 0)
{
if (code == SQL_SUCCESS || code == SQL_SUCCESS_WITH_INFO) return;
if (m_env == NULL) throwSQL(7101, "ODBC Error %d (%0x08x)", code, code);
OdbcErrorContainer e(m_env, connection, statement);
throwSQL(7101, "%s %s", e.getOdbcState(), e.getErrorMessage());
}
bool spi_RecognizeDriverName(const char* driverName)
{
string name(driverName);
return name.ieq("ODBC");
}
const char* spi_GetDriverPrefix()
{
return "ODB";
}
int spi_GetDriverDescription(string& driverDescription)
{
driverDescription = "Generic ODBC driver";
return driverDescription.length();
}
virtual ShhDbHandle spi_Connect(const char* connString)
{
SQLRETURN rc;
if (m_env == NULL)
{
rc = SQLAllocEnv(&m_env);
check_odbc_status(rc);
}
HDBC session;
rc = SQLAllocConnect(m_env, &session);
check_odbc_status(rc);
rc = SQLConnect(session, (SQLTCHAR*) connString, strlen(connString),
(SQLTCHAR*)"", 0, (SQLTCHAR*)"", 0);
check_odbc_status(rc, session);
return (ShhDbHandle) session;
}
virtual int spi_GetLastError(ShhDbHandle conn, string& message)
{
OdbcErrorContainer e(m_env, (SQLHDBC) conn);
message = e.getErrorMessage();
return e.getErrorCode();
}
virtual void spi_Disconnect(ShhDbHandle conn)
{
if (conn != NULL)
{
SQLDisconnect((SQLHDBC) conn);
SQLFreeConnect((SQLHDBC) conn);
}
}
virtual ShhCursorHandle spi_PrepareSQL(ShhDbHandle conn, const char* sql)
{
SQLHSTMT cursorHandle;
SQLRETURN rc = SQLAllocStmt((SQLHDBC) conn, &cursorHandle);
check_odbc_status(rc, (SQLHDBC)conn);
return (ShhCursorHandle) cursorHandle;
}
virtual void spi_CloseCursor(ShhCursorHandle cursor)
{
if (cursor != NULL)
{
SQLFreeStmt((SQLHSTMT) cursor, SQL_CLOSE);
}
}
virtual void spi_CloseResult(ShhResultHandle resultSet)
{
if (resultSet != 0)
{
//SQLFreeStmt((SQLHSTMT) resultSet, SQL_CLOSE);
}
}
virtual int spi_ExecuteImmediate(ShhDbHandle conn, const char* sql)
{
SQLHSTMT cursorHandle;
SQLRETURN rc;
rc = SQLAllocStmt((SQLHDBC) conn, &cursorHandle);
check_odbc_status(rc, (SQLHDBC) conn);
rc = SQLExecDirect((SQLHSTMT) cursorHandle, (SQLTCHAR*) sql, strlen(sql));
check_odbc_status(rc, (SQLHDBC)conn, (SQLHSTMT) cursorHandle);
SQLFreeStmt((SQLHSTMT) cursorHandle, SQL_CLOSE);
return 0;
}
virtual ShhResultHandle spi_ExecuteCursor(ShhDbHandle dbHandle, ShhCursorHandle cursor, const char* sql)
{
SQLRETURN rc = SQLExecDirect((SQLHSTMT) cursor, (SQLTCHAR*) sql, strlen(sql));
check_odbc_status(rc, (SQLHDBC) dbHandle, (SQLHSTMT) cursor);
return (ShhResultHandle) cursor;
}
virtual int spi_GetFieldCount(ShhResultHandle resultHandle)
{
if (resultHandle == 0) return 0;
SQLSMALLINT nColumnCount = 0;
SQLRETURN rc = SQLNumResultCols((SQLHSTMT) resultHandle, &nColumnCount);
return nColumnCount;
}
virtual int spi_GetRowCount(ShhResultHandle resultHandle)
{
if (resultHandle == 0) return 0;
SQLINTEGER nRowCount = 0;
SQLRETURN rc = SQLGetStmtOption((SQLHSTMT) resultHandle, SQL_ROWSET_SIZE, &nRowCount);
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
{
return -1;// ODBC does not provide such information
}
else return nRowCount;
}
virtual int spi_GetFieldName(ShhResultHandle resultHandle, int fieldNumber, string& fieldName)
{
if (resultHandle == 0) { fieldName = ""; return 0; }
char szColName[256];
SQLSMALLINT cbColName = 0, cbColNameMax = sizeof(szColName);
SQLUINTEGER cbColDef = 0;
SQLSMALLINT nType, nScale, nNullable;
SQLRETURN rc = SQLDescribeCol(
(SQLHSTMT) resultHandle, (SQLUSMALLINT) fieldNumber+1,
(SQLTCHAR*) szColName, cbColNameMax, &cbColName,
&nType, &cbColDef, &nScale, &nNullable);
check_odbc_status(rc, 0, (SQLHSTMT) resultHandle);
fieldName = szColName;
return fieldName.length();
}
virtual ShhRowHandle spi_Fetch(ShhResultHandle resultSet)
{
SQLRETURN rc = SQLFetch((SQLHSTMT) resultSet);
if (rc == SQL_NO_DATA) return NULL;
check_odbc_status(rc, 0, (SQLHSTMT) resultSet);
return (ShhRowHandle) resultSet;
}
virtual int spi_GetStringValue(ShhResultHandle resultHandle, ShhRowHandle rowHandle, int fieldNumber, string& value)
{
SQLINTEGER cbData = 256;
SQLRETURN rc;
SQLTCHAR* szData = (SQLTCHAR*) value.provide_window(cbData);
*szData = '\0';
rc = SQLGetData((SQLHSTMT) resultHandle, fieldNumber+1,
SQL_C_CHAR, szData, cbData, &cbData);
check_odbc_status(rc, 0, (SQLHSTMT) resultHandle);
if (cbData > 256)
{
// default buffer too small; reallocate it
szData = (SQLTCHAR*) value.provide_window(cbData+2) + 255;
rc = SQLGetData((SQLHSTMT) resultHandle, fieldNumber+1,
SQL_C_CHAR, szData, cbData - 254, &cbData);
check_odbc_status(rc, 0, (SQLHSTMT) resultHandle);
}
return cbData;
}
virtual int spl_GetAffectedRows(ShhCursorHandle handle)
{
SQLINTEGER rowCount = 0;
SQLRETURN rc = SQLRowCount((SQLHSTMT) handle, &rowCount);
check_odbc_status(rc, 0, (SQLHSTMT) handle);
return rowCount;
}
virtual void spi_CloseRow(ShhRowHandle rowHandle)
{
}
virtual int
spi_ClearParameters(ShhCursorHandle hCursor)
{
SQLRETURN rc = SQLFreeStmt((SQLHSTMT) hCursor, SQL_RESET_PARAMS);
//check_odbc_status(rc, 0, hCursor);
return 0;
}
/**
* Pastes parameter value into SQL statement.
* If the driver supports parameter bindings and markers, it
* pastes marker (usually "?") into SQL instead of value itself
* and binds supplied value to that marker using native driver API.
* If the driver doesn't support binding/markers, it pastes quotes
* and escapes special characters inside strings as necessary.
*/
virtual int
spi_PasteValue(ShhCursorHandle hCursor, ShhDbExecutor* executor, int index, string& output, const char* value)
{
const char* szValue = executor->fpi_StoreParameter(index, value);
output.append("?");
return 0;
}
virtual int
spi_BindValue(ShhCursorHandle hCursor, ShhDbExecutor* executor, int index, const char* szValue)
{
int cbValue = strlen(szValue);
SQLRETURN rc = SQLSetParam((SQLHSTMT)hCursor, index+1,
SQL_C_CHAR, SQL_CHAR, cbValue, 0, (void*) szValue, NULL);
check_odbc_status(rc, (SQLHDBC) executor->fpi_GetConnection(), (SQLHSTMT) hCursor);
return 0;
}
};
ShhDbDriver* create_odbc_driver()
{
return new OdbcDriver();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?