Nic*_*uso 36 sql database sdk odbc odbc-bridge
在我目前的工作中,我们正在寻求实现我们自己的odbc驱动程序,以允许许多不同的应用程序能够连接到我们自己的应用程序作为数据源.现在我们正在尝试权衡开发我们自己的驱动程序到实现规范的选项,这是大规模的,或者使用SDK,允许程序员"填写"特定于数据的部分并允许更高级别的抽象.
有没有其他人实现自定义odbc驱动程序?你遇到了什么陷阱?你自己做了什么好处?花了多少工时呢?您是否使用过SDK?如果是这样,您从该方法中看到了哪些好处/缺点?
任何评论和答案将不胜感激.谢谢!
编辑:我们正在尝试使用我们的代码来维护可移植性,这是用C语言编写的.
cod*_*ape 19
另一种选择:不是创建ODBC驱动程序,而是实现一个后端,它与另一个数据库(例如Postgresql或MySQL)使用的有线协议进行对话.
然后,您的用户可以下载并使用Postgresql ODBC驱动程序.
确切地说,您选择模拟的后端数据库应该最大程度上取决于有线协议格式的记录情况.
双方的Postgres和MySQL的拥有自己的客户端-服务器协议体面的文件.
下面是一个了解Postgresql有线协议部分的服务器后端的简单Python 2.7示例.示例脚本创建一个侦听端口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()
Run Code Online (Sandbox Code Playgroud)
示例命令行psql session:
[~]
$ 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=>
Run Code Online (Sandbox Code Playgroud)
一个说Postgresql协议的ODBC驱动程序应该也可以正常工作(但我还没有尝试过).
ODBC驱动程序非常复杂 - 不应轻易决定编写一个.查看现有的开源驱动程序是一个很好的方法,但大多数都有您可能不想模拟的缺点:)无论OS平台如何,API都是相同的.FreeTDS for MSSQL/Sybase有一个我见过的更好的开源ODBC驱动程序实现.
如果您控制应用程序,您可以在合理的时间内实现可能只是规范的一小部分.要在通用环境中使用可能需要相当多的努力才能正确使用.除了简单地实现几十个包装器调用之外,您还必须实现:
我没有,但我曾经在一家公司采访过这样做过.他们制作了一个名为AMPS的4GL/DBMS产品,与MUMPS具有相同的架构 - 一个集成了4GL的分层数据库(这种系统的整个类型在20世纪70年代出现).他们拥有相当庞大的遗留代码库以及希望使用MS Access连接到它的客户.
采访我的主要开发者分享了一些关于此的战争故事.显然这是非常痛苦的,不应该掉以轻心.但是,他们确实成功地实现了它.
这样做的另一种方法是提供数据集市/ BI产品(沿着SAP BW),在外部数据库中显示您的应用程序数据,并将其按照更友好的格式(如星形或雪花模式)进行压缩.
这将不支持实时访问,但可能比ODBC驱动程序更容易实现(更重要的是维护).如果您的实时访问要求具有合理的可预测性和有限性,则可能需要公开Web服务API来支持这些要求.
| 归档时间: |
|
| 查看次数: |
25156 次 |
| 最近记录: |