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,