8177fa27235d7dd145ba7528d65b486a9286530d
[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             if (operationType == OperationType.Delete)
93                 return;
94
95             Sql sql = new Sql(string.Format("SELECT * from {0} WHERE rowid = {1}", table_name, rowid));
96             using (IStatement stmt = CreateStatement())
97             using (IResultSet resultSet = stmt.ExecuteQuery(sql))
98             {
99                 IRecord record = resultSet.FirstOrDefault();
100                 lock (_lock)
101                 {
102                     RecordChangedEventArgs ev = new RecordChangedEventArgs(operationType, db_name, table_name, record);
103                     _recordChanged?.Invoke(this, ev);
104                 }
105             }
106         }
107
108         internal IntPtr GetHandle()
109         {
110             return _db;
111         }
112
113         public void Open(Uri uri)
114         {
115             if (IsOpen())
116                 return;
117
118             if (uri.Scheme != "tdbc")
119                 throw new ArgumentException("Wrong scheme:" + uri.Scheme);
120
121             if (uri.Host != "localhost")
122                 throw new ArgumentException("Host should be 'localhost':" + uri.Host);
123
124             string query = uri.Query;
125             var queryDictionary = System.Web.HttpUtility.ParseQueryString(query);
126             int mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_READWRITE |
127                 (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_CREATE;
128
129             if (queryDictionary.Get("mode") == "ro")
130             {
131                 mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_READONLY;
132             }
133             else if (queryDictionary.Get("mode") == "rw")
134             {
135                 mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_READWRITE;
136             }
137             else if (queryDictionary.Get("mode") == "rwc")
138             {
139                 mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_READWRITE |
140                     (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_CREATE;
141             }
142             else if (queryDictionary.Get("mode") == "memory")
143             {
144                 mode = (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_MEMORY;
145             }
146
147             if (queryDictionary.Get("cache") == "shared")
148             {
149                 mode |= (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_SHAREDCACHE;
150             }
151             else if (queryDictionary.Get("cache") == "private")
152             {
153                 mode |= (int)Interop.Sqlite.OpenParameter.SQLITE_OPEN_PRIVATECACHE;
154             }
155
156             int ret = Interop.Sqlite.OpenV2(uri.LocalPath, out _db, mode, IntPtr.Zero);
157             if (ret != (int)Interop.Sqlite.ResultCode.SQLITE_OK)
158                 throw new InvalidOperationException("code:" + ret);
159
160             Interop.Sqlite.UpdateHook(_db, UpdateHookCallback, IntPtr.Zero);
161             _opened = true;
162         }
163
164         public IStatement CreateStatement()
165         {
166             if (!IsOpen())
167                 throw new InvalidOperationException("Not opened");
168
169             return new Statement(this);
170         }
171
172         public bool IsOpen()
173         {
174             return _opened;
175         }
176
177         protected virtual void Dispose(bool disposing)
178         {
179             if (!disposedValue)
180             {
181                 if (disposing)
182                 {
183                 }
184
185                 if (_opened)
186                     Close();
187                 disposedValue = true;
188             }
189         }
190
191          ~Connection()
192          {
193              Dispose(disposing: false);
194          }
195
196         public void Dispose()
197         {
198             Dispose(disposing: true);
199             GC.SuppressFinalize(this);
200         }
201     }
202 }