* Mono.Posix.dll.sources: Rename Mono.Posix to Mono.Unix.
[mono.git] / mcs / class / Mono.Data.SqliteClient / Mono.Data.SqliteClient / SqliteConnection.cs
1 //
2 // Mono.Data.SqliteClient.SqliteConnection.cs
3 //
4 // Represents an open connection to a Sqlite database file.
5 //
6 // Author(s): Vladimir Vukicevic  <vladimir@pobox.com>
7 //            Everaldo Canuto  <everaldo_canuto@yahoo.com.br>
8 //
9 // Copyright (C) 2002  Vladimir Vukicevic
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Runtime.InteropServices;
33 using System.Data;
34
35 namespace Mono.Data.SqliteClient
36 {
37         public class SqliteConnection : IDbConnection
38         {
39
40                 #region Fields
41                 
42                 private string conn_str;
43                 private string db_file;
44                 private int db_mode;
45                 private int db_version;
46                 private IntPtr sqlite_handle;
47                 private ConnectionState state;
48                 
49                 #endregion
50
51                 #region Constructors and destructors
52                 
53                 public SqliteConnection ()
54                 {
55                         db_file = null;
56                         db_mode = 0644;
57                         db_version = 2;
58                         state = ConnectionState.Closed;
59                         sqlite_handle = IntPtr.Zero;
60                 }
61                 
62                 public SqliteConnection (string connstring) : this ()
63                 {
64                         ConnectionString = connstring;
65                 }
66                 
67                 public void Dispose ()
68                 {
69                         Close ();
70                 }
71                                 
72                 #endregion
73
74                 #region Properties
75                 
76                 public string ConnectionString {
77                         get { return conn_str; }
78                         set { SetConnectionString(value); }
79                 }
80                 
81                 public int ConnectionTimeout {
82                         get { return 0; }
83                 }
84                 
85                 public string Database {
86                         get { return db_file; }
87                 }
88                 
89                 public ConnectionState State {
90                         get { return state; }
91                 }
92                 
93                 internal int Version {
94                         get { return db_version; }
95                 }
96
97                 internal IntPtr Handle {
98                         get { return sqlite_handle; }
99                 }
100                 
101                 public int LastInsertRowId {
102                         get {
103                                 if (Version == 3)
104                                         return Sqlite.sqlite3_last_insert_rowid (Handle);
105                                 else
106                                         return Sqlite.sqlite_last_insert_rowid (Handle);
107                         }
108                 }
109                 
110                 #endregion
111
112                 #region Private Methods
113                 
114                 private void SetConnectionString(string connstring)
115                 {
116                         if (connstring == null) {
117                                 Close ();
118                                 conn_str = null;
119                                 return;
120                         }
121                         
122                         if (connstring != conn_str) {
123                                 Close ();
124                                 conn_str = connstring;
125                                 
126                                 db_file = null;
127                                 db_mode = 0644;
128                                 
129                                 string[] conn_pieces = connstring.Split (',');
130                                 foreach (string piece in conn_pieces) {
131                                         piece.Trim ();
132                                         string[] arg_pieces = piece.Split ('=');
133                                         if (arg_pieces.Length != 2) {
134                                                 throw new InvalidOperationException ("Invalid connection string");
135                                         }
136                                         string token = arg_pieces[0].ToLower ();
137                                         string tvalue = arg_pieces[1];
138                                         string tvalue_lc = arg_pieces[1].ToLower ();
139                                         if (token == "uri") {
140                                                 if (tvalue_lc.StartsWith ("file://")) {
141                                                         db_file = tvalue.Substring (6);
142                                                 } else if (tvalue_lc.StartsWith ("file:")) {
143                                                         db_file = tvalue.Substring (5);
144                                                 } else if (tvalue_lc.StartsWith ("/")) {
145                                                         db_file = tvalue;
146                                                 } else {
147                                                         throw new InvalidOperationException ("Invalid connection string: invalid URI");
148                                                 }
149                                         } else if (token == "mode") {
150                                                 db_mode = Convert.ToInt32 (tvalue);
151                                         } else if (token == "version") {
152                                                 db_version = Convert.ToInt32 (tvalue);
153                                         }
154                                 }
155                                 
156                                 if (db_file == null) {
157                                         throw new InvalidOperationException ("Invalid connection string: no URI");
158                                 }
159                         }
160                 }
161                 
162                 #endregion
163
164                 #region Internal Methods
165                 
166                 internal void StartExec ()
167                 {
168                         // use a mutex here
169                         state = ConnectionState.Executing;
170                 }
171                 
172                 internal void EndExec ()
173                 {
174                         state = ConnectionState.Open;
175                 }
176                 
177                 #endregion
178
179                 #region Public Methods
180                 
181                 public IDbTransaction BeginTransaction ()
182                 {
183                         if (state != ConnectionState.Open)
184                                 throw new InvalidOperationException("Invalid operation: The connection is close");
185                         
186                         SqliteTransaction t = new SqliteTransaction();
187                         t.Connection = this;
188                         SqliteCommand cmd = this.CreateCommand();
189                         cmd.CommandText = "BEGIN";
190                         cmd.ExecuteNonQuery();
191                         return t;
192                 }
193                 
194                 public IDbTransaction BeginTransaction (IsolationLevel il)
195                 {
196                         return null;
197                 }
198                 
199                 public void Close ()
200                 {
201                         if (state != ConnectionState.Open) {
202                                 return;
203                         }
204                         
205                         state = ConnectionState.Closed;
206                 
207                         if (Version == 3)
208                                 Sqlite.sqlite3_close (sqlite_handle);
209                         else 
210                                 Sqlite.sqlite_close(sqlite_handle);
211                         sqlite_handle = IntPtr.Zero;
212                 }
213                 
214                 public void ChangeDatabase (string databaseName)
215                 {
216                         throw new NotImplementedException ();
217                 }
218                 
219                 IDbCommand IDbConnection.CreateCommand ()
220                 {
221                         return CreateCommand ();
222                 }
223                 
224                 public SqliteCommand CreateCommand ()
225                 {
226                         return new SqliteCommand (null, this);
227                 }
228                 
229                 public void Open ()
230                 {
231                         if (conn_str == null) {
232                                 throw new InvalidOperationException ("No database specified");
233                         }
234                         
235                         if (state != ConnectionState.Closed) {
236                                 return;
237                         }
238                         
239                         IntPtr errmsg = IntPtr.Zero;
240                         if (Version == 3) {
241                                 int err = Sqlite.sqlite3_open(db_file, out sqlite_handle);
242                                 if (err == (int)SqliteError.ERROR)
243                                         throw new ApplicationException (Sqlite.sqlite3_errmsg (sqlite_handle));
244                         } else {
245                                 sqlite_handle = Sqlite.sqlite_open(db_file, db_mode, out errmsg);
246                         
247                                 if (errmsg != IntPtr.Zero) {
248                                         string msg = Marshal.PtrToStringAnsi (errmsg);
249                                         Sqlite.sqliteFree (errmsg);
250                                         throw new ApplicationException (msg);
251                                 }
252                         }
253                         state = ConnectionState.Open;
254                 }
255                 
256                 #endregion
257
258         }
259 }