~ubuntu-branches/ubuntu/precise/postgresql-9.1/precise-security

« back to all changes in this revision

Viewing changes to src/backend/catalog/pg_constraint.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * pg_constraint.c
 
4
 *        routines to support manipulation of the pg_constraint relation
 
5
 *
 
6
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        src/backend/catalog/pg_constraint.c
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
17
#include "access/genam.h"
 
18
#include "access/heapam.h"
 
19
#include "catalog/dependency.h"
 
20
#include "catalog/indexing.h"
 
21
#include "catalog/objectaccess.h"
 
22
#include "catalog/pg_constraint.h"
 
23
#include "catalog/pg_operator.h"
 
24
#include "catalog/pg_type.h"
 
25
#include "commands/defrem.h"
 
26
#include "utils/array.h"
 
27
#include "utils/builtins.h"
 
28
#include "utils/fmgroids.h"
 
29
#include "utils/lsyscache.h"
 
30
#include "utils/rel.h"
 
31
#include "utils/syscache.h"
 
32
#include "utils/tqual.h"
 
33
 
 
34
 
 
35
/*
 
36
 * CreateConstraintEntry
 
37
 *      Create a constraint table entry.
 
38
 *
 
39
 * Subsidiary records (such as triggers or indexes to implement the
 
40
 * constraint) are *not* created here.  But we do make dependency links
 
41
 * from the constraint to the things it depends on.
 
42
 */
 
43
Oid
 
44
CreateConstraintEntry(const char *constraintName,
 
45
                                          Oid constraintNamespace,
 
46
                                          char constraintType,
 
47
                                          bool isDeferrable,
 
48
                                          bool isDeferred,
 
49
                                          bool isValidated,
 
50
                                          Oid relId,
 
51
                                          const int16 *constraintKey,
 
52
                                          int constraintNKeys,
 
53
                                          Oid domainId,
 
54
                                          Oid indexRelId,
 
55
                                          Oid foreignRelId,
 
56
                                          const int16 *foreignKey,
 
57
                                          const Oid *pfEqOp,
 
58
                                          const Oid *ppEqOp,
 
59
                                          const Oid *ffEqOp,
 
60
                                          int foreignNKeys,
 
61
                                          char foreignUpdateType,
 
62
                                          char foreignDeleteType,
 
63
                                          char foreignMatchType,
 
64
                                          const Oid *exclOp,
 
65
                                          Node *conExpr,
 
66
                                          const char *conBin,
 
67
                                          const char *conSrc,
 
68
                                          bool conIsLocal,
 
69
                                          int conInhCount)
 
