ODBC

1.1
申请环境句柄(SQLAllocHandle)
设置环境句柄(SQLSetEnvAttr)
申请连接句柄(SQLAllocHandle)
连接数据源(SQLConnect)
设置连接属性(SQLSertConnect)
连接阶段
设置驱动程序信息(SQLGetInfo)
申请语句句柄(SQLAllocHandle)
设置语句属性(SQLSetStmt)
初始化阶段
程序主体
执行语句、处理结果和提交事务

ODBC应用程序结构
 
1.2
释放语句句柄(SQLFreeHandle)
断开数据源连接(SQLDisconnect)
 
释放连接句柄(SQLFreeHandle)
 
结束部分
释放环境句柄(SQLFreeHandle)

利用ODBC API函数完成对ODBC数据源的连接
int CManuODBC::InitODBC(SQLCHAR *szDsn, SQLCHAR *szUserID, SQLCHAR *szPassword)
{
       SQLRETURN retcode;
       SQLHENV hEnv;
       SQLHDBC hDbc;
       SQLHSTMT hStmt;
       retcode = SQLAllocHandle( SQL_HANDLE_ENV, NULL, &hEnv );
       if ( retcode != SQL_SUCCESS )
              return RT_ERROR;
       else
        SetEnv( hEnv );
      
       retcode = SQLSetEnvAttr( m_hEnv, SQL_ATTR_ODBC_VERSION,
                             ( SQLPOINTER )SQL_OV_ODBC3, SQL_IS_INTEGER );
       if ( retcode != SQL_SUCCESS )
              return RT_ERROR;    
       retcode = SQLAllocHandle( SQL_HANDLE_DBC, m_hEnv, &hDbc );
       if ( retcode != SQL_SUCCESS )
              return RT_ERROR;
       else
              SetDbc( hDbc );
       try
       {
           retcode = SQLConnect( m_hDbc,
                              szDsn, ( SWORD )strlen( ( char* )szDsn ),
                              szUserID, ( SWORD )strlen( ( char* )szUserID ),
                              szPassword, ( SWORD )strlen( ( char* )szPassword ) );
       }
       catch( ... )
       {
              DispErrMsg( hStmt, retcode );
              return RT_ERROR;
       }
    retcode = SQLAllocHandle( SQL_HANDLE_STMT, hDbc, &hStmt );
       if ( retcode != SQL_SUCCESS )
       {
              DispErrMsg( hStmt, retcode );
              return RT_ERROR;
       }
       else
              SetStmt( hStmt ); 
       return RT_OK;
}
1.3 利用ODBC API函数执行SQL语句
int CManuODBC::ExecSQL( CString strManuDB )
{
       SQLRETURN retcode;
       SQLHSTMT hstmt = this->GetStmt();    
             
       retcode = SQLPrepare( hstmt, ( SQLCHAR* )( LPSTR )( LPCSTR )strManuDB, SQL_NTS );      
      
       if ( retcode != SQL_SUCCESS )
       {
              return RT_ERROR;
       }
 
       try
       {
              retcode = SQLExecute( hstmt );
              if ( retcode != SQL_SUCCESS )
              {
                     throw retcode;
              }
       }
       catch( SQLRETURN &rtcde )
       {
        DispErrMsg( hstmt, retcode );
              return RT_ERROR;
       }
       catch( ... )
       {
              AfxMessageBox( "发生异常,中止导入!" );
              return RT_ERROR;
       }
      
       //retcode = SQLBindCol( hstmtNew, 1, SQL_C_CHAR, szName, MAXNAME, &cbName );
       //SQLNumResultCols( hstmtNew, &nNum );        
      
       /*while ( SQLFetch( hstmt ) != SQL_NO_DATA )
       {           
              if ( retcode == SQL_ERROR ) 
              {
            return; 
              }
              if ( retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO )
              {                                                                             
              }           
       }*/
 
       return RT_OK;
}
1.4 自定义配置文件的读取
BOOL CTableInfo::ReadProfile(HANDLE hFile)
{        
    ULONG uBytesWrite = 0;
    ULONG uFileSize = 0;
      
       int nTbCnt;
       char szInitFile[ 128 ];
       CString strSecName, key1, key2, key3, strCurSecName;
       CArray< DBTableConfig, DBTableConfig> tbConfig;
       DBTableConfig tbConfigA;
 
       strcpy( szInitFile, ".//DispTableConfig.INI" );
       //strcpy( szInitFile, ".//EvtTableConfig.INI" );
  
//自定义配置文件格式如下
/*[Gerneral]
ODBCNum = 3
 
[001]
Dsn = DBHistory
UID = sa
PSD = 1
 
[002]
Dsn = DBData
UID = sa
PSD = 1
 
[003]
Dsn = DBEvt
UID = sa
PSD = 1*/
//读取自定义配置文件中的整形变量
    /* UINT GetPrivateProfileInt(
         LPCTSTR lpAppName, // address of section name
         LPCTSTR lpKeyName, // address of key name
         INT nDefault, // return value if key name is not found
         LPCTSTR lpFileName // address of initialization filename
);
   */
       nTbCnt = ::GetPrivateProfileInt( "General", "tbCount", NULL, szInitFile );
       tbConfig.SetSize( nTbCnt );   
 
    WriteFile( hFile, &nTbCnt, sizeof( int ), &uBytesWrite, NULL );
 
       for( int i=0; i<nTbCnt; i++ )
       {
              strSecName.Empty();
             
              if( i < 10 )
                     strCurSecName.Format( "00%d", i+1 );
              else
                     strCurSecName.Format( "0%d", i+1 );                 
             
              memset( &tbConfig[i], 0, sizeof( tbConfigA ) );
 
       //读取自定义配置文件中的字符串变量
       /* DWORD GetPrivateProfileString(
             LPCTSTR lpAppName,       // points to section name
             LPCTSTR lpKeyName,       // points to key name
             LPCTSTR lpDefault,    // points to default string
             LPTSTR lpReturnedString, // points to destination buffer
             DWORD nSize,         // size of destination buffer
             LPCTSTR lpFileName   // points to initialization filename
);*/
      //读取自定义配置文件中的结构体
      /*BOOL GetPrivateProfileStruct(
         LPCTSTR lpszSection, // address of section name
         LPCTSTR lpszKey,      // address of key name
         LPVOID lpStruct,      // address of return buffer
         UINT uSizeStruct,     // size of return buffer
         LPCTSTR szFile // address of initialization filename
);*/
              ::GetPrivateProfileString( strCurSecName, "TbName", "", tbConfig[i].szTbName, sizeof( tbConfig[i].szTbName), szInitFile );
              WriteFile( hFile, tbConfig[i].szTbName, sizeof( tbConfig[i].szTbName ), &uBytesWrite, NULL );
              ::GetPrivateProfileString( strCurSecName, "tbChiDesc", "", tbConfig[i].szTbChiDesc, sizeof( tbConfig[i].szTbChiDesc), szInitFile );
              WriteFile( hFile, tbConfig[i].szTbChiDesc, sizeof( tbConfig[i].szTbChiDesc ), &uBytesWrite, NULL );
 
              tbConfig[i].nTbSrcCount = ::GetPrivateProfileInt( strCurSecName, "tbSrcCount", NULL, szInitFile );
              WriteFile( hFile, &tbConfig[i].nTbSrcCount, sizeof( int ), &uBytesWrite, NULL );
 
              ::GetPrivateProfileString( strCurSecName, "tbSrcInfo", "", tbConfig[i].szTbSrcInfo, sizeof( tbConfig[i].szTbSrcInfo), szInitFile );
              GetFieldInfo( tbConfig[i].szTbSrcInfo, hFile );
 
              tbConfig[i].nTbFieldCount = ::GetPrivateProfileInt( strCurSecName, "tbFieldCount", NULL, szInitFile );
              WriteFile( hFile, &tbConfig[i].nTbFieldCount, sizeof( int ), &uBytesWrite, NULL );
 
              ::GetPrivateProfileString( strCurSecName, "tbFieldInfo", "", tbConfig[i].szTbFieldInfo, sizeof( tbConfig[i].szTbFieldInfo ), szInitFile );
              GetFieldInfo( tbConfig[i].szTbFieldInfo, hFile );
 
              /*for( int j=1; j<=tbConfig[i].CmdTran; j++ )
              {
                     key1.Format( "Tran_0%d_Sql", j );
                     key2.Format( "Tran_0%d_Para", j );
                     key3.Format( "Tran_0%d_Col", j );
                    
                     switch( j )
                     {
                     case 1:
                            {
                                   memset( tbConfig[i].Tran_01_Col, 0, 256 );
                                   memset( tbConfig[i].Tran_01_Para, 0, 256 );
                                   memset( tbConfig[i].Tran_01_Sql, 0, 1024 );
                                   ::GetPrivateProfileString( strCurSecName,key1, "", tbConfig[i].Tran_01_Sql, sizeof(tbConfig[i-1].Tran_01_Sql ), szInitFile );
                                   ::GetPrivateProfileString( strCurSecName,key2, "", tbConfig[i].Tran_01_Para, sizeof(tbConfig[i-1].Tran_01_Para ), szInitFile );
                                   //tbConfig[i-1].Para1_Len=GetParaNum(tbConfig[i-1].Tran_01_Para);
                                   ::GetPrivateProfileString(strCurSecName,key3, "", tbConfig[i].Tran_01_Col, sizeof( tbConfig[i-1].Tran_01_Col ), szInitFile );
                                   //取出配置文件中的命令参数
                                   break;
                            }
                     case 2:
                            {
                                   memset( tbConfig[i].Tran_02_Col, 0, 256 );
                                   memset( tbConfig[i].Tran_02_Para, 0, 256 );
                                   memset( tbConfig[i].Tran_02_Sql, 0, 1024 );
                                   ::GetPrivateProfileString( strCurSecName,key1, "", tbConfig[i].Tran_02_Sql, sizeof( tbConfig[i-1].Tran_02_Sql ), szInitFile );
                                   ::GetPrivateProfileString( strCurSecName,key2, "", tbConfig[i].Tran_02_Para, sizeof( tbConfig[i-1].Tran_02_Para ), szInitFile );
                                   //tbConfig[i-1].Para2_Len=GetParaNum(tbConfig[i-1].Tran_02_Para);
                                   ::GetPrivateProfileString( strCurSecName, key3,"", tbConfig[i].Tran_02_Col, sizeof( tbConfig[i-1].Tran_02_Col ), szInitFile );
                                   break;
                            }
                     case 3:
                            {
                                   memset( tbConfig[i].Tran_03_Col, 0, 256 );
                                   memset( tbConfig[i].Tran_03_Para, 0, 256 );
                                   memset( tbConfig[i].Tran_03_Sql, 0, 1024 );
                                   ::GetPrivateProfileString( strCurSecName,key1, "", tbConfig[i].Tran_03_Sql, sizeof( tbConfig[i-1].Tran_03_Sql ),szInitFile );
                                   ::GetPrivateProfileString( strCurSecName,key2, "", tbConfig[i].Tran_03_Para, sizeof( tbConfig[i-1].Tran_03_Para ),szInitFile );
                                   //tbConfig[i-1].Para3_Len=GetParaNum(tbConfig[i-1].Tran_03_Para);
                                   ::GetPrivateProfileString( strCurSecName,key3, "", tbConfig[i].Tran_03_Col, sizeof( tbConfig[i-1].Tran_03_Col ), szInitFile );
                                   break;
                            }
                     default:
                            break;
                     }
              }*/
       }
   
       return TRUE;
}
1.5 ODBC API函数中的对参数绑定的实现
/*SQLRETURN SQLBindParameter(
SQLHSTMT StatementHandle,
SQLUSMALLINT ParameterNumber,
SQLSMALLINT InputOutputType,
SQLSMALLINT ValueType,
SQLSMALLINT ParameterType,
SQLUINTEGER ColumnSize,
SQLSMALLINT DecimalDigits,
SQLPOINTER ParameterValuePtr,
SQLINTEGER BufferLength,
SQLINTEGER StrLen_or_IndPtr);
*/
   /*注意:
参数一为申请的语句句柄;hStmt
参数二为参数编号;如SQL语句为INSERT INTO T1(value1,value2) VALUES(?,?),则1就代表对value1字段进行的绑定,2亦然
参数三为参数类型,输入或输出,通常为SQL_PARAM_INPUT或者SQL_PARAM_OUTPUT
参数四为参数的ODBC C类型;
参数五为参数的ODBC API类型;C和API类型必须一一对应,且与缓冲区数据类型对应;
参数六为其所在列的长度;一般整型和单精度浮点型为4,双精度浮点型为8等等,字符串类型为创建表是定义的该字段的字符串长度
参数七为参数所对应的小数点位数;
参数八为参数所对应的缓冲区;
参数九为缓冲区长度,整型、浮点型或者日期型等均为&nX(SQLINTEGER nX = 0;)
参数九在参数为整型、浮点型或日期型时为0,参数为字符串时为&nX (SQLINTEGER nX = SQL_NTS;);
*/
retcode = SQLPrepare( hstmt, ( SQLCHAR* )( LPSTR )( LPCSTR )strInsertSQL, SQL_NTS );
       if ( retcode != SQL_SUCCESS )
       {
              return RT_ERROR;
       }
