创建自定义 ODBC 驱动程序

2024-04-08

在我目前的工作中,我们希望实现自己的 odbc 驱动程序,以允许许多不同的应用程序能够作为数据源连接到我们自己的应用程序。现在我们正在尝试权衡根据实施规范开发我们自己的驱动程序的选项,这是巨大的,or使用允许程序员“填充”数据特定部分并允许更高级别的抽象的 SDK。

还有其他人实现了自定义 odbc 驱动程序吗?你遇到过哪些陷阱?您从自己做的事情中看到了什么好处?您估计需要多少工时?您是否使用过 SDK?如果使用过,您从该方法中看到了哪些优点/缺点?

任何意见和答案将不胜感激。谢谢!

EDIT:我们正在努力保持我们用 C 编写的代码的可移植性。


另一种选择:不创建 ODBC 驱动程序,而是实现一个与另一个数据库(例如 Postgresql 或 MySQL)使用的有线协议进行通信的后端。

然后,您的用户可以下载并使用 Postgresql ODBC 驱动程序等。

您选择模拟哪个后端数据库可能最取决于有线协议格式的记录情况。

Both Postgres https://www.postgresql.org/docs/current/protocol.html and MySQL http://dev.mysql.com/doc/internals/en/client-server-protocol.html他们的客户端-服务器协议有不错的文档。

下面是一个简单的 Python 2.7 服务器后端示例,它理解部分 Postgresql 有线协议。示例脚本创建一个侦听端口 9876 的服务器。我可以使用以下命令psql -h localhost -p 9876连接到服务器。执行的任何查询都将返回一个结果集,其中包含 abc 和 def 列以及两行,所有值均为 NULL。

阅读 Postgresql 文档并使用wireshark之​​类的东西来检查真实的协议流量将使实现与Postgresql兼容的后端变得非常简单。

import SocketServer
import struct

def char_to_hex(char):
    retval = hex(ord(char))
    if len(retval) == 4:
        return retval[-2:]
    else:
        assert len(retval) == 3
        return "0" + retval[-1]

def str_to_hex(inputstr):
    return " ".join(char_to_hex(char) for char in inputstr)

class Handler(SocketServer.BaseRequestHandler):
    def handle(self):
        print "handle()"
        self.read_SSLRequest()
        self.send_to_socket("N")

        self.read_StartupMessage()
        self.send_AuthenticationClearText()
        self.read_PasswordMessage()
        self.send_AuthenticationOK()
        self.send_ReadyForQuery()
        self.read_Query()
        self.send_queryresult()

    def send_queryresult(self):
        fieldnames = ['abc', 'def']
        HEADERFORMAT = "!cih"
        fields = ''.join(self.fieldname_msg(name) for name in fieldnames)
        rdheader = struct.pack(HEADERFORMAT, 'T', struct.calcsize(HEADERFORMAT) - 1 + len(fields), len(fieldnames))
        self.send_to_socket(rdheader + fields)

        rows = [[1, 2], [3, 4]]
        DRHEADER = "!cih"
        for row in rows:
            dr_data = struct.pack("!ii", -1, -1)
            dr_header = struct.pack(DRHEADER, 'D', struct.calcsize(DRHEADER) - 1 + len(dr_data), 2)
            self.send_to_socket(dr_header + dr_data)

        self.send_CommandComplete()
        self.send_ReadyForQuery()

    def send_CommandComplete(self):
        HFMT = "!ci"
        msg = "SELECT 2\x00"
        self.send_to_socket(struct.pack(HFMT, "C", struct.calcsize(HFMT) - 1 + len(msg)) + msg)

    def fieldname_msg(self, name):
        tableid = 0
        columnid = 0
        datatypeid = 23
        datatypesize = 4
        typemodifier = -1
        format_code = 0 # 0=text 1=binary
        return name + "\x00" + struct.pack("!ihihih", tableid, columnid, datatypeid, datatypesize, typemodifier, format_code)

    def read_socket(self):
        print "Trying recv..."
        data = self.request.recv(1024)
        print "Received {} bytes: {}".format(len(data), repr(data))
        print "Hex: {}".format(str_to_hex(data))
        return data

    def send_to_socket(self, data):
        print "Sending {} bytes: {}".format(len(data), repr(data))
        print "Hex: {}".format(str_to_hex(data))
        return self.request.sendall(data)

    def read_Query(self):
        data = self.read_socket()
        msgident, msglen = struct.unpack("!ci", data[0:5])
        assert msgident == "Q"
        print data[5:]


    def send_ReadyForQuery(self):
        self.send_to_socket(struct.pack("!cic", 'Z', 5, 'I'))

    def read_PasswordMessage(self):
        data = self.read_socket()
        b, msglen = struct.unpack("!ci", data[0:5])
        assert b == "p"
        print "Password: {}".format(data[5:])


    def read_SSLRequest(self):
        data = self.read_socket()
        msglen, sslcode = struct.unpack("!ii", data)
        assert msglen == 8
        assert sslcode == 80877103

    def read_StartupMessage(self):
        data = self.read_socket()
        msglen, protoversion = struct.unpack("!ii", data[0:8])
        print "msglen: {}, protoversion: {}".format(msglen, protoversion)
        assert msglen == len(data)
        parameters_string = data[8:]
        print parameters_string.split('\x00')

    def send_AuthenticationOK(self):
        self.send_to_socket(struct.pack("!cii", 'R', 8, 0))

    def send_AuthenticationClearText(self):
        self.send_to_socket(struct.pack("!cii", 'R', 8, 3))