70
{
 
71
        Relation        conDesc;
 
72
        Oid                     conOid;
 
73
        HeapTuple       tup;
 
74
        bool            nulls[Natts_pg_constraint];
 
75
        Datum           values[Natts_pg_constraint];
 
76
        ArrayType  *conkeyArray;
 
77
        ArrayType  *confkeyArray;
 
78
        ArrayType  *conpfeqopArray;
 
79
        ArrayType  *conppeqopArray;
 
80
        ArrayType  *conffeqopArray;
 
81
        ArrayType  *conexclopArray;
 
82
        NameData        cname;
 
83
        int                     i;
 
84
        ObjectAddress conobject;
 
85
 
 
86
        conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
 
87
 
 
88
        Assert(constraintName);
 
89
        namestrcpy(&cname, constraintName);
 
90
 
 
91
        /*
 
92
         * Convert C arrays into Postgres arrays.
 
93
         */
 
94
        if (constraintNKeys > 0)
 
95
        {
 
96
                Datum      *conkey;
 
97
 
 
98
                conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
 
99
                for (i = 0; i < constraintNKeys; i++)
 
100
                        conkey[i] = Int16GetDatum(constraintKey[i]);
 
101
                conkeyArray = construct_array(conkey, constraintNKeys,
 
102
                                                                          INT2OID, 2, true, 's');
 
103
        }
 
104
        else
 
105
                conkeyArray = NULL;
 
106
 
 
107
        if (foreignNKeys > 0)
 
108
        {
 
109
                Datum      *fkdatums;
 
110
 
 
111
                fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
 
112
                for (i = 0; i < foreignNKeys; i++)
 
113
                        fkdatums[i] = Int16GetDatum(foreignKey[i]);
 
114
                confkeyArray = construct_array(fkdatums, foreignNKeys,
 
115
                                                                           INT2OID, 2, true, 's');
 
116
                for (i = 0; i < foreignNKeys; i++)
 
117
                        fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
 
118
                conpfeqopArray = construct_array(fkdatums, foreignNKeys,
 
119
                                                                                 OIDOID, sizeof(Oid), true, 'i');
 
120
                for (i = 0; i < foreignNKeys; i++)
 
121
                        fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
 
122
                conppeqopArray = construct_array(fkdatums, foreignNKeys,
 
123
                                                                                 OIDOID, sizeof(Oid), true, 'i');
 
124
                for (i = 0; i < foreignNKeys; i++)
 
125
                        fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
 
126
                conffeqopArray = construct_array(fkdatums, foreignNKeys,
 
127
                                                                                 OIDOID, sizeof(Oid), true, 'i');
 
128
        }
 
129
        else
 
130
        {
 
131
                confkeyArray = NULL;
 
132
                conpfeqopArray = NULL;
 
133
                conppeqopArray = NULL;
 
134
                conffeqopArray = NULL;
 
135
        }
 
136
 
 
137
        if (exclOp != NULL)
 
138
        {
 
139
                Datum      *opdatums;
 
140
 
 
141
                opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
 
142
                for (i = 0; i < constraintNKeys; i++)
 
143
                        opdatums[i] = ObjectIdGetDatum(exclOp[i]);
 
144
                conexclopArray = construct_array(opdatums, constraintNKeys,
 
145
                                                                                 OIDOID, sizeof(Oid), true, 'i');
 
146
        }
 
147
        else
 
148
                conexclopArray = NULL;
 
149
 
 
150
        /* initialize nulls and values */
 
151
        for (i = 0; i < Natts_pg_constraint; i++)
 
152
        {
 
153
                nulls[i] = false;
 
154
                values[i] = (Datum) NULL;
 
155
        }
 
156
 
 
157
        values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
 
158
        values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
 
159
        values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
 
160
        values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
 
161
        values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
 
162
        values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated);
 
163
        values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
 
164
        values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
 
165
        values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId);
 
166
        values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
 
167
        values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
 
168
        values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
 
169
        values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
 
170
        values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
 
171
        values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
 
172
 
 
173
        if (conkeyArray)
 
174
                values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
 
175
        else
 
176
                nulls[Anum_pg_constraint_conkey - 1] = true;
 
177
 
 
178
        if (confkeyArray)
 
179
                values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
 
180
        else
 
181
                nulls[Anum_pg_constraint_confkey - 1] = true;
 
182
 
 
183
        if (conpfeqopArray)
 
184
                values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
 
185
        else
 
186
                nulls[Anum_pg_constraint_conpfeqop - 1] = true;
 
187
 
 
188
        if (conppeqopArray)
 
189
                values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
 
190
        else
 
191
                nulls[Anum_pg_constraint_conppeqop - 1] = true;
 
192
 
 
193
        if (conffeqopArray)
 
194
                values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
 
195
        else
 
196
                nulls[Anum_pg_constraint_conffeqop - 1] = true;
 
197
 
 
198
        if (conexclopArray)
 
199
                values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
 
200
        else
 
201
                nulls[Anum_pg_constraint_conexclop - 1] = true;
 
202
 
 
203
        /*
 
204
         * initialize the binary form of the check constraint.
 
205
         */
 
206
        if (conBin)
 
207
                values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
 
208
        else
 
209
                nulls[Anum_pg_constraint_conbin - 1] = true;
 
210
 
 
211
        /*
 
212
         * initialize the text form of the check constraint
 
213
         */
 
214
        if (conSrc)
 
215
                values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
 
216
        else
 
217
                nulls[Anum_pg_constraint_consrc - 1] = true;
 
218
 
 
219
        tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
 
220
 
 
221
        conOid = simple_heap_insert(conDesc, tup);
 
222
 
 
223
        /* update catalog indexes */
 
224
        CatalogUpdateIndexes(conDesc, tup);
 
225
 
 
226
        conobject.classId = ConstraintRelationId;
 
227
        conobject.objectId = conOid;
 
228
        conobject.objectSubId = 0;
 
229
 
 
230
        heap_close(conDesc, RowExclusiveLock);
 
231
 
 
232
        if (OidIsValid(relId))
 