switch ( pField->GetType() )
            {
            case DATA_INTEGER:
 
                if ( pField->GetLength() > 1 )
                {
                    CString strFieldName = pField->GetName();
                                   int nFieldSize = pField->GetSize();                              
                             }
                else
                {                            
                                   pIntType[nCurIntTypeCount] = *(int* )pData;
                                  
                                   retcode = SQLBindParameter( hstmt, nCurFieldCount, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 4, 0, &pIntType[nCurIntTypeCount], 0, &cbInteger );
                }
                nDataOffset = nDataOffset + pField->GetSize();
                            nCurIntTypeCount++;
                break;
            case DATA_FLOAT_SINGLE:
                if ( pField->GetLength() > 1 )
                {
                }
                else
                {
                    float fValue = *( float* )pData;                                
                                   retcode = SQLBindParameter( hstmt, nCurFieldCount, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_REAL, 4, 0, &fValue, 0, &cbFloat );
                             }
                nDataOffset = nDataOffset + pField->GetSize();
                break;
            case DATA_DATETIME:
            case DATA_DATETIME_SECOND:
            case DATA_DATETIME_MINUTE:
            case DATA_DATETIME_MONTH:
            case DATA_DATETIME_HOUR:
            case DATA_DATETIME_WEEK:
            case DATA_DATETIME_USECOND:
            {               
                            strTime = ( char* )pData;
                            SQL_TIMESTAMP_STRUCT tm;
 
                            tm = FormatTime( strTime );                          
 
                            retcode = SQLBindParameter( hstmt, nCurFieldCount, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 8, 0, &tm, 0, &cbTime );
                nDataOffset = nDataOffset + SIZE_TIMESTR;
                break;
            }
            case DATA_STRING:    
                retcode = SQLBindParameter( hstmt, nCurFieldCount, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, pField->GetSize() - 1, 0, pData, pField->GetSize(), &cbChar );
                            nDataOffset = nDataOffset + pField->GetSize();
                break;
            case INVALID_FIELD_TYPE:
                return RT_ERROR;
            default:
                return RT_ERROR;
            }
