暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

OB-ODBC 驱动

SQL新手 2022-12-12
535

本文介绍了 OceanBase 数据库的 OB-ODBC 驱动和 MySQL 官方 MySQL-ODBC 驱动的使用说明和配置方法。

开放数据库互连(ODBC)是微软公司开放服务结构( WOSA,Windows Open Services Architecture)中有关数据库的一个组成部分,基本思想是为用户提供简单、标准、透明的数据库连接的公共编程接口,开发厂商根据 ODBC 的标准去实现底层的驱动程序,这个驱动对用户是透明的,并允许根据不同的 DBMS 采用不同的技术加以优化实现。

ODBC 主要由驱动程序和驱动程序管理器组成。驱动程序是一个用以支持 ODBC 函数调用的模块,每个驱动程序对应于相应的数据库,当应用程序从一个数据库系统移植到另一个时,只需更改应用程序中由 ODBC 管理程序设定的与相应数据库系统对应的别名即可。

建议使用 OceanBase 数据库的 OB-ODBC 驱动。

连接 MySQL 租户也可以使用 MySQL 官方 MySQL-ODBC 驱动。

连接 OceanBase 数据库的驱动程序管理器和驱动程序 OB-ODBC 均为 OceanBase 自研,通过该驱动可以连接访问 OceanBase 数据库。

Linux 下 OB-ODBC/MySQL-ODBC 连接 OceanBase 数据库的架构图如下所示。

1

连接环境配置