233
        {
 
234
                /*
 
235
                 * Register auto dependency from constraint to owning relation, or to
 
236
                 * specific column(s) if any are mentioned.
 
237
                 */
 
238
                ObjectAddress relobject;
 
239
 
 
240
                relobject.classId = RelationRelationId;
 
241
                relobject.objectId = relId;
 
242
                if (constraintNKeys > 0)
 
243
                {
 
244
                        for (i = 0; i < constraintNKeys; i++)
 
245
                        {
 
246
                                relobject.objectSubId = constraintKey[i];
 
247
 
 
248
                                recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
 
249
                        }
 
250
                }
 
251
                else
 
252
                {
 
253
                        relobject.objectSubId = 0;
 
254
 
 
255
                        recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
 
256
                }
 
257
        }
 
258
 
 
259
        if (OidIsValid(domainId))
 
260
        {
 
261
                /*
 
262
                 * Register auto dependency from constraint to owning domain
 
263
                 */
 
264
                ObjectAddress domobject;
 
265
 
 
266
                domobject.classId = TypeRelationId;
 
267
                domobject.objectId = domainId;
 
268
                domobject.objectSubId = 0;
 
269
 
 
270
                recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
 
271
        }
 
272
 
 
273
        if (OidIsValid(foreignRelId))
 
274
        {
 
275
                /*
 
276
                 * Register normal dependency from constraint to foreign relation, or
 
277
                 * to specific column(s) if any are mentioned.
 
278
                 */
 
279
                ObjectAddress relobject;
 
280
 
 
281
                relobject.classId = RelationRelationId;
 
282
                relobject.objectId = foreignRelId;
 
283
                if (foreignNKeys > 0)
 
284
                {
 
285
                        for (i = 0; i < foreignNKeys; i++)
 
286
                        {
 
287
                                relobject.objectSubId = foreignKey[i];
 
288
 
 
289
                                recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
 
290
                        }
 
291
                }
 
292
                else
 
293
                {
 
294
                        relobject.objectSubId = 0;
 
295
 
 
296
                        recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
 
297
                }
 
298
        }
 
299
 
 
300
        if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
 
301
        {
 
302
                /*
 
303
                 * Register normal dependency on the unique index that supports a
 
304
                 * foreign-key constraint.      (Note: for indexes associated with unique
 
305
                 * or primary-key constraints, the dependency runs the other way, and
 
306
                 * is not made here.)
 
307
                 */
 
308
                ObjectAddress relobject;
 
309
 
 
310
                relobject.classId = RelationRelationId;
 
311
                relobject.objectId = indexRelId;
 
312
                relobject.objectSubId = 0;
 
313
 
 
314
                recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
 
315
        }
 
316
 
 
317
        if (foreignNKeys > 0)
 
318
        {
 
319
                /*
 
320
                 * Register normal dependencies on the equality operators that support
 
321
                 * a foreign-key constraint.  If the PK and FK types are the same then
 
322
                 * all three operators for a column are the same; otherwise they are
 
323
                 * different.
 
324
                 */
 
325
                ObjectAddress oprobject;
 
326
 
 
327
                oprobject.classId = OperatorRelationId;
 
328
                oprobject.objectSubId = 0;
 
329
 
 
330
                for (i = 0; i < foreignNKeys; i++)
 
331
                {
 
332
                        oprobject.objectId = pfEqOp[i];
 
333
                        recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
 
334
                        if (ppEqOp[i] != pfEqOp[i])
 
335
                        {
 
336
                                oprobject.objectId = ppEqOp[i];
 
337
                                recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
 
338
                        }
 
339
                        if (ffEqOp[i] != pfEqOp[i])
 
340
                        {
 
341
                                oprobject.objectId = ffEqOp[i];
 
342
                                recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
 
343
                        }
 
344
                }
 
345
        }
 
346
 
 
347
        /*
 
348
         * We don't bother to register dependencies on the exclusion operators of
 
349
         * an exclusion constraint.  We assume they are members of the opclass
 
350
         * supporting the index, so there's an indirect dependency via that. (This
 
351
         * would be pretty dicey for cross-type operators, but exclusion operators
 
352
         * can never be cross-type.)
 
353
         */
 
354
 
 
355
        if (conExpr != NULL)
 