retcode = SQLExecute( hstmt );

1.8 利用ODBCAPI函数插入或修改二进制数据
BOOL main()
CString strInsertSQL = "Update ";
       strInsertSQL += strTableName;
    strInsertSQL += strTypeSuffix;
       strInsertSQL += " Set ";
    strInsertSQL += strFieldName;
       strInsertSQL += " = ? Where f_Time = ?";   
 
       void* pData = NULL;
       SQLHSTMT hstmt = pODBC->GetStmt();
       SQLRETURN retcode;
       SQL_TIMESTAMP_STRUCT tmNew;
       SDWORD cbBinary = SQL_LEN_DATA_AT_EXEC( MAX_BLOB_DATA_LENGTH );
      
   //准备执行SQL语句
       retcode = SQLPrepare( hstmt, ( SQLCHAR* )( LPSTR )( LPCSTR )strInsertSQL, SQL_NTS );
 
       SDWORD cbTime = 0;
 
   //绑定参数列
       retcode = SQLBindParameter( hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, MAX_BLOB_DATA_LENGTH, 0, pData, 0, &cbBinary );
       retcode = SQLBindParameter( hstmt, 2, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 8, 0, &tmNew, 0, &cbTime );
      
       tmNew = tm;
       pData = data;
 
   //执行SQL语句
       retcode = SQLExecute( hstmt );
       SQLPOINTER pToken;
       SQLINTEGER cbData = MAX_BLOB_DATA_LENGTH;
       //向绑定的参数列传递数据