if __name__ == "__main__":
    server = SocketServer.TCPServer(("localhost", 9876), Handler)
    try:
        server.serve_forever()
    except:
        server.shutdown()

命令行 psql 会话示例:

[~]
$ psql -h localhost -p 9876
Password:
psql (9.1.6, server 0.0.0)
WARNING: psql version 9.1, server version 0.0.
         Some psql features might not work.
Type "help" for help.

codeape=> Select;
 abc | def
-----+-----
     |
     |
(2 rows)

codeape=>

使用 Postgresql 协议的 ODBC 驱动程序也应该可以工作(但我还没有尝试过)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建自定义 ODBC 驱动程序 的相关文章

  • 在 SQL Server 中选择条件的值[重复]

    这个问题在这里已经有答案了 在查询选择中 我想显示字段是否满足条件的结果 想象一下我有一张名为stock 该表有一列告诉我库存中每种商品的数量 我想做的是这样的 SELECT stock name IF stock quantity lt
  • 是否可以从数据库转储生成 knex 种子文件?

    就我而言 我使用的是 mysql 但是 我正在寻找一种通用解决方案 用于从当前运行的数据库或数据库转储生成 knex 种子文件 我可以就像是 https github com tgriesser knex issues 944 issuec
  • 在 Oracle 中创建数据库链接时出错

    我有两个数据库 需要编写跨数据库查询 所以我试图创建一个数据库链接 CREATE PUBLIC DATABASE LINK DBLink CONNECT TO SchemaName IDENTIFIED BY 123 using DBNam
  • 在tomcat中显示Spring-security的SQL错误

    我使用 spring security 框架创建了一个 Web 应用程序 我设置了一个数据库来存储用户及其角色 但 tomcat 给出以下错误 17 sep 2010 11 56 14 org springframework beans f
  • 导致聚集索引扫描的日期参数

    我有以下查询 DECLARE StartDate DATE 2017 09 22 DECLARE EndDate DATE 2017 09 23 SELECT a col1 a col2 b col1 b col2 b col3 a col
  • MySQL:用户对数据库的访问被拒绝

    我正在尝试在 Heroku 上的远程 SQL 服务器上创建一个数据库 clearDB 我与此联系 mysql host lt
  • Firebird数据库模式/数据差异工具

    RedGate http www red gate com为 Microsoft SQL Server 制作一个工具 允许您捕获两个数据库之间的差异 它生成更新数据库模式所需的脚本 同时保留数据 我需要为 Firebird 数据库找到这样的
  • PIVOT 运算符中指定的列名“FirstName”与 PIVOT 参数中的现有列名冲突

    当我尝试替换时收到以下错误消息null to zero PIVOT 运算符中指定的列名 jan 与 PIVOT 参数中的现有列名称 查询如下 select from select isnull jan 0 isnull feb 0 sum
  • 销毁/删除 Rails 中的数据库

    是否可以从现有应用程序中完全删除数据库和所有迁移记录等 以便我可以从头开始重新设计数据库 通过发行rake T您有以下数据库任务 rake db create Create the database from DATABASE URL or
  • 在 C# 中多次使用单个参数的更好方法

    我刚开始使用准备好的语句从数据库查询数据 并且在实现 C 参数 特别是 OracleParameters 时遇到问题 假设我有以下 SQL string sql select from table1 t1 table2 t2 where t
  • 动态SQL生成列名?

    我有一个查询 我正在尝试将行值转换为列名称 目前我正在使用SUM Case As ColumnName 声明 像这样 SELECT SKU1 SUM Case When Sku2 157 Then Quantity Else 0 End A
  • 从Oracle表中删除重复行

    我正在 Oracle 中测试某些内容并使用一些示例数据填充表 但在此过程中我不小心加载了重复记录 因此现在我无法使用某些列创建主键 如何删除所有重复行并只保留其中一行 Use the rowid伪列 DELETE FROM your tab
  • 如何重命名 SQL Server 中名称中带有方括号的内容?

    我的一张桌子上有一列 周围有方括号 Book Category 我想重命名为Book Category 我尝试了以下查询 sp rename BookPublisher Book Category Book Category COLUMN
  • 数据库不存在。确保名称输入正确

    为什么我会出现这个错误 如果您查看屏幕截图 您将看到数据库 仅当我连接到两个数据库引擎时才会发生这种情况 它仅检测下面数据库引擎中的数据库 而不检测突出显示的数据库 除了关闭应用程序并仅打开一个数据库引擎之外 还有其他方法可以使用我的数据库
  • 使用子查询与 LEFT JOIN 一起选择 MAX 值

    我有一个获取搜索结果的查询 效果很好 查询成功示例 SELECT individuals individual id individuals unique id TIMESTAMPDIFF YEAR individuals day of b
  • PHP 中的 SQL 语句与 phpmyadmin 中的 SQL 语句的行为不同

    I have form store sql INSERT INTO myodyssey myaccount id email username password VALUES NULL email unixmiah formtest woo
  • 如何查询多对多表(一个表的值成为列标题)

    给定此表结构 我想展平多对多关系 并将一个表的名称字段中的值设置为列标题 并将同一表中的数量设置为列值 目前可行的想法是将值放入字典 哈希表 中并用代码表示这些数据 但我想知道是否有 SQL 方法可以做到这一点 我还使用 Linq to S
  • 如何将 LEFT JOIN 限制为 SQL Server 中的第一个结果?

    我有一些 SQL 几乎可以做我想做的事情 我正在使用三个表 Users UserPhoneNumbers 和 UserPhoneNumberTypes 我正在尝试获取用户列表及其电话号码以供导出 数据库本身很旧并且存在一些完整性问题 我的问
  • 列的 SQL MAX(包括其主键)

    Short 从下面的 sql select 中 我获取了 cart id 和该购物车中最高价值商品的值 SELECT CartItems cart id MAX ItemValues value FROM CartItems INNER J
  • 当我耗尽 bigint 生成的密钥时会发生什么?怎么处理呢?

    我自己无法想象一个好的答案 所以我想在这里问 在我心里 我总是想知道 如果AUTO INCREMENT PRIMARY ID我的专栏MySQL表用完了吗 举例来说 我有一个有两列的表 一个ID auto increment primary