356
        {
 
357
                /*
 
358
                 * Register dependencies from constraint to objects mentioned in CHECK
 
359
                 * expression.
 
360
                 */
 
361
                recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
 
362
                                                                                DEPENDENCY_NORMAL,
 
363
                                                                                DEPENDENCY_NORMAL);
 
364
        }
 
365
 
 
366
        /* Post creation hook for new constraint */
 
367
        InvokeObjectAccessHook(OAT_POST_CREATE, ConstraintRelationId, conOid, 0);
 
368
 
 
369
        return conOid;
 
370
}
 
371
 
 
372
 
 
373
/*
 
374
 * Test whether given name is currently used as a constraint name
 
375
 * for the given object (relation or domain).
 
376
 *
 
377
 * This is used to decide whether to accept a user-specified constraint name.
 
378
 * It is deliberately not the same test as ChooseConstraintName uses to decide
 
379
 * whether an auto-generated name is OK: here, we will allow it unless there
 
380
 * is an identical constraint name in use *on the same object*.
 
381
 *
 
382
 * NB: Caller should hold exclusive lock on the given object, else
 
383
 * this test can be fooled by concurrent additions.
 
384
 */
 
385
bool
 
386
ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
 
387
                                         Oid objNamespace, const char *conname)
 
388
{
 
389
        bool            found;
 
390
        Relation        conDesc;
 
391
        SysScanDesc conscan;
 
392
        ScanKeyData skey[2];
 
393
        HeapTuple       tup;
 
394
 
 
395
        conDesc = heap_open(ConstraintRelationId, AccessShareLock);
 
396
 
 
397
        found = false;
 
398
 
 
399
        ScanKeyInit(&skey[0],
 
400
                                Anum_pg_constraint_conname,
 
401
                                BTEqualStrategyNumber, F_NAMEEQ,
 
402
                                CStringGetDatum(conname));
 
403
 
 
404
        ScanKeyInit(&skey[1],
 
405
                                Anum_pg_constraint_connamespace,
 
406
                                BTEqualStrategyNumber, F_OIDEQ,
 
407
                                ObjectIdGetDatum(objNamespace));
 
408
 
 
409
        conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
 
410
                                                                 SnapshotNow, 2, skey);
 
411
 
 
412
        while (HeapTupleIsValid(tup = systable_getnext(conscan)))
 
413
        {
 
414
                Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
 
415
 
 
416
                if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
 
417
                {
 
418
                        found = true;
 
419
                        break;
 
420
                }
 
421
                else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
 
422
                {
 
423
                        found = true;
 
424
                        break;
 
425
                }
 
426
        }
 
427
 
 
428
        systable_endscan(conscan);
 
429
        heap_close(conDesc, AccessShareLock);
 
430
 
 
431
        return found;
 
432
}
 
433
 
 
434
/*
 
435
 * Select a nonconflicting name for a new constraint.
 
436
 *
 
437
 * The objective here is to choose a name that is unique within the
 
438
 * specified namespace.  Postgres does not require this, but the SQL
 
439
 * spec does, and some apps depend on it.  Therefore we avoid choosing
 
440
 * default names that so conflict.
 
441
 *
 
442
 * name1, name2, and label are used the same way as for makeObjectName(),
 
443
 * except that the label can't be NULL; digits will be appended to the label
 
444
 * if needed to create a name that is unique within the specified namespace.
 
445
 *
 
446
 * 'others' can be a list of string names already chosen within the current
 
447
 * command (but not yet reflected into the catalogs); we will not choose
 
448
 * a duplicate of one of these either.
 
449
 *
 
450
 * Note: it is theoretically possible to get a collision anyway, if someone
 
451
 * else chooses the same name concurrently.  This is fairly unlikely to be
 
452
 * a problem in practice, especially if one is holding an exclusive lock on
 
453
 * the relation identified by name1.
 
454
 *
 
455
 * Returns a palloc'd string.
 
456
 */
 
457
char *
 
458
ChooseConstraintName(const char *name1, const char *name2,
 
459
                                         const char *label, Oid namespaceid,
 
460
                                         List *others)
 
