File: ocamlodbc.ml

package info (click to toggle)
ocamlodbc 2.10-5
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 412 kB
  • ctags: 273
  • sloc: ansic: 865; ml: 784; makefile: 375; sh: 101
file content (234 lines) | stat: -rw-r--r-- 7,636 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
(*********************************************************************************)
(*                OCamlODBC                                                         *)
(*                                                                               *)
(*    Copyright (C) 2004 Institut National de Recherche en Informatique et       *)
(*    en Automatique. All rights reserved.                                       *)
(*                                                                               *)
(*    This program is free software; you can redistribute it and/or modify       *)
(*    it under the terms of the GNU Lesser General Public License as published   *)
(*    by the Free Software Foundation; either version 2.1 of the License, or     *)
(*    any later version.                                                         *)
(*                                                                               *)
(*    This program is distributed in the hope that it will be useful,            *)
(*    but WITHOUT ANY WARRANTY; without even the implied warranty of             *)
(*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *)
(*    GNU Lesser General Public License for more details.                        *)
(*                                                                               *)
(*    You should have received a copy of the GNU Lesser General Public License   *)
(*    along with this program; if not, write to the Free Software                *)
(*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA                   *)
(*    02111-1307  USA                                                            *)
(*                                                                               *)
(*    Contact: Maxence.Guesdon@inria.fr                                          *)
(*********************************************************************************)

(**  *)

(** The software name *)
let logiciel = "OCamlODBC"

(** The software version *)
let version = "2.10"

exception SQL_Error of string

type sql_column_type =
  | SQL_unknown
  | SQL_char
  | SQL_numeric
  | SQL_decimal
  | SQL_integer
  | SQL_smallint
  | SQL_float
  | SQL_real
  | SQL_double
  | SQL_varchar
  | SQL_date
  | SQL_time
  | SQL_timestamp
  | SQL_longvarchar
  | SQL_binary
  | SQL_varbinary
  | SQL_longvarbinary
  | SQL_bigint
  | SQL_tinyint
  | SQL_bit
;;

(** The module for the column type and its conversion into a string. *)
module SQL_column =
  struct
    type t = sql_column_type
    let string col_type =
      match col_type with
	SQL_unknown -> "SQL_unknown"
      | SQL_char -> "SQL_char"
      | SQL_numeric -> "SQL_numeric"
      |	SQL_decimal -> "SQL_decimal"
      | SQL_integer -> "SQL_integer"
      | SQL_smallint -> "SQL_smallint"
      | SQL_float -> "SQL_float"
      | SQL_real -> "SQL_real"
      | SQL_double -> "SQL_double"
      | SQL_varchar -> "SQL_varchar"
      | SQL_date -> "SQL_date"
      | SQL_time -> "SQL_time"
      | SQL_timestamp -> "SQL_timestamp"
      | SQL_longvarchar -> "SQL_longvarchar"
      | SQL_binary -> "SQL_binary"
      | SQL_varbinary -> "SQL_varbinary"
      | SQL_longvarbinary -> "SQL_longvarbinary"
      | SQL_bigint -> "SQL_bigint"
      | SQL_tinyint -> "SQL_tinyint"
      | SQL_bit -> "SQL_bit"
  end;;

module SQLInterface = Ocaml_odbc.Interface (SQL_column);;

module OCamlODBC_messages =
  struct
    let disconnect = "ODBC : problem while disconnecting"
    let connection nom_base nom_user pzPasswd iRC1 = "Error while connecting to database "^nom_base^" as "^nom_user^" with password <"^pzPasswd^"> : "^(string_of_int iRC1)
    let connection_driver connect_string iRC1 = "Error while connecting to database with connection string "^connect_string^"> : "^(string_of_int iRC1)
  end

type connection =
    {
      phEnv : Ocaml_odbc.sQLHENV ;
      phDbc : Ocaml_odbc.sQLHDBC ;
      base : string ;
      user : string ;
      passwd : string ;
    }