连接数据库前,需要配置连接环境,配置方法如下:

  1. 修改配置文件 odbc.ini,路径为 /etc/odbc.ini,配置文件 odbc.ini也可以放在除了/etc以外的其他目录,通过设置环境变量到相应的目录即可。

    [ODBC Data Sources]
    data_source_name = Name
    [Name]
    Driver=Oceanbase
    Description = MyODBC 5 Driver DSN
    SERVER      = [OBProxy IP地址]
    PORT        = [OBProxy 端口]
    USER        = [用户名@租户名#集群名称]
    Password    = [用户密码]
    Database    = [数据库名]
    OPTION      = 3
    charset=UTF8
    
  2. 配置 /etc/odbcinst.ini

    [Oceanbase]
    Driver=/u01/mysql-odbc/lib/libmyodbc5a.so
    
  3. 设置环境变量。

    export ODBCSYSINI=/etc
    export ODBCINI=/etc/odbc.ini
    export LD_LIBRARY_PATH=/u01/mysql/lib:/usr/lib64:$LD_LIBRARY_PATH
    export PATH=$PATH:/u01/unix-odbc/bin
    
  4. 配置完成后使用 odbcinst -j 命令查看配置是否正确。

    返回结果如下所示:

    unixODBC 2.3.7
    DRIVERS............: /etc/odbcinst.ini
    SYSTEM DATA SOURCES: /etc/odbc.ini
    FILE DATA SOURCES..: /etc/ODBCDataSources
    USER DATA SOURCES..: /etc/odbc.ini
    SQLULEN Size.......: 8
    SQLLEN Size........: 8
    SQLSETPOSIROW Size.: 8
    

使用示例

  1. 以 OceanBase 数据库的 mysql 租户为测试环境,运行下述语句在数据库中创建一张示例表 TEST。

    CREATE TABLE "TEST" (
      "ID" NUMBER(38) NOT NULL,
      "NAME" VARCHAR2(32),
      CONSTRAINT "TEST_PK" PRIMARY KEY ("ID")
    ) COMPRESS FOR ARCHIVE REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 10
    
  2. 编写连接数据库的驱动程序。

    驱动程序的代码示例如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "sql.h"
    #include "sqlext.h"
    
    typedef struct tagODBCHandler {
        SQLHENV henv;
        SQLHDBC hdbc;
        SQLHSTMT hstmt;
    }ODBCHandler;
    
    int IS_SUCC(SQLRETURN retcode) {
        if  (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) return 1;
        return 0;
    }
    void checkError(SQLRETURN retcode, const char* msg, ODBCHandler* handler) {
        SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1];
        SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1];
        SQLINTEGER error;
        SQLSMALLINT len;
        SQLRETURN tmpcode;
    
        switch (retcode){
        case SQL_SUCCESS:
            printf("%s retcode is SQLRETURN\n", msg);
            break;
        case SQL_SUCCESS_WITH_INFO:
            printf("%s retcode is SQL_SUCCESS_WITH_INFO\n", msg);
            break;
        case SQL_ERROR:
            printf("%s retcode is SQL_ERROR\n", msg);
            tmpcode = SQLError(handler->henv, handler->hdbc, handler->hstmt, sqlstate, &error, message, sizeof(message), &len);
            if (tmpcode != SQL_SUCCESS && tmpcode != SQL_SUCCESS_WITH_INFO) {
                printf("get sqlerror failed %d", tmpcode);
            } else {
                printf("error is %d, meeesage is %s, sqlstate is %s, len is %d\n", error, message, sqlstate, len);
            }
            break;
        case SQL_INVALID_HANDLE:
            printf("%s retcode is SQL_INVALID_HANDLE\n", msg);
            break;
        case SQL_STILL_EXECUTING:
            printf("%s retcode is SQL_STILL_EXECUTING\n", msg);
            break;
        case SQL_NO_DATA:
            printf("%s retcode is SQL_NO_DATA\n", msg);
            break;
        default:
            printf("%s retcode is UNKNOWN retcode\n", msg);
            break;
        }
    }
    int main(int argc, char** argv) {
        ODBCHandler handler;
        SQLRETURN retcode;
    #define MAX_NAME_LEN 255
        SQLCHAR   connOut[MAX_NAME_LEN+1];
        SQLSMALLINT len;
        //Allocate environment handle 
        retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handler.henv);
        // Set the ODBC version environment attribute  
        if (!IS_SUCC(retcode)) {
            checkError(retcode, "SQLAllocHandle", &handler);
            return -1;
        }
        retcode = SQLSetEnvAttr(handler.henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3_80, 0);
        // Allocate connection handle  
        if (!IS_SUCC(retcode)) {  
            checkError(retcode, "SQLSetEnvAttr", &handler);
            return -1;
        }
        retcode = SQLAllocHandle(SQL_HANDLE_DBC, handler.henv, &handler.hdbc);  
        if (!IS_SUCC(retcode)) {  
            checkError(retcode, "SQLAllocHandle", &handler);
            return -1;
        }
      // Set login timeout to 5 seconds  
      SQLSetConnectAttr(handler.hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
      // Connect to data source  
      retcode = SQLDriverConnect(handler.hdbc, NULL, (SQLCHAR*)"DSN=odbctest", SQL_NTS, connOut, MAX_NAME_LEN, &len,SQL_DRIVER_NOPROMPT);
      if (!IS_SUCC(retcode)) {  
            checkError(retcode, "SQLDriverConnect", &handler);
            return -1;
        }
      retcode = SQLAllocHandle(SQL_HANDLE_STMT, handler.hdbc, &handler.hstmt);
      if (!IS_SUCC(retcode)) {  
            checkError(retcode, "SQLAllocHandle", &handler);
            return -1;
        }
        {
            //insert 
            retcode = SQLPrepare(handler.hstmt, (SQLCHAR*)"INSERT INTO test VALUES(?,'robin')", SQL_NTS);
            if (!IS_SUCC(retcode)) {  
                checkError(retcode, "SQLPrepare", &handler);
                return -1;
            }
            SQLINTEGER id = 2;
            retcode = SQLBindParameter(handler.hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &id, 0, NULL);
            if (!IS_SUCC(retcode)) {  
                checkError(retcode, "SQLBindParameter", &handler);
                return -1;
            }
            retcode = SQLExecute(handler.hstmt);
            if (!IS_SUCC(retcode)) {  
                checkError(retcode, "SQLExecute", &handler);
                return -1;
            }
        }
        // clean handle
        SQLFreeHandle(SQL_HANDLE_STMT, handler.hstmt);
        SQLDisconnect(handler.hdbc);
        SQLFreeHandle(SQL_HANDLE_DBC, handler.hdbc);
        SQLFreeHandle(SQL_HANDLE_ENV, handler.henv);
        return 0;
    }
    
  3. 编译并执行驱动程序。

    GCC 编译时,使用 -I选项指定头文件, -L指定库文件目录, -l指定库名。

    示例语句如下所示:

    gcc test.c -L/u01/unix-odbc/lib -lodbc -I/u01/unix-odbc/include -otest
    ./test
    

    检查结果:

    obclient -hobproxy.oceanbase.abc.com -uhr@test0_5#obtest -p'hr' -P2883
    obclient> select * from test;
    +----+-------+
    | ID | NAME  |
    +----+-------+
    |  1 | jason |
    |  2 | robin |
    +----+-------+
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论