461
{
 
462
        int                     pass = 0;
 
463
        char       *conname = NULL;
 
464
        char            modlabel[NAMEDATALEN];
 
465
        Relation        conDesc;
 
466
        SysScanDesc conscan;
 
467
        ScanKeyData skey[2];
 
468
        bool            found;
 
469
        ListCell   *l;
 
470
 
 
471
        conDesc = heap_open(ConstraintRelationId, AccessShareLock);
 
472
 
 
473
        /* try the unmodified label first */
 
474
        StrNCpy(modlabel, label, sizeof(modlabel));
 
475
 
 
476
        for (;;)
 
477
        {
 
478
                conname = makeObjectName(name1, name2, modlabel);
 
479
 
 
480
                found = false;
 
481
 
 
482
                foreach(l, others)
 
483
                {
 
484
                        if (strcmp((char *) lfirst(l), conname) == 0)
 
485
                        {
 
486
                                found = true;
 
487
                                break;
 
488
                        }
 
489
                }
 
490
 
 
491
                if (!found)
 
492
                {
 
493
                        ScanKeyInit(&skey[0],
 
494
                                                Anum_pg_constraint_conname,
 
495
                                                BTEqualStrategyNumber, F_NAMEEQ,
 
496
                                                CStringGetDatum(conname));
 
497
 
 
498
                        ScanKeyInit(&skey[1],
 
499
                                                Anum_pg_constraint_connamespace,
 
500
                                                BTEqualStrategyNumber, F_OIDEQ,
 
501
                                                ObjectIdGetDatum(namespaceid));
 
502
 
 
503
                        conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
 
504
                                                                                 SnapshotNow, 2, skey);
 
505
 
 
506
                        found = (HeapTupleIsValid(systable_getnext(conscan)));
 
507
 
 
508
                        systable_endscan(conscan);
 
509
                }
 
510
 
 
511
                if (!found)
 
512
                        break;
 
513
 
 
514
                /* found a conflict, so try a new name component */
 
515
                pfree(conname);
 
516
                snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
 
517
        }
 
518
 
 
519
        heap_close(conDesc, AccessShareLock);
 
520
 
 
521
        return conname;
 
522
}
 
523
 
 
524
/*
 
525
 * Delete a single constraint record.
 
526
 */
 
527
void
 
528
RemoveConstraintById(Oid conId)
 
529
{
 
530
        Relation        conDesc;
 
531
        HeapTuple       tup;
 
532
        Form_pg_constraint con;
 
533
 
 
534
        conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
 
535
 
 
536
        tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conId));
 
537
        if (!HeapTupleIsValid(tup)) /* should not happen */
 
538
                elog(ERROR, "cache lookup failed for constraint %u", conId);
 
539
        con = (Form_pg_constraint) GETSTRUCT(tup);
 
540
 
 
541
        /*
 
542
         * Special processing depending on what the constraint is for.
 
543
         */
 
544
        if (OidIsValid(con->conrelid))
 
545
        {
 
546
                Relation        rel;
 
547
 
 
548
                /*
 
549
                 * If the constraint is for a relation, open and exclusive-lock the
 
550
                 * relation it's for.
 
551
                 */
 
552
                rel = heap_open(con->conrelid, AccessExclusiveLock);
 
553
 
 
554
                /*
 
555
                 * We need to update the relcheck count if it is a check constraint
 
556
                 * being dropped.  This update will force backends to rebuild relcache
 
557
                 * entries when we commit.
 
558
                 */
 
559
                if (con->contype == CONSTRAINT_CHECK)
 
560
                {
 
561
                        Relation        pgrel;
 
562
                        HeapTuple       relTup;
 
563
                        Form_pg_class classForm;
 
564
 
 
565
                        pgrel = heap_open(RelationRelationId, RowExclusiveLock);
 
566
                        relTup = SearchSysCacheCopy1(RELOID,
 
567
                                                                                 ObjectIdGetDatum(con->conrelid));
 
568
                        if (!HeapTupleIsValid(relTup))
 
569
                                elog(ERROR, "cache lookup failed for relation %u",
 
570
                                         con->conrelid);
 
571
                        classForm = (Form_pg_class) GETSTRUCT(relTup);
 
572
 
 
573
                        if (classForm->relchecks == 0)          /* should not happen */
 
574
                                elog(ERROR, "relation \"%s\" has relchecks = 0",
 
575
                                         RelationGetRelationName(rel));
 
576
                        classForm->relchecks--;
 
577
 
 
578
                        simple_heap_update(pgrel, &relTup->t_self, relTup);
 
579
 
 
580
                        CatalogUpdateIndexes(pgrel, relTup);
 
581
 
 
582
                        heap_freetuple(relTup);
 
583
 
 
584
                        heap_close(pgrel, RowExclusiveLock);
 
585
                }
 
586
 
 
587
                /* Keep lock on constraint's rel until end of xact */
 
588
                heap_close(rel, NoLock);
 
589
        }
 
