comparison PostgreSQL/Plugins/SQL/PrepareIndex.sql @ 448:f2427f94d879 pg-transactions

added downgrade script + renames version
author Alain Mazy <am@osimis.io>
date Wed, 17 Jan 2024 16:22:08 +0100
parents PostgreSQL/Plugins/SQL/PrepareIndexV2.sql@2ca939d02d39
children da0586c5cbd8
comparison
equal deleted inserted replaced
447:5881e4af5799 448:f2427f94d879
1 -- This SQL file creates a DB in version.revision 6.2 directly
2 -- It is also run after upgrade scripts to create new tables and or create/replace triggers and functions.
3 -- This script is self contained, it contains everything that needs to be run to create an Orthanc DB.
4 -- Note to developers:
5 -- - it is and must stay idempotent.
6 -- - it is executed when the DB is "locked", only one Orthanc instance can execute it at a given time.
7
8 CREATE TABLE IF NOT EXISTS GlobalProperties(
9 property INTEGER PRIMARY KEY,
10 value TEXT
11 );
12
13 CREATE TABLE IF NOT EXISTS Resources(
14 internalId BIGSERIAL NOT NULL PRIMARY KEY,
15 resourceType INTEGER NOT NULL,
16 publicId VARCHAR(64) NOT NULL,
17 parentId BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
18 CONSTRAINT UniquePublicId UNIQUE (publicId)
19 );
20
21 CREATE TABLE IF NOT EXISTS MainDicomTags(
22 id BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
23 tagGroup INTEGER,
24 tagElement INTEGER,
25 value TEXT,
26 PRIMARY KEY(id, tagGroup, tagElement)
27 );
28
29 CREATE TABLE IF NOT EXISTS DicomIdentifiers(
30 id BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
31 tagGroup INTEGER,
32 tagElement INTEGER,
33 value TEXT,
34 PRIMARY KEY(id, tagGroup, tagElement)
35 );
36
37 CREATE TABLE IF NOT EXISTS Metadata(
38 id BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
39 type INTEGER NOT NULL,
40 value TEXT,
41 revision INTEGER,
42 PRIMARY KEY(id, type)
43 );
44
45 CREATE TABLE IF NOT EXISTS AttachedFiles(
46 id BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
47 fileType INTEGER,
48 uuid VARCHAR(64) NOT NULL,
49 compressedSize BIGINT,
50 uncompressedSize BIGINT,
51 compressionType INTEGER,
52 uncompressedHash VARCHAR(40),
53 compressedHash VARCHAR(40),
54 revision INTEGER,
55 PRIMARY KEY(id, fileType)
56 );
57
58 CREATE TABLE IF NOT EXISTS Changes(
59 seq BIGSERIAL NOT NULL PRIMARY KEY,
60 changeType INTEGER,
61 internalId BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
62 resourceType INTEGER,
63 date VARCHAR(64)
64 );
65
66 CREATE TABLE IF NOT EXISTS ExportedResources(
67 seq BIGSERIAL NOT NULL PRIMARY KEY,
68 resourceType INTEGER,
69 publicId VARCHAR(64),
70 remoteModality TEXT,
71 patientId VARCHAR(64),
72 studyInstanceUid TEXT,
73 seriesInstanceUid TEXT,
74 sopInstanceUid TEXT,
75 date VARCHAR(64)
76 );
77
78 CREATE TABLE IF NOT EXISTS PatientRecyclingOrder(
79 seq BIGSERIAL NOT NULL PRIMARY KEY,
80 patientId BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
81 CONSTRAINT UniquePatientId UNIQUE (patientId)
82 );
83
84 CREATE TABLE IF NOT EXISTS Labels(
85 id BIGINT REFERENCES Resources(internalId) ON DELETE CASCADE,
86 label TEXT,
87 PRIMARY KEY(id, label)
88 );
89
90 CREATE TABLE IF NOT EXISTS GlobalIntegers(
91 key INTEGER PRIMARY KEY,
92 value BIGINT);
93 -- GlobalIntegers keys:
94 -- 0: CompressedSize
95 -- 1: UncompressedSize
96 -- 2: PatientsCount
97 -- 3: StudiesCount
98 -- 4: SeriesCount
99 -- 5: InstancesCount
100 -- 6: ChangeSeq
101 -- 7: PatientRecyclingOrderSeq
102
103 CREATE TABLE IF NOT EXISTS ServerProperties(
104 server VARCHAR(64) NOT NULL,
105 property INTEGER, value TEXT,
106 PRIMARY KEY(server, property)
107 );
108
109 CREATE INDEX IF NOT EXISTS ChildrenIndex ON Resources(parentId);
110 CREATE INDEX IF NOT EXISTS PublicIndex ON Resources(publicId);
111 CREATE INDEX IF NOT EXISTS ResourceTypeIndex ON Resources(resourceType);
112 CREATE INDEX IF NOT EXISTS PatientRecyclingIndex ON PatientRecyclingOrder(patientId);
113
114 CREATE INDEX IF NOT EXISTS MainDicomTagsIndex ON MainDicomTags(id);
115 CREATE INDEX IF NOT EXISTS DicomIdentifiersIndex1 ON DicomIdentifiers(id);
116 CREATE INDEX IF NOT EXISTS DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement);
117 CREATE INDEX IF NOT EXISTS DicomIdentifiersIndexValues ON DicomIdentifiers(value);
118
119 CREATE INDEX IF NOT EXISTS ChangesIndex ON Changes(internalId);
120 CREATE INDEX IF NOT EXISTS LabelsIndex1 ON LABELS(id);
121 CREATE INDEX IF NOT EXISTS LabelsIndex2 ON LABELS(label);
122
123 ------------------- Trigram index creation -------------------
124
125
126 -- Apply fix for performance issue (speed up wildcard search by using GIN trigrams). This implements the patch suggested
127 -- in issue #47, BUT we also keep the original "DicomIdentifiersIndexValues", as it leads to better
128 -- performance for "strict" searches (i.e. searches involving no wildcard).
129 -- https://www.postgresql.org/docs/current/static/pgtrgm.html
130 -- https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=47
131
132 DO $body$
133 begin
134 IF EXISTS (SELECT 1 FROM pg_available_extensions WHERE name='pg_trgm') THEN
135 CREATE EXTENSION IF NOT EXISTS pg_trgm;
136 CREATE INDEX IF NOT EXISTS DicomIdentifiersIndexValues2 ON DicomIdentifiers USING gin(value gin_trgm_ops);
137 ELSE
138 RAISE NOTICE 'pg_trgm extension is not available on you system';
139 END IF;
140 END $body$;
141
142
143 ------------------- PatientAdded trigger & PatientRecyclingOrder -------------------
144 DROP TRIGGER IF EXISTS PatientAdded ON Resources;
145
146 CREATE OR REPLACE FUNCTION PatientAddedOrUpdated(
147 IN patient_id BIGINT,
148 IN is_update BIGINT
149 )
150 RETURNS VOID AS $body$
151 BEGIN
152 DECLARE
153 newSeq BIGINT;
154 BEGIN
155 UPDATE GlobalIntegers SET value = value + 1 WHERE key = 7 RETURNING value INTO newSeq;
156 IF is_update > 0 THEN
157 -- Note: Protected patients are not listed in this table ! So, they won't be updated
158 UPDATE PatientRecyclingOrder SET seq = newSeq WHERE PatientRecyclingOrder.patientId = patient_id;
159 ELSE
160 INSERT INTO PatientRecyclingOrder VALUES (newSeq, patient_id);
161 END IF;
162 END;
163 END;
164 $body$ LANGUAGE plpgsql;
165
166 CREATE OR REPLACE FUNCTION PatientAddedFunc()
167 RETURNS TRIGGER AS $body$
168 BEGIN
169 -- The "0" corresponds to "OrthancPluginResourceType_Patient"
170 IF new.resourceType = 0 THEN
171 PERFORM PatientAddedOrUpdated(new.internalId, 0);
172 END IF;
173 RETURN NULL;
174 END;
175 $body$ LANGUAGE plpgsql;
176
177 CREATE TRIGGER PatientAdded
178 AFTER INSERT ON Resources
179 FOR EACH ROW
180 EXECUTE PROCEDURE PatientAddedFunc();
181
182 -- initial population of PatientRecyclingOrderSeq
183 INSERT INTO GlobalIntegers
184 SELECT 7, CAST(COALESCE(MAX(seq), 0) AS BIGINT) FROM PatientRecyclingOrder
185 ON CONFLICT DO NOTHING;
186
187
188 ------------------- ResourceDeleted trigger -------------------
189 DROP TRIGGER IF EXISTS ResourceDeleted ON Resources;
190
191 -- The following trigger combines 2 triggers from SQLite:
192 -- ResourceDeleted + ResourceDeletedParentCleaning
193 CREATE OR REPLACE FUNCTION ResourceDeletedFunc()
194 RETURNS TRIGGER AS $body$
195 BEGIN
196 -- RAISE NOTICE 'ResourceDeletedFunc %', old.publicId;
197 INSERT INTO DeletedResources VALUES (old.resourceType, old.publicId);
198
199 -- If this resource is the latest child, delete the parent
200 DELETE FROM Resources WHERE internalId = old.parentId
201 AND NOT EXISTS (SELECT 1 FROM Resources WHERE parentId = old.parentId);
202 RETURN NULL;
203 END;
204 $body$ LANGUAGE plpgsql;
205
206 CREATE TRIGGER ResourceDeleted
207 AFTER DELETE ON Resources
208 FOR EACH ROW
209 EXECUTE PROCEDURE ResourceDeletedFunc();
210
211
212 ------------------- DeleteResource function -------------------
213
214 CREATE OR REPLACE FUNCTION DeleteResource(
215 IN id BIGINT,
216 OUT remaining_ancestor_resource_type INTEGER,
217 OUT remaining_anncestor_public_id TEXT) AS $body$
218
219 DECLARE
220 deleted_row RECORD;
221 locked_row RECORD;
222
223 BEGIN
224
225 SET client_min_messages = warning; -- suppress NOTICE: relation "deletedresources" already exists, skipping
226
227 -- note: temporary tables are created at session (connection) level -> they are likely to exist
228 -- these tables are used by the triggers
229 CREATE TEMPORARY TABLE IF NOT EXISTS DeletedResources(
230 resourceType INTEGER NOT NULL,
231 publicId VARCHAR(64) NOT NULL
232 );
233
234 RESET client_min_messages;
235
236 -- clear the temporary table in case it has been created earlier in the session
237 DELETE FROM DeletedResources;
238
239 -- create/clear the DeletedFiles temporary table
240 PERFORM CreateDeletedFilesTemporaryTable();
241
242 -- Before deleting an object, we need to lock its parent until the end of the transaction to avoid that
243 -- 2 threads deletes the last 2 instances of a series at the same time -> none of them would realize
244 -- that they are deleting the last instance and the parent resources would not be deleted.
245 -- Locking only the immediate parent is sufficient to prevent from this.
246 SELECT * INTO locked_row FROM resources WHERE internalid = (SELECT parentid FROM resources WHERE internalid = id) FOR UPDATE;
247
248 -- delete the resource itself
249 DELETE FROM Resources WHERE internalId=id RETURNING * INTO deleted_row;
250 -- note: there is a ResourceDeletedFunc trigger that will execute here and delete the parents if there are no remaining children +
251
252 -- If this resource still has siblings, keep track of the remaining parent
253 -- (a parent that must not be deleted but whose LastUpdate must be updated)
254 SELECT resourceType, publicId INTO remaining_ancestor_resource_type, remaining_anncestor_public_id
255 FROM Resources
256 WHERE internalId = deleted_row.parentId
257 AND EXISTS (SELECT 1 FROM Resources WHERE parentId = deleted_row.parentId);
258
259 END;
260
261 $body$ LANGUAGE plpgsql;
262
263 CREATE OR REPLACE FUNCTION CreateDeletedFilesTemporaryTable(
264 ) RETURNS VOID AS $body$
265
266 BEGIN
267
268 SET client_min_messages = warning; -- suppress NOTICE: relation "deletedresources" already exists, skipping
269
270 -- note: temporary tables are created at session (connection) level -> they are likely to exist
271 CREATE TEMPORARY TABLE IF NOT EXISTS DeletedFiles(
272 uuid VARCHAR(64) NOT NULL,
273 fileType INTEGER,
274 compressedSize BIGINT,
275 uncompressedSize BIGINT,
276 compressionType INTEGER,
277 uncompressedHash VARCHAR(40),
278 compressedHash VARCHAR(40)
279 );
280
281 RESET client_min_messages;
282
283 -- clear the temporary table in case it has been created earlier in the session
284 DELETE FROM DeletedFiles;
285 END;
286
287 $body$ LANGUAGE plpgsql;
288
289
290 CREATE OR REPLACE FUNCTION AttachedFileDeletedFunc()
291 RETURNS TRIGGER AS $body$
292 BEGIN
293 INSERT INTO DeletedFiles VALUES
294 (old.uuid, old.filetype, old.compressedSize,
295 old.uncompressedSize, old.compressionType,
296 old.uncompressedHash, old.compressedHash);
297 RETURN NULL;
298 END;
299 $body$ LANGUAGE plpgsql;
300
301 CREATE TRIGGER AttachedFileDeleted
302 AFTER DELETE ON AttachedFiles
303 FOR EACH ROW
304 EXECUTE PROCEDURE AttachedFileDeletedFunc();
305
306
307 ------------------- Fast Statistics -------------------
308
309 -- initial population of GlobalIntegers if not already there
310 INSERT INTO GlobalIntegers
311 SELECT 0, CAST(COALESCE(SUM(compressedSize), 0) AS BIGINT) FROM AttachedFiles
312 ON CONFLICT DO NOTHING;
313
314 INSERT INTO GlobalIntegers
315 SELECT 1, CAST(COALESCE(SUM(uncompressedSize), 0) AS BIGINT) FROM AttachedFiles
316 ON CONFLICT DO NOTHING;
317
318 INSERT INTO GlobalIntegers
319 SELECT 2, CAST(COALESCE(COUNT(*), 0) AS BIGINT) FROM Resources WHERE resourceType = 0 -- Count patients
320 ON CONFLICT DO NOTHING;
321
322 INSERT INTO GlobalIntegers
323 SELECT 3, CAST(COALESCE(COUNT(*), 0) AS BIGINT) FROM Resources WHERE resourceType = 1 -- Count studies
324 ON CONFLICT DO NOTHING;
325
326 INSERT INTO GlobalIntegers
327 SELECT 4, CAST(COALESCE(COUNT(*), 0) AS BIGINT) FROM Resources WHERE resourceType = 2 -- Count series
328 ON CONFLICT DO NOTHING;
329
330 INSERT INTO GlobalIntegers
331 SELECT 5, CAST(COALESCE(COUNT(*), 0) AS BIGINT) FROM Resources WHERE resourceType = 3 -- Count instances
332 ON CONFLICT DO NOTHING;
333
334
335 -- this table stores all changes that needs to be performed to the GlobalIntegers table
336 -- This way, each transaction can add row independently in this table without having to lock
337 -- any row (which was the case with previous FastTotalSize).
338 -- These changes will be applied at regular interval by an external thread or when someone
339 -- requests the statistics
340 CREATE TABLE IF NOT EXISTS GlobalIntegersChanges(
341 key INTEGER,
342 value BIGINT);
343
344 CREATE OR REPLACE FUNCTION UpdateSingleStatistic(
345 IN statistics_key INTEGER,
346 OUT new_value BIGINT
347 ) AS $body$
348 BEGIN
349
350 -- Delete the current changes, sum them and update the GlobalIntegers row.
351 -- New rows can be added in the meantime, they won't be deleted or summed.
352 WITH deleted_rows AS (
353 DELETE FROM GlobalIntegersChanges
354 WHERE GlobalIntegersChanges.key = statistics_key
355 RETURNING value
356 )
357 UPDATE GlobalIntegers
358 SET value = value + (
359 SELECT COALESCE(SUM(value), 0)
360 FROM deleted_rows
361 )
362 WHERE GlobalIntegers.key = statistics_key
363 RETURNING value INTO new_value;
364
365 END;
366 $body$ LANGUAGE plpgsql;
367
368
369 CREATE OR REPLACE FUNCTION UpdateStatistics(
370 OUT patients_cunt BIGINT,
371 OUT studies_count BIGINT,
372 OUT series_count BIGINT,
373 OUT instances_count BIGINT,
374 OUT total_compressed_size BIGINT,
375 OUT total_uncompressed_size BIGINT
376 ) AS $body$
377 BEGIN
378
379 SELECT UpdateSingleStatistic(0) INTO total_compressed_size;
380 SELECT UpdateSingleStatistic(1) INTO total_uncompressed_size;
381 SELECT UpdateSingleStatistic(2) INTO patients_cunt;
382 SELECT UpdateSingleStatistic(3) INTO studies_count;
383 SELECT UpdateSingleStatistic(4) INTO series_count;
384 SELECT UpdateSingleStatistic(5) INTO instances_count;
385
386 END;
387 $body$ LANGUAGE plpgsql;
388
389
390 CREATE OR REPLACE FUNCTION IncrementResourcesTrackerFunc()
391 RETURNS TRIGGER AS $$
392 BEGIN
393 INSERT INTO GlobalIntegersChanges VALUES(new.resourceType + 2, 1);
394 RETURN NULL;
395 END;
396 $$ LANGUAGE plpgsql;
397
398 CREATE OR REPLACE FUNCTION DecrementResourcesTrackerFunc()
399 RETURNS TRIGGER AS $$
400 BEGIN
401 INSERT INTO GlobalIntegersChanges VALUES(old.resourceType + 2, -1);
402 RETURN NULL;
403 END;
404 $$ LANGUAGE plpgsql;
405
406
407 CREATE OR REPLACE FUNCTION AttachedFileIncrementSizeFunc()
408 RETURNS TRIGGER AS $body$
409 BEGIN
410 INSERT INTO GlobalIntegersChanges VALUES(0, new.compressedSize);
411 INSERT INTO GlobalIntegersChanges VALUES(1, new.uncompressedSize);
412 RETURN NULL;
413 END;
414 $body$ LANGUAGE plpgsql;
415
416 CREATE OR REPLACE FUNCTION AttachedFileDecrementSizeFunc()
417 RETURNS TRIGGER AS $body$
418 BEGIN
419 INSERT INTO GlobalIntegersChanges VALUES(0, -old.compressedSize);
420 INSERT INTO GlobalIntegersChanges VALUES(1, -old.uncompressedSize);
421 RETURN NULL;
422 END;
423 $body$ LANGUAGE plpgsql;
424
425 DROP TRIGGER IF EXISTS AttachedFileIncrementSize on AttachedFiles;
426 CREATE TRIGGER AttachedFileIncrementSize
427 AFTER INSERT ON AttachedFiles
428 FOR EACH ROW
429 EXECUTE PROCEDURE AttachedFileIncrementSizeFunc();
430
431 DROP TRIGGER IF EXISTS AttachedFileDecrementSize on AttachedFiles;
432 CREATE TRIGGER AttachedFileDecrementSize
433 AFTER DELETE ON AttachedFiles
434 FOR EACH ROW
435 EXECUTE PROCEDURE AttachedFileDecrementSizeFunc();
436
437 DROP TRIGGER IF EXISTS IncrementResourcesTracker on Resources;
438 CREATE TRIGGER IncrementResourcesTracker
439 AFTER INSERT ON Resources
440 FOR EACH ROW
441 EXECUTE PROCEDURE IncrementResourcesTrackerFunc();
442
443 DROP TRIGGER IF EXISTS DecrementResourcesTracker on Resources;
444 CREATE TRIGGER DecrementResourcesTracker
445 AFTER DELETE ON Resources
446 FOR EACH ROW
447 EXECUTE PROCEDURE DecrementResourcesTrackerFunc();
448
449
450 ------------------- InsertOrUpdateMetadata function -------------------
451 CREATE OR REPLACE FUNCTION InsertOrUpdateMetadata(resource_ids BIGINT[],
452 metadata_types INTEGER[],
453 metadata_values TEXT[],
454 revisions INTEGER[])
455 RETURNS VOID AS $body$
456 BEGIN
457 FOR i IN 1 .. ARRAY_LENGTH(resource_ids, 1) LOOP
458 -- RAISE NOTICE 'Parameter %: % % %', i, resource_ids[i], metadata_types[i], metadata_values[i];
459 INSERT INTO Metadata VALUES(resource_ids[i], metadata_types[i], metadata_values[i], revisions[i])
460 ON CONFLICT (id, type) DO UPDATE SET value = EXCLUDED.value, revision = EXCLUDED.revision;
461 END LOOP;
462
463 END;
464 $body$ LANGUAGE plpgsql;
465
466
467 ------------------- GetLastChange function -------------------
468 DROP TRIGGER IF EXISTS InsertedChange ON Changes;
469
470 -- insert the value if not already there
471 INSERT INTO GlobalIntegers
472 SELECT 6, CAST(COALESCE(MAX(seq), 0) AS BIGINT) FROM Changes
473 ON CONFLICT DO NOTHING;
474
475 CREATE OR REPLACE FUNCTION InsertedChangeFunc()
476 RETURNS TRIGGER AS $body$
477 BEGIN
478 UPDATE GlobalIntegers SET value = new.seq WHERE key = 6;
479 RETURN NULL;
480 END;
481 $body$ LANGUAGE plpgsql;
482
483 CREATE TRIGGER InsertedChange
484 AFTER INSERT ON Changes
485 FOR EACH ROW
486 EXECUTE PROCEDURE InsertedChangeFunc();
487
488
489 ------------------- CreateInstance function -------------------
490 CREATE OR REPLACE FUNCTION CreateInstance(
491 IN patient_public_id TEXT,
492 IN study_public_id TEXT,
493 IN series_public_id TEXT,
494 IN instance_public_id TEXT,
495 OUT is_new_patient BIGINT,
496 OUT is_new_study BIGINT,
497 OUT is_new_series BIGINT,
498 OUT is_new_instance BIGINT,
499 OUT patient_internal_id BIGINT,
500 OUT study_internal_id BIGINT,
501 OUT series_internal_id BIGINT,
502 OUT instance_internal_id BIGINT) AS $body$
503
504 BEGIN
505 is_new_patient := 1;
506 is_new_study := 1;
507 is_new_series := 1;
508 is_new_instance := 1;
509
510 BEGIN
511 INSERT INTO "resources" VALUES (DEFAULT, 0, patient_public_id, NULL) RETURNING internalid INTO patient_internal_id;
512 EXCEPTION
513 WHEN unique_violation THEN
514 is_new_patient := 0;
515 SELECT internalid INTO patient_internal_id FROM "resources" WHERE publicId = patient_public_id FOR UPDATE; -- also locks the resource and its parent to prevent from deletion while we complete this transaction
516 END;
517
518 BEGIN
519 INSERT INTO "resources" VALUES (DEFAULT, 1, study_public_id, patient_internal_id) RETURNING internalid INTO study_internal_id;
520 EXCEPTION
521 WHEN unique_violation THEN
522 is_new_study := 0;
523 SELECT internalid INTO study_internal_id FROM "resources" WHERE publicId = study_public_id FOR UPDATE; -- also locks the resource and its parent to prevent from deletion while we complete this transaction END;
524 END;
525
526 BEGIN
527 INSERT INTO "resources" VALUES (DEFAULT, 2, series_public_id, study_internal_id) RETURNING internalid INTO series_internal_id;
528 EXCEPTION
529 WHEN unique_violation THEN
530 is_new_series := 0;
531 SELECT internalid INTO series_internal_id FROM "resources" WHERE publicId = series_public_id FOR UPDATE; -- also locks the resource and its parent to prevent from deletion while we complete this transaction END;
532 END;
533
534 BEGIN
535 INSERT INTO "resources" VALUES (DEFAULT, 3, instance_public_id, series_internal_id) RETURNING internalid INTO instance_internal_id;
536 EXCEPTION
537 WHEN unique_violation THEN
538 is_new_instance := 0;
539 SELECT internalid INTO instance_internal_id FROM "resources" WHERE publicId = instance_public_id FOR UPDATE; -- also locks the resource and its parent to prevent from deletion while we complete this transaction
540 END;
541
542 IF is_new_instance > 0 THEN
543 -- Move the patient to the end of the recycling order.
544 PERFORM PatientAddedOrUpdated(patient_internal_id, 1);
545 END IF;
546 END;
547
548 $body$ LANGUAGE plpgsql;
549
550
551
552 -- set the global properties that actually documents the DB version, revision and some of the capabilities
553 DELETE FROM GlobalProperties WHERE property IN (1, 4, 6, 10, 11, 12, 13);
554 INSERT INTO GlobalProperties VALUES (1, 6); -- GlobalProperty_DatabaseSchemaVersion
555 INSERT INTO GlobalProperties VALUES (4, 2); -- GlobalProperty_DatabasePatchLevel
556 INSERT INTO GlobalProperties VALUES (6, 1); -- GlobalProperty_GetTotalSizeIsFast
557 INSERT INTO GlobalProperties VALUES (10, 1); -- GlobalProperty_HasTrigramIndex
558 INSERT INTO GlobalProperties VALUES (11, 3); -- GlobalProperty_HasCreateInstance -- this is actually the 3rd version of HasCreateInstance
559 INSERT INTO GlobalProperties VALUES (12, 1); -- GlobalProperty_HasFastCountResources
560 INSERT INTO GlobalProperties VALUES (13, 1); -- GlobalProperty_GetLastChangeIndex