随机推荐

  • 如何在 SQL 中过滤掉包含空数据或空数据的特定列的行?

    在 SQL 中 我们如何进行检查以过滤包含列数据为 null 或空的所有行 例如 Select Name Age from MEMBERS 我们需要检查 Name 不应等于 null 或空 这将适用于所有理智的数据库 眨眼眨眼 并将返回名称
  • 在无父 LinearLayout 上设置 LayoutParams

    我以编程方式创建 LinearLayout 然后我想通过自定义编写的适配器将其附加到 GridView 我想为新创建的 LinearLayout 设置宽度和高度 当我尝试这样做时 出现以下异常 03 18 15 50 54 648 E An
  • 使用 JSON 将用户定义的对象从 jQuery 传递到 ASP.NET Webmethod

    我正在尝试将一些简单的 JSON 从 jQuery 传递到 ASP NET 4 5 Webmethod 它并没有按照我想要的方式工作 如果我接受输入作为单独的参数 它就会起作用 WebMethod public static Address
  • 为 Matlab 编译 MEX 文件时如何忽略 `mexopts.sh`?

    The f命令行参数mex允许指定的位置mexopts sh我们希望使用的 但是有没有办法告诉Matlab忽略mexopts sh 为了编译特定的 MEX 文件 我需要指定CC CFLAGS等 调用时直接在命令行mex 已给出的值mexop
  • 在 Eclipse 中调试(Java);中断查看值时无法将鼠标悬停在变量上

    我正在使用 Eclipse 编写 Java 代码 适用于 Android 并尝试像平常一样调试代码 不过我通常使用 C 据我所知 在 Eclipse 中调试非常糟糕 我不知道我是否做错了什么 但这似乎很糟糕 这是正在运行的代码 我收到某种异
  • SQL 更新 WHERE xx AND 最近记录

    我需要做一些看似非常简单的事情 bdd gt query UPDATE mytable SET aaa aaa bbb bbb WHERE name name 我的问题 我有多个记录与此 WHERE 匹配 并且我只想更新最新的记录 我有一个
  • 仅捕获 UIView 2 手指 UIPanGestureRecognizer

    我有几个UIScrollViews 在我的视图控制器中 我想覆盖一个捕获 2 根手指滑动的视图UIPanGestureRecognizer这不会记录UIScrollView滑动手势 当我使用 2 根手指平移手势在内容上放置透明视图时 不会检
  • 该脚本的安全性(强化程度)如何?

    下面的脚本 test php 旨在放置在我所有 WordPress 站点的特定目录中 它的目的是抓取下面 source地址处的文件并将其解压到它所在的目录中 这就是它的全部目的 例如 我的中央服务器上将有一个仪表板界面 其中列出了存在此脚本
  • 用于静态管理的包装组件

    我想创建一个新组件 其中包含Inputs and Fields from aor并用在
  • 如何使用urllib3下载文件?

    这是基于该网站上的另一个问题 使用 urllib3 下载文件的最佳方式是什么 https stackoverflow com questions 17285464 whats the best way to download file us
  • Python仅枚举反向索引

    我正在尝试反转给出的索引enumerate同时保留被枚举列表的原始顺序 假设我有以下内容 gt gt range 5 0 1 2 3 4 如果我列举这一点 我会得到以下结果 gt gt list enumerate range 5 0 0
  • 如何可靠地检查工作站上当前用户的 Windows 域 ID

    我正在使用 C 和 Net Framework 4 我正在寻找一种万无一失的方法来获取当前登录的 Windows 用户的登录 ID 该方法不易被假冒或黑客攻击 我正在以以下形式查找此内容 域名 用户名 例如某个域 JohnDoe 目前我拥有
  • 限制 Django 的 inlineformset_factory 只创建新对象

    我正在使用 django 的内联表单集工厂 要使用文档中的示例 author Author objects get pk 1 BookFormSet inlineformset factory Author Book formset Boo
  • 如何使用一个 R 包中被另一包屏蔽的函数? [复制]

    这个问题在这里已经有答案了 我想用recode来自car包裹 但如果我有Hmisc加载后 它掩盖了car版本 可能有一种方法可以调用屏蔽函数 也许还有一种方法可以强制一个包成为主导包 你可能会遇到更深层次的问题 但在顶层car recode
  • 在 Angular / Typescript 中对包含整数和字母字母的数组进行排序

    我打算做什么 我尝试像这样对数组进行排序 1 2 2 a 2 b 2 b AsimpleName 2 b NameWithN 3 4 4 a 在 Angular2 中 我当前的代码 成分 this streetDetailRef this
  • 在 Yosemite 上编译 caffe

    我正在尝试在 Yosemite 上安装 caffe 但我的 C 不是最强的 这是我的错误 Alis MacBook Pro caffe ali make all NVCC src caffe layers absval layer cu u
  • Carbon Emacs 不粘贴 Microsoft Word 复制的内容

    不确定 Stackoverflow 是否是正确的站点 我在 mac ox 10 6 7 上使用 Carbon emacs 22 0 971 和 MS Word 12 2 8 我在 MS Word 中有一些文本 我想将其复制并粘贴到 emac
  • python将文件发送到作为服务运行的tika

    参考这个问题 https stackoverflow com questions 16251436 unable to run java command from cgi我想将 MS Word doc 文件发送到作为服务运行的 tika 应
  • 将子目录分离(移动)到单独的 Git 存储库中

    我有一个Git http en wikipedia org wiki Git 28software 29存储库 其中包含许多子目录 现在我发现其中一个子目录与另一个子目录无关 应该分离到一个单独的存储库 如何在保留子目录中文件的历史记录的同
  • 创建自定义 ODBC 驱动程序

    在我目前的工作中 我们希望实现自己的 odbc 驱动程序 以允许许多不同的应用程序能够作为数据源连接到我们自己的应用程序 现在我们正在尝试权衡根据实施规范开发我们自己的驱动程序的选项 这是巨大的 or使用允许程序员 填充 数据特定部分并允许