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