Mercurial > hg > orthanc-databases
comparison MySQL/Plugins/MySQLIndex.cpp @ 226:a4918d57435c
DatabaseManager doesn't IDatabaseFactory anymore
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 02 Apr 2021 19:23:36 +0200 |
parents | 94c9908e6aca |
children | d1b124d116c1 |
comparison
equal
deleted
inserted
replaced
225:94c9908e6aca | 226:a4918d57435c |
---|---|
34 | 34 |
35 #include <ctype.h> | 35 #include <ctype.h> |
36 | 36 |
37 namespace OrthancDatabases | 37 namespace OrthancDatabases |
38 { | 38 { |
39 MySQLIndex::MySQLIndex(OrthancPluginContext* context, | |
40 const MySQLParameters& parameters) : | |
41 IndexBackend(context), | |
42 parameters_(parameters), | |
43 clearAll_(false) | |
44 { | |
45 } | |
46 | |
47 | |
48 IDatabase* MySQLIndex::OpenDatabaseConnection() | |
49 { | |
50 return MySQLDatabase::OpenDatabaseConnection(parameters_); | |
51 } | |
52 | |
53 | |
39 static void ThrowCannotCreateTrigger() | 54 static void ThrowCannotCreateTrigger() |
40 { | 55 { |
41 LOG(ERROR) << "The MySQL user is not allowed to create triggers => 2 possible solutions:"; | 56 LOG(ERROR) << "The MySQL user is not allowed to create triggers => 2 possible solutions:"; |
42 LOG(ERROR) << " 1- Give the SUPER privilege to the MySQL database user, or"; | 57 LOG(ERROR) << " 1- Give the SUPER privilege to the MySQL database user, or"; |
43 LOG(ERROR) << " 2- Run \"set global log_bin_trust_function_creators=1;\" as MySQL root user."; | 58 LOG(ERROR) << " 2- Run \"set global log_bin_trust_function_creators=1;\" as MySQL root user."; |
44 LOG(ERROR) << "Once you are done, drop and recreate the MySQL database"; | 59 LOG(ERROR) << "Once you are done, drop and recreate the MySQL database"; |
45 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, | 60 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, |
46 "Need to fix the MySQL permissions for \"CREATE TRIGGER\""); | 61 "Need to fix the MySQL permissions for \"CREATE TRIGGER\""); |
47 } | 62 } |
48 | 63 |
49 IDatabase* MySQLIndex::OpenInternal() | 64 |
50 { | 65 void MySQLIndex::ConfigureDatabase(IDatabase& database) |
66 { | |
67 MySQLDatabase& db = dynamic_cast<MySQLDatabase&>(database); | |
68 | |
51 uint32_t expectedVersion = 6; | 69 uint32_t expectedVersion = 6; |
52 | 70 |
53 if (GetContext()) // "GetContext()" can possibly be NULL in the unit tests | 71 if (GetContext()) // "GetContext()" can possibly be NULL in the unit tests |
54 { | 72 { |
55 expectedVersion = OrthancPluginGetExpectedDatabaseVersion(GetContext()); | 73 expectedVersion = OrthancPluginGetExpectedDatabaseVersion(GetContext()); |
72 if (clearAll_) | 90 if (clearAll_) |
73 { | 91 { |
74 MySQLDatabase::ClearDatabase(parameters_); | 92 MySQLDatabase::ClearDatabase(parameters_); |
75 } | 93 } |
76 | 94 |
77 std::unique_ptr<MySQLDatabase> db(new MySQLDatabase(parameters_)); | 95 db.Execute("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE", false); |
78 | 96 |
79 db->Open(); | 97 { |
80 db->Execute("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE", false); | 98 MySQLDatabase::TransientAdvisoryLock lock(db, MYSQL_LOCK_DATABASE_SETUP); |
81 | |
82 { | |
83 MySQLDatabase::TransientAdvisoryLock lock(*db, MYSQL_LOCK_DATABASE_SETUP); | |
84 | 99 |
85 /** | 100 /** |
86 * In a first transaction, we create the tables. Such a | 101 * In a first transaction, we create the tables. Such a |
87 * transaction cannot be rollback: "The CREATE TABLE statement | 102 * transaction cannot be rollback: "The CREATE TABLE statement |
88 * in InnoDB is processed as a single transaction. This means | 103 * in InnoDB is processed as a single transaction. This means |
95 * error message "MySQL plugin is incompatible with database | 110 * error message "MySQL plugin is incompatible with database |
96 * schema version: 0" that was reported in the forum: | 111 * schema version: 0" that was reported in the forum: |
97 * https://groups.google.com/d/msg/orthanc-users/OCFFkm1qm0k/Mbroy8VWAQAJ | 112 * https://groups.google.com/d/msg/orthanc-users/OCFFkm1qm0k/Mbroy8VWAQAJ |
98 **/ | 113 **/ |
99 { | 114 { |
100 MySQLTransaction t(*db, TransactionType_ReadWrite); | 115 MySQLTransaction t(db, TransactionType_ReadWrite); |
101 | 116 |
102 db->Execute("ALTER DATABASE " + parameters_.GetDatabase() + | 117 db.Execute("ALTER DATABASE " + parameters_.GetDatabase() + |
103 " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci", false); | 118 " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci", false); |
104 | 119 |
105 // This is the first table to be created | 120 // This is the first table to be created |
106 if (!db->DoesTableExist(t, "GlobalProperties")) | 121 if (!db.DoesTableExist(t, "GlobalProperties")) |
107 { | 122 { |
108 std::string query; | 123 std::string query; |
109 | 124 |
110 Orthanc::EmbeddedResources::GetFileResource | 125 Orthanc::EmbeddedResources::GetFileResource |
111 (query, Orthanc::EmbeddedResources::MYSQL_PREPARE_INDEX); | 126 (query, Orthanc::EmbeddedResources::MYSQL_PREPARE_INDEX); |
112 db->Execute(query, true); | 127 db.Execute(query, true); |
113 } | 128 } |
114 | 129 |
115 t.Commit(); | 130 t.Commit(); |
116 } | 131 } |
117 | 132 |
124 **/ | 139 **/ |
125 | 140 |
126 int version = 0; | 141 int version = 0; |
127 | 142 |
128 { | 143 { |
129 MySQLTransaction t(*db, TransactionType_ReadWrite); | 144 MySQLTransaction t(db, TransactionType_ReadWrite); |
130 | 145 |
131 // This is the last table to be created | 146 // This is the last table to be created |
132 if (!db->DoesTableExist(t, "PatientRecyclingOrder")) | 147 if (!db.DoesTableExist(t, "PatientRecyclingOrder")) |
133 { | 148 { |
134 LOG(ERROR) << "Corrupted MySQL database"; | 149 LOG(ERROR) << "Corrupted MySQL database"; |
135 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 150 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
136 } | 151 } |
137 | 152 |
138 // This is the last item to be created | 153 // This is the last item to be created |
139 if (!db->DoesTriggerExist(t, "PatientAdded")) | 154 if (!db.DoesTriggerExist(t, "PatientAdded")) |
140 { | 155 { |
141 ThrowCannotCreateTrigger(); | 156 ThrowCannotCreateTrigger(); |
142 } | 157 } |
143 | 158 |
144 if (!LookupGlobalIntegerProperty(version, *db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseSchemaVersion)) | 159 if (!LookupGlobalIntegerProperty(version, db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseSchemaVersion)) |
145 { | 160 { |
146 SetGlobalIntegerProperty(*db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseSchemaVersion, expectedVersion); | 161 SetGlobalIntegerProperty(db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabaseSchemaVersion, expectedVersion); |
147 SetGlobalIntegerProperty(*db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, 1); | 162 SetGlobalIntegerProperty(db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, 1); |
148 version = expectedVersion; | 163 version = expectedVersion; |
149 } | 164 } |
150 | 165 |
151 if (version != 6) | 166 if (version != 6) |
152 { | 167 { |
158 } | 173 } |
159 | 174 |
160 int revision = 0; | 175 int revision = 0; |
161 | 176 |
162 { | 177 { |
163 MySQLTransaction t(*db, TransactionType_ReadWrite); | 178 MySQLTransaction t(db, TransactionType_ReadWrite); |
164 | 179 |
165 if (!LookupGlobalIntegerProperty(revision, *db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel)) | 180 if (!LookupGlobalIntegerProperty(revision, db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel)) |
166 { | 181 { |
167 revision = 1; | 182 revision = 1; |
168 SetGlobalIntegerProperty(*db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); | 183 SetGlobalIntegerProperty(db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); |
169 } | 184 } |
170 | 185 |
171 t.Commit(); | 186 t.Commit(); |
172 } | 187 } |
173 | 188 |
174 if (revision == 1) | 189 if (revision == 1) |
175 { | 190 { |
176 MySQLTransaction t(*db, TransactionType_ReadWrite); | 191 MySQLTransaction t(db, TransactionType_ReadWrite); |
177 | 192 |
178 // The serialization of jobs as a global property can lead to | 193 // The serialization of jobs as a global property can lead to |
179 // very long values => switch to the LONGTEXT type that can | 194 // very long values => switch to the LONGTEXT type that can |
180 // store up to 4GB: | 195 // store up to 4GB: |
181 // https://stackoverflow.com/a/13932834/881731 | 196 // https://stackoverflow.com/a/13932834/881731 |
182 db->Execute("ALTER TABLE GlobalProperties MODIFY value LONGTEXT", false); | 197 db.Execute("ALTER TABLE GlobalProperties MODIFY value LONGTEXT", false); |
183 | 198 |
184 revision = 2; | 199 revision = 2; |
185 SetGlobalIntegerProperty(*db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); | 200 SetGlobalIntegerProperty(db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); |
186 | 201 |
187 t.Commit(); | 202 t.Commit(); |
188 } | 203 } |
189 | 204 |
190 if (revision == 2) | 205 if (revision == 2) |
191 { | 206 { |
192 MySQLTransaction t(*db, TransactionType_ReadWrite); | 207 MySQLTransaction t(db, TransactionType_ReadWrite); |
193 | 208 |
194 // Install the "GetLastChangeIndex" extension | 209 // Install the "GetLastChangeIndex" extension |
195 std::string query; | 210 std::string query; |
196 | 211 |
197 Orthanc::EmbeddedResources::GetFileResource | 212 Orthanc::EmbeddedResources::GetFileResource |
198 (query, Orthanc::EmbeddedResources::MYSQL_GET_LAST_CHANGE_INDEX); | 213 (query, Orthanc::EmbeddedResources::MYSQL_GET_LAST_CHANGE_INDEX); |
199 db->Execute(query, true); | 214 db.Execute(query, true); |
200 | 215 |
201 if (!db->DoesTriggerExist(t, "ChangeAdded")) | 216 if (!db.DoesTriggerExist(t, "ChangeAdded")) |
202 { | 217 { |
203 ThrowCannotCreateTrigger(); | 218 ThrowCannotCreateTrigger(); |
204 } | 219 } |
205 | 220 |
206 revision = 3; | 221 revision = 3; |
207 SetGlobalIntegerProperty(*db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); | 222 SetGlobalIntegerProperty(db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); |
208 | 223 |
209 t.Commit(); | 224 t.Commit(); |
210 } | 225 } |
211 | 226 |
212 if (revision == 3) | 227 if (revision == 3) |
213 { | 228 { |
214 MySQLTransaction t(*db, TransactionType_ReadWrite); | 229 MySQLTransaction t(db, TransactionType_ReadWrite); |
215 | 230 |
216 // Reconfiguration of "Metadata" from TEXT type (up to 64KB) | 231 // Reconfiguration of "Metadata" from TEXT type (up to 64KB) |
217 // to the LONGTEXT type (up to 4GB). This might be important | 232 // to the LONGTEXT type (up to 4GB). This might be important |
218 // for applications such as the Osimis Web viewer that stores | 233 // for applications such as the Osimis Web viewer that stores |
219 // large amount of metadata. | 234 // large amount of metadata. |
220 // http://book.orthanc-server.com/faq/features.html#central-registry-of-metadata-and-attachments | 235 // http://book.orthanc-server.com/faq/features.html#central-registry-of-metadata-and-attachments |
221 db->Execute("ALTER TABLE Metadata MODIFY value LONGTEXT", false); | 236 db.Execute("ALTER TABLE Metadata MODIFY value LONGTEXT", false); |
222 | 237 |
223 revision = 4; | 238 revision = 4; |
224 SetGlobalIntegerProperty(*db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); | 239 SetGlobalIntegerProperty(db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); |
225 | 240 |
226 t.Commit(); | 241 t.Commit(); |
227 } | 242 } |
228 | 243 |
229 if (revision == 4) | 244 if (revision == 4) |
230 { | 245 { |
231 MySQLTransaction t(*db, TransactionType_ReadWrite); | 246 MySQLTransaction t(db, TransactionType_ReadWrite); |
232 | 247 |
233 // Install the "CreateInstance" extension | 248 // Install the "CreateInstance" extension |
234 std::string query; | 249 std::string query; |
235 | 250 |
236 Orthanc::EmbeddedResources::GetFileResource | 251 Orthanc::EmbeddedResources::GetFileResource |
237 (query, Orthanc::EmbeddedResources::MYSQL_CREATE_INSTANCE); | 252 (query, Orthanc::EmbeddedResources::MYSQL_CREATE_INSTANCE); |
238 db->Execute(query, true); | 253 db.Execute(query, true); |
239 | 254 |
240 revision = 5; | 255 revision = 5; |
241 SetGlobalIntegerProperty(*db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); | 256 SetGlobalIntegerProperty(db, t, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_DatabasePatchLevel, revision); |
242 | 257 |
243 t.Commit(); | 258 t.Commit(); |
244 } | 259 } |
245 | 260 |
246 if (revision != 5) | 261 if (revision != 5) |
258 * previously-acquired locks. | 273 * previously-acquired locks. |
259 * https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html | 274 * https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html |
260 **/ | 275 **/ |
261 if (parameters_.HasLock()) | 276 if (parameters_.HasLock()) |
262 { | 277 { |
263 db->AdvisoryLock(MYSQL_LOCK_INDEX); | 278 db.AdvisoryLock(MYSQL_LOCK_INDEX); |
264 } | 279 } |
265 | |
266 return db.release(); | |
267 } | |
268 | |
269 | |
270 MySQLIndex::MySQLIndex(OrthancPluginContext* context, | |
271 const MySQLParameters& parameters) : | |
272 IndexBackend(context), | |
273 parameters_(parameters), | |
274 clearAll_(false) | |
275 { | |
276 } | 280 } |
277 | 281 |
278 | 282 |
279 int64_t MySQLIndex::CreateResource(DatabaseManager& manager, | 283 int64_t MySQLIndex::CreateResource(DatabaseManager& manager, |
280 const char* publicId, | 284 const char* publicId, |