590
        else if (OidIsValid(con->contypid))
 
591
        {
 
592
                /*
 
593
                 * XXX for now, do nothing special when dropping a domain constraint
 
594
                 *
 
595
                 * Probably there should be some form of locking on the domain type,
 
596
                 * but we have no such concept at the moment.
 
597
                 */
 
598
        }
 
599
        else
 
600
                elog(ERROR, "constraint %u is not of a known type", conId);
 
601
 
 
602
        /* Fry the constraint itself */
 
603
        simple_heap_delete(conDesc, &tup->t_self);
 
604
 
 
605
        /* Clean up */
 
606
        ReleaseSysCache(tup);
 
607
        heap_close(conDesc, RowExclusiveLock);
 
608
}
 
609
 
 
610
/*
 
611
 * RenameConstraintById
 
612
 *              Rename a constraint.
 
613
 *
 
614
 * Note: this isn't intended to be a user-exposed function; it doesn't check
 
615
 * permissions etc.  Currently this is only invoked when renaming an index
 
616
 * that is associated with a constraint, but it's made a little more general
 
617
 * than that with the expectation of someday having ALTER TABLE RENAME
 
618
 * CONSTRAINT.
 
619
 */
 
620
void
 
621
RenameConstraintById(Oid conId, const char *newname)
 
622
{
 
623
        Relation        conDesc;
 
624
        HeapTuple       tuple;
 
625
        Form_pg_constraint con;
 
626
 
 
627
        conDesc = heap_open(ConstraintRelationId, RowExclusiveLock);
 
628
 
 
629
        tuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(conId));
 
630
        if (!HeapTupleIsValid(tuple))
 
631
                elog(ERROR, "cache lookup failed for constraint %u", conId);
 
632
        con = (Form_pg_constraint) GETSTRUCT(tuple);
 
633
 
 
634
        /*
 
635
         * We need to check whether the name is already in use --- note that there
 
636
         * currently is not a unique index that would catch this.
 
637
         */
 
638
        if (OidIsValid(con->conrelid) &&
 
639
                ConstraintNameIsUsed(CONSTRAINT_RELATION,
 
640
                                                         con->conrelid,
 
641
                                                         con->connamespace,
 
642
                                                         newname))
 
643
                ereport(ERROR,
 
644
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
 
645
                           errmsg("constraint \"%s\" for relation \"%s\" already exists",
 
646
                                          newname, get_rel_name(con->conrelid))));
 
647
        if (OidIsValid(con->contypid) &&
 
648
                ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
 
649
                                                         con->contypid,
 
650
                                                         con->connamespace,
 
651
                                                         newname))
 
652
                ereport(ERROR,
 
653
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
 
654
                                 errmsg("constraint \"%s\" for domain \"%s\" already exists",
 
655
                                                newname, format_type_be(con->contypid))));
 
656
 
 
657
        /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
 
658
        namestrcpy(&(con->conname), newname);
 
659
 
 
660
        simple_heap_update(conDesc, &tuple->t_self, tuple);
 
661
 
 
662
        /* update the system catalog indexes */
 
663
        CatalogUpdateIndexes(conDesc, tuple);
 
664
 
 
665
        heap_freetuple(tuple);
 
666
        heap_close(conDesc, RowExclusiveLock);
 
667
}
 
668
 
 
669
/*
 
670
 * AlterConstraintNamespaces
 
671
 *              Find any constraints belonging to the specified object,
 
672
 *              and move them to the specified new namespace.
 
673
 *
 
674
 * isType indicates whether the owning object is a type or a relation.
 
675
 */
 
676
void
 
677
AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 
678
                                                  Oid newNspId, bool isType)
 
679
{
 
680
        Relation        conRel;
 
681
        ScanKeyData key[1];
 
682
        SysScanDesc scan;
 
683
        HeapTuple       tup;
 
684
 
 
685
        conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
 
686
 
 
687
        if (isType)
 
688
        {
 
689
                ScanKeyInit(&key[0],
 
690
                                        Anum_pg_constraint_contypid,
 
691
                                        BTEqualStrategyNumber, F_OIDEQ,
 
692
                                        ObjectIdGetDatum(ownerId));
 
693
 
 
694
                scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
 
695
                                                                  SnapshotNow, 1, key);
 
696
        }
 
