]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/008.schema.query.sql
1. Add a boolean "negate" column to query.expression.
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 008.schema.query.sql
1 -- Script to create the query schema and the tables therein
2
3 BEGIN;
4
5 DROP SCHEMA IF EXISTS query CASCADE;
6 CREATE SCHEMA query;
7 COMMENT ON SCHEMA actor IS $$
8 /*
9  * Copyright (C) 2009  Equinox Software, Inc. / Georgia Public Library Service
10  * Scott McKellar <scott@esilibrary.com>
11  *
12  * Schema: query
13  *
14  * Contains tables designed to represent user-defined queries for
15  * reports and the like.
16  *
17  * ****
18  *
19  * This program is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU General Public License
21  * as published by the Free Software Foundation; either version 2
22  * of the License, or (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  */
29 $$;
30
31 CREATE TABLE  query.stored_query (
32         id            SERIAL         PRIMARY KEY,
33         type          TEXT           NOT NULL CONSTRAINT query_type CHECK
34                                      ( type IN ( 'SELECT', 'UNION', 'INTERSECT', 'EXCEPT' ) ),
35         use_all       BOOLEAN        NOT NULL DEFAULT FALSE,
36         use_distinct  BOOLEAN        NOT NULL DEFAULT FALSE,
37         from_clause   INT,           --REFERENCES query.from_clause
38                                      --DEFERRABLE INITIALLY DEFERRED,
39         where_clause  INT,           --REFERENCES query.expression
40                                      --DEFERRABLE INITIALLY DEFERRED,
41         having_clause INT            --REFERENCES query.expression
42                                      --DEFERRABLE INITIALLY DEFERRED
43 );
44
45 -- (Foreign keys to be defined later after other tables are created)
46
47 CREATE TABLE query.query_sequence (
48         id              SERIAL            PRIMARY KEY,
49         parent_query    INT               NOT NULL
50                                           REFERENCES query.stored_query
51                                                                           ON DELETE CASCADE
52                                                                           DEFERRABLE INITIALLY DEFERRED,
53         seq_no          INT               NOT NULL,
54         child_query     INT               NOT NULL
55                                           REFERENCES query.stored_query
56                                                                           ON DELETE CASCADE
57                                                                           DEFERRABLE INITIALLY DEFERRED,
58         CONSTRAINT query_query_seq UNIQUE( parent_query, seq_no )
59 );
60
61 CREATE TABLE query.datatype (
62         id              SERIAL            PRIMARY KEY,
63         datatype_name   TEXT              NOT NULL UNIQUE,
64         is_numeric      BOOL              NOT NULL DEFAULT FALSE,
65         is_composite    BOOL              NOT NULL DEFAULT FALSE,
66         CONSTRAINT qdt_comp_not_num CHECK
67         ( is_numeric IS FALSE OR is_composite IS FALSE )
68 );
69
70 CREATE TABLE query.subfield (
71         id              SERIAL            PRIMARY KEY,
72         composite_type  INT               NOT NULL
73                                           REFERENCES query.datatype(id)
74                                           ON DELETE CASCADE
75                                           DEFERRABLE INITIALLY DEFERRED,
76         seq_no          INT               NOT NULL
77                                           CONSTRAINT qsf_pos_seq_no
78                                           CHECK( seq_no > 0 ),
79         subfield_type   INT               NOT NULL
80                                           REFERENCES query.datatype(id)
81                                           DEFERRABLE INITIALLY DEFERRED,
82         CONSTRAINT qsf_datatype_seq_no UNIQUE (composite_type, seq_no)
83 );
84
85 CREATE TABLE query.function_sig (
86         id              SERIAL            PRIMARY KEY,
87         function_name   TEXT              NOT NULL,
88         return_type     INT               REFERENCES query.datatype(id)
89                                           DEFERRABLE INITIALLY DEFERRED,
90         is_aggregate    BOOL              NOT NULL DEFAULT FALSE,
91         CONSTRAINT qfd_rtn_or_aggr CHECK
92         ( return_type IS NULL OR is_aggregate = FALSE )
93 );
94
95 CREATE INDEX query_function_sig_name_idx 
96         ON query.function_sig (function_name);
97
98 CREATE TABLE query.function_param_def (
99         id              SERIAL            PRIMARY KEY,
100         function_id     INT               NOT NULL
101                                           REFERENCES query.function_sig( id )
102                                           ON DELETE CASCADE
103                                           DEFERRABLE INITIALLY DEFERRED,
104         seq_no          INT               NOT NULL
105                                           CONSTRAINT qfpd_pos_seq_no CHECK
106                                           ( seq_no > 0 ),
107         datatype        INT               NOT NULL
108                                           REFERENCES query.datatype( id )
109                                           DEFERRABLE INITIALLY DEFERRED,
110         CONSTRAINT qfpd_function_param_seq UNIQUE (function_id, seq_no)
111 );
112
113 CREATE TABLE query.expression (
114         id            SERIAL        PRIMARY KEY,
115         type          TEXT          NOT NULL CONSTRAINT predicate_type CHECK
116                                     ( type IN (
117                                         'xbet',    -- between
118                                                                         'xbool',   -- boolean
119                                         'xcase',   -- case
120                                                                         'xcast',   -- cast
121                                                                         'xcol',    -- column
122                                                                         'xex',     -- exists
123                                                                         'xfld',    -- field
124                                                                         'xfunc',   -- function
125                                                                         'xin',     -- in
126                                         'xnull',   -- null
127                                                                         'xnum',    -- number
128                                                                         'xop',     -- operator
129                                                                         'xstr',    -- string
130                                                 'xsubq'    -- subquery
131                                                                 ) ),
132         parenthesize  BOOL          NOT NULL DEFAULT FALSE,
133         parent_expr   INT           REFERENCES query.expression
134                                     ON DELETE CASCADE
135                                     DEFERRABLE INITIALLY DEFERRED,
136         seq_no        INT           NOT NULL DEFAULT 1,
137         literal       TEXT,
138         table_alias   TEXT,
139         column_name   TEXT,
140         left_operand  INT           REFERENCES query.expression
141                                     DEFERRABLE INITIALLY DEFERRED,
142         operator      TEXT,
143         right_operand INT           REFERENCES query.expression
144                                     DEFERRABLE INITIALLY DEFERRED,
145         function_id   INT           REFERENCES query.function_sig
146                                     DEFERRABLE INITIALLY DEFERRED,
147         subquery      INT           REFERENCES query.stored_query
148                                     DEFERRABLE INITIALLY DEFERRED,
149         cast_type     INT           REFERENCES query.datatype
150                                     DEFERRABLE INITIALLY DEFERRED,
151         negate        BOOL          NOT NULL DEFAULT FALSE
152 );
153
154 CREATE UNIQUE INDEX query_expr_parent_seq
155         ON query.expression( parent_expr, seq_no )
156         WHERE parent_expr IS NOT NULL;
157
158 -- Due to some circular references, the following foreign key definitions
159 -- had to be deferred until query.expression existed:
160
161 ALTER TABLE query.stored_query
162         ADD FOREIGN KEY ( where_clause )
163         REFERENCES query.expression( id )
164         DEFERRABLE INITIALLY DEFERRED;
165
166 ALTER TABLE query.stored_query
167         ADD FOREIGN KEY ( having_clause )
168         REFERENCES query.expression( id )
169         DEFERRABLE INITIALLY DEFERRED;
170
171 CREATE TABLE query.case_branch (
172         id            SERIAL        PRIMARY KEY,
173         parent_expr   INT           NOT NULL REFERENCES query.expression
174                                     ON DELETE CASCADE
175                                     DEFERRABLE INITIALLY DEFERRED,
176         seq_no        INT           NOT NULL,
177         condition     INT           REFERENCES query.expression
178                                     DEFERRABLE INITIALLY DEFERRED,
179         result        INT           NOT NULL REFERENCES query.expression
180                                     DEFERRABLE INITIALLY DEFERRED,
181         CONSTRAINT case_branch_parent_seq UNIQUE (parent_expr, seq_no)
182 );
183
184 CREATE TABLE query.from_relation (
185         id               SERIAL        PRIMARY KEY,
186         type             TEXT          NOT NULL CONSTRAINT relation_type CHECK (
187                                            type IN ( 'RELATION', 'SUBQUERY', 'FUNCTION' ) ),
188         table_name       TEXT,
189         class_name       TEXT,
190         subquery         INT           REFERENCES query.stored_query,
191         function_call    INT           REFERENCES query.expression,
192         table_alias      TEXT,
193         parent_relation  INT           REFERENCES query.from_relation
194                                        ON DELETE CASCADE
195                                        DEFERRABLE INITIALLY DEFERRED,
196         seq_no           INT           NOT NULL DEFAULT 1,
197         join_type        TEXT          CONSTRAINT good_join_type CHECK (
198                                            join_type IS NULL OR join_type IN
199                                            ( 'INNER', 'LEFT', 'RIGHT', 'FULL' )
200                                        ),
201         on_clause        INT           REFERENCES query.expression
202                                        DEFERRABLE INITIALLY DEFERRED,
203         CONSTRAINT join_or_core CHECK (
204             ( parent_relation IS NULL AND join_type IS NULL 
205               AND on_clause IS NULL )
206             OR
207             ( parent_relation IS NOT NULL AND join_type IS NOT NULL
208               AND on_clause IS NOT NULL )
209         )
210 );
211
212 CREATE UNIQUE INDEX from_parent_seq
213         ON query.from_relation( parent_relation, seq_no )
214         WHERE parent_relation IS NOT NULL;
215
216 -- The following foreign key had to be deferred until
217 -- query.from_relation existed
218
219 ALTER TABLE query.stored_query
220         ADD FOREIGN KEY (from_clause)
221         REFERENCES query.from_relation
222         DEFERRABLE INITIALLY DEFERRED;
223
224 CREATE TABLE query.record_column (
225         id            SERIAL            PRIMARY KEY,
226         from_relation INT               NOT NULL REFERENCES query.from_relation
227                                         ON DELETE CASCADE
228                                         DEFERRABLE INITIALLY DEFERRED,
229         seq_no        INT               NOT NULL,
230         column_name   TEXT              NOT NULL,
231     column_type   INT               NOT NULL REFERENCES query.datatype
232                                     ON DELETE CASCADE
233                                     DEFERRABLE INITIALLY DEFERRED,
234         CONSTRAINT column_sequence UNIQUE (from_relation, seq_no)
235 );
236
237 CREATE TABLE query.select_item (
238         id               SERIAL         PRIMARY KEY,
239         stored_query     INT            NOT NULL REFERENCES query.stored_query
240                                         ON DELETE CASCADE
241                                         DEFERRABLE INITIALLY DEFERRED,
242         seq_no           INT            NOT NULL,
243         expression       INT            NOT NULL REFERENCES query.expression
244                                         DEFERRABLE INITIALLY DEFERRED,
245         column_alias     TEXT,
246         grouped_by       BOOL           NOT NULL DEFAULT FALSE,
247         CONSTRAINT select_sequence UNIQUE( stored_query, seq_no )
248 );
249
250 CREATE TABLE query.order_by_item (
251         id               SERIAL         PRIMARY KEY,
252         stored_query     INT            NOT NULL REFERENCES query.stored_query
253                                         ON DELETE CASCADE
254                                         DEFERRABLE INITIALLY DEFERRED,
255         seq_no           INT            NOT NULL,
256         expression       INT            NOT NULL REFERENCES query.expression
257                                         ON DELETE CASCADE
258                                         DEFERRABLE INITIALLY DEFERRED,
259         CONSTRAINT order_by_sequence UNIQUE( stored_query, seq_no )
260 );
261
262 -- Create updatable views -------------------------------------------
263
264 -- Create updatable view for BETWEEN expressions
265
266 CREATE OR REPLACE VIEW query.expr_xbet AS
267     SELECT
268                 id,
269                 parenthesize,
270                 parent_expr,
271                 seq_no
272     FROM
273         query.expression
274     WHERE
275         type = 'xbet';
276
277 CREATE OR REPLACE RULE query_expr_xbet_insert_rule AS
278     ON INSERT TO query.expr_xbet
279     DO INSTEAD
280     INSERT INTO query.expression (
281                 id,
282                 type,
283                 parenthesize,
284                 parent_expr,
285                 seq_no
286     ) VALUES (
287         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
288         'xbet',
289         COALESCE(NEW.parenthesize, FALSE),
290         NEW.parent_expr,
291         COALESCE(NEW.seq_no, 1)
292     );
293
294 CREATE OR REPLACE RULE query_expr_xbet_update_rule AS
295     ON UPDATE TO query.expr_xbet
296     DO INSTEAD
297     UPDATE query.expression SET
298         id = NEW.id,
299         parenthesize = NEW.parenthesize,
300         parent_expr = NEW.parent_expr,
301         seq_no = NEW.seq_no
302     WHERE
303         id = OLD.id;
304
305 CREATE OR REPLACE RULE query_expr_xbet_delete_rule AS
306     ON DELETE TO query.expr_xbet
307     DO INSTEAD
308     DELETE FROM query.expression WHERE id = OLD.id;
309
310 -- Create updatable view for boolean expressions
311
312 CREATE OR REPLACE VIEW query.expr_xbool AS
313     SELECT
314                 id,
315                 parenthesize,
316                 parent_expr,
317                 seq_no,
318                 literal
319     FROM
320         query.expression
321     WHERE
322         type = 'xbool';
323
324 CREATE OR REPLACE RULE query_expr_xbool_insert_rule AS
325     ON INSERT TO query.expr_xbool
326     DO INSTEAD
327     INSERT INTO query.expression (
328                 id,
329                 type,
330                 parenthesize,
331                 parent_expr,
332                 seq_no,
333                 literal
334     ) VALUES (
335         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
336         'xbool',
337         COALESCE(NEW.parenthesize, FALSE),
338         NEW.parent_expr,
339         COALESCE(NEW.seq_no, 1),
340         NEW.literal
341     );
342
343 CREATE OR REPLACE RULE query_expr_xbool_update_rule AS
344     ON UPDATE TO query.expr_xbool
345     DO INSTEAD
346     UPDATE query.expression SET
347         id = NEW.id,
348         parenthesize = NEW.parenthesize,
349         parent_expr = NEW.parent_expr,
350         seq_no = NEW.seq_no,
351         literal = NEW.literal
352     WHERE
353         id = OLD.id;
354
355 CREATE OR REPLACE RULE query_expr_xbool_delete_rule AS
356     ON DELETE TO query.expr_xbool
357     DO INSTEAD
358     DELETE FROM query.expression WHERE id = OLD.id;
359
360 -- Create updatable view for CASE expressions
361
362 CREATE OR REPLACE VIEW query.expr_xcase AS
363     SELECT
364                 id,
365                 parenthesize,
366                 parent_expr,
367                 seq_no
368     FROM
369         query.expression
370     WHERE
371         type = 'xcase';
372
373 CREATE OR REPLACE RULE query_expr_xcase_insert_rule AS
374     ON INSERT TO query.expr_xcase
375     DO INSTEAD
376     INSERT INTO query.expression (
377                 id,
378                 type,
379                 parenthesize,
380                 parent_expr,
381                 seq_no
382     ) VALUES (
383         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
384         'xcase',
385         COALESCE(NEW.parenthesize, FALSE),
386         NEW.parent_expr,
387         COALESCE(NEW.seq_no, 1)
388     );
389
390 CREATE OR REPLACE RULE query_expr_xcase_update_rule AS
391     ON UPDATE TO query.expr_xcase
392     DO INSTEAD
393     UPDATE query.expression SET
394         id = NEW.id,
395         parenthesize = NEW.parenthesize,
396         parent_expr = NEW.parent_expr,
397         seq_no = NEW.seq_no
398     WHERE
399         id = OLD.id;
400
401 CREATE OR REPLACE RULE query_expr_xcase_delete_rule AS
402     ON DELETE TO query.expr_xcase
403     DO INSTEAD
404     DELETE FROM query.expression WHERE id = OLD.id;
405
406 -- Create updatable view for cast expressions
407
408 CREATE OR REPLACE VIEW query.expr_xcast AS
409     SELECT
410                 id,
411                 parenthesize,
412                 parent_expr,
413                 seq_no,
414                 left_operand,
415                 cast_type
416     FROM
417         query.expression
418     WHERE
419         type = 'xcast';
420
421 CREATE OR REPLACE RULE query_expr_xcast_insert_rule AS
422     ON INSERT TO query.expr_xcast
423     DO INSTEAD
424     INSERT INTO query.expression (
425                 id,
426                 type,
427                 parenthesize,
428                 parent_expr,
429                 seq_no,
430                 left_operand,
431                 cast_type
432     ) VALUES (
433         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
434         'xcast',
435         COALESCE(NEW.parenthesize, FALSE),
436         NEW.parent_expr,
437         COALESCE(NEW.seq_no, 1),
438                 NEW.left_operand,
439                 NEW.cast_type
440     );
441
442 CREATE OR REPLACE RULE query_expr_xcast_update_rule AS
443     ON UPDATE TO query.expr_xcast
444     DO INSTEAD
445     UPDATE query.expression SET
446         id = NEW.id,
447         parenthesize = NEW.parenthesize,
448         parent_expr = NEW.parent_expr,
449         seq_no = NEW.seq_no,
450                 left_operand = NEW.left_operand,
451                 cast_type = NEW.cast_type
452     WHERE
453         id = OLD.id;
454
455 CREATE OR REPLACE RULE query_expr_xcast_delete_rule AS
456     ON DELETE TO query.expr_xcast
457     DO INSTEAD
458     DELETE FROM query.expression WHERE id = OLD.id;
459
460 -- Create updatable view for column expressions
461
462 CREATE OR REPLACE VIEW query.expr_xcol AS
463     SELECT
464                 id,
465                 parenthesize,
466                 parent_expr,
467                 seq_no,
468                 table_alias,
469                 column_name
470     FROM
471         query.expression
472     WHERE
473         type = 'xcol';
474
475 CREATE OR REPLACE RULE query_expr_xcol_insert_rule AS
476     ON INSERT TO query.expr_xcol
477     DO INSTEAD
478     INSERT INTO query.expression (
479                 id,
480                 type,
481                 parenthesize,
482                 parent_expr,
483                 seq_no,
484                 table_alias,
485                 column_name
486     ) VALUES (
487         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
488         'xcol',
489         COALESCE(NEW.parenthesize, FALSE),
490         NEW.parent_expr,
491         COALESCE(NEW.seq_no, 1),
492                 NEW.table_alias,
493                 NEW.column_name
494     );
495
496 CREATE OR REPLACE RULE query_expr_xcol_update_rule AS
497     ON UPDATE TO query.expr_xcol
498     DO INSTEAD
499     UPDATE query.expression SET
500         id = NEW.id,
501         parenthesize = NEW.parenthesize,
502         parent_expr = NEW.parent_expr,
503         seq_no = NEW.seq_no,
504                 table_alias = NEW.table_alias,
505                 column_name = NEW.column_name
506     WHERE
507         id = OLD.id;
508
509 CREATE OR REPLACE RULE query_expr_xcol_delete_rule AS
510     ON DELETE TO query.expr_xcol
511     DO INSTEAD
512     DELETE FROM query.expression WHERE id = OLD.id;
513
514 -- Create updatable view for EXISTS expressions
515
516 CREATE OR REPLACE VIEW query.expr_xex AS
517     SELECT
518                 id,
519                 parenthesize,
520                 parent_expr,
521                 seq_no,
522                 subquery
523     FROM
524         query.expression
525     WHERE
526         type = 'xex';
527
528 CREATE OR REPLACE RULE query_expr_xex_insert_rule AS
529     ON INSERT TO query.expr_xex
530     DO INSTEAD
531     INSERT INTO query.expression (
532                 id,
533                 type,
534                 parenthesize,
535                 parent_expr,
536                 seq_no,
537                 subquery
538     ) VALUES (
539         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
540         'xex',
541         COALESCE(NEW.parenthesize, FALSE),
542         NEW.parent_expr,
543         COALESCE(NEW.seq_no, 1),
544                 NEW.subquery
545     );
546
547 CREATE OR REPLACE RULE query_expr_xex_update_rule AS
548     ON UPDATE TO query.expr_xex
549     DO INSTEAD
550     UPDATE query.expression SET
551         id = NEW.id,
552         parenthesize = NEW.parenthesize,
553         parent_expr = NEW.parent_expr,
554         seq_no = NEW.seq_no,
555                 subquery = NEW.subquery
556     WHERE
557         id = OLD.id;
558
559 CREATE OR REPLACE RULE query_expr_xex_delete_rule AS
560     ON DELETE TO query.expr_xex
561     DO INSTEAD
562     DELETE FROM query.expression WHERE id = OLD.id;
563
564 -- Create updatable view for field expressions
565
566 CREATE OR REPLACE VIEW query.expr_xfld AS
567     SELECT
568                 id,
569                 parenthesize,
570                 parent_expr,
571                 seq_no,
572                 column_name,
573                 left_operand
574     FROM
575         query.expression
576     WHERE
577         type = 'xfld';
578
579 CREATE OR REPLACE RULE query_expr_xfld_insert_rule AS
580     ON INSERT TO query.expr_xfld
581     DO INSTEAD
582     INSERT INTO query.expression (
583                 id,
584                 type,
585                 parenthesize,
586                 parent_expr,
587                 seq_no,
588                 column_name,
589                 left_operand
590     ) VALUES (
591         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
592         'xfld',
593         COALESCE(NEW.parenthesize, FALSE),
594         NEW.parent_expr,
595         COALESCE(NEW.seq_no, 1),
596                 NEW.column_name,
597                 NEW.left_operand
598     );
599
600 CREATE OR REPLACE RULE query_expr_xfld_update_rule AS
601     ON UPDATE TO query.expr_xfld
602     DO INSTEAD
603     UPDATE query.expression SET
604         id = NEW.id,
605         parenthesize = NEW.parenthesize,
606         parent_expr = NEW.parent_expr,
607         seq_no = NEW.seq_no,
608                 column_name = NEW.column_name,
609                 left_operand = NEW.left_operand
610     WHERE
611         id = OLD.id;
612
613 CREATE OR REPLACE RULE query_expr_xfld_delete_rule AS
614     ON DELETE TO query.expr_xfld
615     DO INSTEAD
616     DELETE FROM query.expression WHERE id = OLD.id;
617
618 -- Create updatable view for function call expressions
619
620 CREATE OR REPLACE VIEW query.expr_xfunc AS
621     SELECT
622                 id,
623                 parenthesize,
624                 parent_expr,
625                 seq_no,
626                 function_id
627     FROM
628         query.expression
629     WHERE
630         type = 'xfunc';
631
632 CREATE OR REPLACE RULE query_expr_xfunc_insert_rule AS
633     ON INSERT TO query.expr_xfunc
634     DO INSTEAD
635     INSERT INTO query.expression (
636                 id,
637                 type,
638                 parenthesize,
639                 parent_expr,
640                 seq_no,
641                 function_id
642     ) VALUES (
643         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
644         'xfunc',
645         COALESCE(NEW.parenthesize, FALSE),
646         NEW.parent_expr,
647         COALESCE(NEW.seq_no, 1),
648                 NEW.function_id
649     );
650
651 CREATE OR REPLACE RULE query_expr_xfunc_update_rule AS
652     ON UPDATE TO query.expr_xfunc
653     DO INSTEAD
654     UPDATE query.expression SET
655         id = NEW.id,
656         parenthesize = NEW.parenthesize,
657         parent_expr = NEW.parent_expr,
658         seq_no = NEW.seq_no,
659                 function_id = NEW.function_id
660     WHERE
661         id = OLD.id;
662
663 CREATE OR REPLACE RULE query_expr_xfunc_delete_rule AS
664     ON DELETE TO query.expr_xfunc
665     DO INSTEAD
666     DELETE FROM query.expression WHERE id = OLD.id;
667
668 -- Create updatable view for IN expressions
669
670 CREATE OR REPLACE VIEW query.expr_xin AS
671     SELECT
672                 id,
673                 parenthesize,
674                 parent_expr,
675                 seq_no,
676                 subquery
677     FROM
678         query.expression
679     WHERE
680         type = 'xin';
681
682 CREATE OR REPLACE RULE query_expr_xin_insert_rule AS
683     ON INSERT TO query.expr_xin
684     DO INSTEAD
685     INSERT INTO query.expression (
686                 id,
687                 type,
688                 parenthesize,
689                 parent_expr,
690                 seq_no,
691                 subquery
692     ) VALUES (
693         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
694         'xin',
695         COALESCE(NEW.parenthesize, FALSE),
696         NEW.parent_expr,
697         COALESCE(NEW.seq_no, 1),
698                 NEW.subquery
699     );
700
701 CREATE OR REPLACE RULE query_expr_xin_update_rule AS
702     ON UPDATE TO query.expr_xin
703     DO INSTEAD
704     UPDATE query.expression SET
705         id = NEW.id,
706         parenthesize = NEW.parenthesize,
707         parent_expr = NEW.parent_expr,
708         seq_no = NEW.seq_no,
709                 subquery = NEW.subquery
710     WHERE
711         id = OLD.id;
712
713 CREATE OR REPLACE RULE query_expr_xin_delete_rule AS
714     ON DELETE TO query.expr_xin
715     DO INSTEAD
716     DELETE FROM query.expression WHERE id = OLD.id;
717
718 -- Create updatable view for NULL expressions
719
720 CREATE OR REPLACE VIEW query.expr_xnull AS
721     SELECT
722                 id,
723                 parenthesize,
724                 parent_expr,
725                 seq_no
726     FROM
727         query.expression
728     WHERE
729         type = 'xnull';
730
731 CREATE OR REPLACE RULE query_expr_xnull_insert_rule AS
732     ON INSERT TO query.expr_xnull
733     DO INSTEAD
734     INSERT INTO query.expression (
735                 id,
736                 type,
737                 parenthesize,
738                 parent_expr,
739                 seq_no
740     ) VALUES (
741         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
742         'xnull',
743         COALESCE(NEW.parenthesize, FALSE),
744         NEW.parent_expr,
745         COALESCE(NEW.seq_no, 1)
746     );
747
748 CREATE OR REPLACE RULE query_expr_xnull_update_rule AS
749     ON UPDATE TO query.expr_xnull
750     DO INSTEAD
751     UPDATE query.expression SET
752         id = NEW.id,
753         parenthesize = NEW.parenthesize,
754         parent_expr = NEW.parent_expr,
755         seq_no = NEW.seq_no
756     WHERE
757         id = OLD.id;
758
759 CREATE OR REPLACE RULE query_expr_xnull_delete_rule AS
760     ON DELETE TO query.expr_xnull
761     DO INSTEAD
762     DELETE FROM query.expression WHERE id = OLD.id;
763
764 -- Create updatable view for numeric literal expressions
765
766 CREATE OR REPLACE VIEW query.expr_xnum AS
767     SELECT
768                 id,
769                 parenthesize,
770                 parent_expr,
771                 seq_no,
772                 literal
773     FROM
774         query.expression
775     WHERE
776         type = 'xnum';
777
778 CREATE OR REPLACE RULE query_expr_xnum_insert_rule AS
779     ON INSERT TO query.expr_xnum
780     DO INSTEAD
781     INSERT INTO query.expression (
782                 id,
783                 type,
784                 parenthesize,
785                 parent_expr,
786                 seq_no,
787                 literal
788     ) VALUES (
789         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
790         'xnum',
791         COALESCE(NEW.parenthesize, FALSE),
792         NEW.parent_expr,
793         COALESCE(NEW.seq_no, 1),
794         NEW.literal
795     );
796
797 CREATE OR REPLACE RULE query_expr_xnum_update_rule AS
798     ON UPDATE TO query.expr_xnum
799     DO INSTEAD
800     UPDATE query.expression SET
801         id = NEW.id,
802         parenthesize = NEW.parenthesize,
803         parent_expr = NEW.parent_expr,
804         seq_no = NEW.seq_no,
805         literal = NEW.literal
806     WHERE
807         id = OLD.id;
808
809 CREATE OR REPLACE RULE query_expr_xnum_delete_rule AS
810     ON DELETE TO query.expr_xnum
811     DO INSTEAD
812     DELETE FROM query.expression WHERE id = OLD.id;
813
814 -- Create updatable view for operator expressions
815
816 CREATE OR REPLACE VIEW query.expr_xop AS
817     SELECT
818                 id,
819                 parenthesize,
820                 parent_expr,
821                 seq_no,
822                 left_operand,
823                 operator,
824                 right_operand
825     FROM
826         query.expression
827     WHERE
828         type = 'xop';
829
830 CREATE OR REPLACE RULE query_expr_xop_insert_rule AS
831     ON INSERT TO query.expr_xop
832     DO INSTEAD
833     INSERT INTO query.expression (
834                 id,
835                 type,
836                 parenthesize,
837                 parent_expr,
838                 seq_no,
839                 left_operand,
840                 operator,
841                 right_operand
842     ) VALUES (
843         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
844         'xop',
845         COALESCE(NEW.parenthesize, FALSE),
846         NEW.parent_expr,
847         COALESCE(NEW.seq_no, 1),
848                 NEW.left_operand,
849                 NEW.operator,
850                 NEW.right_operand
851     );
852
853 CREATE OR REPLACE RULE query_expr_xop_update_rule AS
854     ON UPDATE TO query.expr_xop
855     DO INSTEAD
856     UPDATE query.expression SET
857         id = NEW.id,
858         parenthesize = NEW.parenthesize,
859         parent_expr = NEW.parent_expr,
860         seq_no = NEW.seq_no,
861                 left_operand = NEW.left_operand,
862                 operator = NEW.operator,
863                 right_operand = NEW.right_operand
864     WHERE
865         id = OLD.id;
866
867 CREATE OR REPLACE RULE query_expr_xop_delete_rule AS
868     ON DELETE TO query.expr_xop
869     DO INSTEAD
870     DELETE FROM query.expression WHERE id = OLD.id;
871
872 -- Create updatable view for string literal expressions
873
874 CREATE OR REPLACE VIEW query.expr_string AS
875     SELECT
876         id,
877         parenthesize,
878         parent_expr,
879         seq_no,
880         literal
881     FROM
882         query.expression
883     WHERE
884         type = 'xstr';
885
886 CREATE OR REPLACE RULE query_expr_string_insert_rule AS
887     ON INSERT TO query.expr_string
888     DO INSTEAD
889     INSERT INTO query.expression (
890         id,
891         type,
892         parenthesize,
893         parent_expr,
894         seq_no,
895         literal
896     ) VALUES (
897         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
898         'xstr',
899         COALESCE(NEW.parenthesize, FALSE),
900         NEW.parent_expr,
901         COALESCE(NEW.seq_no, 1),
902         NEW.literal
903     );
904
905 CREATE OR REPLACE RULE query_expr_string_update_rule AS
906     ON UPDATE TO query.expr_string
907     DO INSTEAD
908     UPDATE query.expression SET
909         id = NEW.id,
910         parenthesize = NEW.parenthesize,
911         parent_expr = NEW.parent_expr,
912         seq_no = NEW.seq_no,
913         literal = NEW.literal
914     WHERE
915         id = OLD.id;
916
917 CREATE OR REPLACE RULE query_expr_string_delete_rule AS
918     ON DELETE TO query.expr_string
919     DO INSTEAD
920     DELETE FROM query.expression WHERE id = OLD.id;
921
922 -- Create updatable view for subquery expressions
923
924 CREATE OR REPLACE VIEW query.expr_xsubq AS
925     SELECT
926                 id,
927                 parenthesize,
928                 parent_expr,
929                 seq_no,
930                 subquery
931     FROM
932         query.expression
933     WHERE
934         type = 'xsubq';
935
936 CREATE OR REPLACE RULE query_expr_xsubq_insert_rule AS
937     ON INSERT TO query.expr_xsubq
938     DO INSTEAD
939     INSERT INTO query.expression (
940                 id,
941                 type,
942                 parenthesize,
943                 parent_expr,
944                 seq_no,
945                 subquery
946     ) VALUES (
947         COALESCE(NEW.id, NEXTVAL('query.expression_id_seq'::REGCLASS)),
948         'xsubq',
949         COALESCE(NEW.parenthesize, FALSE),
950         NEW.parent_expr,
951         COALESCE(NEW.seq_no, 1),
952                 NEW.subquery
953     );
954
955 CREATE OR REPLACE RULE query_expr_xsubq_update_rule AS
956     ON UPDATE TO query.expr_xsubq
957     DO INSTEAD
958     UPDATE query.expression SET
959         id = NEW.id,
960         parenthesize = NEW.parenthesize,
961         parent_expr = NEW.parent_expr,
962         seq_no = NEW.seq_no,
963                 subquery = NEW.subquery
964     WHERE
965         id = OLD.id;
966
967 CREATE OR REPLACE RULE query_expr_xsubq_delete_rule AS
968     ON DELETE TO query.expr_xsubq
969     DO INSTEAD
970     DELETE FROM query.expression WHERE id = OLD.id;
971
972 COMMIT;