retcode = SQLParamData( hstmt, &pToken );     
 
       while ( retcode == SQL_NEED_DATA )
       {
       //开始传递                                     
              retcode = SQLPutData( hstmt, pData, cbData );
              //pData = ( char* )data + MAX_BLOB_DATA_LENGTH;
       //完成数据传递
              retcode = SQLParamData( hstmt, &pToken );             
       }
 
       return RT_OK;

}  

l        软件运行的初始化工作必须在撰写代码之前做详细的规划。例如程序在执行一段循环程序,在每一步的循环中都要用到注册表中的一个或几个键值,此时可以在程序初始化时定义一个全局变量,在程序启动时就将要用到的注册表键值全部读入一个结构体中;再比如用ODBC编写数据库程序,则只需建立一个ODBC连接,每次执行新的SQL语句时只需重新申请语句句柄即可,这样即可以节省数据库操作时间,又使程序出错机会大大减少。

1.10 读取注册表
bool ReadHKey( void )
{
HKEY hkey = HKEY_LOCAL_MACHINE;
       DWORD len;
       DWORD type;
    Char szKey1[128], szKey2[128];
       //打开键
       if ( ::RegOpenKeyEx( hkey, "Software//WSPQMC//WSPQMCS", 0, KEY_ALL_ACCESS, &hkey ) == ERROR_SUCCESS )
       {
              len = 128; //设置读取键值的最大长度
              type = REG_SZ; //设置读取键值的类型
       //读取键值
              if ( ::RegSetValueEx( hkey, "DSNHistory", NULL, &type, szKey1, &len ) != ERROR_SUCCESS )
{
                     ::RegCloseKey( hkey );
                     return FALSE;
              }
       //读取新键值,首先重新设置键值长度和类型
              len = 128;
              type = REG_SZ;
              if ( ::RegSetValueEx( hkey, "DSNData", NULL, &type, ( unsigned char* ) szKey2, &len ) != ERROR_SUCCESS )
              {
                     ::RegCloseKey( hkey );
                     return FALSE;
              }
Cstring strKey1,strKey2;
strKey1 = szKey1;
strKey2 = szKey2;
}
return true;
}