697
        else
 
698
        {
 
699
                ScanKeyInit(&key[0],
 
700
                                        Anum_pg_constraint_conrelid,
 
701
                                        BTEqualStrategyNumber, F_OIDEQ,
 
702
                                        ObjectIdGetDatum(ownerId));
 
703
 
 
704
                scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
 
705
                                                                  SnapshotNow, 1, key);
 
706
        }
 
707
 
 
708
        while (HeapTupleIsValid((tup = systable_getnext(scan))))
 
709
        {
 
710
                Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
 
711
 
 
712
                if (conform->connamespace == oldNspId)
 
713
                {
 
714
                        tup = heap_copytuple(tup);
 
715
                        conform = (Form_pg_constraint) GETSTRUCT(tup);
 
716
 
 
717
                        conform->connamespace = newNspId;
 
718
 
 
719
                        simple_heap_update(conRel, &tup->t_self, tup);
 
720
                        CatalogUpdateIndexes(conRel, tup);
 
721
 
 
722
                        /*
 
723
                         * Note: currently, the constraint will not have its own
 
724
                         * dependency on the namespace, so we don't need to do
 
725
                         * changeDependencyFor().
 
726
                         */
 
727
                }
 
728
        }
 
729
 
 
730
        systable_endscan(scan);
 
731
 
 
732
        heap_close(conRel, RowExclusiveLock);
 
733
}
 
734
 
 
735
/*
 
736
 * get_constraint_oid
 
737
 *              Find a constraint on the specified relation with the specified name.
 
738
 *              Returns constraint's OID.
 
739
 */
 
740
Oid
 
741
get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
 
742
{
 
743
        Relation        pg_constraint;
 
744
        HeapTuple       tuple;
 
745
        SysScanDesc scan;
 
746
        ScanKeyData skey[1];
 
747
        Oid                     conOid = InvalidOid;
 
748
 
 
749
        /*
 
750
         * Fetch the constraint tuple from pg_constraint.  There may be more than
 
751
         * one match, because constraints are not required to have unique names;
 
752
         * if so, error out.
 
753
         */
 
754
        pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
 
755
 
 
756
        ScanKeyInit(&skey[0],
 
757
                                Anum_pg_constraint_conrelid,
 
758
                                BTEqualStrategyNumber, F_OIDEQ,
 
759
                                ObjectIdGetDatum(relid));
 
760
 
 
761
        scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
 
762
                                                          SnapshotNow, 1, skey);
 
763
 
 
764
        while (HeapTupleIsValid(tuple = systable_getnext(scan)))
 
765
        {
 
766
                Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
 
767
 
 
768
                if (strcmp(NameStr(con->conname), conname) == 0)
 
769
                {
 
770
                        if (OidIsValid(conOid))
 
771
                                ereport(ERROR,
 
772
                                                (errcode(ERRCODE_DUPLICATE_OBJECT),
 
773
                                 errmsg("table \"%s\" has multiple constraints named \"%s\"",
 
774
                                                get_rel_name(relid), conname)));
 
775
                        conOid = HeapTupleGetOid(tuple);
 
776
                }
 
777
        }
 
778
 
 
779
        systable_endscan(scan);
 
780
 
 
781
        /* If no such constraint exists, complain */
 
782
        if (!OidIsValid(conOid) && !missing_ok)
 
783
                ereport(ERROR,
 
784
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
785
                                 errmsg("constraint \"%s\" for table \"%s\" does not exist",
 
786
                                                conname, get_rel_name(relid))));
 
787
 
 
788
        heap_close(pg_constraint, AccessShareLock);
 
789
 
 
790
        return conOid;
 
791
}
 
