我现在的工作是希望实现我们自己的ODBC驱动程序,以允许许多不同的应用程序能够将我们的应用程序作为数据源连接。目前,我们正在权衡开发符合实现规范的自己的驱动程序,这需要大量的工作量,或者使用允许程序员“填写”特定数据部分并允许更高级别抽象的SDK。
有其他人实现过自定义ODBC驱动程序吗?你遇到了什么问题?从自行完成中你看到了哪些好处?你估计需要多少人时来完成它?如果使用了SDK,你看到了什么优缺点?
任何评论和答案都将不胜感激。谢谢!
编辑:我们希望保持代码的可移植性,它是用C编写的。
我现在的工作是希望实现我们自己的ODBC驱动程序,以允许许多不同的应用程序能够将我们的应用程序作为数据源连接。目前,我们正在权衡开发符合实现规范的自己的驱动程序,这需要大量的工作量,或者使用允许程序员“填写”特定数据部分并允许更高级别抽象的SDK。
有其他人实现过自定义ODBC驱动程序吗?你遇到了什么问题?从自行完成中你看到了哪些好处?你估计需要多少人时来完成它?如果使用了SDK,你看到了什么优缺点?
任何评论和答案都将不胜感激。谢谢!
编辑:我们希望保持代码的可移植性,它是用C编写的。
psql -h localhost -p 9876
连接到服务器。执行的任何查询都将返回一个具有列abc和def以及两行的结果集,所有值均为空。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驱动程序也应该可以使用(但我还没有尝试过)。
ODBC驱动程序非常复杂,编写一个驱动程序的决定不应该轻率地做出。查看现有的开源驱动程序是一个好方法,但大多数驱动程序都存在缺陷,您可能不想效仿:) 无论操作系统平台如何,API都是相同的。
如果您控制应用程序,可以在合理的时间内实现可能只是规范的非常小的子集。但在通用环境中使用则需要更多的努力来使其正确运行。除了简单地实现几十个包装器函数之外,还需要实现以下功能:
对于MSSQL/Sybase,FreeTDS具有我见过的最好的开源ODBC驱动程序实现之一。
这篇文章有点老,但值得一提的是,如果您需要使用ODBC驱动程序,可以使用像这样的SDK:http://www.simba.com/drivers/simba-engine-sdk/它解决了其他答案中提到的大部分问题,并为您提供了一个更简化的接口来实现。
我恰好在Simba工作,所以有点偏见,但使用SDK确实很容易为您正在尝试完成的任何任务创建ODBC驱动程序。如果您对编码有一定的熟练程度,可以在5天内开始使用。
其中一篇帖子推荐使用unixODBC或iODBC作为起点,但这不起作用。重要的是要意识到驱动程序管理器(unixODBC,iODBC等)和驱动程序之间的区别。驱动程序管理器充当应用程序和驱动程序之间的中间人,消除了直接链接到驱动程序的必要性。
您可以从Postgres或MySQL驱动程序开始,并将其分叉以使用自己的数据库,但这可能不是一项微不足道的任务。从头开始创建驱动程序甚至更加困难,可能会有比预期更高的维护成本。只要您知道这种方法的成本,它也可以是可行的。