1.13 在VC中使用ADO
首先要在CMyApp::InitInstance()函数中加入初始化Com环境
if ( FAILED(::CoInitialize(NULL)) )
{
     ::AfxMessageBox( "Com Init Fail !" );
     ::exit(0);
}
在CMyApp::ExitInstance()函数中加入
::CoUninitialize();
       然后引入ADO库文件,一般是在stdAfx.h文件中添加
#import <msado15.dll> no_namespace rename( "EOF", "adoEOF" )
       这条语句会在工程所在目录生成msado15.tlh和msado15.tli两个文件。
在你的类声明文件中加入智能指针对象实例的定义,做为成员变量,
_ConnectionPtr m_pConn;
_RecordsetPtr m_pRs;
使用之前先初始化,
//初始化ADO成员
TESTHR( m_pConn.CreateInstance(     __uuidof( Connection ) ) );
TESTHR( m_pRs.CreateInstance(    __uuidof( Recordset ) ) );
其中TESTHR定义如下:
void TESTHR(HRESULT x)
{
 if FAILED(x)
        _com_issue_error(x);
};
然后就是连接数据库,获取Recordset……用不着我多说了吧,代码如下:
//Open Connection
TESTHR( m_pConn->Open( strConn/*连接字符串*/, "", "", adConnectUnspecified ) );
//Open table
TESTHR( m_pRs->Open( SQL/*SQL查询语句*/
                 _variant_t((IDispatch*)m_pConn, true),
                 adOpenKeyset,//adOpenForwardOnly,
                 adLockReadOnly,
                 adCmdText) );
1.14 写注册表动态创建SQL Server ODBC数据源
各个参数的意义:
DBServer: 数据库所在主机
DBName:  数据库名称
DSN:   数据源名称
UID:   登陆用户
返回值:
-1: 没有安装SQL Server驱动程序
-2: 其他错误
0: 成功
 
实现函数:
int MakeSQLServerODBCDSN(LPCTSTR DBServer,LPCTSTR DBName,LPCTSTR DSN,LPCTSTR UID)
{
BOOL  bInstallDriver = TRUE;
CRegKey  regKey;
 
LONG lRet = regKey.Open( HKEY_LOCAL_MACHINE, "Software//ODBC//ODBCINST.INI//SQL Server" );
If ( lRet != ERROR_SUCCESS )
{
bInstallDriver = FALSE;
}
else
{
char  szDirverPath[MAX_PATH] = "";
DWORD  dwCount = 100;
lRet=regKey.QueryValue(szDirverPath,"Driver",&dwCount);
if ( ( lRet != ERROR_SUCCESS ) || ( dwCount < 1 ) )
{
       DWORD dwErr = GetLastError();
       BinstallDriver = FALSE;
   }
regKey.Close();
}
if ( !bInstallDriver )
{
return -1;
}
CString  strKeyValueName="Software//ODBC//ODBC.INI//";
StrKeyValueName += DSN;
lRet=regKey.Create(HKEY_LOCAL_MACHINE,strKeyValueName);
if ( lRet != ERROR_SUCCESS )
{
return -2;
}
regKey.SetValue(DBName,"Database");
regKey.SetValue("SQLSrv32.dll","Driver");
regKey.SetValue(DBServer,"Server");
regKey.SetValue(UID,"LastUser");
regKey.m_hKey=HKEY_LOCAL_MACHINE;
regKey.SetKeyValue("Software//ODBC//ODBC.INI//ODBC Data Sources","SQL Server",DSN);
regKey.Close();
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值