This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / Mono.Data.SqliteClient / Mono.Data.SqliteClient / SqliteCommand.cs
1 // -*- c-basic-offset: 8; inent-tabs-mode: nil -*-
2 //
3 //  SqliteCommand.cs
4 //
5 //  Author(s): Vladimir Vukicevic  <vladimir@pobox.com>
6 //
7 //  Copyright (C) 2002  Vladimir Vukicevic
8 //
9
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.Text;
33 using System.Runtime.InteropServices;
34 using System.Data;
35
36 namespace Mono.Data.SqliteClient {
37         public class SqliteCommand : IDbCommand
38         {
39                 SqliteConnection parent_conn;
40 //                SqliteTransaction transaction;
41                 IDbTransaction transaction;
42                 string sql;
43                 int timeout;
44                 CommandType type;
45                 UpdateRowSource upd_row_source;
46                 SqliteParameterCollection sql_params;
47
48                 public SqliteCommand ()
49                 {
50                         sql = "";
51                         sql_params = new SqliteParameterCollection ();
52                 }
53
54                 public SqliteCommand (string sqlText, SqliteConnection dbConn)
55                 {
56                         sql = sqlText;
57                         parent_conn = dbConn;
58                         sql_params = new SqliteParameterCollection ();
59                 }
60
61                 public SqliteCommand (string sqlText, SqliteConnection dbConn, IDbTransaction trans)
62                 {
63                         sql = sqlText;
64                         parent_conn = dbConn;
65                         transaction = trans;
66                         sql_params = new SqliteParameterCollection ();
67                 }
68
69                 public void Dispose ()
70                 {
71                 }
72
73                 public string CommandText {
74                         get {
75                                 return sql;
76                         }
77                         set {
78                                 sql = value;
79                         }
80                 }
81
82                 // note that we could actually implement
83                 // a timeout with sqlite, but setting up a signal to interrupt us after
84                 // a certain amount of time, but it's probably not worth the effort
85                 public int CommandTimeout {
86                         get {
87                                 return timeout;
88                         }
89                         set {
90                                 timeout = value;
91                         }
92                 }
93
94                 IDbConnection IDbCommand.Connection {
95                         get {
96                                 return parent_conn;
97                         }
98                         set {
99                                 if (!(value is SqliteConnection)) {
100                                         throw new InvalidOperationException ("Can't set Connection to something other than a SqliteConnection");
101                                 }
102                                 parent_conn = (SqliteConnection) value;
103                         }
104                 }
105
106                 public SqliteConnection Connection {
107                         get {
108                                 return parent_conn;
109                         }
110                         set {
111                                 parent_conn = value;
112                         }
113                 }
114
115                 public CommandType CommandType {
116                         get {
117                                 return type;
118                         }
119                         set {
120                                 type = value;
121                         }
122                 }
123
124                 IDataParameterCollection IDbCommand.Parameters {
125                         get {
126                                 return Parameters;
127                         }
128                 }
129
130                 public SqliteParameterCollection Parameters {
131                         get {
132                                 return sql_params;
133                         }
134                 }
135
136                 public IDbTransaction Transaction {
137                         get {
138                                 return transaction;
139                         }
140                         set {
141                                 transaction = value;
142                         }
143                 }
144
145                 public UpdateRowSource UpdatedRowSource {
146                         get {
147                                 return upd_row_source;
148                         }
149                         set {
150                                 upd_row_source = value;
151                         }
152                 }
153
154                 public void Prepare ()
155                 {
156                 }
157
158                 public void Cancel ()
159                 {
160                 }
161
162                 IDbDataParameter IDbCommand.CreateParameter ()
163                 {
164                         return CreateParameter ();
165                 }
166
167                 public SqliteParameter CreateParameter ()
168                 {
169                         return new SqliteParameter ();
170                 }
171
172                 public int ExecuteNonQuery ()
173                 {
174                         int rows_affected;
175                         SqliteDataReader r = ExecuteReader (CommandBehavior.Default, false, out rows_affected);
176                         return rows_affected;
177                 }
178
179                 public object ExecuteScalar ()
180                 {
181                         SqliteDataReader r = ExecuteReader ();
182                         if (r == null || !r.Read ()) {
183                                 return null;
184                         }
185                         object o = r[0];
186                         r.Close ();
187                         return o;
188                 }
189
190                 IDataReader IDbCommand.ExecuteReader ()
191                 {
192                         return ExecuteReader ();
193                 }
194
195                 IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
196                 {
197                         return ExecuteReader (behavior);
198                 }
199
200                 public SqliteDataReader ExecuteReader ()
201                 {
202                         return ExecuteReader (CommandBehavior.Default);
203                 }
204
205                 public SqliteDataReader ExecuteReader (CommandBehavior behavior)
206                 {
207                         int r;
208                         return ExecuteReader (behavior, true, out r);
209                 }
210
211                 public SqliteDataReader ExecuteReader (CommandBehavior behavior, bool want_results, out int rows_affected)
212                 {
213                         SqliteDataReader reader = null;
214                         SqliteError err;
215
216                         parent_conn.StartExec ();
217
218                         string msg = "";
219                         unsafe {
220                                 byte *msg_result;
221
222                                 try {
223                                         if (want_results) {
224                                                 reader = new SqliteDataReader (this);
225                                                 
226                                                 err = sqlite_exec (parent_conn.Handle,
227                                                                    sql,
228                                                                    new SqliteCallbackFunction (reader.SqliteCallback),
229                                                                    IntPtr.Zero, &msg_result);
230                                                 reader.ReadingDone ();
231                                         } else {
232                                                 err = sqlite_exec (parent_conn.Handle,
233                                                                    sql,
234                                                                    null,
235                                                                    IntPtr.Zero, &msg_result);
236                                         }
237                                 } finally {
238                                         parent_conn.EndExec ();
239                                 }
240
241                                 if (msg_result != null){
242                                         StringBuilder sb = new StringBuilder ();
243
244                                         for (byte *y = msg_result; *y != 0; y++)
245                                                 sb.Append ((char) *y);
246                                         msg = sb.ToString ();
247
248                                         sqliteFree (msg_result);
249                                 }
250                         }
251
252                         if (err != SqliteError.OK)
253                                 throw new ApplicationException ("Sqlite error " + msg);
254
255                         rows_affected = NumChanges ();
256                         return reader;
257                 }
258
259
260                 internal int NumChanges () {
261                         return sqlite_changes (parent_conn.Handle);
262                 }
263
264                 public int LastInsertRowID () {
265                         return sqlite_last_insert_rowid (parent_conn.Handle);
266                 }
267
268                 internal unsafe delegate int SqliteCallbackFunction (ref object o, int argc, sbyte **argv, sbyte **colnames);
269
270                 [DllImport("sqlite")]
271                 unsafe static extern SqliteError sqlite_exec (IntPtr handle, string sql, SqliteCallbackFunction callback,
272                                                               IntPtr user_data, byte **errstr_ptr);
273
274                 [DllImport ("sqlite")]
275                 unsafe static extern void sqliteFree (void *ptr);
276                 
277                 [DllImport("sqlite")]
278                 static extern int sqlite_changes (IntPtr handle);
279
280                 [DllImport("sqlite")]
281                 static extern int sqlite_last_insert_rowid (IntPtr sqlite_handle);
282
283                 internal enum SqliteError : int {
284                         OK,
285                         Error,
286                         Internal,
287                         Perm,
288                         Abort,
289                         Busy,
290                         Locked,
291                         NoMem,
292                         ReadOnly,
293                         Interrupt,
294                         IOErr,
295                         Corrupt,
296                         NotFound,
297                         Full,
298                         CantOpen,
299                         Protocol,
300                         Empty,
301                         Schema,
302                         TooBig,
303                         Constraint,
304                         Mismatch,
305                         Misuse
306                 }
307         }
308 }