let connect base user passwd =
  let (iRC1,hEnv,pHDbc) = SQLInterface.initDB base user passwd in
  if (iRC1 = 0) then
    {
      phEnv = hEnv;
      phDbc = pHDbc;
      base = base ;
      user = user ;
      passwd = passwd ;
    }
  else
    raise (SQL_Error (OCamlODBC_messages.connection base user passwd iRC1))

let connect_driver ?(prompt=false) connect_string =
  let (iRC1,hEnv,pHDbc) = SQLInterface.initDB_driver connect_string prompt in
  if (iRC1 = 0) then 
    {
      phEnv = hEnv;
      phDbc = pHDbc;
      base = connect_string ;
      user = "" ;
      passwd = "" ;
    } 
  else
    raise (SQL_Error (OCamlODBC_messages.connection_driver connect_string iRC1))

let disconnect connection =
  let iRC = (SQLInterface.exitDB connection.phEnv connection.phDbc) in
  if (iRC > 0) then
    raise (SQL_Error OCamlODBC_messages.disconnect)
  else
    ()

(** Cette fonction prive excute une requte interrompue par des appels
   rguliers au GC. Elle retourne un triplet : code d'erreur (0 si ok),
   liste de couples (nom, type) pour dcrire les colonnes retournes,
   liste de liste de chaines reprsentant les enregistrements.
*)
let execute_gen connection ?(get_info=false) ?(n_rec=1) req callback =
  if req = "" then
    (-1, ([] : (string * sql_column_type) list))
  else
    (
     let phEnv = connection.phEnv in
     let phDbc = connection.phDbc in
     let (ret, env) = SQLInterface.execDB phEnv phDbc req in
     match ret with
       0 ->
	 let l_desc_col =
	   if get_info then
             (* rcuprer les informations sur les champs retourns
		(nom et type) par la dernire requte excute *)
	     SQLInterface.get_infoDB env phEnv phDbc
	   else
	     []
	 in
         (* rcuprer les records en plusieurs fois *)
	 (
	  let rec iter () =
	    let (n, ll_res) = SQLInterface.itereDB env n_rec in
	    (*Gc.minor();*)

	    let no_more = n < n_rec in
	    (
	      callback ll_res;
	      if   no_more
	      then ()
	      else iter ()
	    )
	  in
	  let _ = iter () in
	  let _ = SQLInterface.free_execDB env in
	  (ret, l_desc_col)
      	 )

     | 1 ->
	 (* pas de colonne, donc pas d'enregistrements  rcuprer *)
	 let _ = SQLInterface.free_execDB env in
	 (0, [])
     | _ ->
	 let _ = SQLInterface.free_execDB env in
	 (ret, [])
    )

let execute_fetchall connection get_info req =
  let res  = ref [] in
  let step = 40     in
  let callback  ll = res := (!res) @ ll in
  let (code, info) =
      execute_gen connection ~get_info:get_info ~n_rec:step req callback
  in
  (code, info, !res)

let execute connection req =
  let (c, _, l) = execute_fetchall connection false req in
  (c, l)

let execute_with_info connection req =
  execute_fetchall connection true req

(** Object-oriented interface. *)

(**
   @param base the database to connect to
   @param user the user to use when connecting
   @param passwd the password to use when connecting, can be [""]
*)
class data_base base user passwd =
  object (self)
    (** The connection, initialized when the object is created. *)
    val connection = connect base user passwd
    (** The flag to indicates whether we are connected or not,
       used not to disconnect more than once.*)
    val mutable connected = true

    method connect () = ()

    method disconnect () =
      if connected then
	(
	 connected <- false;
	 disconnect connection
	)

    method execute req = execute connection req

    method execute_with_info req = execute_with_info connection req

    method execute_gen ?(get_info=false) ?(n_rec=1) req (callback : string list list -> unit) =
      execute_gen connection ~get_info:get_info ~n_rec:n_rec req callback
  end