File: ocamlodbc.ml

package info (click to toggle)
ocamlodbc 2.15-7
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 476 kB
  • sloc: ansic: 842; ml: 779; makefile: 341; sh: 7
file content (222 lines) | stat: -rw-r--r-- 7,304 bytes parent folder | download | duplicates (4)
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
(*****************************************************************************)
(*              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                                        *)
(*****************************************************************************)

(* $Id: ocamlodbc.ml,v 1.18 2007/06/20 18:28:35 chris Exp $ *)

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

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

exception SQL_Error of string

(* BEWARE: Keep constructor in the right order w.r.t. OCAML_SQL_*
   constants in ocaml_odbc_c.c *)
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)

(** Cette fonction 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 conn ?(get_info=false) ?(n_rec=40) req callback =
  if req = "" then
    (-1, ([] : (string * sql_column_type) list))
  else (
    let (ret, env) = SQLInterface.execDB conn.phEnv conn.phDbc req in
    match ret with
    | 0 ->
	let l_desc_col =
	  if get_info then SQLInterface.get_infoDB env
            (* rcuprer les informations sur les champs retourns
	       (nom et type) par la dernire requte excute *)
	  else [] in
        (* rcuprer les records en plusieurs fois *)
	let rec iter () =
	  let (n, ll_res) = SQLInterface.itereDB env n_rec in
	  (*Gc.minor();*)
	  callback ll_res;
	  if n >= n_rec (* maybe more rows *) then iter() in
	iter();
	SQLInterface.free_execDB env;
	(ret, l_desc_col)

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

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

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

let execute_with_info conn req =
  execute_fetchall conn 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 option list list -> unit) =
    execute_gen connection ~get_info:get_info ~n_rec:n_rec req callback
end