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