【发布时间】:2021-03-12 14:05:46
【问题描述】:
我想在 Prolog 和 MongoDB 之间实现一个 API,经过一些研究,第一个障碍是连接到 MongoDB 服务器。我知道 API prolongo 已经有了,所以我试图理解它,但我没有。我是 Prolog 的新手,所以我的问题是:实际连接到 MongoDB 服务器的位置在哪里?
编辑: 我已经理解了更多的代码,但我遇到了一个我无法解释的错误:
这里是 mongo_connection.pl 的代码:
:- module(_, [
host/1,
port/1
]).
:- include(include/common).
%% host(?Host) is semidet.
%
% True if Host is the default hostname used by MongoDB.
host(localhost).
%% port(?Port) is semidet.
%
% True if Port is the default port used by MongoDB.
port(27017).
/** <module> Connection handling and response parsing.
*/
:- module(_, [
new_connection/1,
new_connection/3,
free_connection/1,
get_database/3,
send_to_server/2,
read_reply/4
]).
:- include(include/common).
%% new_connection(-Connection) is det.
%% new_connection(+Host, +Port, -Connection) is det.
%
% True if Connection represents an opaque handle to a new MongoDB
% server connection. Default values (see mongo_defaults) are used unless
% Host and Port are provided.
new_connection(Connection) :-
mongo_defaults:host(Host),
mongo_defaults:port(Port),
new_connection(Host, Port, Connection).
new_connection(Host, Port, Connection) :-
mongo_socket:new_socket(Host, Port, Socket),
Connection = connection(Socket).
connection_socket(Connection, Socket) :-
mongo_util:get_nth1_arg(Connection, 1, Socket).
%% free_connection(+Connection) is det.
%
% Frees any resources associated with the Connection handle,
% rendering it unusable.
free_connection(Connection) :-
connection_socket(Connection, Socket),
mongo_socket:free_socket(Socket).
%% get_database(+Connection, +DatabaseName, -Database) is det.
%
% True if Database is a handle to the database called DatabaseName
% on Connection. No communication is performed, so the actual database
% might or might not already exist.
get_database(Connection, DatabaseName, Database) :-
mongo_database:new_database(Connection, DatabaseName, Database).
%% send_to_server(+Connection, +Bytes) is det.
%
% True if Bytes are sent over Connection.
send_to_server(Connection, Bytes) :-
connection_socket(Connection, Socket),
mongo_socket:send_bytes(Socket, Bytes).
%% read_reply(+Connection, -Header, -Info, -Docs) is det.
%
% True if Header, Info and Docs together represent the next message
% received over Connection. Blocks until a message is completely read.
%
% Header is the structure header(MessageLength,RequestId,ResponseTo,OpCode)
% where:
% - MessageLength is the total number of bytes comprising the message
% - RequestId is the ID of this message (unused)
% - ResponseTo is the ID of the query that triggered this response (unused)
% - OpCode is the code signifying that this is a response (always 1)
%
% Info is the structure info(Flags,CursorId,StartingFrom,NumberReturned)
% where:
% - Flags is the bitmask of flags set for this response
% - CursorId is the cursor ID of this response
% - StartingFrom is the query offset of the first document in Docs
% - NumberReturned is the number of documents in Docs
read_reply(Connection, Header, Info, Docs) :-
connection_socket(Connection, Socket),
read_response_bytes(Socket, Bytes),
parse_response(Bytes, Header, Info, Docs).
read_response_bytes(Socket, [B0,B1,B2,B3|Bytes]) :-
read_message_length(Socket, [B0,B1,B2,B3], TotalLength),
read_rest_of_message(Socket, TotalLength, Bytes).
read_message_length(Socket, Bytes, Length) :-
mongo_socket:receive_n_bytes(Socket, 4, Bytes),
bson_bits:integer_bytes(Length, 4, little, Bytes).
read_rest_of_message(Socket, TotalLength, Bytes) :-
LengthRest is TotalLength - 4,
mongo_socket:receive_n_bytes(Socket, LengthRest, Bytes).
parse_response(Bytes, Header, Info, Docs) :-
% inspect_response_bytes(Bytes), % For debugging.
phrase(parse_response_meta(Header, Info), Bytes, RestBytes),
parse_response_docs(RestBytes, Docs).
parse_response_meta(Header, Info) -->
parse_response_header(Header),
parse_response_info(Info).
parse_response_header(Header) -->
{ Header = header(MessageLength,RequestId,ResponseTo,OpCode) },
mongo_bytes:int32(MessageLength),
mongo_bytes:int32(RequestId),
mongo_bytes:int32(ResponseTo),
mongo_bytes:int32(OpCode).
parse_response_info(Info) -->
{ Info = info(Flags,CursorId,StartingFrom,NumberReturned) },
mongo_bytes:int32(Flags),
mongo_bytes:int64(CursorId),
mongo_bytes:int32(StartingFrom),
mongo_bytes:int32(NumberReturned).
parse_response_docs(Bytes, Docs) :-
bson:docs_bytes(Docs, Bytes).
这里是mongo_socket.pl的代码:
:- module(_, [
new_socket/3,
free_socket/1,
send_bytes/2,
receive_n_bytes/3
]).
:- include(include/common).
%% new_socket(+Host, +Port, -Socket) is det.
%
% True if Socket is a new TCP socket connected to Host:Port.
%
% @throws mongo_error(Description, [SocketException])
new_socket(Host, Port, Socket) :-
setup_call_catcher_cleanup(
socket:tcp_socket(SocketId),
socket:tcp_connect(SocketId, Host:Port, ReadStream, WriteStream),
exception(SocketException),
close_socket_and_throw(SocketId, SocketException)),
Socket = socket(ReadStream,WriteStream).
close_socket_and_throw(SocketId, Exception) :-
socket:tcp_close_socket(SocketId),
throw(mongo_error('could not connect to server', [Exception])).
socket_read(Socket, ReadStream) :-
mongo_util:get_nth1_arg(Socket, 1, ReadStream).
socket_write(Socket, WriteStream) :-
mongo_util:get_nth1_arg(Socket, 2, WriteStream).
%% free_socket(+Socket) is det.
%
% Frees any resources associated with Socket, rendering it unusable.
free_socket(Socket) :-
socket_read(Socket, ReadStream),
socket_write(Socket, WriteStream),
core:close(ReadStream, [force(true)]),
core:close(WriteStream, [force(true)]).
%% send_bytes(+Socket, +Bytes) is det.
%
% True if Bytes are sent (and flushed) over Socket.
send_bytes(Socket, Bytes) :-
socket_write(Socket, WriteStream),
send_bytes_and_flush(Bytes, WriteStream).
send_bytes_and_flush(Bytes, WriteStream) :-
core:format(WriteStream, '~s', [Bytes]),
core:flush_output(WriteStream).
%% receive_n_bytes(+Socket, +N, -Bytes) is det.
%
% True if Bytes is the next N bytes received over Socket.
receive_n_bytes(Socket, N, Bytes) :-
socket_read(Socket, ReadStream),
receive_n_bytes_aux(ReadStream, N, Bytes).
receive_n_bytes_aux(_ReadStream, 0, []) :- !.
receive_n_bytes_aux(ReadStream, N, [Byte|Bytes]) :-
core:get_byte(ReadStream, Byte),
N1 is N - 1,
receive_n_bytes_aux(ReadStream, N1, Bytes).
线条也是如此
socket:tcp_socket(SocketId),
socket:tcp_connect(SocketId, Host:Port, ReadStream, WriteStream),..
Prolog 创建一个INET-domain stream-socket。我正在使用 MS-Windows,如果套接字库尚未初始化,这也会初始化该库。
但是我收到了这个错误:
所以这是我的问题:
- 我是否尝试使用错误的文件建立新连接?
- 应该自动加载 Socket 库还是必须将 prolongo 文件放入路径“C:\Program Files\swipl\library”?
- 如何解释上面的这个错误?
【问题讨论】:
-
这是专门为 SWI-Prolog 设计的吗?
-
如果您愿意在 SWI-Prolog 上尝试 ODBC,请参阅:SWI-Prolog connecting to PostgreSQL via ODBC 虽然部分是 PostgreSQL 特定的,但许多部分与 DB 无关。如果您可以完成这项工作,您可以将其用作满足您需求的垫脚石。
-
交叉张贴在SWI-Prolog forum。