4381acaf84847c4353b723c932260f761f786288
[platform/core/csapi/tizenfx.git] / src / Tizen.Data.Tdbc.Driver.Sqlite / Tizen.Data.Tdbc.Driver.Sqlite / Connection.cs
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.ComponentModel;
19 using System.Linq;
20
21 namespace Tizen.Data.Tdbc.Driver.Sqlite
22 {
23     [EditorBrowsable(EditorBrowsableState.Never)]
24     internal class Connection : IConnection
25     {
26         private bool _opened;
27         private IntPtr _db;
28         private bool disposedValue;
29         private readonly object _lock = new object();
30         private EventHandler<RecordChangedEventArgs> _recordChanged;
31
32
33         static Connection()
34         {
35             Interop.Sqlite.Init();
36         }
37
38         public Connection()
39         {
40         }
41
42         public event EventHandler<RecordChangedEventArgs> RecordChanged
43         {
44             add
45             {
46                 lock (_lock)
47                 {
48                     _recordChanged += value;
49                 }
50             }
51
52             remove
53             {
54                 lock (_lock)
55                 {
56                     _recordChanged -= value;
57                 }
58             }
59         }
60
61         public void Open(String openString)
62         {
63             Open(new Uri(openString));
64         }
65
66         public void Close()
67         {
68             if (_opened)
69             {
70                 Interop.Sqlite.UpdateHook(_db, null, IntPtr.Zero);
71                 Interop.Sqlite.Close(_db);
72                 _opened = false;
73             }
74         }
75
76         private void UpdateHookCallback(IntPtr data, int action, string db_name, string table_name, long rowid)
77         {
78             OperationType operationType = OperationType.None;
79             switch (((Interop.Sqlite.UpdateHookAction)action))
80             {
81                 case Interop.Sqlite.UpdateHookAction.SQLITE_UPDATE:
82                     operationType = OperationType.Update;
83                     break;
84                 case Interop.Sqlite.UpdateHookAction.SQLITE_INSERT:
85                     operationType = OperationType.Insert;
86                     break;
87                 case Interop.Sqlite.UpdateHookAction.SQLITE_DELETE:
88                     operationType = OperationType.Delete;
89                     break;
90             }
91
92             Sql sql = new Sql(string.Format("SELECT * from {0} WHERE rowid = {1}", table_name, rowid));
93             using (IStatement stmt = CreateStatement())
94             {
95                 IRecord record = (operationType != OperationType.Delete ? stmt.ExecuteQuery(sql).FirstOrDefault() : null);
96                 RecordChangedEventArgs ev = new RecordChangedEventArgs(operationType, db_name, table_name, record);
97                 _recordChanged?.Invoke(this, ev);
98             }
99         }
100
101         internal IntPtr GetHandle()
102         {
103             return _db;
104         }
105
106         public void Open(Uri uri)
107         {
108             if (IsOpen())
109                 return;
110
111             if (uri.Scheme != "tdbc")
112                 throw new ArgumentException("Wrong scheme:" + uri.Scheme);
113
114             if (uri.Host != "localhost")
115                 throw new ArgumentException("Host should be 'localhost':" + uri.Host);
116
117             string query = uri.Query;
118             var queryDictionary = System.Web.HttpUtility.ParseQueryString(query);
119             int mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_READWRITE |
120                 (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_CREATE;
121
122             if (queryDictionary.Get("mode") == "ro")
123             {
124                 mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_READONLY;
125             }
126             else if (queryDictionary.Get("mode") == "rw")
127             {
128                 mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_READWRITE;
129             }
130             else if (queryDictionary.Get("mode") == "rwc")
131             {
132                 mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_READWRITE |
133                     (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_CREATE;
134             }
135             else if (queryDictionary.Get("mode") == "memory")
136             {
137                 mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_MEMORY;
138             }
139
140             if (queryDictionary.Get("cache") == "shared")
141             {
142                 mode |= (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_SHAREDCACHE;
143             }
144             else if (queryDictionary.Get("cache") == "private")
145             {
146                 mode |= (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_PRIVATECACHE;
147             }
148
149             int ret = Interop.Sqlite.OpenV2(uri.LocalPath, out _db, mode, IntPtr.Zero);
150             if (ret != (int)Interop.Sqlite.ResultCode.SQLITE_OK)
151                 throw new InvalidOperationException("code:" + ret);
152
153             Interop.Sqlite.UpdateHook(_db, UpdateHookCallback, IntPtr.Zero);
154             _opened = true;
155         }
156
157         public IStatement CreateStatement()
158         {
159             if (!IsOpen())
160                 throw new InvalidOperationException("Not opened");
161
162             return new Statement(this);
163         }
164
165         public bool IsOpen()
166         {
167             return _opened;
168         }
169
170         protected virtual void Dispose(bool disposing)
171         {
172             if (!disposedValue)
173             {
174                 if (disposing)
175                 {
176                 }
177
178                 if (_opened)
179                     Close();
180                 disposedValue = true;
181             }
182         }
183
184          ~Connection()
185          {
186              Dispose(disposing: false);
187          }
188
189         public void Dispose()
190         {
191             Dispose(disposing: true);
192             GC.SuppressFinalize(this);
193         }
194     }
195 }