Statistics
| Revision:

root / online_search / indexer / tables_pgsql.sql @ 1818

History | View | Annotate | Download (20.8 KB)

1
CREATE LANGUAGE plpgsql;
2

                
3
CREATE TABLE row_counts (relname text PRIMARY KEY, reltuples numeric);
4
CLUSTER row_counts USING row_counts_pkey;
5

                
6
CREATE OR REPLACE FUNCTION count_trig()
7
    RETURNS TRIGGER AS
8
    $$
9
       DECLARE
10
    BEGIN
11
    IF TG_OP = 'INSERT' THEN
12
       EXECUTE 'UPDATE row_counts set reltuples=reltuples +1 where relname = ''' || TG_RELNAME || '''';
13
       RETURN NEW;
14
    ELSIF TG_OP = 'DELETE' THEN
15
       EXECUTE 'UPDATE row_counts set reltuples=reltuples -1 where relname = ''' || TG_RELNAME || '''';
16
       RETURN OLD;
17
    END IF;
18
    END;
19
 $$
20
 LANGUAGE 'plpgsql';
21
CREATE TABLE sph_counter (counter_id INTEGER NOT NULL PRIMARY KEY, max_doc_id BIGINT NOT NULL);
22
INSERT INTO sph_counter VALUES (1,0);
23

                
24
CREATE TABLE newsgroups
25
 (
26
         newsgroup_id                    SERIAL NOT NULL PRIMARY KEY,
27
         newsgroup                       VARCHAR(256) NOT NULL,
28
         indexing_since                  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
29
         oldest_file_stamp               TIMESTAMP,
30
         newest_file_stamp               TIMESTAMP,
31
         last_checked                    TIMESTAMP,
32
         prev_last_checked               TIMESTAMP,
33
         bytes_transferred               BIGINT NOT NULL DEFAULT 0,
34
         last_article_id                 BIGINT NOT NULL DEFAULT 0,
35
         number_of_files                 BIGINT NOT NULL DEFAULT 0,
36
         number_of_files_unsorted        BIGINT NOT NULL DEFAULT 0
37
 );
38
ALTER TABLE newsgroups ADD CONSTRAINT newsgroups_newsgroup UNIQUE (newsgroup);
39

                
40
CREATE SEQUENCE collection_id_seq NO CYCLE;
41
CREATE TABLE collections
42
 (
43
         collection_id           BIGINT NOT NULL PRIMARY KEY DEFAULT NEXTVAL('collection_id_seq'),
44
         newsgroup_id            INT NOT NULL REFERENCES newsgroups,
45
         stamp                   TIMESTAMP NOT NULL,
46
         hash                    BIGINT NOT NULL,
47
         collection_name         VARCHAR(256) NOT NULL,
48
         display_collection_name VARCHAR(256) NOT NULL,
49
         poster                  VARCHAR(128) NOT NULL,
50
         total_size              BIGINT NOT NULL,
51
         num_parts_found         INT NOT NULL,
52
         num_parts_expected      INT NOT NULL,
53
         num_regular_files       INT NOT NULL,
54
         num_par2_files          INT NOT NULL,
55
         stamp_changed_in_db     TIMESTAMP NOT NULL
56
 );
57
CREATE INDEX collections_hash_idx ON collections(hash);
58
CLUSTER collections USING collections_pkey;
59

                
60
CREATE TABLE files_in_collections
61
 (
62
         collection_id           BIGINT NOT NULL REFERENCES collections,
63
         file_id                 BIGINT NOT NULL,
64
         stamp                   TIMESTAMP NOT NULL,
65
                                 PRIMARY KEY (collection_id, file_id)
66
 );
67
CREATE TABLE files_in_collections_unsorted (PRIMARY KEY (file_id)) INHERITS (files_in_collections);
68
CREATE INDEX files_in_collections_unsorted_stamp_idx ON files_in_collections_unsorted(stamp);
69
CLUSTER files_in_collections_unsorted USING files_in_collections_unsorted_pkey;
70
ALTER TABLE files_in_collections_unsorted ADD FOREIGN KEY (file_id) REFERENCES files_unsorted;
71
ALTER TABLE files_in_collections_unsorted NO INHERIT files_in_collections;
72
CREATE TRIGGER files_in_collections_unsorted_count_delete_trig AFTER DELETE on files_in_collections_unsorted FOR EACH ROW EXECUTE PROCEDURE count_trig();
73
CREATE TRIGGER files_in_collections_unsorted_count_insert_trig AFTER INSERT on files_in_collections_unsorted FOR EACH ROW EXECUTE PROCEDURE count_trig();
74
INSERT INTO row_counts VALUES('files_in_collections_unsorted', 0);
75

                
76
CREATE SEQUENCE file_id_seq NO CYCLE;
77
CREATE TYPE file_type AS ENUM ('Unknown', 'RAR', 'PAR', 'PAR2', 'SFV', 'NFO', 'NZB', 'Other');
78
CREATE TABLE files
79
 (
80
         file_id                 BIGINT NOT NULL PRIMARY KEY DEFAULT NEXTVAL('file_id_seq'),
81
         stamp                   TIMESTAMP NOT NULL,
82
         -- collection_id                BIGINT NOT NULL REFERENCES collections,
83
         newsgroup_id            INT NOT NULL REFERENCES newsgroups,
84
         hash                    BIGINT NOT NULL,
85
         subject                 VARCHAR(256) NOT NULL,
86
         poster                  VARCHAR(128) NOT NULL,
87
         filename                VARCHAR(256) NOT NULL,
88
         file_type               file_type NOT NULL DEFAULT 'Unknown',
89
         file_size               BIGINT NOT NULL,
90
         num_parts_found         INT NOT NULL,
91
         num_parts_expected      INT NOT NULL,
92
         stamp_changed_in_db     TIMESTAMP NOT NULL
93
 );
94
CREATE TRIGGER files_count_delete_trig AFTER DELETE on files FOR EACH ROW EXECUTE PROCEDURE count_trig();
95
CREATE TRIGGER files_count_insert_trig AFTER INSERT on files FOR EACH ROW EXECUTE PROCEDURE count_trig();
96
INSERT INTO row_counts VALUES('files', 0);
97

                
98
CREATE TABLE files_unsorted (PRIMARY KEY (file_id)) INHERITS (files);
99
ALTER TABLE files_unsorted ADD FOREIGN KEY (newsgroup_id) REFERENCES newsgroups;
100
ALTER TABLE files_unsorted NO INHERIT files;
101
CREATE INDEX files_unsorted_hash_idx ON files_unsorted(hash);
102
CREATE INDEX files_unsorted_newsgroup_idx ON files_unsorted(newsgroup_id);
103
CREATE INDEX files_unsorted_stamp_changed_idx ON files_unsorted(stamp_changed_in_db);
104
CREATE INDEX files_unsorted_stamp_idx ON files_unsorted(stamp);
105
CLUSTER files_unsorted USING files_unsorted_newsgroup_idx;
106
CREATE TRIGGER files_unsorted_count_delete_trig AFTER DELETE on files_unsorted FOR EACH ROW EXECUTE PROCEDURE count_trig();
107
CREATE TRIGGER files_unsorted_count_insert_trig AFTER INSERT on files_unsorted FOR EACH ROW EXECUTE PROCEDURE count_trig();
108
INSERT INTO row_counts VALUES('files_unsorted', 0);
109

                
110
CREATE TABLE file_parts
111
      (
112
              file_id                 BIGINT NOT NULL PRIMARY KEY REFERENCES files,
113
              stamp                   TIMESTAMP NOT NULL,
114
              parts                   TEXT NOT NULL
115
      );
116
CREATE TRIGGER file_parts_count_delete_trig AFTER DELETE on file_parts FOR EACH ROW EXECUTE PROCEDURE count_trig();
117
CREATE TRIGGER file_parts_count_insert_trig AFTER INSERT on file_parts FOR EACH ROW EXECUTE PROCEDURE count_trig();
118
INSERT INTO row_counts VALUES('file_parts', 0);
119

                
120
CREATE TABLE file_parts_unsorted (PRIMARY KEY (file_id)) INHERITS (file_parts);
121
CREATE INDEX file_parts_unsorted_stamp_idx ON file_parts_unsorted(stamp);
122
CLUSTER file_parts_unsorted USING file_parts_unsorted_pkey;
123
ALTER TABLE file_parts_unsorted ADD FOREIGN KEY (file_id) REFERENCES files_unsorted;
124
ALTER TABLE file_parts_unsorted NO INHERIT file_parts;
125
CREATE TRIGGER file_parts_unsorted_count_delete_trig AFTER DELETE on file_parts_unsorted FOR EACH ROW EXECUTE PROCEDURE count_trig();
126
CREATE TRIGGER file_parts_unsorted_count_insert_trig AFTER INSERT on file_parts_unsorted FOR EACH ROW EXECUTE PROCEDURE count_trig();
127
INSERT INTO row_counts VALUES('file_parts_unsorted', 0);
128

                
129
-- CREATE TABLE files_in_newsgroups
130
--    (
131
--            file_id                 BIGINT NOT NULL REFERENCES files,
132
--            stamp                   TIMESTAMP NOT NULL,
133
--            newsgroup_id            INT NOT NULL REFERENCES newsgroups,
134
--                                    PRIMARY KEY(file_id, newsgroup_id)
135
--    );
136

                
137
CREATE TABLE statistics
138
      (
139
              statistic_id            BIGSERIAL NOT NULL PRIMARY KEY,
140
              stamp                   TIMESTAMP NOT NULL,
141
              query                   VARCHAR(128) NOT NULL,
142
              number_of_hits          INT NOT NULL,
143
              number_of_results       INT NOT NULL,
144
              time_needed_for_sphinx  REAL NOT NULL,
145
              time_needed_for_db      REAL NOT NULL,
146
              time_needed_for_php     REAL NOT NULL
147
      );
148

                
149
CREATE TABLE newsgroup_statistics
150
      (
151
              newsgroup_id            BIGINT NOT NULL REFERENCES newsgroups,
152
              day                     DATE NOT NULL,
153
              num_files               BIGINT NOT NULL,
154
              PRIMARY KEY(newsgroup_id, day)
155
      );
156

                
157
-- procedure to create a specific partition
158
-- the first argument is the name of the base table which needs to be partitioned
159
-- the second argument is the name of the primary key of the base table
160
-- the third argument is the name of the foreign key (can be NULL)
161
-- the fourth argument is the name of the table which needs to be references to (can be NULL)
162
-- the fifth argument is a stamp containing the week for which a partition needs to be made
163
CREATE OR REPLACE FUNCTION create_partition(VARCHAR(64), VARCHAR(64), VARCHAR(64), VARCHAR(64), TIMESTAMP WITH TIME ZONE) RETURNS VOID AS $$
164
DECLARE
165
      v_base_table            ALIAS FOR $1;
166
      v_base_table_pk         ALIAS FOR $2;
167
      v_reference_fk          ALIAS FOR $3;
168
      v_reference_table       ALIAS FOR $4;
169
      v_reference_partition   VARCHAR(64);
170
      v_partition_name        VARCHAR(64);
171

                
172
      v_date_from_incoming    ALIAS FOR $5;
173
      v_date_from             TIMESTAMP;
174
      v_date_to               TIMESTAMP;
175

                
176
      -- used just for checking existence of the partitions
177
      v_exists                BOOLEAN;
178

                
179
BEGIN
180

                
181
      IF (v_base_table IS NULL) THEN
182
              RAISE EXCEPTION 'Missing argument base_table';
183
      END IF;
184

                
185
        IF (v_base_table_pk IS NULL) THEN
186
                RAISE EXCEPTION 'Missing argument base_table_pk';
187
        END IF;
188

                
189
      IF (v_date_from_incoming IS NULL) THEN
190
                RAISE EXCEPTION 'Missing argument date_from';
191
        END IF;
192

                
193
      v_date_from := date_trunc('week', v_date_from_incoming);
194
      v_date_to := v_date_from + '1 week';
195
      v_partition_name := v_base_table || '_' || TO_CHAR(v_date_from, 'IYYY_IW');
196

                
197
      SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables WHERE schemaname = 'public' AND tablename = v_partition_name;
198

                
199
      IF (NOT v_exists) THEN
200

                
201
              EXECUTE 'CREATE TABLE ' || v_partition_name || ' (PRIMARY KEY (' || v_base_table_pk || '), CHECK (stamp >= ''' || v_date_from || ''' AND stamp < ''' || v_date_to || ''')) INHERITS (' || v_base_table || ')';
202

                
203
              -- if you need to create indexes / foreign keys / whatever on the partition, you may do it here
204
              IF (v_reference_table IS NOT NULL) THEN
205
                      v_reference_partition := v_reference_table || TO_CHAR(v_date_from, '_IYYY_IW');
206
                      EXECUTE 'ALTER TABLE ' || v_partition_name || ' ADD FOREIGN KEY (' || v_reference_fk || ') REFERENCES ' || v_reference_partition || ' (' || v_reference_fk || ')';
207
              END IF;
208

                
209
              EXECUTE 'CREATE INDEX ' || v_partition_name || '_stamp_idx ON ' || v_partition_name || '(stamp)';
210

                
211
              IF (v_base_table = 'files') THEN
212
                      EXECUTE 'CREATE INDEX ' || v_partition_name || '_hash_idx ON ' || v_partition_name || '(hash)';
213
                      EXECUTE 'CREATE INDEX ' || v_partition_name || '_newsgroup_idx ON ' || v_partition_name || '(newsgroup_id)';
214
                      EXECUTE 'CREATE INDEX ' || v_partition_name || '_stamp_changed_idx ON ' || v_partition_name || '(stamp_changed_in_db)';
215
                      EXECUTE 'ALTER TABLE ' || v_partition_name || ' ADD FOREIGN KEY (newsgroup_id) REFERENCES newsgroups';
216
                      EXECUTE 'CLUSTER ' || v_partition_name || ' USING ' || v_partition_name || '_newsgroup_idx';
217
              END IF;
218
              IF (v_base_table = 'file_parts') THEN
219
                      EXECUTE 'CLUSTER ' || v_partition_name || ' USING ' || v_partition_name || '_stamp_idx';
220
              END IF;
221
              IF (v_base_table = 'files_in_collections') THEN
222
                      EXECUTE 'CLUSTER ' || v_partition_name || ' USING ' || v_partition_name || '_stamp_idx';
223
              END IF;
224

                
225
              EXECUTE 'CREATE TRIGGER ' || v_partition_name || '_count_delete_trig AFTER DELETE on ' || v_partition_name || ' FOR EACH ROW EXECUTE PROCEDURE count_trig()';
226
              EXECUTE 'CREATE TRIGGER ' || v_partition_name || '_count_insert_trig AFTER INSERT on ' || v_partition_name || ' FOR EACH ROW EXECUTE PROCEDURE count_trig()';
227
              EXECUTE 'INSERT INTO row_counts VALUES(''' || v_partition_name || ''', 0)';
228
      END IF;
229

                
230
END;
231
$$ LANGUAGE plpgsql;
232

                
233
-- procedure that manages the partitions
234
-- the first argument is the name of the base table which needs to be partitioned
235
-- the second argument is the name of the primary key of the base table
236
-- the third argument is the name of the foreign key (can be NULL)
237
-- the fourth argument is the name of the table which needs to be references to (can be NULL)
238
CREATE OR REPLACE FUNCTION manage_partitions(VARCHAR(64), VARCHAR(64), VARCHAR(64), VARCHAR(64)) RETURNS void AS $$
239
DECLARE
240

                
241
      -- name of the next partition (and interval boundaries)
242
      v_base_table            ALIAS FOR $1;
243
      v_base_table_pk         ALIAS FOR $2;
244
      v_reference_fk          ALIAS FOR $3;
245
      v_reference_table       ALIAS FOR $4;
246
        v_reference_partition VARCHAR(64);
247
      v_partition_name        VARCHAR(64);
248
      v_date_from             TIMESTAMP;
249
      v_date_to               TIMESTAMP;
250
      v_current_date          TIMESTAMP;
251
      v_offset                INTERVAL;
252

                
253
      -- used to prepare the partitioning trigger
254
      v_trigger               TEXT := '';
255
      v_trigger_upd           TEXT := '';
256

                
257
      -- used just for checking existence of the partitions
258
      v_exists                BOOLEAN;
259

                
260
      v_num                   INTEGER;
261

                
262
BEGIN
263

                
264
      IF (v_base_table IS NULL) THEN
265
              RAISE EXCEPTION 'Missing argument base_table';
266
      END IF;
267

                
268
      IF (v_base_table_pk IS NULL) THEN
269
              RAISE EXCEPTION 'Missing argument base_table_pk';
270
      END IF;
271

                
272
      v_current_date := current_timestamp;
273

                
274
      -- purge the very old partitions if they exist
275
      v_date_from := date_trunc('week', v_current_date - '507 days'::interval);
276
      v_partition_name := v_base_table || '_' || TO_CHAR(v_date_from, 'IYYY_IW');
277

                
278
      SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables WHERE schemaname = 'public' AND tablename = v_partition_name;
279

                
280
      IF (v_exists) THEN
281
              RAISE NOTICE 'Now trying to drop partition %', v_partition_name;
282
              BEGIN
283
                      EXECUTE 'DROP TABLE ' || v_partition_name;
284
                      EXECUTE 'DELETE FROM row_counts WHERE relname=''' || v_partition_name || '''';
285

                
286
                      IF (v_base_table = 'files') THEN
287
                              EXECUTE 'DELETE FROM newsgroup_statistics WHERE day < ''' || v_date_from || '''';
288
                      END IF;
289
              EXCEPTION
290
                      WHEN dependent_objects_still_exist THEN
291
                              RAISE NOTICE 'Unable to drop partition due to referential integrity. Please try again later';
292
              END;
293
      END IF;
294

                
295
      -- create partitions for 2 weeks ago, 1 week ago, current week and next week
296
      FOR i IN -2..1 LOOP
297

                
298
              -- create a partition for this week
299
              v_offset := '1 week'::interval * i;
300
              v_date_from := date_trunc('week', v_current_date + v_offset);
301
              v_partition_name := v_base_table || '_' || TO_CHAR(v_date_from, 'IYYY_IW');
302

                
303
              SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables WHERE schemaname = 'public' AND tablename = v_partition_name;
304

                
305
              IF (NOT v_exists) THEN
306

                
307
                      EXECUTE 'SELECT create_partition($1, $2, $3, $4, $5)' USING v_base_table, v_base_table_pk, v_reference_fk, v_reference_table, v_date_from;
308

                
309
              END IF;
310

                
311
      END LOOP;
312

                
313
      -- for optimalisation purposes we add the trigger in a special order
314
      -- the current week needs to be handled first, followed by next week, previous week, two weeks ago and the rest needs to head to 'unsorted'
315
      v_date_from := date_trunc('week', v_current_date);
316
      v_date_to := v_date_from + '1 week';
317
      v_partition_name := v_base_table || '_' || TO_CHAR(v_date_from, 'IYYY_IW');
318
      v_trigger := 'IF (NEW.stamp >= ''' || v_date_from || ''' AND NEW.stamp < ''' || v_date_to || ''') THEN INSERT INTO ' || v_partition_name || ' VALUES (NEW.*);';
319

                
320
      -- next week
321
      v_date_from := date_trunc('week', v_current_date + '1 week'::interval);
322
      v_date_to := v_date_from + '1 week';
323
      v_partition_name := v_base_table || '_' || TO_CHAR(v_date_from, 'IYYY_IW');
324
      v_trigger := v_trigger || ' ELSIF (NEW.stamp >= ''' || v_date_from || ''' AND NEW.stamp < ''' || v_date_to || ''') THEN INSERT INTO ' || v_partition_name || ' VALUES (NEW.*);';
325

                
326
      -- build triggers for all earlier weeks
327
      v_num = 1;
328
      LOOP
329

                
330
              v_offset := '1 week'::interval * v_num;
331
              v_date_from := date_trunc('week', v_current_date - v_offset);
332
              v_date_to := v_date_from + '1 week';
333
              v_partition_name := v_base_table || '_' || TO_CHAR(v_date_from, 'IYYY_IW');
334

                
335
              SELECT COUNT(*) = 1 INTO v_exists FROM pg_tables WHERE schemaname = 'public' AND tablename = v_partition_name;
336

                
337
              IF (NOT v_exists) THEN
338

                
339
                      EXIT;
340

                
341
              END IF;
342

                
343
              v_trigger := v_trigger || ' ELSIF (NEW.stamp >= ''' || v_date_from || ''' AND NEW.stamp < ''' || v_date_to || ''') THEN INSERT INTO ' || v_partition_name || ' VALUES (NEW.*);';
344

                
345
              v_num := v_num + 1;
346

                
347
      END LOOP;
348

                
349
      -- everything else
350
        v_trigger := v_trigger || ' ELSE INSERT INTO ' || v_base_table || '_unsorted VALUES (NEW.*); END IF;';
351

                
352
      -- prepare a new version of the trigger procedure distributing rows into partitions
353
      v_trigger := 'CREATE OR REPLACE FUNCTION partitioning_trigger_' || v_base_table || '() RETURNS trigger AS $t$ BEGIN ' || v_trigger || ' RETURN NULL; END; $t$ LANGUAGE plpgsql;';
354

                
355
      EXECUTE v_trigger;
356

                
357
      -- drop the old trigger first
358
      EXECUTE 'DROP TRIGGER IF EXISTS partition_rows_' || v_base_table || ' ON ' || v_base_table;
359

                
360
      -- create a new trigger
361
      EXECUTE 'CREATE TRIGGER partition_rows_' || v_base_table || ' BEFORE INSERT ON ' || v_base_table || ' FOR EACH ROW EXECUTE PROCEDURE partitioning_trigger_' || v_base_table || '()';
362

                
363
END;
364
$$ LANGUAGE plpgsql;
365

                
366
-- procedure to update statistics in the newsgroups table
367
-- the first argument is the newsgroup_id
368
-- the second argument is the last received article id
369
-- the third argument is the number of bytes transferred in this run
370
-- the fourth argument is the number of added files in this run
371
CREATE OR REPLACE FUNCTION update_newsgroup_info(INT, BIGINT, BIGINT, INT) RETURNS void AS $$
372
DECLARE
373

                
374
      v_newsgroup_id                  ALIAS FOR $1;
375
      v_last_article_id               ALIAS FOR $2;
376
      v_bytes_transferred             ALIAS FOR $3;
377
      v_num_files_added               ALIAS FOR $4;
378

                
379
      v_oldest_partition              VARCHAR(64);
380
      v_newest_partition              VARCHAR(64);
381

                
382
      -- calculated values
383
      v_record                        RECORD;
384
      v_min_files_stamp               TIMESTAMP;
385
      v_max_files_stamp               TIMESTAMP;
386
      v_count_files                   BIGINT;
387

                
388
      v_min_files_unsorted_stamp      TIMESTAMP;
389
      v_max_files_unsorted_stamp      TIMESTAMP;
390
      v_count_files_unsorted          BIGINT;
391

                
392
      v_offset                        INTEGER;
393
      v_partition_name                VARCHAR(64);
394
BEGIN
395

                
396
      IF (v_newsgroup_id IS NULL) THEN
397
              RAISE EXCEPTION 'Missing argument v_newsgroup_id';
398
      END IF;
399

                
400
      IF (v_last_article_id IS NULL) THEN
401
              RAISE EXCEPTION 'Missing argument v_last_article_id';
402
      END IF;
403

                
404
      IF (v_bytes_transferred IS NULL) THEN
405
              RAISE EXCEPTION 'Missing argument v_bytes_transferred';
406
      END IF;
407

                
408
      IF (v_num_files_added IS NULL) THEN
409
              RAISE EXCEPTION 'Missing argument v_num_files_added';
410
      END IF;
411

                
412
      -- If no new data has been received, only update the last_checked stamp
413
      IF (v_bytes_transferred = 0) THEN
414

                
415
              UPDATE newsgroups SET last_checked=CURRENT_TIMESTAMP WHERE newsgroup_id=v_newsgroup_id;
416

                
417
              RETURN;
418

                
419
      END IF;
420

                
421
      -- Find out the min(stamp), max(stamp) and count(*) of the unsorted partition
422
      SELECT min(stamp) AS min, max(stamp) AS max, count(*) AS count INTO v_record FROM files_unsorted WHERE newsgroup_id = v_newsgroup_id;
423
      --v_min_files_unsorted_stamp := v_record.min;
424
      --v_max_files_unsorted_stamp := v_record.max;
425
      v_count_files_unsorted := v_record.count;
426
      v_min_files_unsorted_stamp := NULL;
427
      v_max_files_unsorted_stamp := NULL;
428

                
429
      -- Find out the min(stamp) of the files table
430
      v_offset := 0;
431
      LOOP
432

                
433
              SELECT tablename INTO v_record FROM pg_tables WHERE schemaname = 'public' AND tablename LIKE 'files_20%' ORDER BY tablename LIMIT 1 OFFSET v_offset;
434
              v_partition_name := v_record.tablename;
435

                
436
              EXECUTE 'SELECT MIN(stamp) FROM ' || v_partition_name || ' WHERE newsgroup_id = ' || v_newsgroup_id INTO v_min_files_stamp;
437

                
438
              EXIT WHEN v_min_files_stamp IS NOT NULL;
439

                
440
              v_offset := v_offset + 1;
441

                
442
        END LOOP;
443

                
444
      -- Find out the max(stamp) of the files table
445
        v_offset := 0;
446
        LOOP
447

                
448
                SELECT tablename INTO v_record FROM pg_tables WHERE schemaname = 'public' AND tablename LIKE 'files_20%' ORDER BY tablename DESC LIMIT 1 OFFSET v_offset;
449
              v_partition_name := v_record.tablename;
450

                
451
              EXECUTE 'SELECT MAX(stamp) FROM ' || v_partition_name || ' WHERE newsgroup_id = ' || v_newsgroup_id INTO v_max_files_stamp;
452

                
453
                EXIT WHEN v_max_files_stamp IS NOT NULL;
454

                
455
                v_offset := v_offset + 1;
456

                
457
        END LOOP;
458

                
459
      UPDATE newsgroups SET 
460
                      last_article_id=v_last_article_id, 
461
                      bytes_transferred=bytes_transferred + v_bytes_transferred,
462
                      last_checked=CURRENT_TIMESTAMP,
463
                      prev_last_checked=LEAST(last_checked, current_timestamp - interval '2 hours'),
464
                      oldest_file_stamp=least(cast(v_min_files_stamp as timestamp), cast(v_min_files_unsorted_stamp as timestamp)),
465
                      newest_file_stamp=greatest(cast(v_max_files_stamp as timestamp), cast(v_max_files_unsorted_stamp as timestamp)),
466
                      number_of_files=number_of_files + v_num_files_added,
467
                      number_of_files_unsorted=v_count_files_unsorted 
468
              WHERE newsgroup_id=v_newsgroup_id;
469
END;
470
$$ LANGUAGE plpgsql;
471

                
472
-- procedure to update newsgroup statistics (used to generate graphs)
473
-- the first argument is the day for which the statistics need to be updated
474
CREATE OR REPLACE FUNCTION update_newsgroup_statistics(DATE) RETURNS INTEGER AS $$
475
DECLARE
476

                
477
      v_stamp                         ALIAS FOR $1;
478
      v_record                        RECORD;
479
      v_count                         INTEGER;
480
      v_exists                        BOOLEAN;
481

                
482
BEGIN
483

                
484
      IF (v_stamp IS NULL) THEN
485
              RAISE EXCEPTION 'Missing argument v_stamp';
486
      END IF;
487

                
488
      v_count := 0;
489

                
490
      FOR v_record IN SELECT newsgroup_id, count(*) AS num FROM files WHERE stamp >= v_stamp AND stamp < v_stamp + interval '1 day' GROUP by newsgroup_id LOOP
491

                
492
              -- Do we already have statistics for this day?
493
              SELECT COUNT(*) = 1 INTO v_exists FROM newsgroup_statistics WHERE newsgroup_id=v_record.newsgroup_id AND day=v_stamp;
494

                
495
              IF (v_exists) THEN
496
                      UPDATE newsgroup_statistics SET num_files=v_record.num WHERE newsgroup_id=v_record.newsgroup_id AND day=v_stamp;
497
              ELSE
498
                      INSERT INTO newsgroup_statistics (newsgroup_id, day, num_files) VALUES (v_record.newsgroup_id, v_stamp, v_record.num);
499
              END IF;
500

                
501
              v_count := v_count + 1;
502

                
503
      END LOOP;
504

                
505
      RETURN v_count;
506
END;
507
$$ LANGUAGE plpgsql;
508

                
509
-- procedure to update ALL newsgroup statistics
510
CREATE OR REPLACE FUNCTION update_all_newsgroup_statistics() RETURNS INTEGER AS $$
511
DECLARE
512

                
513
      v_stamp                         DATE;
514
      v_count                         INTEGER;
515

                
516
BEGIN
517

                
518
      -- Find out the oldest file stamp
519
      SELECT min(oldest_file_stamp) INTO v_stamp FROM newsgroups;
520

                
521
      IF (v_stamp IS NULL) THEN
522
              RETURN 0;
523
      END IF;
524

                
525
      v_count := 0;
526

                
527
      -- Loop through all the days from oldest_file_stamp to current_timestamp
528
      LOOP
529

                
530
              PERFORM update_newsgroup_statistics(v_stamp);
531

                
532
              v_count := v_count + 1;
533

                
534
              -- Stop when we've reached today
535
              EXIT WHEN v_stamp = date_trunc('day', current_timestamp);
536

                
537
              v_stamp := CAST((CAST(v_stamp AS TIMESTAMP) + INTERVAL '1 day') AS DATE);
538

                
539
      END LOOP;
540

                
541
      RETURN v_count;
542
END;
543
$$ LANGUAGE plpgsql;
544

                
545
-- SELECT manage_partitions('collections', 'collection_id', NULL, NULL);
546
-- SELECT manage_partitions('collections_in_newsgroups', 'collection_id', 'collection_id', 'collections');
547
-- SELECT manage_partitions('files', 'file_id', 'collection_id', 'collections');
548
SELECT manage_partitions('files', 'file_id', NULL, NULL);
549
SELECT manage_partitions('file_parts', 'file_id', 'file_id', 'files');
550
SELECT manage_partitions('files_in_collections', 'file_id', 'file_id', 'files');
551

                
552