odbc.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 911 行 · 第 1/3 页

ERL
911
字号
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%-module(odbc).-behaviour(gen_server).-include("odbc_internal.hrl").%% API ---------------------------------------------------------------------export([connect/2, disconnect/1, commit/2, commit/3, sql_query/2,	 sql_query/3, select_count/2, select_count/3, first/1, first/2,	 last/1, last/2, next/1, next/2, prev/1, prev/2, select/3,	 select/4, param_query/3, param_query/4, describe_table/2,	 describe_table/3]).%%-------------------------------------------------------------------------%% supervisor callbacks-export([start_link_sup/1]).%% gen_server callbacks-export([init/1, handle_call/3, handle_cast/2, handle_info/2, 	 terminate/2, code_change/3]).%%--------------------------------------------------------------------------%% Internal state-record(state, {erlang_port,                 % The port to the c-program		reply_to,		     % gen_server From parameter 		owner,                       % Pid of the connection owner		result_set = undefined,      % exists | undefined		auto_commit_mode = on,       % on | off		%% Indicates if first, last and "select absolut"		%% is supported by the odbc driver.		absolute_pos,                % true | false  		%% Indicates if prev and "select relative"		%% is supported by the odbc driver.		relative_pos,                % true | false		scrollable_cursors,      % on | off		%% connecting | connected | disconnecting		state = connecting,	    		%% For timeout handling		pending_request,      		num_timeouts = 0,		listen_sockets,		sup_socket,		odbc_socket	       }).%%--------------------------------------------------------------------------%%%=========================================================================%%%  API%%%=========================================================================%%-------------------------------------------------------------------------%% connect(ConnectionStr, Options) -> {ok, ConnectionReferense} |%%                                    {error, Reason}%% Description: Spawns an erlang control process that will open a port%%              to a c-process that uses the ODBC API to open a connection%%              to the database. %%-------------------------------------------------------------------------connect(ConnectionStr, Options) when list(ConnectionStr), list(Options) ->        %% Start of the odbc application should really be handled by the     %% application using odbc.     case application:start(odbc) of	{error,{already_started,odbc}} ->	    ok;	ok ->	    error_logger:info_report("The odbc application was not started."				     " Has now been started as a temporary" 				     " application.")    end,        %% Spawn the erlang control process.    case supervisor:start_child(odbc_sup, [[{client, self()}]]) of	{ok, Pid} ->	    connect(Pid, ConnectionStr, Options);	{error, Reason} ->	    {error, Reason}    end.%%--------------------------------------------------------------------------%% disconnect(ConnectionReferense) -> ok | {error, Reason}%%                                    %% Description: Disconnects from the database and terminates both the erlang%%              control process and the database handling c-process. %%--------------------------------------------------------------------------disconnect(ConnectionReference) when pid(ConnectionReference)->    ODBCCmd = [?CLOSE_CONNECTION],    case call(ConnectionReference, {disconnect, ODBCCmd}, 5000) of 	{error, connection_closed} ->	    %% If the connection has already been closed the effect of	    %% disconnect has already been acomplished	    ok; 	%% Note a time out of this call will return ok, as disconnect	%% will always succeed, the time out is to make sure	%% the connection is killed brutaly if it will not be shut down	%% gracefully.	ok ->	    ok;	%% However you may receive an error message as result if you try to	%% disconnect a connection started by another process.	Other ->	    Other    end. 	    %%--------------------------------------------------------------------------%% commit(ConnectionReference, CommitMode, <TimeOut>) -> ok | {error,Reason}%%                                    %% Description: Commits or rollbacks a transaction. Needed on connections%%              where automatic commit is turned off.  %%--------------------------------------------------------------------------commit(ConnectionReference, CommitMode) ->    commit(ConnectionReference, CommitMode, ?DEFAULT_TIMEOUT).commit(ConnectionReference, commit, infinity)   when pid(ConnectionReference) ->    ODBCCmd = [?COMMIT_TRANSACTION, ?COMMIT],    call(ConnectionReference, {commit, ODBCCmd}, infinity);commit(ConnectionReference, commit, TimeOut)   when pid(ConnectionReference), integer(TimeOut), TimeOut > 0  ->    ODBCCmd = [?COMMIT_TRANSACTION, ?COMMIT],    call(ConnectionReference, {commit, ODBCCmd}, TimeOut);commit(ConnectionReference, rollback, infinity)   when pid(ConnectionReference) ->    ODBCCmd = [?COMMIT_TRANSACTION, ?ROLLBACK],    call(ConnectionReference, {commit, ODBCCmd}, infinity);commit(ConnectionReference, rollback, TimeOut)   when pid(ConnectionReference), integer(TimeOut), TimeOut > 0  ->    ODBCCmd = [?COMMIT_TRANSACTION, ?ROLLBACK],    call(ConnectionReference, {commit, ODBCCmd}, TimeOut).%%--------------------------------------------------------------------------%% sql_query(ConnectionReference, SQLQuery, <TimeOut>) -> {updated, NRows} |%%			       {selected, ColNames, Rows} | {error, Reason} %%                                    %% Description: Executes a SQL query. If it is a SELECT query the%%              result set is returned, otherwise the number of affected %%       	rows are returned.%%--------------------------------------------------------------------------sql_query(ConnectionReference, SQLQuery) ->    sql_query(ConnectionReference, SQLQuery, ?DEFAULT_TIMEOUT).sql_query(ConnectionReference, SQLQuery, infinity) when   pid(ConnectionReference), list(SQLQuery) ->     ODBCCmd = [?QUERY, SQLQuery],    call(ConnectionReference, {sql_query, ODBCCmd}, infinity);sql_query(ConnectionReference, SQLQuery, TimeOut)   when pid(ConnectionReference),list(SQLQuery),integer(TimeOut),TimeOut>0 ->     ODBCCmd = [?QUERY, SQLQuery],    call(ConnectionReference, {sql_query, ODBCCmd}, TimeOut).%%--------------------------------------------------------------------------%% select_count(ConnectionReference, SQLQuery, <TimeOut>) -> {ok, NrRows} |%%							    {error, Reason} %%                                    %% Description: Executes a SQL SELECT query and associates the result set%%              with the connection. A cursor is positioned before%%        	the first row in the result set and the number of%%	        rows in the result set is returned.%%--------------------------------------------------------------------------select_count(ConnectionReference, SQLQuery) ->	    select_count(ConnectionReference, SQLQuery, ?DEFAULT_TIMEOUT).select_count(ConnectionReference, SQLQuery, infinity) when   pid(ConnectionReference), list(SQLQuery) ->    ODBCCmd = [?SELECT_COUNT, SQLQuery],    call(ConnectionReference, {select_count, ODBCCmd}, infinity);select_count(ConnectionReference, SQLQuery, TimeOut) when   pid(ConnectionReference), list(SQLQuery), integer(TimeOut), TimeOut > 0 ->    ODBCCmd = [?SELECT_COUNT, SQLQuery],    call(ConnectionReference, {select_count, ODBCCmd}, TimeOut).%%--------------------------------------------------------------------------%% first(ConnectionReference, <TimeOut>) ->  {selected, ColNames, Rows} | %%					     {error, Reason} %%                                    %% Description: Selects the first row in the current result set. The cursor%%            : is positioned at this row. %%--------------------------------------------------------------------------first(ConnectionReference) ->	    first(ConnectionReference, ?DEFAULT_TIMEOUT).	first(ConnectionReference, infinity) when pid(ConnectionReference) ->	    ODBCCmd = [?SELECT, ?SELECT_FIRST],    call(ConnectionReference, {select_cmd, absolute, ODBCCmd}, infinity);first(ConnectionReference, TimeOut)  when pid(ConnectionReference), integer(TimeOut), TimeOut > 0 ->	    ODBCCmd = [?SELECT, ?SELECT_FIRST],    call(ConnectionReference, {select_cmd, absolute, ODBCCmd}, TimeOut).%%--------------------------------------------------------------------------%% last(ConnectionReference, <TimeOut>) -> {selected, ColNames, Rows} | %%					   {error, Reason} %%                                    %% Description: Selects the last row in the current result set. The cursor%%            : is positioned at this row. %%--------------------------------------------------------------------------last(ConnectionReference) ->	    last(ConnectionReference, ?DEFAULT_TIMEOUT).	last(ConnectionReference, infinity) when pid(ConnectionReference) ->	    ODBCCmd = [?SELECT, ?SELECT_LAST],    call(ConnectionReference, {select_cmd, absolute, ODBCCmd}, infinity);last(ConnectionReference, TimeOut)   when pid(ConnectionReference), integer(TimeOut), TimeOut > 0 ->	    ODBCCmd = [?SELECT, ?SELECT_LAST],    call(ConnectionReference, {select_cmd, absolute, ODBCCmd}, TimeOut).%%--------------------------------------------------------------------------%% next(ConnectionReference, <TimeOut>) -> {selected, ColNames, Rows} | %%					   {error, Reason}  %%                                    %% Description: Selects the next row relative the current cursor position %%            : in the current result set. The cursor is positioned at %%            : this row. %%--------------------------------------------------------------------------next(ConnectionReference) ->	    next(ConnectionReference, ?DEFAULT_TIMEOUT).	    next(ConnectionReference, infinity) when pid(ConnectionReference) ->	    ODBCCmd = [?SELECT, ?SELECT_NEXT],    call(ConnectionReference, {select_cmd, next, ODBCCmd}, infinity);next(ConnectionReference, TimeOut)   when pid(ConnectionReference), integer(TimeOut), TimeOut > 0 ->	    ODBCCmd = [?SELECT, ?SELECT_NEXT],    call(ConnectionReference, {select_cmd, next, ODBCCmd}, TimeOut).%%--------------------------------------------------------------------------%% prev(ConnectionReference, <TimeOut>) -> {selected, ColNames, Rows} | %%					   {error, Reason}   %%                                    %% Description: Selects the previous row relative the current cursor %%            : position in the current result set. The cursor is%%            : positioned at this row. %%--------------------------------------------------------------------------prev(ConnectionReference) ->	    prev(ConnectionReference, ?DEFAULT_TIMEOUT).	prev(ConnectionReference, infinity) when pid(ConnectionReference) ->	    ODBCCmd = [?SELECT, ?SELECT_PREV],    call(ConnectionReference, {select_cmd, relative, ODBCCmd}, infinity);prev(ConnectionReference, TimeOut)   when pid(ConnectionReference), integer(TimeOut), TimeOut > 0 ->	    ODBCCmd = [?SELECT, ?SELECT_PREV],    call(ConnectionReference, {select_cmd, relative, ODBCCmd}, TimeOut).%%--------------------------------------------------------------------------%% select(ConnectionReference, <Timeout>) -> {selected, ColNames, Rows} | %%					     {error, Reason}   %%                                   %% Description: Selects <N> rows. If <Position> is next it is%%              semanticly eqvivivalent of calling next/[1,2] <N>%%              times. If <Position> is {relative, Pos} <Pos> will be%%              used as an offset from the current cursor position to%%              determine the first selected row. If <Position> is%%              {absolute, Pos}, <Pos> will be the number of the first%%              row selected. After this function has returned the%%              cursor is positioned at the last selected row.%%--------------------------------------------------------------------------select(ConnectionReference, Position, N) ->    select(ConnectionReference, Position, N, ?DEFAULT_TIMEOUT).select(ConnectionReference, next, N, infinity)   when pid(ConnectionReference), integer(N), N > 0 ->    ODBCCmd = [?SELECT, ?SELECT_N_NEXT,	       integer_to_list(?DUMMY_OFFSET), ";", 	       integer_to_list(N), ";"],    call(ConnectionReference, {select_cmd, next, ODBCCmd},	 infinity);select(ConnectionReference, next, N, TimeOut)   when pid(ConnectionReference), integer(N), N > 0,  integer(TimeOut), TimeOut > 0 ->    ODBCCmd = [?SELECT, ?SELECT_N_NEXT,	       integer_to_list(?DUMMY_OFFSET), ";", 	       integer_to_list(N), ";"],    call(ConnectionReference, {select_cmd, next, ODBCCmd},	 TimeOut);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?