792
 
 
793
/*
 
794
 * Determine whether a relation can be proven functionally dependent on
 
795
 * a set of grouping columns.  If so, return TRUE and add the pg_constraint
 
796
 * OIDs of the constraints needed for the proof to the *constraintDeps list.
 
797
 *
 
798
 * grouping_columns is a list of grouping expressions, in which columns of
 
799
 * the rel of interest are Vars with the indicated varno/varlevelsup.
 
800
 *
 
801
 * Currently we only check to see if the rel has a primary key that is a
 
802
 * subset of the grouping_columns.      We could also use plain unique constraints
 
803
 * if all their columns are known not null, but there's a problem: we need
 
804
 * to be able to represent the not-null-ness as part of the constraints added
 
805
 * to *constraintDeps.  FIXME whenever not-null constraints get represented
 
806
 * in pg_constraint.
 
807
 */
 
808
bool
 
809
check_functional_grouping(Oid relid,
 
810
                                                  Index varno, Index varlevelsup,
 
811
                                                  List *grouping_columns,
 
812
                                                  List **constraintDeps)
 
813
{
 
814
        bool            result = false;
 
815
        Relation        pg_constraint;
 
816
        HeapTuple       tuple;
 
817
        SysScanDesc scan;
 
818
        ScanKeyData skey[1];
 
819
 
 
820
        /* Scan pg_constraint for constraints of the target rel */
 
821
        pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
 
822
 
 
823
        ScanKeyInit(&skey[0],
 
824
                                Anum_pg_constraint_conrelid,
 
825
                                BTEqualStrategyNumber, F_OIDEQ,
 
826
                                ObjectIdGetDatum(relid));
 
827
 
 
828
        scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
 
829
                                                          SnapshotNow, 1, skey);
 
830
 
 
831
        while (HeapTupleIsValid(tuple = systable_getnext(scan)))
 
832
        {
 
833
                Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
 
834
                Datum           adatum;
 
835
                bool            isNull;
 
836
                ArrayType  *arr;
 
837
                int16      *attnums;
 
838
                int                     numkeys;
 
839
                int                     i;
 
840
                bool            found_col;
 
841
 
 
842
                /* Only PK constraints are of interest for now, see comment above */
 
843
                if (con->contype != CONSTRAINT_PRIMARY)
 
844
                        continue;
 
845
                /* Constraint must be non-deferrable */
 
846
                if (con->condeferrable)
 
847
                        continue;
 
848
 
 
849
                /* Extract the conkey array, ie, attnums of PK's columns */
 
850
                adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
 
851
                                                          RelationGetDescr(pg_constraint), &isNull);
 
852
                if (isNull)
 
853
                        elog(ERROR, "null conkey for constraint %u",
 
854
                                 HeapTupleGetOid(tuple));
 
855
                arr = DatumGetArrayTypeP(adatum);               /* ensure not toasted */
 
856
                numkeys = ARR_DIMS(arr)[0];
 
857
                if (ARR_NDIM(arr) != 1 ||
 
858
                        numkeys < 0 ||
 
859
                        ARR_HASNULL(arr) ||
 
860
                        ARR_ELEMTYPE(arr) != INT2OID)
 
861
                        elog(ERROR, "conkey is not a 1-D smallint array");
 
862
                attnums = (int16 *) ARR_DATA_PTR(arr);
 
863
 
 
864
                found_col = false;
 
865
                for (i = 0; i < numkeys; i++)
 
866
                {
 
867
                        AttrNumber      attnum = attnums[i];
 
868
                        ListCell   *gl;
 
869
 
 
870
                        found_col = false;
 
871
                        foreach(gl, grouping_columns)
 
872
                        {
 
873
                                Var                *gvar = (Var *) lfirst(gl);
 
874
 
 
875
                                if (IsA(gvar, Var) &&
 
876
                                        gvar->varno == varno &&
 
877
                                        gvar->varlevelsup == varlevelsup &&
 
878
                                        gvar->varattno == attnum)
 
879
                                {
 
880
                                        found_col = true;
 
881
                                        break;
 
882
                                }
 
883
                        }
 
884
                        if (!found_col)
 
885
                                break;
 
886
                }
 
887
 
 
888
                if (found_col)
 
889
                {
 
890
                        /* The PK is a subset of grouping_columns, so we win */
 
891
                        *constraintDeps = lappend_oid(*constraintDeps,
 
892
                                                                                  HeapTupleGetOid(tuple));
 
893
                        result = true;
 
894
                        break;
 
895
                }
 
896
        }
 
897
 
 
898
        systable_endscan(scan);
 
899
 
 
900
        heap_close(pg_constraint, AccessShareLock);
 
901
 
 
902
        return result;
 
903
}