Coverage Report

Created: 2025-08-12 06:43

/src/postgres/src/backend/utils/cache/lsyscache.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * lsyscache.c
4
 *    Convenience routines for common queries in the system catalog cache.
5
 *
6
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 * IDENTIFICATION
10
 *    src/backend/utils/cache/lsyscache.c
11
 *
12
 * NOTES
13
 *    Eventually, the index information should go through here, too.
14
 *-------------------------------------------------------------------------
15
 */
16
#include "postgres.h"
17
18
#include "access/hash.h"
19
#include "access/htup_details.h"
20
#include "bootstrap/bootstrap.h"
21
#include "catalog/namespace.h"
22
#include "catalog/pg_am.h"
23
#include "catalog/pg_amop.h"
24
#include "catalog/pg_amproc.h"
25
#include "catalog/pg_cast.h"
26
#include "catalog/pg_class.h"
27
#include "catalog/pg_collation.h"
28
#include "catalog/pg_constraint.h"
29
#include "catalog/pg_index.h"
30
#include "catalog/pg_language.h"
31
#include "catalog/pg_namespace.h"
32
#include "catalog/pg_opclass.h"
33
#include "catalog/pg_opfamily.h"
34
#include "catalog/pg_operator.h"
35
#include "catalog/pg_proc.h"
36
#include "catalog/pg_publication.h"
37
#include "catalog/pg_range.h"
38
#include "catalog/pg_statistic.h"
39
#include "catalog/pg_subscription.h"
40
#include "catalog/pg_transform.h"
41
#include "catalog/pg_type.h"
42
#include "miscadmin.h"
43
#include "nodes/makefuncs.h"
44
#include "utils/array.h"
45
#include "utils/builtins.h"
46
#include "utils/catcache.h"
47
#include "utils/datum.h"
48
#include "utils/fmgroids.h"
49
#include "utils/lsyscache.h"
50
#include "utils/syscache.h"
51
#include "utils/typcache.h"
52
53
/* Hook for plugins to get control in get_attavgwidth() */
54
get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
55
56
57
/*        ---------- AMOP CACHES ----------            */
58
59
/*
60
 * op_in_opfamily
61
 *
62
 *    Return t iff operator 'opno' is in operator family 'opfamily'.
63
 *
64
 * This function only considers search operators, not ordering operators.
65
 */
66
bool
67
op_in_opfamily(Oid opno, Oid opfamily)
68
0
{
69
0
  return SearchSysCacheExists3(AMOPOPID,
70
0
                 ObjectIdGetDatum(opno),
71
0
                 CharGetDatum(AMOP_SEARCH),
72
0
                 ObjectIdGetDatum(opfamily));
73
0
}
74
75
/*
76
 * get_op_opfamily_strategy
77
 *
78
 *    Get the operator's strategy number within the specified opfamily,
79
 *    or 0 if it's not a member of the opfamily.
80
 *
81
 * This function only considers search operators, not ordering operators.
82
 */
83
int
84
get_op_opfamily_strategy(Oid opno, Oid opfamily)
85
0
{
86
0
  HeapTuple tp;
87
0
  Form_pg_amop amop_tup;
88
0
  int     result;
89
90
0
  tp = SearchSysCache3(AMOPOPID,
91
0
             ObjectIdGetDatum(opno),
92
0
             CharGetDatum(AMOP_SEARCH),
93
0
             ObjectIdGetDatum(opfamily));
94
0
  if (!HeapTupleIsValid(tp))
95
0
    return 0;
96
0
  amop_tup = (Form_pg_amop) GETSTRUCT(tp);
97
0
  result = amop_tup->amopstrategy;
98
0
  ReleaseSysCache(tp);
99
0
  return result;
100
0
}
101
102
/*
103
 * get_op_opfamily_sortfamily
104
 *
105
 *    If the operator is an ordering operator within the specified opfamily,
106
 *    return its amopsortfamily OID; else return InvalidOid.
107
 */
108
Oid
109
get_op_opfamily_sortfamily(Oid opno, Oid opfamily)
110
0
{
111
0
  HeapTuple tp;
112
0
  Form_pg_amop amop_tup;
113
0
  Oid     result;
114
115
0
  tp = SearchSysCache3(AMOPOPID,
116
0
             ObjectIdGetDatum(opno),
117
0
             CharGetDatum(AMOP_ORDER),
118
0
             ObjectIdGetDatum(opfamily));
119
0
  if (!HeapTupleIsValid(tp))
120
0
    return InvalidOid;
121
0
  amop_tup = (Form_pg_amop) GETSTRUCT(tp);
122
0
  result = amop_tup->amopsortfamily;
123
0
  ReleaseSysCache(tp);
124
0
  return result;
125
0
}
126
127
/*
128
 * get_op_opfamily_properties
129
 *
130
 *    Get the operator's strategy number and declared input data types
131
 *    within the specified opfamily.
132
 *
133
 * Caller should already have verified that opno is a member of opfamily,
134
 * therefore we raise an error if the tuple is not found.
135
 */
136
void
137
get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op,
138
               int *strategy,
139
               Oid *lefttype,
140
               Oid *righttype)
141
0
{
142
0
  HeapTuple tp;
143
0
  Form_pg_amop amop_tup;
144
145
0
  tp = SearchSysCache3(AMOPOPID,
146
0
             ObjectIdGetDatum(opno),
147
0
             CharGetDatum(ordering_op ? AMOP_ORDER : AMOP_SEARCH),
148
0
             ObjectIdGetDatum(opfamily));
149
0
  if (!HeapTupleIsValid(tp))
150
0
    elog(ERROR, "operator %u is not a member of opfamily %u",
151
0
       opno, opfamily);
152
0
  amop_tup = (Form_pg_amop) GETSTRUCT(tp);
153
0
  *strategy = amop_tup->amopstrategy;
154
0
  *lefttype = amop_tup->amoplefttype;
155
0
  *righttype = amop_tup->amoprighttype;
156
0
  ReleaseSysCache(tp);
157
0
}
158
159
/*
160
 * get_opfamily_member
161
 *    Get the OID of the operator that implements the specified strategy
162
 *    with the specified datatypes for the specified opfamily.
163
 *
164
 * Returns InvalidOid if there is no pg_amop entry for the given keys.
165
 */
166
Oid
167
get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
168
          int16 strategy)
169
0
{
170
0
  HeapTuple tp;
171
0
  Form_pg_amop amop_tup;
172
0
  Oid     result;
173
174
0
  tp = SearchSysCache4(AMOPSTRATEGY,
175
0
             ObjectIdGetDatum(opfamily),
176
0
             ObjectIdGetDatum(lefttype),
177
0
             ObjectIdGetDatum(righttype),
178
0
             Int16GetDatum(strategy));
179
0
  if (!HeapTupleIsValid(tp))
180
0
    return InvalidOid;
181
0
  amop_tup = (Form_pg_amop) GETSTRUCT(tp);
182
0
  result = amop_tup->amopopr;
183
0
  ReleaseSysCache(tp);
184
0
  return result;
185
0
}
186
187
/*
188
 * get_opfamily_member_for_cmptype
189
 *    Get the OID of the operator that implements the specified comparison
190
 *    type with the specified datatypes for the specified opfamily.
191
 *
192
 * Returns InvalidOid if there is no mapping for the comparison type or no
193
 * pg_amop entry for the given keys.
194
 */
195
Oid
196
get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype,
197
                CompareType cmptype)
198
0
{
199
0
  Oid     opmethod;
200
0
  StrategyNumber strategy;
201
202
0
  opmethod = get_opfamily_method(opfamily);
203
0
  strategy = IndexAmTranslateCompareType(cmptype, opmethod, opfamily, true);
204
0
  if (!strategy)
205
0
    return InvalidOid;
206
0
  return get_opfamily_member(opfamily, lefttype, righttype, strategy);
207
0
}
208
209
/*
210
 * get_opmethod_canorder
211
 *    Return amcanorder field for given index AM.
212
 *
213
 * To speed things up in the common cases, we're hardcoding the results from
214
 * the built-in index types.  Note that we also need to hardcode the negative
215
 * results from the built-in non-btree index types, since you'll usually get a
216
 * few hits for those as well.  It would be nice to organize and cache this a
217
 * bit differently to avoid the hardcoding.
218
 */
219
static bool
220
get_opmethod_canorder(Oid amoid)
221
0
{
222
0
  switch (amoid)
223
0
  {
224
0
    case BTREE_AM_OID:
225
0
      return true;
226
0
    case HASH_AM_OID:
227
0
    case GIST_AM_OID:
228
0
    case GIN_AM_OID:
229
0
    case SPGIST_AM_OID:
230
0
    case BRIN_AM_OID:
231
0
      return false;
232
0
    default:
233
0
      {
234
0
        bool    result;
235
0
        IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
236
237
0
        result = amroutine->amcanorder;
238
0
        pfree(amroutine);
239
0
        return result;
240
0
      }
241
0
  }
242
0
}
243
244
/*
245
 * get_ordering_op_properties
246
 *    Given the OID of an ordering operator (a "<" or ">" operator),
247
 *    determine its opfamily, its declared input datatype, and its
248
 *    comparison type.
249
 *
250
 * Returns true if successful, false if no matching pg_amop entry exists.
251
 * (This indicates that the operator is not a valid ordering operator.)
252
 *
253
 * Note: the operator could be registered in multiple families, for example
254
 * if someone were to build a "reverse sort" opfamily.  This would result in
255
 * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST
256
 * or NULLS LAST, as well as inefficient planning due to failure to match up
257
 * pathkeys that should be the same.  So we want a determinate result here.
258
 * Because of the way the syscache search works, we'll use the interpretation
259
 * associated with the opfamily with smallest OID, which is probably
260
 * determinate enough.  Since there is no longer any particularly good reason
261
 * to build reverse-sort opfamilies, it doesn't seem worth expending any
262
 * additional effort on ensuring consistency.
263
 */
264
bool
265
get_ordering_op_properties(Oid opno,
266
               Oid *opfamily, Oid *opcintype, CompareType *cmptype)
267
0
{
268
0
  bool    result = false;
269
0
  CatCList   *catlist;
270
0
  int     i;
271
272
  /* ensure outputs are initialized on failure */
273
0
  *opfamily = InvalidOid;
274
0
  *opcintype = InvalidOid;
275
0
  *cmptype = COMPARE_INVALID;
276
277
  /*
278
   * Search pg_amop to see if the target operator is registered as the "<"
279
   * or ">" operator of any btree opfamily.
280
   */
281
0
  catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
282
283
0
  for (i = 0; i < catlist->n_members; i++)
284
0
  {
285
0
    HeapTuple tuple = &catlist->members[i]->tuple;
286
0
    Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
287
0
    CompareType am_cmptype;
288
289
    /* must be ordering index */
290
0
    if (!get_opmethod_canorder(aform->amopmethod))
291
0
      continue;
292
293
0
    am_cmptype = IndexAmTranslateStrategy(aform->amopstrategy,
294
0
                        aform->amopmethod,
295
0
                        aform->amopfamily,
296
0
                        true);
297
298
0
    if (am_cmptype == COMPARE_LT || am_cmptype == COMPARE_GT)
299
0
    {
300
      /* Found it ... should have consistent input types */
301
0
      if (aform->amoplefttype == aform->amoprighttype)
302
0
      {
303
        /* Found a suitable opfamily, return info */
304
0
        *opfamily = aform->amopfamily;
305
0
        *opcintype = aform->amoplefttype;
306
0
        *cmptype = am_cmptype;
307
0
        result = true;
308
0
        break;
309
0
      }
310
0
    }
311
0
  }
312
313
0
  ReleaseSysCacheList(catlist);
314
315
0
  return result;
316
0
}
317
318
/*
319
 * get_equality_op_for_ordering_op
320
 *    Get the OID of the datatype-specific equality operator
321
 *    associated with an ordering operator (a "<" or ">" operator).
322
 *
323
 * If "reverse" isn't NULL, also set *reverse to false if the operator is "<",
324
 * true if it's ">"
325
 *
326
 * Returns InvalidOid if no matching equality operator can be found.
327
 * (This indicates that the operator is not a valid ordering operator.)
328
 */
329
Oid
330
get_equality_op_for_ordering_op(Oid opno, bool *reverse)
331
0
{
332
0
  Oid     result = InvalidOid;
333
0
  Oid     opfamily;
334
0
  Oid     opcintype;
335
0
  CompareType cmptype;
336
337
  /* Find the operator in pg_amop */
338
0
  if (get_ordering_op_properties(opno,
339
0
                   &opfamily, &opcintype, &cmptype))
340
0
  {
341
    /* Found a suitable opfamily, get matching equality operator */
342
0
    result = get_opfamily_member_for_cmptype(opfamily,
343
0
                         opcintype,
344
0
                         opcintype,
345
0
                         COMPARE_EQ);
346
0
    if (reverse)
347
0
      *reverse = (cmptype == COMPARE_GT);
348
0
  }
349
350
0
  return result;
351
0
}
352
353
/*
354
 * get_ordering_op_for_equality_op
355
 *    Get the OID of a datatype-specific "less than" ordering operator
356
 *    associated with an equality operator.  (If there are multiple
357
 *    possibilities, assume any one will do.)
358
 *
359
 * This function is used when we have to sort data before unique-ifying,
360
 * and don't much care which sorting op is used as long as it's compatible
361
 * with the intended equality operator.  Since we need a sorting operator,
362
 * it should be single-data-type even if the given operator is cross-type.
363
 * The caller specifies whether to find an op for the LHS or RHS data type.
364
 *
365
 * Returns InvalidOid if no matching ordering operator can be found.
366
 */
367
Oid
368
get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
369
0
{
370
0
  Oid     result = InvalidOid;
371
0
  CatCList   *catlist;
372
0
  int     i;
373
374
  /*
375
   * Search pg_amop to see if the target operator is registered as the "="
376
   * operator of any btree opfamily.
377
   */
378
0
  catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
379
380
0
  for (i = 0; i < catlist->n_members; i++)
381
0
  {
382
0
    HeapTuple tuple = &catlist->members[i]->tuple;
383
0
    Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
384
0
    CompareType cmptype;
385
386
    /* must be ordering index */
387
0
    if (!get_opmethod_canorder(aform->amopmethod))
388
0
      continue;
389
390
0
    cmptype = IndexAmTranslateStrategy(aform->amopstrategy,
391
0
                       aform->amopmethod,
392
0
                       aform->amopfamily,
393
0
                       true);
394
0
    if (cmptype == COMPARE_EQ)
395
0
    {
396
      /* Found a suitable opfamily, get matching ordering operator */
397
0
      Oid     typid;
398
399
0
      typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
400
0
      result = get_opfamily_member_for_cmptype(aform->amopfamily,
401
0
                           typid, typid,
402
0
                           COMPARE_LT);
403
0
      if (OidIsValid(result))
404
0
        break;
405
      /* failure probably shouldn't happen, but keep looking if so */
406
0
    }
407
0
  }
408
409
0
  ReleaseSysCacheList(catlist);
410
411
0
  return result;
412
0
}
413
414
/*
415
 * get_mergejoin_opfamilies
416
 *    Given a putatively mergejoinable operator, return a list of the OIDs
417
 *    of the amcanorder opfamilies in which it represents equality.
418
 *
419
 * It is possible (though at present unusual) for an operator to be equality
420
 * in more than one opfamily, hence the result is a list.  This also lets us
421
 * return NIL if the operator is not found in any opfamilies.
422
 *
423
 * The planner currently uses simple equal() tests to compare the lists
424
 * returned by this function, which makes the list order relevant, though
425
 * strictly speaking it should not be.  Because of the way syscache list
426
 * searches are handled, in normal operation the result will be sorted by OID
427
 * so everything works fine.  If running with system index usage disabled,
428
 * the result ordering is unspecified and hence the planner might fail to
429
 * recognize optimization opportunities ... but that's hardly a scenario in
430
 * which performance is good anyway, so there's no point in expending code
431
 * or cycles here to guarantee the ordering in that case.
432
 */
433
List *
434
get_mergejoin_opfamilies(Oid opno)
435
0
{
436
0
  List     *result = NIL;
437
0
  CatCList   *catlist;
438
0
  int     i;
439
440
  /*
441
   * Search pg_amop to see if the target operator is registered as the "="
442
   * operator of any opfamily of an ordering index type.
443
   */
444
0
  catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
445
446
0
  for (i = 0; i < catlist->n_members; i++)
447
0
  {
448
0
    HeapTuple tuple = &catlist->members[i]->tuple;
449
0
    Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
450
451
    /* must be ordering index equality */
452
0
    if (get_opmethod_canorder(aform->amopmethod) &&
453
0
      IndexAmTranslateStrategy(aform->amopstrategy,
454
0
                   aform->amopmethod,
455
0
                   aform->amopfamily,
456
0
                   true) == COMPARE_EQ)
457
0
      result = lappend_oid(result, aform->amopfamily);
458
0
  }
459
460
0
  ReleaseSysCacheList(catlist);
461
462
0
  return result;
463
0
}
464
465
/*
466
 * get_compatible_hash_operators
467
 *    Get the OID(s) of hash equality operator(s) compatible with the given
468
 *    operator, but operating on its LHS and/or RHS datatype.
469
 *
470
 * An operator for the LHS type is sought and returned into *lhs_opno if
471
 * lhs_opno isn't NULL.  Similarly, an operator for the RHS type is sought
472
 * and returned into *rhs_opno if rhs_opno isn't NULL.
473
 *
474
 * If the given operator is not cross-type, the results should be the same
475
 * operator, but in cross-type situations they will be different.
476
 *
477
 * Returns true if able to find the requested operator(s), false if not.
478
 * (This indicates that the operator should not have been marked oprcanhash.)
479
 */
480
bool
481
get_compatible_hash_operators(Oid opno,
482
                Oid *lhs_opno, Oid *rhs_opno)
483
0
{
484
0
  bool    result = false;
485
0
  CatCList   *catlist;
486
0
  int     i;
487
488
  /* Ensure output args are initialized on failure */
489
0
  if (lhs_opno)
490
0
    *lhs_opno = InvalidOid;
491
0
  if (rhs_opno)
492
0
    *rhs_opno = InvalidOid;
493
494
  /*
495
   * Search pg_amop to see if the target operator is registered as the "="
496
   * operator of any hash opfamily.  If the operator is registered in
497
   * multiple opfamilies, assume we can use any one.
498
   */
499
0
  catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
500
501
0
  for (i = 0; i < catlist->n_members; i++)
502
0
  {
503
0
    HeapTuple tuple = &catlist->members[i]->tuple;
504
0
    Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
505
506
0
    if (aform->amopmethod == HASH_AM_OID &&
507
0
      aform->amopstrategy == HTEqualStrategyNumber)
508
0
    {
509
      /* No extra lookup needed if given operator is single-type */
510
0
      if (aform->amoplefttype == aform->amoprighttype)
511
0
      {
512
0
        if (lhs_opno)
513
0
          *lhs_opno = opno;
514
0
        if (rhs_opno)
515
0
          *rhs_opno = opno;
516
0
        result = true;
517
0
        break;
518
0
      }
519
520
      /*
521
       * Get the matching single-type operator(s).  Failure probably
522
       * shouldn't happen --- it implies a bogus opfamily --- but
523
       * continue looking if so.
524
       */
525
0
      if (lhs_opno)
526
0
      {
527
0
        *lhs_opno = get_opfamily_member(aform->amopfamily,
528
0
                        aform->amoplefttype,
529
0
                        aform->amoplefttype,
530
0
                        HTEqualStrategyNumber);
531
0
        if (!OidIsValid(*lhs_opno))
532
0
          continue;
533
        /* Matching LHS found, done if caller doesn't want RHS */
534
0
        if (!rhs_opno)
535
0
        {
536
0
          result = true;
537
0
          break;
538
0
        }
539
0
      }
540
0
      if (rhs_opno)
541
0
      {
542
0
        *rhs_opno = get_opfamily_member(aform->amopfamily,
543
0
                        aform->amoprighttype,
544
0
                        aform->amoprighttype,
545
0
                        HTEqualStrategyNumber);
546
0
        if (!OidIsValid(*rhs_opno))
547
0
        {
548
          /* Forget any LHS operator from this opfamily */
549
0
          if (lhs_opno)
550
0
            *lhs_opno = InvalidOid;
551
0
          continue;
552
0
        }
553
        /* Matching RHS found, so done */
554
0
        result = true;
555
0
        break;
556
0
      }
557
0
    }
558
0
  }
559
560
0
  ReleaseSysCacheList(catlist);
561
562
0
  return result;
563
0
}
564
565
/*
566
 * get_op_hash_functions
567
 *    Get the OID(s) of the standard hash support function(s) compatible with
568
 *    the given operator, operating on its LHS and/or RHS datatype as required.
569
 *
570
 * A function for the LHS type is sought and returned into *lhs_procno if
571
 * lhs_procno isn't NULL.  Similarly, a function for the RHS type is sought
572
 * and returned into *rhs_procno if rhs_procno isn't NULL.
573
 *
574
 * If the given operator is not cross-type, the results should be the same
575
 * function, but in cross-type situations they will be different.
576
 *
577
 * Returns true if able to find the requested function(s), false if not.
578
 * (This indicates that the operator should not have been marked oprcanhash.)
579
 */
580
bool
581
get_op_hash_functions(Oid opno,
582
            RegProcedure *lhs_procno, RegProcedure *rhs_procno)
583
0
{
584
0
  bool    result = false;
585
0
  CatCList   *catlist;
586
0
  int     i;
587
588
  /* Ensure output args are initialized on failure */
589
0
  if (lhs_procno)
590
0
    *lhs_procno = InvalidOid;
591
0
  if (rhs_procno)
592
0
    *rhs_procno = InvalidOid;
593
594
  /*
595
   * Search pg_amop to see if the target operator is registered as the "="
596
   * operator of any hash opfamily.  If the operator is registered in
597
   * multiple opfamilies, assume we can use any one.
598
   */
599
0
  catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
600
601
0
  for (i = 0; i < catlist->n_members; i++)
602
0
  {
603
0
    HeapTuple tuple = &catlist->members[i]->tuple;
604
0
    Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
605
606
0
    if (aform->amopmethod == HASH_AM_OID &&
607
0
      aform->amopstrategy == HTEqualStrategyNumber)
608
0
    {
609
      /*
610
       * Get the matching support function(s).  Failure probably
611
       * shouldn't happen --- it implies a bogus opfamily --- but
612
       * continue looking if so.
613
       */
614
0
      if (lhs_procno)
615
0
      {
616
0
        *lhs_procno = get_opfamily_proc(aform->amopfamily,
617
0
                        aform->amoplefttype,
618
0
                        aform->amoplefttype,
619
0
                        HASHSTANDARD_PROC);
620
0
        if (!OidIsValid(*lhs_procno))
621
0
          continue;
622
        /* Matching LHS found, done if caller doesn't want RHS */
623
0
        if (!rhs_procno)
624
0
        {
625
0
          result = true;
626
0
          break;
627
0
        }
628
        /* Only one lookup needed if given operator is single-type */
629
0
        if (aform->amoplefttype == aform->amoprighttype)
630
0
        {
631
0
          *rhs_procno = *lhs_procno;
632
0
          result = true;
633
0
          break;
634
0
        }
635
0
      }
636
0
      if (rhs_procno)
637
0
      {
638
0
        *rhs_procno = get_opfamily_proc(aform->amopfamily,
639
0
                        aform->amoprighttype,
640
0
                        aform->amoprighttype,
641
0
                        HASHSTANDARD_PROC);
642
0
        if (!OidIsValid(*rhs_procno))
643
0
        {
644
          /* Forget any LHS function from this opfamily */
645
0
          if (lhs_procno)
646
0
            *lhs_procno = InvalidOid;
647
0
          continue;
648
0
        }
649
        /* Matching RHS found, so done */
650
0
        result = true;
651
0
        break;
652
0
      }
653
0
    }
654
0
  }
655
656
0
  ReleaseSysCacheList(catlist);
657
658
0
  return result;
659
0
}
660
661
/*
662
 * get_op_index_interpretation
663
 *    Given an operator's OID, find out which amcanorder opfamilies it belongs to,
664
 *    and what properties it has within each one.  The results are returned
665
 *    as a palloc'd list of OpIndexInterpretation structs.
666
 *
667
 * In addition to the normal btree operators, we consider a <> operator to be
668
 * a "member" of an opfamily if its negator is an equality operator of the
669
 * opfamily.  COMPARE_NE is returned as the strategy number for this case.
670
 */
671
List *
672
get_op_index_interpretation(Oid opno)
673
0
{
674
0
  List     *result = NIL;
675
0
  OpIndexInterpretation *thisresult;
676
0
  CatCList   *catlist;
677
0
  int     i;
678
679
  /*
680
   * Find all the pg_amop entries containing the operator.
681
   */
682
0
  catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
683
684
0
  for (i = 0; i < catlist->n_members; i++)
685
0
  {
686
0
    HeapTuple op_tuple = &catlist->members[i]->tuple;
687
0
    Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
688
0
    CompareType cmptype;
689
690
    /* must be ordering index */
691
0
    if (!get_opmethod_canorder(op_form->amopmethod))
692
0
      continue;
693
694
    /* Get the operator's comparision type */
695
0
    cmptype = IndexAmTranslateStrategy(op_form->amopstrategy,
696
0
                       op_form->amopmethod,
697
0
                       op_form->amopfamily,
698
0
                       true);
699
700
    /* should not happen */
701
0
    if (cmptype == COMPARE_INVALID)
702
0
      continue;
703
704
0
    thisresult = (OpIndexInterpretation *)
705
0
      palloc(sizeof(OpIndexInterpretation));
706
0
    thisresult->opfamily_id = op_form->amopfamily;
707
0
    thisresult->cmptype = cmptype;
708
0
    thisresult->oplefttype = op_form->amoplefttype;
709
0
    thisresult->oprighttype = op_form->amoprighttype;
710
0
    result = lappend(result, thisresult);
711
0
  }
712
713
0
  ReleaseSysCacheList(catlist);
714
715
  /*
716
   * If we didn't find any btree opfamily containing the operator, perhaps
717
   * it is a <> operator.  See if it has a negator that is in an opfamily.
718
   */
719
0
  if (result == NIL)
720
0
  {
721
0
    Oid     op_negator = get_negator(opno);
722
723
0
    if (OidIsValid(op_negator))
724
0
    {
725
0
      catlist = SearchSysCacheList1(AMOPOPID,
726
0
                      ObjectIdGetDatum(op_negator));
727
728
0
      for (i = 0; i < catlist->n_members; i++)
729
0
      {
730
0
        HeapTuple op_tuple = &catlist->members[i]->tuple;
731
0
        Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
732
0
        IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
733
0
        CompareType cmptype;
734
735
        /* must be ordering index */
736
0
        if (!amroutine->amcanorder)
737
0
          continue;
738
739
        /* Get the operator's comparision type */
740
0
        cmptype = IndexAmTranslateStrategy(op_form->amopstrategy,
741
0
                           op_form->amopmethod,
742
0
                           op_form->amopfamily,
743
0
                           true);
744
745
        /* Only consider negators that are = */
746
0
        if (cmptype != COMPARE_EQ)
747
0
          continue;
748
749
        /* OK, report it as COMPARE_NE */
750
0
        thisresult = (OpIndexInterpretation *)
751
0
          palloc(sizeof(OpIndexInterpretation));
752
0
        thisresult->opfamily_id = op_form->amopfamily;
753
0
        thisresult->cmptype = COMPARE_NE;
754
0
        thisresult->oplefttype = op_form->amoplefttype;
755
0
        thisresult->oprighttype = op_form->amoprighttype;
756
0
        result = lappend(result, thisresult);
757
0
      }
758
759
0
      ReleaseSysCacheList(catlist);
760
0
    }
761
0
  }
762
763
0
  return result;
764
0
}
765
766
/*
767
 * equality_ops_are_compatible
768
 *    Return true if the two given equality operators have compatible
769
 *    semantics.
770
 *
771
 * This is trivially true if they are the same operator.  Otherwise,
772
 * Otherwise, we look to see if they both belong to an opfamily that
773
 * guarantees compatible semantics for equality.  Either finding allows us to
774
 * assume that they have compatible notions of equality.  (The reason we need
775
 * to do these pushups is that one might be a cross-type operator; for
776
 * instance int24eq vs int4eq.)
777
 */
778
bool
779
equality_ops_are_compatible(Oid opno1, Oid opno2)
780
0
{
781
0
  bool    result;
782
0
  CatCList   *catlist;
783
0
  int     i;
784
785
  /* Easy if they're the same operator */
786
0
  if (opno1 == opno2)
787
0
    return true;
788
789
  /*
790
   * We search through all the pg_amop entries for opno1.
791
   */
792
0
  catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
793
794
0
  result = false;
795
0
  for (i = 0; i < catlist->n_members; i++)
796
0
  {
797
0
    HeapTuple op_tuple = &catlist->members[i]->tuple;
798
0
    Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
799
800
    /*
801
     * op_in_opfamily() is cheaper than GetIndexAmRoutineByAmId(), so
802
     * check it first
803
     */
804
0
    if (op_in_opfamily(opno2, op_form->amopfamily))
805
0
    {
806
0
      IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
807
808
0
      if (amroutine->amconsistentequality)
809
0
      {
810
0
        result = true;
811
0
        break;
812
0
      }
813
0
    }
814
0
  }
815
816
0
  ReleaseSysCacheList(catlist);
817
818
0
  return result;
819
0
}
820
821
/*
822
 * comparison_ops_are_compatible
823
 *    Return true if the two given comparison operators have compatible
824
 *    semantics.
825
 *
826
 * This is trivially true if they are the same operator.  Otherwise, we look
827
 * to see if they both belong to an opfamily that guarantees compatible
828
 * semantics for ordering.  (For example, for btree, '<' and '>=' ops match if
829
 * they belong to the same family.)
830
 *
831
 * (This is identical to equality_ops_are_compatible(), except that we check
832
 * amconsistentordering instead of amconsistentequality.)
833
 */
834
bool
835
comparison_ops_are_compatible(Oid opno1, Oid opno2)
836
0
{
837
0
  bool    result;
838
0
  CatCList   *catlist;
839
0
  int     i;
840
841
  /* Easy if they're the same operator */
842
0
  if (opno1 == opno2)
843
0
    return true;
844
845
  /*
846
   * We search through all the pg_amop entries for opno1.
847
   */
848
0
  catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
849
850
0
  result = false;
851
0
  for (i = 0; i < catlist->n_members; i++)
852
0
  {
853
0
    HeapTuple op_tuple = &catlist->members[i]->tuple;
854
0
    Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
855
856
    /*
857
     * op_in_opfamily() is cheaper than GetIndexAmRoutineByAmId(), so
858
     * check it first
859
     */
860
0
    if (op_in_opfamily(opno2, op_form->amopfamily))
861
0
    {
862
0
      IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
863
864
0
      if (amroutine->amconsistentordering)
865
0
      {
866
0
        result = true;
867
0
        break;
868
0
      }
869
0
    }
870
0
  }
871
872
0
  ReleaseSysCacheList(catlist);
873
874
0
  return result;
875
0
}
876
877
878
/*        ---------- AMPROC CACHES ----------            */
879
880
/*
881
 * get_opfamily_proc
882
 *    Get the OID of the specified support function
883
 *    for the specified opfamily and datatypes.
884
 *
885
 * Returns InvalidOid if there is no pg_amproc entry for the given keys.
886
 */
887
Oid
888
get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
889
0
{
890
0
  HeapTuple tp;
891
0
  Form_pg_amproc amproc_tup;
892
0
  RegProcedure result;
893
894
0
  tp = SearchSysCache4(AMPROCNUM,
895
0
             ObjectIdGetDatum(opfamily),
896
0
             ObjectIdGetDatum(lefttype),
897
0
             ObjectIdGetDatum(righttype),
898
0
             Int16GetDatum(procnum));
899
0
  if (!HeapTupleIsValid(tp))
900
0
    return InvalidOid;
901
0
  amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
902
0
  result = amproc_tup->amproc;
903
0
  ReleaseSysCache(tp);
904
0
  return result;
905
0
}
906
907
908
/*        ---------- ATTRIBUTE CACHES ----------           */
909
910
/*
911
 * get_attname
912
 *    Given the relation id and the attribute number, return the "attname"
913
 *    field from the attribute relation as a palloc'ed string.
914
 *
915
 * If no such attribute exists and missing_ok is true, NULL is returned;
916
 * otherwise a not-intended-for-user-consumption error is thrown.
917
 */
918
char *
919
get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
920
0
{
921
0
  HeapTuple tp;
922
923
0
  tp = SearchSysCache2(ATTNUM,
924
0
             ObjectIdGetDatum(relid), Int16GetDatum(attnum));
925
0
  if (HeapTupleIsValid(tp))
926
0
  {
927
0
    Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
928
0
    char     *result;
929
930
0
    result = pstrdup(NameStr(att_tup->attname));
931
0
    ReleaseSysCache(tp);
932
0
    return result;
933
0
  }
934
935
0
  if (!missing_ok)
936
0
    elog(ERROR, "cache lookup failed for attribute %d of relation %u",
937
0
       attnum, relid);
938
0
  return NULL;
939
0
}
940
941
/*
942
 * get_attnum
943
 *
944
 *    Given the relation id and the attribute name,
945
 *    return the "attnum" field from the attribute relation.
946
 *
947
 *    Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
948
 */
949
AttrNumber
950
get_attnum(Oid relid, const char *attname)
951
0
{
952
0
  HeapTuple tp;
953
954
0
  tp = SearchSysCacheAttName(relid, attname);
955
0
  if (HeapTupleIsValid(tp))
956
0
  {
957
0
    Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
958
0
    AttrNumber  result;
959
960
0
    result = att_tup->attnum;
961
0
    ReleaseSysCache(tp);
962
0
    return result;
963
0
  }
964
0
  else
965
0
    return InvalidAttrNumber;
966
0
}
967
968
/*
969
 * get_attgenerated
970
 *
971
 *    Given the relation id and the attribute number,
972
 *    return the "attgenerated" field from the attribute relation.
973
 *
974
 *    Errors if not found.
975
 *
976
 *    Since not generated is represented by '\0', this can also be used as a
977
 *    Boolean test.
978
 */
979
char
980
get_attgenerated(Oid relid, AttrNumber attnum)
981
0
{
982
0
  HeapTuple tp;
983
0
  Form_pg_attribute att_tup;
984
0
  char    result;
985
986
0
  tp = SearchSysCache2(ATTNUM,
987
0
             ObjectIdGetDatum(relid),
988
0
             Int16GetDatum(attnum));
989
0
  if (!HeapTupleIsValid(tp))
990
0
    elog(ERROR, "cache lookup failed for attribute %d of relation %u",
991
0
       attnum, relid);
992
0
  att_tup = (Form_pg_attribute) GETSTRUCT(tp);
993
0
  result = att_tup->attgenerated;
994
0
  ReleaseSysCache(tp);
995
0
  return result;
996
0
}
997
998
/*
999
 * get_atttype
1000
 *
1001
 *    Given the relation OID and the attribute number with the relation,
1002
 *    return the attribute type OID.
1003
 */
1004
Oid
1005
get_atttype(Oid relid, AttrNumber attnum)
1006
0
{
1007
0
  HeapTuple tp;
1008
1009
0
  tp = SearchSysCache2(ATTNUM,
1010
0
             ObjectIdGetDatum(relid),
1011
0
             Int16GetDatum(attnum));
1012
0
  if (HeapTupleIsValid(tp))
1013
0
  {
1014
0
    Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
1015
0
    Oid     result;
1016
1017
0
    result = att_tup->atttypid;
1018
0
    ReleaseSysCache(tp);
1019
0
    return result;
1020
0
  }
1021
0
  else
1022
0
    return InvalidOid;
1023
0
}
1024
1025
/*
1026
 * get_atttypetypmodcoll
1027
 *
1028
 *    A three-fer: given the relation id and the attribute number,
1029
 *    fetch atttypid, atttypmod, and attcollation in a single cache lookup.
1030
 *
1031
 * Unlike the otherwise-similar get_atttype, this routine
1032
 * raises an error if it can't obtain the information.
1033
 */
1034
void
1035
get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
1036
            Oid *typid, int32 *typmod, Oid *collid)
1037
0
{
1038
0
  HeapTuple tp;
1039
0
  Form_pg_attribute att_tup;
1040
1041
0
  tp = SearchSysCache2(ATTNUM,
1042
0
             ObjectIdGetDatum(relid),
1043
0
             Int16GetDatum(attnum));
1044
0
  if (!HeapTupleIsValid(tp))
1045
0
    elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1046
0
       attnum, relid);
1047
0
  att_tup = (Form_pg_attribute) GETSTRUCT(tp);
1048
1049
0
  *typid = att_tup->atttypid;
1050
0
  *typmod = att_tup->atttypmod;
1051
0
  *collid = att_tup->attcollation;
1052
0
  ReleaseSysCache(tp);
1053
0
}
1054
1055
/*
1056
 * get_attoptions
1057
 *
1058
 *    Given the relation id and the attribute number,
1059
 *    return the attribute options text[] datum, if any.
1060
 */
1061
Datum
1062
get_attoptions(Oid relid, int16 attnum)
1063
0
{
1064
0
  HeapTuple tuple;
1065
0
  Datum   attopts;
1066
0
  Datum   result;
1067
0
  bool    isnull;
1068
1069
0
  tuple = SearchSysCache2(ATTNUM,
1070
0
              ObjectIdGetDatum(relid),
1071
0
              Int16GetDatum(attnum));
1072
1073
0
  if (!HeapTupleIsValid(tuple))
1074
0
    elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1075
0
       attnum, relid);
1076
1077
0
  attopts = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
1078
0
                &isnull);
1079
1080
0
  if (isnull)
1081
0
    result = (Datum) 0;
1082
0
  else
1083
0
    result = datumCopy(attopts, false, -1); /* text[] */
1084
1085
0
  ReleaseSysCache(tuple);
1086
1087
0
  return result;
1088
0
}
1089
1090
/*        ---------- PG_CAST CACHE ----------          */
1091
1092
/*
1093
 * get_cast_oid - given two type OIDs, look up a cast OID
1094
 *
1095
 * If missing_ok is false, throw an error if the cast is not found.  If
1096
 * true, just return InvalidOid.
1097
 */
1098
Oid
1099
get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok)
1100
0
{
1101
0
  Oid     oid;
1102
1103
0
  oid = GetSysCacheOid2(CASTSOURCETARGET, Anum_pg_cast_oid,
1104
0
              ObjectIdGetDatum(sourcetypeid),
1105
0
              ObjectIdGetDatum(targettypeid));
1106
0
  if (!OidIsValid(oid) && !missing_ok)
1107
0
    ereport(ERROR,
1108
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
1109
0
         errmsg("cast from type %s to type %s does not exist",
1110
0
            format_type_be(sourcetypeid),
1111
0
            format_type_be(targettypeid))));
1112
0
  return oid;
1113
0
}
1114
1115
/*        ---------- COLLATION CACHE ----------          */
1116
1117
/*
1118
 * get_collation_name
1119
 *    Returns the name of a given pg_collation entry.
1120
 *
1121
 * Returns a palloc'd copy of the string, or NULL if no such collation.
1122
 *
1123
 * NOTE: since collation name is not unique, be wary of code that uses this
1124
 * for anything except preparing error messages.
1125
 */
1126
char *
1127
get_collation_name(Oid colloid)
1128
0
{
1129
0
  HeapTuple tp;
1130
1131
0
  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
1132
0
  if (HeapTupleIsValid(tp))
1133
0
  {
1134
0
    Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp);
1135
0
    char     *result;
1136
1137
0
    result = pstrdup(NameStr(colltup->collname));
1138
0
    ReleaseSysCache(tp);
1139
0
    return result;
1140
0
  }
1141
0
  else
1142
0
    return NULL;
1143
0
}
1144
1145
bool
1146
get_collation_isdeterministic(Oid colloid)
1147
0
{
1148
0
  HeapTuple tp;
1149
0
  Form_pg_collation colltup;
1150
0
  bool    result;
1151
1152
0
  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
1153
0
  if (!HeapTupleIsValid(tp))
1154
0
    elog(ERROR, "cache lookup failed for collation %u", colloid);
1155
0
  colltup = (Form_pg_collation) GETSTRUCT(tp);
1156
0
  result = colltup->collisdeterministic;
1157
0
  ReleaseSysCache(tp);
1158
0
  return result;
1159
0
}
1160
1161
/*        ---------- CONSTRAINT CACHE ----------           */
1162
1163
/*
1164
 * get_constraint_name
1165
 *    Returns the name of a given pg_constraint entry.
1166
 *
1167
 * Returns a palloc'd copy of the string, or NULL if no such constraint.
1168
 *
1169
 * NOTE: since constraint name is not unique, be wary of code that uses this
1170
 * for anything except preparing error messages.
1171
 */
1172
char *
1173
get_constraint_name(Oid conoid)
1174
0
{
1175
0
  HeapTuple tp;
1176
1177
0
  tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
1178
0
  if (HeapTupleIsValid(tp))
1179
0
  {
1180
0
    Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
1181
0
    char     *result;
1182
1183
0
    result = pstrdup(NameStr(contup->conname));
1184
0
    ReleaseSysCache(tp);
1185
0
    return result;
1186
0
  }
1187
0
  else
1188
0
    return NULL;
1189
0
}
1190
1191
/*
1192
 * get_constraint_index
1193
 *    Given the OID of a unique, primary-key, or exclusion constraint,
1194
 *    return the OID of the underlying index.
1195
 *
1196
 * Returns InvalidOid if the constraint could not be found or is of
1197
 * the wrong type.
1198
 *
1199
 * The intent of this function is to return the index "owned" by the
1200
 * specified constraint.  Therefore we must check contype, since some
1201
 * pg_constraint entries (e.g. for foreign-key constraints) store the
1202
 * OID of an index that is referenced but not owned by the constraint.
1203
 */
1204
Oid
1205
get_constraint_index(Oid conoid)
1206
0
{
1207
0
  HeapTuple tp;
1208
1209
0
  tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
1210
0
  if (HeapTupleIsValid(tp))
1211
0
  {
1212
0
    Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
1213
0
    Oid     result;
1214
1215
0
    if (contup->contype == CONSTRAINT_UNIQUE ||
1216
0
      contup->contype == CONSTRAINT_PRIMARY ||
1217
0
      contup->contype == CONSTRAINT_EXCLUSION)
1218
0
      result = contup->conindid;
1219
0
    else
1220
0
      result = InvalidOid;
1221
0
    ReleaseSysCache(tp);
1222
0
    return result;
1223
0
  }
1224
0
  else
1225
0
    return InvalidOid;
1226
0
}
1227
1228
/*
1229
 * get_constraint_type
1230
 *    Return the pg_constraint.contype value for the given constraint.
1231
 *
1232
 * No frills.
1233
 */
1234
char
1235
get_constraint_type(Oid conoid)
1236
0
{
1237
0
  HeapTuple tp;
1238
0
  char    contype;
1239
1240
0
  tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
1241
0
  if (!HeapTupleIsValid(tp))
1242
0
    elog(ERROR, "cache lookup failed for constraint %u", conoid);
1243
1244
0
  contype = ((Form_pg_constraint) GETSTRUCT(tp))->contype;
1245
0
  ReleaseSysCache(tp);
1246
1247
0
  return contype;
1248
0
}
1249
1250
/*        ---------- LANGUAGE CACHE ----------           */
1251
1252
char *
1253
get_language_name(Oid langoid, bool missing_ok)
1254
0
{
1255
0
  HeapTuple tp;
1256
1257
0
  tp = SearchSysCache1(LANGOID, ObjectIdGetDatum(langoid));
1258
0
  if (HeapTupleIsValid(tp))
1259
0
  {
1260
0
    Form_pg_language lantup = (Form_pg_language) GETSTRUCT(tp);
1261
0
    char     *result;
1262
1263
0
    result = pstrdup(NameStr(lantup->lanname));
1264
0
    ReleaseSysCache(tp);
1265
0
    return result;
1266
0
  }
1267
1268
0
  if (!missing_ok)
1269
0
    elog(ERROR, "cache lookup failed for language %u",
1270
0
       langoid);
1271
0
  return NULL;
1272
0
}
1273
1274
/*        ---------- OPCLASS CACHE ----------            */
1275
1276
/*
1277
 * get_opclass_family
1278
 *
1279
 *    Returns the OID of the operator family the opclass belongs to.
1280
 */
1281
Oid
1282
get_opclass_family(Oid opclass)
1283
0
{
1284
0
  HeapTuple tp;
1285
0
  Form_pg_opclass cla_tup;
1286
0
  Oid     result;
1287
1288
0
  tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1289
0
  if (!HeapTupleIsValid(tp))
1290
0
    elog(ERROR, "cache lookup failed for opclass %u", opclass);
1291
0
  cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1292
1293
0
  result = cla_tup->opcfamily;
1294
0
  ReleaseSysCache(tp);
1295
0
  return result;
1296
0
}
1297
1298
/*
1299
 * get_opclass_input_type
1300
 *
1301
 *    Returns the OID of the datatype the opclass indexes.
1302
 */
1303
Oid
1304
get_opclass_input_type(Oid opclass)
1305
0
{
1306
0
  HeapTuple tp;
1307
0
  Form_pg_opclass cla_tup;
1308
0
  Oid     result;
1309
1310
0
  tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1311
0
  if (!HeapTupleIsValid(tp))
1312
0
    elog(ERROR, "cache lookup failed for opclass %u", opclass);
1313
0
  cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1314
1315
0
  result = cla_tup->opcintype;
1316
0
  ReleaseSysCache(tp);
1317
0
  return result;
1318
0
}
1319
1320
/*
1321
 * get_opclass_opfamily_and_input_type
1322
 *
1323
 *    Returns the OID of the operator family the opclass belongs to,
1324
 *        the OID of the datatype the opclass indexes
1325
 */
1326
bool
1327
get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
1328
0
{
1329
0
  HeapTuple tp;
1330
0
  Form_pg_opclass cla_tup;
1331
1332
0
  tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1333
0
  if (!HeapTupleIsValid(tp))
1334
0
    return false;
1335
1336
0
  cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1337
1338
0
  *opfamily = cla_tup->opcfamily;
1339
0
  *opcintype = cla_tup->opcintype;
1340
1341
0
  ReleaseSysCache(tp);
1342
1343
0
  return true;
1344
0
}
1345
1346
/*
1347
 * get_opclass_method
1348
 *
1349
 *    Returns the OID of the index access method the opclass belongs to.
1350
 */
1351
Oid
1352
get_opclass_method(Oid opclass)
1353
0
{
1354
0
  HeapTuple tp;
1355
0
  Form_pg_opclass cla_tup;
1356
0
  Oid     result;
1357
1358
0
  tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1359
0
  if (!HeapTupleIsValid(tp))
1360
0
    elog(ERROR, "cache lookup failed for opclass %u", opclass);
1361
0
  cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
1362
1363
0
  result = cla_tup->opcmethod;
1364
0
  ReleaseSysCache(tp);
1365
0
  return result;
1366
0
}
1367
1368
/*        ---------- OPFAMILY CACHE ----------           */
1369
1370
/*
1371
 * get_opfamily_method
1372
 *
1373
 *    Returns the OID of the index access method the opfamily is for.
1374
 */
1375
Oid
1376
get_opfamily_method(Oid opfid)
1377
0
{
1378
0
  HeapTuple tp;
1379
0
  Form_pg_opfamily opfform;
1380
0
  Oid     result;
1381
1382
0
  tp = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
1383
0
  if (!HeapTupleIsValid(tp))
1384
0
    elog(ERROR, "cache lookup failed for operator family %u", opfid);
1385
0
  opfform = (Form_pg_opfamily) GETSTRUCT(tp);
1386
1387
0
  result = opfform->opfmethod;
1388
0
  ReleaseSysCache(tp);
1389
0
  return result;
1390
0
}
1391
1392
char *
1393
get_opfamily_name(Oid opfid, bool missing_ok)
1394
0
{
1395
0
  HeapTuple tup;
1396
0
  char     *opfname;
1397
0
  Form_pg_opfamily opfform;
1398
1399
0
  tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
1400
1401
0
  if (!HeapTupleIsValid(tup))
1402
0
  {
1403
0
    if (!missing_ok)
1404
0
      elog(ERROR, "cache lookup failed for operator family %u", opfid);
1405
0
    return NULL;
1406
0
  }
1407
1408
0
  opfform = (Form_pg_opfamily) GETSTRUCT(tup);
1409
0
  opfname = pstrdup(NameStr(opfform->opfname));
1410
1411
0
  ReleaseSysCache(tup);
1412
1413
0
  return opfname;
1414
0
}
1415
1416
/*        ---------- OPERATOR CACHE ----------           */
1417
1418
/*
1419
 * get_opcode
1420
 *
1421
 *    Returns the regproc id of the routine used to implement an
1422
 *    operator given the operator oid.
1423
 */
1424
RegProcedure
1425
get_opcode(Oid opno)
1426
0
{
1427
0
  HeapTuple tp;
1428
1429
0
  tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1430
0
  if (HeapTupleIsValid(tp))
1431
0
  {
1432
0
    Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1433
0
    RegProcedure result;
1434
1435
0
    result = optup->oprcode;
1436
0
    ReleaseSysCache(tp);
1437
0
    return result;
1438
0
  }
1439
0
  else
1440
0
    return (RegProcedure) InvalidOid;
1441
0
}
1442
1443
/*
1444
 * get_opname
1445
 *    returns the name of the operator with the given opno
1446
 *
1447
 * Note: returns a palloc'd copy of the string, or NULL if no such operator.
1448
 */
1449
char *
1450
get_opname(Oid opno)
1451
0
{
1452
0
  HeapTuple tp;
1453
1454
0
  tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1455
0
  if (HeapTupleIsValid(tp))
1456
0
  {
1457
0
    Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1458
0
    char     *result;
1459
1460
0
    result = pstrdup(NameStr(optup->oprname));
1461
0
    ReleaseSysCache(tp);
1462
0
    return result;
1463
0
  }
1464
0
  else
1465
0
    return NULL;
1466
0
}
1467
1468
/*
1469
 * get_op_rettype
1470
 *    Given operator oid, return the operator's result type.
1471
 */
1472
Oid
1473
get_op_rettype(Oid opno)
1474
0
{
1475
0
  HeapTuple tp;
1476
1477
0
  tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1478
0
  if (HeapTupleIsValid(tp))
1479
0
  {
1480
0
    Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1481
0
    Oid     result;
1482
1483
0
    result = optup->oprresult;
1484
0
    ReleaseSysCache(tp);
1485
0
    return result;
1486
0
  }
1487
0
  else
1488
0
    return InvalidOid;
1489
0
}
1490
1491
/*
1492
 * op_input_types
1493
 *
1494
 *    Returns the left and right input datatypes for an operator
1495
 *    (InvalidOid if not relevant).
1496
 */
1497
void
1498
op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
1499
0
{
1500
0
  HeapTuple tp;
1501
0
  Form_pg_operator optup;
1502
1503
0
  tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1504
0
  if (!HeapTupleIsValid(tp)) /* shouldn't happen */
1505
0
    elog(ERROR, "cache lookup failed for operator %u", opno);
1506
0
  optup = (Form_pg_operator) GETSTRUCT(tp);
1507
0
  *lefttype = optup->oprleft;
1508
0
  *righttype = optup->oprright;
1509
0
  ReleaseSysCache(tp);
1510
0
}
1511
1512
/*
1513
 * op_mergejoinable
1514
 *
1515
 * Returns true if the operator is potentially mergejoinable.  (The planner
1516
 * will fail to find any mergejoin plans unless there are suitable btree
1517
 * opfamily entries for this operator and associated sortops.  The pg_operator
1518
 * flag is just a hint to tell the planner whether to bother looking.)
1519
 *
1520
 * In some cases (currently only array_eq and record_eq), mergejoinability
1521
 * depends on the specific input data type the operator is invoked for, so
1522
 * that must be passed as well. We currently assume that only one input's type
1523
 * is needed to check this --- by convention, pass the left input's data type.
1524
 */
1525
bool
1526
op_mergejoinable(Oid opno, Oid inputtype)
1527
0
{
1528
0
  bool    result = false;
1529
0
  HeapTuple tp;
1530
0
  TypeCacheEntry *typentry;
1531
1532
  /*
1533
   * For array_eq or record_eq, we can sort if the element or field types
1534
   * are all sortable.  We could implement all the checks for that here, but
1535
   * the typcache already does that and caches the results too, so let's
1536
   * rely on the typcache.
1537
   */
1538
0
  if (opno == ARRAY_EQ_OP)
1539
0
  {
1540
0
    typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
1541
0
    if (typentry->cmp_proc == F_BTARRAYCMP)
1542
0
      result = true;
1543
0
  }
1544
0
  else if (opno == RECORD_EQ_OP)
1545
0
  {
1546
0
    typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
1547
0
    if (typentry->cmp_proc == F_BTRECORDCMP)
1548
0
      result = true;
1549
0
  }
1550
0
  else
1551
0
  {
1552
    /* For all other operators, rely on pg_operator.oprcanmerge */
1553
0
    tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1554
0
    if (HeapTupleIsValid(tp))
1555
0
    {
1556
0
      Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1557
1558
0
      result = optup->oprcanmerge;
1559
0
      ReleaseSysCache(tp);
1560
0
    }
1561
0
  }
1562
0
  return result;
1563
0
}
1564
1565
/*
1566
 * op_hashjoinable
1567
 *
1568
 * Returns true if the operator is hashjoinable.  (There must be a suitable
1569
 * hash opfamily entry for this operator if it is so marked.)
1570
 *
1571
 * In some cases (currently only array_eq), hashjoinability depends on the
1572
 * specific input data type the operator is invoked for, so that must be
1573
 * passed as well.  We currently assume that only one input's type is needed
1574
 * to check this --- by convention, pass the left input's data type.
1575
 */
1576
bool
1577
op_hashjoinable(Oid opno, Oid inputtype)
1578
0
{
1579
0
  bool    result = false;
1580
0
  HeapTuple tp;
1581
0
  TypeCacheEntry *typentry;
1582
1583
  /* As in op_mergejoinable, let the typcache handle the hard cases */
1584
0
  if (opno == ARRAY_EQ_OP)
1585
0
  {
1586
0
    typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
1587
0
    if (typentry->hash_proc == F_HASH_ARRAY)
1588
0
      result = true;
1589
0
  }
1590
0
  else if (opno == RECORD_EQ_OP)
1591
0
  {
1592
0
    typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
1593
0
    if (typentry->hash_proc == F_HASH_RECORD)
1594
0
      result = true;
1595
0
  }
1596
0
  else
1597
0
  {
1598
    /* For all other operators, rely on pg_operator.oprcanhash */
1599
0
    tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1600
0
    if (HeapTupleIsValid(tp))
1601
0
    {
1602
0
      Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1603
1604
0
      result = optup->oprcanhash;
1605
0
      ReleaseSysCache(tp);
1606
0
    }
1607
0
  }
1608
0
  return result;
1609
0
}
1610
1611
/*
1612
 * op_strict
1613
 *
1614
 * Get the proisstrict flag for the operator's underlying function.
1615
 */
1616
bool
1617
op_strict(Oid opno)
1618
0
{
1619
0
  RegProcedure funcid = get_opcode(opno);
1620
1621
0
  if (funcid == (RegProcedure) InvalidOid)
1622
0
    elog(ERROR, "operator %u does not exist", opno);
1623
1624
0
  return func_strict((Oid) funcid);
1625
0
}
1626
1627
/*
1628
 * op_volatile
1629
 *
1630
 * Get the provolatile flag for the operator's underlying function.
1631
 */
1632
char
1633
op_volatile(Oid opno)
1634
0
{
1635
0
  RegProcedure funcid = get_opcode(opno);
1636
1637
0
  if (funcid == (RegProcedure) InvalidOid)
1638
0
    elog(ERROR, "operator %u does not exist", opno);
1639
1640
0
  return func_volatile((Oid) funcid);
1641
0
}
1642
1643
/*
1644
 * get_commutator
1645
 *
1646
 *    Returns the corresponding commutator of an operator.
1647
 */
1648
Oid
1649
get_commutator(Oid opno)
1650
0
{
1651
0
  HeapTuple tp;
1652
1653
0
  tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1654
0
  if (HeapTupleIsValid(tp))
1655
0
  {
1656
0
    Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1657
0
    Oid     result;
1658
1659
0
    result = optup->oprcom;
1660
0
    ReleaseSysCache(tp);
1661
0
    return result;
1662
0
  }
1663
0
  else
1664
0
    return InvalidOid;
1665
0
}
1666
1667
/*
1668
 * get_negator
1669
 *
1670
 *    Returns the corresponding negator of an operator.
1671
 */
1672
Oid
1673
get_negator(Oid opno)
1674
0
{
1675
0
  HeapTuple tp;
1676
1677
0
  tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1678
0
  if (HeapTupleIsValid(tp))
1679
0
  {
1680
0
    Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1681
0
    Oid     result;
1682
1683
0
    result = optup->oprnegate;
1684
0
    ReleaseSysCache(tp);
1685
0
    return result;
1686
0
  }
1687
0
  else
1688
0
    return InvalidOid;
1689
0
}
1690
1691
/*
1692
 * get_oprrest
1693
 *
1694
 *    Returns procedure id for computing selectivity of an operator.
1695
 */
1696
RegProcedure
1697
get_oprrest(Oid opno)
1698
0
{
1699
0
  HeapTuple tp;
1700
1701
0
  tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1702
0
  if (HeapTupleIsValid(tp))
1703
0
  {
1704
0
    Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1705
0
    RegProcedure result;
1706
1707
0
    result = optup->oprrest;
1708
0
    ReleaseSysCache(tp);
1709
0
    return result;
1710
0
  }
1711
0
  else
1712
0
    return (RegProcedure) InvalidOid;
1713
0
}
1714
1715
/*
1716
 * get_oprjoin
1717
 *
1718
 *    Returns procedure id for computing selectivity of a join.
1719
 */
1720
RegProcedure
1721
get_oprjoin(Oid opno)
1722
0
{
1723
0
  HeapTuple tp;
1724
1725
0
  tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
1726
0
  if (HeapTupleIsValid(tp))
1727
0
  {
1728
0
    Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
1729
0
    RegProcedure result;
1730
1731
0
    result = optup->oprjoin;
1732
0
    ReleaseSysCache(tp);
1733
0
    return result;
1734
0
  }
1735
0
  else
1736
0
    return (RegProcedure) InvalidOid;
1737
0
}
1738
1739
/*        ---------- FUNCTION CACHE ----------           */
1740
1741
/*
1742
 * get_func_name
1743
 *    returns the name of the function with the given funcid
1744
 *
1745
 * Note: returns a palloc'd copy of the string, or NULL if no such function.
1746
 */
1747
char *
1748
get_func_name(Oid funcid)
1749
0
{
1750
0
  HeapTuple tp;
1751
1752
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1753
0
  if (HeapTupleIsValid(tp))
1754
0
  {
1755
0
    Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1756
0
    char     *result;
1757
1758
0
    result = pstrdup(NameStr(functup->proname));
1759
0
    ReleaseSysCache(tp);
1760
0
    return result;
1761
0
  }
1762
0
  else
1763
0
    return NULL;
1764
0
}
1765
1766
/*
1767
 * get_func_namespace
1768
 *
1769
 *    Returns the pg_namespace OID associated with a given function.
1770
 */
1771
Oid
1772
get_func_namespace(Oid funcid)
1773
0
{
1774
0
  HeapTuple tp;
1775
1776
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1777
0
  if (HeapTupleIsValid(tp))
1778
0
  {
1779
0
    Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
1780
0
    Oid     result;
1781
1782
0
    result = functup->pronamespace;
1783
0
    ReleaseSysCache(tp);
1784
0
    return result;
1785
0
  }
1786
0
  else
1787
0
    return InvalidOid;
1788
0
}
1789
1790
/*
1791
 * get_func_rettype
1792
 *    Given procedure id, return the function's result type.
1793
 */
1794
Oid
1795
get_func_rettype(Oid funcid)
1796
0
{
1797
0
  HeapTuple tp;
1798
0
  Oid     result;
1799
1800
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1801
0
  if (!HeapTupleIsValid(tp))
1802
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1803
1804
0
  result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
1805
0
  ReleaseSysCache(tp);
1806
0
  return result;
1807
0
}
1808
1809
/*
1810
 * get_func_nargs
1811
 *    Given procedure id, return the number of arguments.
1812
 */
1813
int
1814
get_func_nargs(Oid funcid)
1815
0
{
1816
0
  HeapTuple tp;
1817
0
  int     result;
1818
1819
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1820
0
  if (!HeapTupleIsValid(tp))
1821
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1822
1823
0
  result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs;
1824
0
  ReleaseSysCache(tp);
1825
0
  return result;
1826
0
}
1827
1828
/*
1829
 * get_func_signature
1830
 *    Given procedure id, return the function's argument and result types.
1831
 *    (The return value is the result type.)
1832
 *
1833
 * The arguments are returned as a palloc'd array.
1834
 */
1835
Oid
1836
get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
1837
0
{
1838
0
  HeapTuple tp;
1839
0
  Form_pg_proc procstruct;
1840
0
  Oid     result;
1841
1842
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1843
0
  if (!HeapTupleIsValid(tp))
1844
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1845
1846
0
  procstruct = (Form_pg_proc) GETSTRUCT(tp);
1847
1848
0
  result = procstruct->prorettype;
1849
0
  *nargs = (int) procstruct->pronargs;
1850
0
  Assert(*nargs == procstruct->proargtypes.dim1);
1851
0
  *argtypes = (Oid *) palloc(*nargs * sizeof(Oid));
1852
0
  memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid));
1853
1854
0
  ReleaseSysCache(tp);
1855
0
  return result;
1856
0
}
1857
1858
/*
1859
 * get_func_variadictype
1860
 *    Given procedure id, return the function's provariadic field.
1861
 */
1862
Oid
1863
get_func_variadictype(Oid funcid)
1864
0
{
1865
0
  HeapTuple tp;
1866
0
  Oid     result;
1867
1868
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1869
0
  if (!HeapTupleIsValid(tp))
1870
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1871
1872
0
  result = ((Form_pg_proc) GETSTRUCT(tp))->provariadic;
1873
0
  ReleaseSysCache(tp);
1874
0
  return result;
1875
0
}
1876
1877
/*
1878
 * get_func_retset
1879
 *    Given procedure id, return the function's proretset flag.
1880
 */
1881
bool
1882
get_func_retset(Oid funcid)
1883
0
{
1884
0
  HeapTuple tp;
1885
0
  bool    result;
1886
1887
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1888
0
  if (!HeapTupleIsValid(tp))
1889
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1890
1891
0
  result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
1892
0
  ReleaseSysCache(tp);
1893
0
  return result;
1894
0
}
1895
1896
/*
1897
 * func_strict
1898
 *    Given procedure id, return the function's proisstrict flag.
1899
 */
1900
bool
1901
func_strict(Oid funcid)
1902
0
{
1903
0
  HeapTuple tp;
1904
0
  bool    result;
1905
1906
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1907
0
  if (!HeapTupleIsValid(tp))
1908
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1909
1910
0
  result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
1911
0
  ReleaseSysCache(tp);
1912
0
  return result;
1913
0
}
1914
1915
/*
1916
 * func_volatile
1917
 *    Given procedure id, return the function's provolatile flag.
1918
 */
1919
char
1920
func_volatile(Oid funcid)
1921
0
{
1922
0
  HeapTuple tp;
1923
0
  char    result;
1924
1925
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1926
0
  if (!HeapTupleIsValid(tp))
1927
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1928
1929
0
  result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
1930
0
  ReleaseSysCache(tp);
1931
0
  return result;
1932
0
}
1933
1934
/*
1935
 * func_parallel
1936
 *    Given procedure id, return the function's proparallel flag.
1937
 */
1938
char
1939
func_parallel(Oid funcid)
1940
0
{
1941
0
  HeapTuple tp;
1942
0
  char    result;
1943
1944
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1945
0
  if (!HeapTupleIsValid(tp))
1946
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1947
1948
0
  result = ((Form_pg_proc) GETSTRUCT(tp))->proparallel;
1949
0
  ReleaseSysCache(tp);
1950
0
  return result;
1951
0
}
1952
1953
/*
1954
 * get_func_prokind
1955
 *     Given procedure id, return the routine kind.
1956
 */
1957
char
1958
get_func_prokind(Oid funcid)
1959
0
{
1960
0
  HeapTuple tp;
1961
0
  char    result;
1962
1963
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1964
0
  if (!HeapTupleIsValid(tp))
1965
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1966
1967
0
  result = ((Form_pg_proc) GETSTRUCT(tp))->prokind;
1968
0
  ReleaseSysCache(tp);
1969
0
  return result;
1970
0
}
1971
1972
/*
1973
 * get_func_leakproof
1974
 *     Given procedure id, return the function's leakproof field.
1975
 */
1976
bool
1977
get_func_leakproof(Oid funcid)
1978
0
{
1979
0
  HeapTuple tp;
1980
0
  bool    result;
1981
1982
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1983
0
  if (!HeapTupleIsValid(tp))
1984
0
    elog(ERROR, "cache lookup failed for function %u", funcid);
1985
1986
0
  result = ((Form_pg_proc) GETSTRUCT(tp))->proleakproof;
1987
0
  ReleaseSysCache(tp);
1988
0
  return result;
1989
0
}
1990
1991
/*
1992
 * get_func_support
1993
 *
1994
 *    Returns the support function OID associated with a given function,
1995
 *    or InvalidOid if there is none.
1996
 */
1997
RegProcedure
1998
get_func_support(Oid funcid)
1999
0
{
2000
0
  HeapTuple tp;
2001
2002
0
  tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
2003
0
  if (HeapTupleIsValid(tp))
2004
0
  {
2005
0
    Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
2006
0
    RegProcedure result;
2007
2008
0
    result = functup->prosupport;
2009
0
    ReleaseSysCache(tp);
2010
0
    return result;
2011
0
  }
2012
0
  else
2013
0
    return (RegProcedure) InvalidOid;
2014
0
}
2015
2016
/*        ---------- RELATION CACHE ----------           */
2017
2018
/*
2019
 * get_relname_relid
2020
 *    Given name and namespace of a relation, look up the OID.
2021
 *
2022
 * Returns InvalidOid if there is no such relation.
2023
 */
2024
Oid
2025
get_relname_relid(const char *relname, Oid relnamespace)
2026
0
{
2027
0
  return GetSysCacheOid2(RELNAMENSP, Anum_pg_class_oid,
2028
0
               PointerGetDatum(relname),
2029
0
               ObjectIdGetDatum(relnamespace));
2030
0
}
2031
2032
#ifdef NOT_USED
2033
/*
2034
 * get_relnatts
2035
 *
2036
 *    Returns the number of attributes for a given relation.
2037
 */
2038
int
2039
get_relnatts(Oid relid)
2040
{
2041
  HeapTuple tp;
2042
2043
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2044
  if (HeapTupleIsValid(tp))
2045
  {
2046
    Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2047
    int     result;
2048
2049
    result = reltup->relnatts;
2050
    ReleaseSysCache(tp);
2051
    return result;
2052
  }
2053
  else
2054
    return InvalidAttrNumber;
2055
}
2056
#endif
2057
2058
/*
2059
 * get_rel_name
2060
 *    Returns the name of a given relation.
2061
 *
2062
 * Returns a palloc'd copy of the string, or NULL if no such relation.
2063
 *
2064
 * NOTE: since relation name is not unique, be wary of code that uses this
2065
 * for anything except preparing error messages.
2066
 */
2067
char *
2068
get_rel_name(Oid relid)
2069
0
{
2070
0
  HeapTuple tp;
2071
2072
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2073
0
  if (HeapTupleIsValid(tp))
2074
0
  {
2075
0
    Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2076
0
    char     *result;
2077
2078
0
    result = pstrdup(NameStr(reltup->relname));
2079
0
    ReleaseSysCache(tp);
2080
0
    return result;
2081
0
  }
2082
0
  else
2083
0
    return NULL;
2084
0
}
2085
2086
/*
2087
 * get_rel_namespace
2088
 *
2089
 *    Returns the pg_namespace OID associated with a given relation.
2090
 */
2091
Oid
2092
get_rel_namespace(Oid relid)
2093
0
{
2094
0
  HeapTuple tp;
2095
2096
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2097
0
  if (HeapTupleIsValid(tp))
2098
0
  {
2099
0
    Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2100
0
    Oid     result;
2101
2102
0
    result = reltup->relnamespace;
2103
0
    ReleaseSysCache(tp);
2104
0
    return result;
2105
0
  }
2106
0
  else
2107
0
    return InvalidOid;
2108
0
}
2109
2110
/*
2111
 * get_rel_type_id
2112
 *
2113
 *    Returns the pg_type OID associated with a given relation.
2114
 *
2115
 * Note: not all pg_class entries have associated pg_type OIDs; so be
2116
 * careful to check for InvalidOid result.
2117
 */
2118
Oid
2119
get_rel_type_id(Oid relid)
2120
0
{
2121
0
  HeapTuple tp;
2122
2123
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2124
0
  if (HeapTupleIsValid(tp))
2125
0
  {
2126
0
    Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2127
0
    Oid     result;
2128
2129
0
    result = reltup->reltype;
2130
0
    ReleaseSysCache(tp);
2131
0
    return result;
2132
0
  }
2133
0
  else
2134
0
    return InvalidOid;
2135
0
}
2136
2137
/*
2138
 * get_rel_relkind
2139
 *
2140
 *    Returns the relkind associated with a given relation.
2141
 */
2142
char
2143
get_rel_relkind(Oid relid)
2144
0
{
2145
0
  HeapTuple tp;
2146
2147
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2148
0
  if (HeapTupleIsValid(tp))
2149
0
  {
2150
0
    Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2151
0
    char    result;
2152
2153
0
    result = reltup->relkind;
2154
0
    ReleaseSysCache(tp);
2155
0
    return result;
2156
0
  }
2157
0
  else
2158
0
    return '\0';
2159
0
}
2160
2161
/*
2162
 * get_rel_relispartition
2163
 *
2164
 *    Returns the relispartition flag associated with a given relation.
2165
 */
2166
bool
2167
get_rel_relispartition(Oid relid)
2168
0
{
2169
0
  HeapTuple tp;
2170
2171
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2172
0
  if (HeapTupleIsValid(tp))
2173
0
  {
2174
0
    Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2175
0
    bool    result;
2176
2177
0
    result = reltup->relispartition;
2178
0
    ReleaseSysCache(tp);
2179
0
    return result;
2180
0
  }
2181
0
  else
2182
0
    return false;
2183
0
}
2184
2185
/*
2186
 * get_rel_tablespace
2187
 *
2188
 *    Returns the pg_tablespace OID associated with a given relation.
2189
 *
2190
 * Note: InvalidOid might mean either that we couldn't find the relation,
2191
 * or that it is in the database's default tablespace.
2192
 */
2193
Oid
2194
get_rel_tablespace(Oid relid)
2195
0
{
2196
0
  HeapTuple tp;
2197
2198
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2199
0
  if (HeapTupleIsValid(tp))
2200
0
  {
2201
0
    Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
2202
0
    Oid     result;
2203
2204
0
    result = reltup->reltablespace;
2205
0
    ReleaseSysCache(tp);
2206
0
    return result;
2207
0
  }
2208
0
  else
2209
0
    return InvalidOid;
2210
0
}
2211
2212
/*
2213
 * get_rel_persistence
2214
 *
2215
 *    Returns the relpersistence associated with a given relation.
2216
 */
2217
char
2218
get_rel_persistence(Oid relid)
2219
0
{
2220
0
  HeapTuple tp;
2221
0
  Form_pg_class reltup;
2222
0
  char    result;
2223
2224
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2225
0
  if (!HeapTupleIsValid(tp))
2226
0
    elog(ERROR, "cache lookup failed for relation %u", relid);
2227
0
  reltup = (Form_pg_class) GETSTRUCT(tp);
2228
0
  result = reltup->relpersistence;
2229
0
  ReleaseSysCache(tp);
2230
2231
0
  return result;
2232
0
}
2233
2234
/*
2235
 * get_rel_relam
2236
 *
2237
 *    Returns the relam associated with a given relation.
2238
 */
2239
Oid
2240
get_rel_relam(Oid relid)
2241
0
{
2242
0
  HeapTuple tp;
2243
0
  Form_pg_class reltup;
2244
0
  Oid     result;
2245
2246
0
  tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
2247
0
  if (!HeapTupleIsValid(tp))
2248
0
    elog(ERROR, "cache lookup failed for relation %u", relid);
2249
0
  reltup = (Form_pg_class) GETSTRUCT(tp);
2250
0
  result = reltup->relam;
2251
0
  ReleaseSysCache(tp);
2252
2253
0
  return result;
2254
0
}
2255
2256
2257
/*        ---------- TRANSFORM CACHE ----------            */
2258
2259
Oid
2260
get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
2261
0
{
2262
0
  HeapTuple tup;
2263
2264
0
  if (!list_member_oid(trftypes, typid))
2265
0
    return InvalidOid;
2266
2267
0
  tup = SearchSysCache2(TRFTYPELANG, ObjectIdGetDatum(typid),
2268
0
              ObjectIdGetDatum(langid));
2269
0
  if (HeapTupleIsValid(tup))
2270
0
  {
2271
0
    Oid     funcid;
2272
2273
0
    funcid = ((Form_pg_transform) GETSTRUCT(tup))->trffromsql;
2274
0
    ReleaseSysCache(tup);
2275
0
    return funcid;
2276
0
  }
2277
0
  else
2278
0
    return InvalidOid;
2279
0
}
2280
2281
Oid
2282
get_transform_tosql(Oid typid, Oid langid, List *trftypes)
2283
0
{
2284
0
  HeapTuple tup;
2285
2286
0
  if (!list_member_oid(trftypes, typid))
2287
0
    return InvalidOid;
2288
2289
0
  tup = SearchSysCache2(TRFTYPELANG, ObjectIdGetDatum(typid),
2290
0
              ObjectIdGetDatum(langid));
2291
0
  if (HeapTupleIsValid(tup))
2292
0
  {
2293
0
    Oid     funcid;
2294
2295
0
    funcid = ((Form_pg_transform) GETSTRUCT(tup))->trftosql;
2296
0
    ReleaseSysCache(tup);
2297
0
    return funcid;
2298
0
  }
2299
0
  else
2300
0
    return InvalidOid;
2301
0
}
2302
2303
2304
/*        ---------- TYPE CACHE ----------             */
2305
2306
/*
2307
 * get_typisdefined
2308
 *
2309
 *    Given the type OID, determine whether the type is defined
2310
 *    (if not, it's only a shell).
2311
 */
2312
bool
2313
get_typisdefined(Oid typid)
2314
0
{
2315
0
  HeapTuple tp;
2316
2317
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2318
0
  if (HeapTupleIsValid(tp))
2319
0
  {
2320
0
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2321
0
    bool    result;
2322
2323
0
    result = typtup->typisdefined;
2324
0
    ReleaseSysCache(tp);
2325
0
    return result;
2326
0
  }
2327
0
  else
2328
0
    return false;
2329
0
}
2330
2331
/*
2332
 * get_typlen
2333
 *
2334
 *    Given the type OID, return the length of the type.
2335
 */
2336
int16
2337
get_typlen(Oid typid)
2338
0
{
2339
0
  HeapTuple tp;
2340
2341
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2342
0
  if (HeapTupleIsValid(tp))
2343
0
  {
2344
0
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2345
0
    int16   result;
2346
2347
0
    result = typtup->typlen;
2348
0
    ReleaseSysCache(tp);
2349
0
    return result;
2350
0
  }
2351
0
  else
2352
0
    return 0;
2353
0
}
2354
2355
/*
2356
 * get_typbyval
2357
 *
2358
 *    Given the type OID, determine whether the type is returned by value or
2359
 *    not.  Returns true if by value, false if by reference.
2360
 */
2361
bool
2362
get_typbyval(Oid typid)
2363
0
{
2364
0
  HeapTuple tp;
2365
2366
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2367
0
  if (HeapTupleIsValid(tp))
2368
0
  {
2369
0
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2370
0
    bool    result;
2371
2372
0
    result = typtup->typbyval;
2373
0
    ReleaseSysCache(tp);
2374
0
    return result;
2375
0
  }
2376
0
  else
2377
0
    return false;
2378
0
}
2379
2380
/*
2381
 * get_typlenbyval
2382
 *
2383
 *    A two-fer: given the type OID, return both typlen and typbyval.
2384
 *
2385
 *    Since both pieces of info are needed to know how to copy a Datum,
2386
 *    many places need both.  Might as well get them with one cache lookup
2387
 *    instead of two.  Also, this routine raises an error instead of
2388
 *    returning a bogus value when given a bad type OID.
2389
 */
2390
void
2391
get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
2392
0
{
2393
0
  HeapTuple tp;
2394
0
  Form_pg_type typtup;
2395
2396
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2397
0
  if (!HeapTupleIsValid(tp))
2398
0
    elog(ERROR, "cache lookup failed for type %u", typid);
2399
0
  typtup = (Form_pg_type) GETSTRUCT(tp);
2400
0
  *typlen = typtup->typlen;
2401
0
  *typbyval = typtup->typbyval;
2402
0
  ReleaseSysCache(tp);
2403
0
}
2404
2405
/*
2406
 * get_typlenbyvalalign
2407
 *
2408
 *    A three-fer: given the type OID, return typlen, typbyval, typalign.
2409
 */
2410
void
2411
get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
2412
           char *typalign)
2413
0
{
2414
0
  HeapTuple tp;
2415
0
  Form_pg_type typtup;
2416
2417
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2418
0
  if (!HeapTupleIsValid(tp))
2419
0
    elog(ERROR, "cache lookup failed for type %u", typid);
2420
0
  typtup = (Form_pg_type) GETSTRUCT(tp);
2421
0
  *typlen = typtup->typlen;
2422
0
  *typbyval = typtup->typbyval;
2423
0
  *typalign = typtup->typalign;
2424
0
  ReleaseSysCache(tp);
2425
0
}
2426
2427
/*
2428
 * getTypeIOParam
2429
 *    Given a pg_type row, select the type OID to pass to I/O functions
2430
 *
2431
 * Formerly, all I/O functions were passed pg_type.typelem as their second
2432
 * parameter, but we now have a more complex rule about what to pass.
2433
 * This knowledge is intended to be centralized here --- direct references
2434
 * to typelem elsewhere in the code are wrong, if they are associated with
2435
 * I/O calls and not with actual subscripting operations!  (But see
2436
 * bootstrap.c's boot_get_type_io_data() if you need to change this.)
2437
 *
2438
 * As of PostgreSQL 8.1, output functions receive only the value itself
2439
 * and not any auxiliary parameters, so the name of this routine is now
2440
 * a bit of a misnomer ... it should be getTypeInputParam.
2441
 */
2442
Oid
2443
getTypeIOParam(HeapTuple typeTuple)
2444
0
{
2445
0
  Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
2446
2447
  /*
2448
   * Array types get their typelem as parameter; everybody else gets their
2449
   * own type OID as parameter.
2450
   */
2451
0
  if (OidIsValid(typeStruct->typelem))
2452
0
    return typeStruct->typelem;
2453
0
  else
2454
0
    return typeStruct->oid;
2455
0
}
2456
2457
/*
2458
 * get_type_io_data
2459
 *
2460
 *    A six-fer:  given the type OID, return typlen, typbyval, typalign,
2461
 *          typdelim, typioparam, and IO function OID. The IO function
2462
 *          returned is controlled by IOFuncSelector
2463
 */
2464
void
2465
get_type_io_data(Oid typid,
2466
         IOFuncSelector which_func,
2467
         int16 *typlen,
2468
         bool *typbyval,
2469
         char *typalign,
2470
         char *typdelim,
2471
         Oid *typioparam,
2472
         Oid *func)
2473
0
{
2474
0
  HeapTuple typeTuple;
2475
0
  Form_pg_type typeStruct;
2476
2477
  /*
2478
   * In bootstrap mode, pass it off to bootstrap.c.  This hack allows us to
2479
   * use array_in and array_out during bootstrap.
2480
   */
2481
0
  if (IsBootstrapProcessingMode())
2482
0
  {
2483
0
    Oid     typinput;
2484
0
    Oid     typoutput;
2485
2486
0
    boot_get_type_io_data(typid,
2487
0
                typlen,
2488
0
                typbyval,
2489
0
                typalign,
2490
0
                typdelim,
2491
0
                typioparam,
2492
0
                &typinput,
2493
0
                &typoutput);
2494
0
    switch (which_func)
2495
0
    {
2496
0
      case IOFunc_input:
2497
0
        *func = typinput;
2498
0
        break;
2499
0
      case IOFunc_output:
2500
0
        *func = typoutput;
2501
0
        break;
2502
0
      default:
2503
0
        elog(ERROR, "binary I/O not supported during bootstrap");
2504
0
        break;
2505
0
    }
2506
0
    return;
2507
0
  }
2508
2509
0
  typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2510
0
  if (!HeapTupleIsValid(typeTuple))
2511
0
    elog(ERROR, "cache lookup failed for type %u", typid);
2512
0
  typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
2513
2514
0
  *typlen = typeStruct->typlen;
2515
0
  *typbyval = typeStruct->typbyval;
2516
0
  *typalign = typeStruct->typalign;
2517
0
  *typdelim = typeStruct->typdelim;
2518
0
  *typioparam = getTypeIOParam(typeTuple);
2519
0
  switch (which_func)
2520
0
  {
2521
0
    case IOFunc_input:
2522
0
      *func = typeStruct->typinput;
2523
0
      break;
2524
0
    case IOFunc_output:
2525
0
      *func = typeStruct->typoutput;
2526
0
      break;
2527
0
    case IOFunc_receive:
2528
0
      *func = typeStruct->typreceive;
2529
0
      break;
2530
0
    case IOFunc_send:
2531
0
      *func = typeStruct->typsend;
2532
0
      break;
2533
0
  }
2534
0
  ReleaseSysCache(typeTuple);
2535
0
}
2536
2537
#ifdef NOT_USED
2538
char
2539
get_typalign(Oid typid)
2540
{
2541
  HeapTuple tp;
2542
2543
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2544
  if (HeapTupleIsValid(tp))
2545
  {
2546
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2547
    char    result;
2548
2549
    result = typtup->typalign;
2550
    ReleaseSysCache(tp);
2551
    return result;
2552
  }
2553
  else
2554
    return TYPALIGN_INT;
2555
}
2556
#endif
2557
2558
char
2559
get_typstorage(Oid typid)
2560
0
{
2561
0
  HeapTuple tp;
2562
2563
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2564
0
  if (HeapTupleIsValid(tp))
2565
0
  {
2566
0
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2567
0
    char    result;
2568
2569
0
    result = typtup->typstorage;
2570
0
    ReleaseSysCache(tp);
2571
0
    return result;
2572
0
  }
2573
0
  else
2574
0
    return TYPSTORAGE_PLAIN;
2575
0
}
2576
2577
/*
2578
 * get_typdefault
2579
 *    Given a type OID, return the type's default value, if any.
2580
 *
2581
 *    The result is a palloc'd expression node tree, or NULL if there
2582
 *    is no defined default for the datatype.
2583
 *
2584
 * NB: caller should be prepared to coerce result to correct datatype;
2585
 * the returned expression tree might produce something of the wrong type.
2586
 */
2587
Node *
2588
get_typdefault(Oid typid)
2589
0
{
2590
0
  HeapTuple typeTuple;
2591
0
  Form_pg_type type;
2592
0
  Datum   datum;
2593
0
  bool    isNull;
2594
0
  Node     *expr;
2595
2596
0
  typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2597
0
  if (!HeapTupleIsValid(typeTuple))
2598
0
    elog(ERROR, "cache lookup failed for type %u", typid);
2599
0
  type = (Form_pg_type) GETSTRUCT(typeTuple);
2600
2601
  /*
2602
   * typdefault and typdefaultbin are potentially null, so don't try to
2603
   * access 'em as struct fields. Must do it the hard way with
2604
   * SysCacheGetAttr.
2605
   */
2606
0
  datum = SysCacheGetAttr(TYPEOID,
2607
0
              typeTuple,
2608
0
              Anum_pg_type_typdefaultbin,
2609
0
              &isNull);
2610
2611
0
  if (!isNull)
2612
0
  {
2613
    /* We have an expression default */
2614
0
    expr = stringToNode(TextDatumGetCString(datum));
2615
0
  }
2616
0
  else
2617
0
  {
2618
    /* Perhaps we have a plain literal default */
2619
0
    datum = SysCacheGetAttr(TYPEOID,
2620
0
                typeTuple,
2621
0
                Anum_pg_type_typdefault,
2622
0
                &isNull);
2623
2624
0
    if (!isNull)
2625
0
    {
2626
0
      char     *strDefaultVal;
2627
2628
      /* Convert text datum to C string */
2629
0
      strDefaultVal = TextDatumGetCString(datum);
2630
      /* Convert C string to a value of the given type */
2631
0
      datum = OidInputFunctionCall(type->typinput, strDefaultVal,
2632
0
                     getTypeIOParam(typeTuple), -1);
2633
      /* Build a Const node containing the value */
2634
0
      expr = (Node *) makeConst(typid,
2635
0
                    -1,
2636
0
                    type->typcollation,
2637
0
                    type->typlen,
2638
0
                    datum,
2639
0
                    false,
2640
0
                    type->typbyval);
2641
0
      pfree(strDefaultVal);
2642
0
    }
2643
0
    else
2644
0
    {
2645
      /* No default */
2646
0
      expr = NULL;
2647
0
    }
2648
0
  }
2649
2650
0
  ReleaseSysCache(typeTuple);
2651
2652
0
  return expr;
2653
0
}
2654
2655
/*
2656
 * getBaseType
2657
 *    If the given type is a domain, return its base type;
2658
 *    otherwise return the type's own OID.
2659
 */
2660
Oid
2661
getBaseType(Oid typid)
2662
0
{
2663
0
  int32   typmod = -1;
2664
2665
0
  return getBaseTypeAndTypmod(typid, &typmod);
2666
0
}
2667
2668
/*
2669
 * getBaseTypeAndTypmod
2670
 *    If the given type is a domain, return its base type and typmod;
2671
 *    otherwise return the type's own OID, and leave *typmod unchanged.
2672
 *
2673
 * Note that the "applied typmod" should be -1 for every domain level
2674
 * above the bottommost; therefore, if the passed-in typid is indeed
2675
 * a domain, *typmod should be -1.
2676
 */
2677
Oid
2678
getBaseTypeAndTypmod(Oid typid, int32 *typmod)
2679
0
{
2680
  /*
2681
   * We loop to find the bottom base type in a stack of domains.
2682
   */
2683
0
  for (;;)
2684
0
  {
2685
0
    HeapTuple tup;
2686
0
    Form_pg_type typTup;
2687
2688
0
    tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2689
0
    if (!HeapTupleIsValid(tup))
2690
0
      elog(ERROR, "cache lookup failed for type %u", typid);
2691
0
    typTup = (Form_pg_type) GETSTRUCT(tup);
2692
0
    if (typTup->typtype != TYPTYPE_DOMAIN)
2693
0
    {
2694
      /* Not a domain, so done */
2695
0
      ReleaseSysCache(tup);
2696
0
      break;
2697
0
    }
2698
2699
0
    Assert(*typmod == -1);
2700
0
    typid = typTup->typbasetype;
2701
0
    *typmod = typTup->typtypmod;
2702
2703
0
    ReleaseSysCache(tup);
2704
0
  }
2705
2706
0
  return typid;
2707
0
}
2708
2709
/*
2710
 * get_typavgwidth
2711
 *
2712
 *    Given a type OID and a typmod value (pass -1 if typmod is unknown),
2713
 *    estimate the average width of values of the type.  This is used by
2714
 *    the planner, which doesn't require absolutely correct results;
2715
 *    it's OK (and expected) to guess if we don't know for sure.
2716
 */
2717
int32
2718
get_typavgwidth(Oid typid, int32 typmod)
2719
0
{
2720
0
  int     typlen = get_typlen(typid);
2721
0
  int32   maxwidth;
2722
2723
  /*
2724
   * Easy if it's a fixed-width type
2725
   */
2726
0
  if (typlen > 0)
2727
0
    return typlen;
2728
2729
  /*
2730
   * type_maximum_size knows the encoding of typmod for some datatypes;
2731
   * don't duplicate that knowledge here.
2732
   */
2733
0
  maxwidth = type_maximum_size(typid, typmod);
2734
0
  if (maxwidth > 0)
2735
0
  {
2736
    /*
2737
     * For BPCHAR, the max width is also the only width.  Otherwise we
2738
     * need to guess about the typical data width given the max. A sliding
2739
     * scale for percentage of max width seems reasonable.
2740
     */
2741
0
    if (typid == BPCHAROID)
2742
0
      return maxwidth;
2743
0
    if (maxwidth <= 32)
2744
0
      return maxwidth; /* assume full width */
2745
0
    if (maxwidth < 1000)
2746
0
      return 32 + (maxwidth - 32) / 2; /* assume 50% */
2747
2748
    /*
2749
     * Beyond 1000, assume we're looking at something like
2750
     * "varchar(10000)" where the limit isn't actually reached often, and
2751
     * use a fixed estimate.
2752
     */
2753
0
    return 32 + (1000 - 32) / 2;
2754
0
  }
2755
2756
  /*
2757
   * Oops, we have no idea ... wild guess time.
2758
   */
2759
0
  return 32;
2760
0
}
2761
2762
/*
2763
 * get_typtype
2764
 *
2765
 *    Given the type OID, find if it is a basic type, a complex type, etc.
2766
 *    It returns the null char if the cache lookup fails...
2767
 */
2768
char
2769
get_typtype(Oid typid)
2770
0
{
2771
0
  HeapTuple tp;
2772
2773
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2774
0
  if (HeapTupleIsValid(tp))
2775
0
  {
2776
0
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2777
0
    char    result;
2778
2779
0
    result = typtup->typtype;
2780
0
    ReleaseSysCache(tp);
2781
0
    return result;
2782
0
  }
2783
0
  else
2784
0
    return '\0';
2785
0
}
2786
2787
/*
2788
 * type_is_rowtype
2789
 *
2790
 *    Convenience function to determine whether a type OID represents
2791
 *    a "rowtype" type --- either RECORD or a named composite type
2792
 *    (including a domain over a named composite type).
2793
 */
2794
bool
2795
type_is_rowtype(Oid typid)
2796
0
{
2797
0
  if (typid == RECORDOID)
2798
0
    return true;     /* easy case */
2799
0
  switch (get_typtype(typid))
2800
0
  {
2801
0
    case TYPTYPE_COMPOSITE:
2802
0
      return true;
2803
0
    case TYPTYPE_DOMAIN:
2804
0
      if (get_typtype(getBaseType(typid)) == TYPTYPE_COMPOSITE)
2805
0
        return true;
2806
0
      break;
2807
0
    default:
2808
0
      break;
2809
0
  }
2810
0
  return false;
2811
0
}
2812
2813
/*
2814
 * type_is_enum
2815
 *    Returns true if the given type is an enum type.
2816
 */
2817
bool
2818
type_is_enum(Oid typid)
2819
0
{
2820
0
  return (get_typtype(typid) == TYPTYPE_ENUM);
2821
0
}
2822
2823
/*
2824
 * type_is_range
2825
 *    Returns true if the given type is a range type.
2826
 */
2827
bool
2828
type_is_range(Oid typid)
2829
0
{
2830
0
  return (get_typtype(typid) == TYPTYPE_RANGE);
2831
0
}
2832
2833
/*
2834
 * type_is_multirange
2835
 *    Returns true if the given type is a multirange type.
2836
 */
2837
bool
2838
type_is_multirange(Oid typid)
2839
0
{
2840
0
  return (get_typtype(typid) == TYPTYPE_MULTIRANGE);
2841
0
}
2842
2843
/*
2844
 * get_type_category_preferred
2845
 *
2846
 *    Given the type OID, fetch its category and preferred-type status.
2847
 *    Throws error on failure.
2848
 */
2849
void
2850
get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
2851
0
{
2852
0
  HeapTuple tp;
2853
0
  Form_pg_type typtup;
2854
2855
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2856
0
  if (!HeapTupleIsValid(tp))
2857
0
    elog(ERROR, "cache lookup failed for type %u", typid);
2858
0
  typtup = (Form_pg_type) GETSTRUCT(tp);
2859
0
  *typcategory = typtup->typcategory;
2860
0
  *typispreferred = typtup->typispreferred;
2861
0
  ReleaseSysCache(tp);
2862
0
}
2863
2864
/*
2865
 * get_typ_typrelid
2866
 *
2867
 *    Given the type OID, get the typrelid (InvalidOid if not a complex
2868
 *    type).
2869
 */
2870
Oid
2871
get_typ_typrelid(Oid typid)
2872
0
{
2873
0
  HeapTuple tp;
2874
2875
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2876
0
  if (HeapTupleIsValid(tp))
2877
0
  {
2878
0
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2879
0
    Oid     result;
2880
2881
0
    result = typtup->typrelid;
2882
0
    ReleaseSysCache(tp);
2883
0
    return result;
2884
0
  }
2885
0
  else
2886
0
    return InvalidOid;
2887
0
}
2888
2889
/*
2890
 * get_element_type
2891
 *
2892
 *    Given the type OID, get the typelem (InvalidOid if not an array type).
2893
 *
2894
 * NB: this only succeeds for "true" arrays having array_subscript_handler
2895
 * as typsubscript.  For other types, InvalidOid is returned independently
2896
 * of whether they have typelem or typsubscript set.
2897
 */
2898
Oid
2899
get_element_type(Oid typid)
2900
0
{
2901
0
  HeapTuple tp;
2902
2903
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2904
0
  if (HeapTupleIsValid(tp))
2905
0
  {
2906
0
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
2907
0
    Oid     result;
2908
2909
0
    if (IsTrueArrayType(typtup))
2910
0
      result = typtup->typelem;
2911
0
    else
2912
0
      result = InvalidOid;
2913
0
    ReleaseSysCache(tp);
2914
0
    return result;
2915
0
  }
2916
0
  else
2917
0
    return InvalidOid;
2918
0
}
2919
2920
/*
2921
 * get_array_type
2922
 *
2923
 *    Given the type OID, get the corresponding "true" array type.
2924
 *    Returns InvalidOid if no array type can be found.
2925
 */
2926
Oid
2927
get_array_type(Oid typid)
2928
0
{
2929
0
  HeapTuple tp;
2930
0
  Oid     result = InvalidOid;
2931
2932
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2933
0
  if (HeapTupleIsValid(tp))
2934
0
  {
2935
0
    result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
2936
0
    ReleaseSysCache(tp);
2937
0
  }
2938
0
  return result;
2939
0
}
2940
2941
/*
2942
 * get_promoted_array_type
2943
 *
2944
 *    The "promoted" type is what you'd get from an ARRAY(SELECT ...)
2945
 *    construct, that is, either the corresponding "true" array type
2946
 *    if the input is a scalar type that has such an array type,
2947
 *    or the same type if the input is already a "true" array type.
2948
 *    Returns InvalidOid if neither rule is satisfied.
2949
 */
2950
Oid
2951
get_promoted_array_type(Oid typid)
2952
0
{
2953
0
  Oid     array_type = get_array_type(typid);
2954
2955
0
  if (OidIsValid(array_type))
2956
0
    return array_type;
2957
0
  if (OidIsValid(get_element_type(typid)))
2958
0
    return typid;
2959
0
  return InvalidOid;
2960
0
}
2961
2962
/*
2963
 * get_base_element_type
2964
 *    Given the type OID, get the typelem, looking "through" any domain
2965
 *    to its underlying array type.
2966
 *
2967
 * This is equivalent to get_element_type(getBaseType(typid)), but avoids
2968
 * an extra cache lookup.  Note that it fails to provide any information
2969
 * about the typmod of the array.
2970
 */
2971
Oid
2972
get_base_element_type(Oid typid)
2973
0
{
2974
  /*
2975
   * We loop to find the bottom base type in a stack of domains.
2976
   */
2977
0
  for (;;)
2978
0
  {
2979
0
    HeapTuple tup;
2980
0
    Form_pg_type typTup;
2981
2982
0
    tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2983
0
    if (!HeapTupleIsValid(tup))
2984
0
      break;
2985
0
    typTup = (Form_pg_type) GETSTRUCT(tup);
2986
0
    if (typTup->typtype != TYPTYPE_DOMAIN)
2987
0
    {
2988
      /* Not a domain, so stop descending */
2989
0
      Oid     result;
2990
2991
      /* This test must match get_element_type */
2992
0
      if (IsTrueArrayType(typTup))
2993
0
        result = typTup->typelem;
2994
0
      else
2995
0
        result = InvalidOid;
2996
0
      ReleaseSysCache(tup);
2997
0
      return result;
2998
0
    }
2999
3000
0
    typid = typTup->typbasetype;
3001
0
    ReleaseSysCache(tup);
3002
0
  }
3003
3004
  /* Like get_element_type, silently return InvalidOid for bogus input */
3005
0
  return InvalidOid;
3006
0
}
3007
3008
/*
3009
 * getTypeInputInfo
3010
 *
3011
 *    Get info needed for converting values of a type to internal form
3012
 */
3013
void
3014
getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
3015
0
{
3016
0
  HeapTuple typeTuple;
3017
0
  Form_pg_type pt;
3018
3019
0
  typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
3020
0
  if (!HeapTupleIsValid(typeTuple))
3021
0
    elog(ERROR, "cache lookup failed for type %u", type);
3022
0
  pt = (Form_pg_type) GETSTRUCT(typeTuple);
3023
3024
0
  if (!pt->typisdefined)
3025
0
    ereport(ERROR,
3026
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
3027
0
         errmsg("type %s is only a shell",
3028
0
            format_type_be(type))));
3029
0
  if (!OidIsValid(pt->typinput))
3030
0
    ereport(ERROR,
3031
0
        (errcode(ERRCODE_UNDEFINED_FUNCTION),
3032
0
         errmsg("no input function available for type %s",
3033
0
            format_type_be(type))));
3034
3035
0
  *typInput = pt->typinput;
3036
0
  *typIOParam = getTypeIOParam(typeTuple);
3037
3038
0
  ReleaseSysCache(typeTuple);
3039
0
}
3040
3041
/*
3042
 * getTypeOutputInfo
3043
 *
3044
 *    Get info needed for printing values of a type
3045
 */
3046
void
3047
getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
3048
0
{
3049
0
  HeapTuple typeTuple;
3050
0
  Form_pg_type pt;
3051
3052
0
  typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
3053
0
  if (!HeapTupleIsValid(typeTuple))
3054
0
    elog(ERROR, "cache lookup failed for type %u", type);
3055
0
  pt = (Form_pg_type) GETSTRUCT(typeTuple);
3056
3057
0
  if (!pt->typisdefined)
3058
0
    ereport(ERROR,
3059
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
3060
0
         errmsg("type %s is only a shell",
3061
0
            format_type_be(type))));
3062
0
  if (!OidIsValid(pt->typoutput))
3063
0
    ereport(ERROR,
3064
0
        (errcode(ERRCODE_UNDEFINED_FUNCTION),
3065
0
         errmsg("no output function available for type %s",
3066
0
            format_type_be(type))));
3067
3068
0
  *typOutput = pt->typoutput;
3069
0
  *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
3070
3071
0
  ReleaseSysCache(typeTuple);
3072
0
}
3073
3074
/*
3075
 * getTypeBinaryInputInfo
3076
 *
3077
 *    Get info needed for binary input of values of a type
3078
 */
3079
void
3080
getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
3081
0
{
3082
0
  HeapTuple typeTuple;
3083
0
  Form_pg_type pt;
3084
3085
0
  typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
3086
0
  if (!HeapTupleIsValid(typeTuple))
3087
0
    elog(ERROR, "cache lookup failed for type %u", type);
3088
0
  pt = (Form_pg_type) GETSTRUCT(typeTuple);
3089
3090
0
  if (!pt->typisdefined)
3091
0
    ereport(ERROR,
3092
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
3093
0
         errmsg("type %s is only a shell",
3094
0
            format_type_be(type))));
3095
0
  if (!OidIsValid(pt->typreceive))
3096
0
    ereport(ERROR,
3097
0
        (errcode(ERRCODE_UNDEFINED_FUNCTION),
3098
0
         errmsg("no binary input function available for type %s",
3099
0
            format_type_be(type))));
3100
3101
0
  *typReceive = pt->typreceive;
3102
0
  *typIOParam = getTypeIOParam(typeTuple);
3103
3104
0
  ReleaseSysCache(typeTuple);
3105
0
}
3106
3107
/*
3108
 * getTypeBinaryOutputInfo
3109
 *
3110
 *    Get info needed for binary output of values of a type
3111
 */
3112
void
3113
getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
3114
0
{
3115
0
  HeapTuple typeTuple;
3116
0
  Form_pg_type pt;
3117
3118
0
  typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
3119
0
  if (!HeapTupleIsValid(typeTuple))
3120
0
    elog(ERROR, "cache lookup failed for type %u", type);
3121
0
  pt = (Form_pg_type) GETSTRUCT(typeTuple);
3122
3123
0
  if (!pt->typisdefined)
3124
0
    ereport(ERROR,
3125
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
3126
0
         errmsg("type %s is only a shell",
3127
0
            format_type_be(type))));
3128
0
  if (!OidIsValid(pt->typsend))
3129
0
    ereport(ERROR,
3130
0
        (errcode(ERRCODE_UNDEFINED_FUNCTION),
3131
0
         errmsg("no binary output function available for type %s",
3132
0
            format_type_be(type))));
3133
3134
0
  *typSend = pt->typsend;
3135
0
  *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
3136
3137
0
  ReleaseSysCache(typeTuple);
3138
0
}
3139
3140
/*
3141
 * get_typmodin
3142
 *
3143
 *    Given the type OID, return the type's typmodin procedure, if any.
3144
 */
3145
Oid
3146
get_typmodin(Oid typid)
3147
0
{
3148
0
  HeapTuple tp;
3149
3150
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3151
0
  if (HeapTupleIsValid(tp))
3152
0
  {
3153
0
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
3154
0
    Oid     result;
3155
3156
0
    result = typtup->typmodin;
3157
0
    ReleaseSysCache(tp);
3158
0
    return result;
3159
0
  }
3160
0
  else
3161
0
    return InvalidOid;
3162
0
}
3163
3164
#ifdef NOT_USED
3165
/*
3166
 * get_typmodout
3167
 *
3168
 *    Given the type OID, return the type's typmodout procedure, if any.
3169
 */
3170
Oid
3171
get_typmodout(Oid typid)
3172
{
3173
  HeapTuple tp;
3174
3175
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3176
  if (HeapTupleIsValid(tp))
3177
  {
3178
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
3179
    Oid     result;
3180
3181
    result = typtup->typmodout;
3182
    ReleaseSysCache(tp);
3183
    return result;
3184
  }
3185
  else
3186
    return InvalidOid;
3187
}
3188
#endif              /* NOT_USED */
3189
3190
/*
3191
 * get_typcollation
3192
 *
3193
 *    Given the type OID, return the type's typcollation attribute.
3194
 */
3195
Oid
3196
get_typcollation(Oid typid)
3197
0
{
3198
0
  HeapTuple tp;
3199
3200
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3201
0
  if (HeapTupleIsValid(tp))
3202
0
  {
3203
0
    Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
3204
0
    Oid     result;
3205
3206
0
    result = typtup->typcollation;
3207
0
    ReleaseSysCache(tp);
3208
0
    return result;
3209
0
  }
3210
0
  else
3211
0
    return InvalidOid;
3212
0
}
3213
3214
3215
/*
3216
 * type_is_collatable
3217
 *
3218
 *    Return whether the type cares about collations
3219
 */
3220
bool
3221
type_is_collatable(Oid typid)
3222
0
{
3223
0
  return OidIsValid(get_typcollation(typid));
3224
0
}
3225
3226
3227
/*
3228
 * get_typsubscript
3229
 *
3230
 *    Given the type OID, return the type's subscripting handler's OID,
3231
 *    if it has one.
3232
 *
3233
 * If typelemp isn't NULL, we also store the type's typelem value there.
3234
 * This saves some callers an extra catalog lookup.
3235
 */
3236
RegProcedure
3237
get_typsubscript(Oid typid, Oid *typelemp)
3238
0
{
3239
0
  HeapTuple tp;
3240
3241
0
  tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3242
0
  if (HeapTupleIsValid(tp))
3243
0
  {
3244
0
    Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
3245
0
    RegProcedure handler = typform->typsubscript;
3246
3247
0
    if (typelemp)
3248
0
      *typelemp = typform->typelem;
3249
0
    ReleaseSysCache(tp);
3250
0
    return handler;
3251
0
  }
3252
0
  else
3253
0
  {
3254
0
    if (typelemp)
3255
0
      *typelemp = InvalidOid;
3256
0
    return InvalidOid;
3257
0
  }
3258
0
}
3259
3260
/*
3261
 * getSubscriptingRoutines
3262
 *
3263
 *    Given the type OID, fetch the type's subscripting methods struct.
3264
 *    Return NULL if type is not subscriptable.
3265
 *
3266
 * If typelemp isn't NULL, we also store the type's typelem value there.
3267
 * This saves some callers an extra catalog lookup.
3268
 */
3269
const struct SubscriptRoutines *
3270
getSubscriptingRoutines(Oid typid, Oid *typelemp)
3271
0
{
3272
0
  RegProcedure typsubscript = get_typsubscript(typid, typelemp);
3273
3274
0
  if (!OidIsValid(typsubscript))
3275
0
    return NULL;
3276
3277
0
  return (const struct SubscriptRoutines *)
3278
0
    DatumGetPointer(OidFunctionCall0(typsubscript));
3279
0
}
3280
3281
3282
/*        ---------- STATISTICS CACHE ----------           */
3283
3284
/*
3285
 * get_attavgwidth
3286
 *
3287
 *    Given the table and attribute number of a column, get the average
3288
 *    width of entries in the column.  Return zero if no data available.
3289
 *
3290
 * Currently this is only consulted for individual tables, not for inheritance
3291
 * trees, so we don't need an "inh" parameter.
3292
 *
3293
 * Calling a hook at this point looks somewhat strange, but is required
3294
 * because the optimizer calls this function without any other way for
3295
 * plug-ins to control the result.
3296
 */
3297
int32
3298
get_attavgwidth(Oid relid, AttrNumber attnum)
3299
0
{
3300
0
  HeapTuple tp;
3301
0
  int32   stawidth;
3302
3303
0
  if (get_attavgwidth_hook)
3304
0
  {
3305
0
    stawidth = (*get_attavgwidth_hook) (relid, attnum);
3306
0
    if (stawidth > 0)
3307
0
      return stawidth;
3308
0
  }
3309
0
  tp = SearchSysCache3(STATRELATTINH,
3310
0
             ObjectIdGetDatum(relid),
3311
0
             Int16GetDatum(attnum),
3312
0
             BoolGetDatum(false));
3313
0
  if (HeapTupleIsValid(tp))
3314
0
  {
3315
0
    stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
3316
0
    ReleaseSysCache(tp);
3317
0
    if (stawidth > 0)
3318
0
      return stawidth;
3319
0
  }
3320
0
  return 0;
3321
0
}
3322
3323
/*
3324
 * get_attstatsslot
3325
 *
3326
 *    Extract the contents of a "slot" of a pg_statistic tuple.
3327
 *    Returns true if requested slot type was found, else false.
3328
 *
3329
 * Unlike other routines in this file, this takes a pointer to an
3330
 * already-looked-up tuple in the pg_statistic cache.  We do this since
3331
 * most callers will want to extract more than one value from the cache
3332
 * entry, and we don't want to repeat the cache lookup unnecessarily.
3333
 * Also, this API allows this routine to be used with statistics tuples
3334
 * that have been provided by a stats hook and didn't really come from
3335
 * pg_statistic.
3336
 *
3337
 * sslot: pointer to output area (typically, a local variable in the caller).
3338
 * statstuple: pg_statistic tuple to be examined.
3339
 * reqkind: STAKIND code for desired statistics slot kind.
3340
 * reqop: STAOP value wanted, or InvalidOid if don't care.
3341
 * flags: bitmask of ATTSTATSSLOT_VALUES and/or ATTSTATSSLOT_NUMBERS.
3342
 *
3343
 * If a matching slot is found, true is returned, and *sslot is filled thus:
3344
 * staop: receives the actual STAOP value.
3345
 * stacoll: receives the actual STACOLL value.
3346
 * valuetype: receives actual datatype of the elements of stavalues.
3347
 * values: receives pointer to an array of the slot's stavalues.
3348
 * nvalues: receives number of stavalues.
3349
 * numbers: receives pointer to an array of the slot's stanumbers (as float4).
3350
 * nnumbers: receives number of stanumbers.
3351
 *
3352
 * valuetype/values/nvalues are InvalidOid/NULL/0 if ATTSTATSSLOT_VALUES
3353
 * wasn't specified.  Likewise, numbers/nnumbers are NULL/0 if
3354
 * ATTSTATSSLOT_NUMBERS wasn't specified.
3355
 *
3356
 * If no matching slot is found, false is returned, and *sslot is zeroed.
3357
 *
3358
 * Note that the current API doesn't allow for searching for a slot with
3359
 * a particular collation.  If we ever actually support recording more than
3360
 * one collation, we'll have to extend the API, but for now simple is good.
3361
 *
3362
 * The data referred to by the fields of sslot is locally palloc'd and
3363
 * is independent of the original pg_statistic tuple.  When the caller
3364
 * is done with it, call free_attstatsslot to release the palloc'd data.
3365
 *
3366
 * If it's desirable to call free_attstatsslot when get_attstatsslot might
3367
 * not have been called, memset'ing sslot to zeroes will allow that.
3368
 *
3369
 * Passing flags=0 can be useful to quickly check if the requested slot type
3370
 * exists.  In this case no arrays are extracted, so free_attstatsslot need
3371
 * not be called.
3372
 */
3373
bool
3374
get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple,
3375
         int reqkind, Oid reqop, int flags)
3376
0
{
3377
0
  Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
3378
0
  int     i;
3379
0
  Datum   val;
3380
0
  ArrayType  *statarray;
3381
0
  Oid     arrayelemtype;
3382
0
  int     narrayelem;
3383
0
  HeapTuple typeTuple;
3384
0
  Form_pg_type typeForm;
3385
3386
  /* initialize *sslot properly */
3387
0
  memset(sslot, 0, sizeof(AttStatsSlot));
3388
3389
0
  for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
3390
0
  {
3391
0
    if ((&stats->stakind1)[i] == reqkind &&
3392
0
      (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
3393
0
      break;
3394
0
  }
3395
0
  if (i >= STATISTIC_NUM_SLOTS)
3396
0
    return false;     /* not there */
3397
3398
0
  sslot->staop = (&stats->staop1)[i];
3399
0
  sslot->stacoll = (&stats->stacoll1)[i];
3400
3401
0
  if (flags & ATTSTATSSLOT_VALUES)
3402
0
  {
3403
0
    val = SysCacheGetAttrNotNull(STATRELATTINH, statstuple,
3404
0
                   Anum_pg_statistic_stavalues1 + i);
3405
3406
    /*
3407
     * Detoast the array if needed, and in any case make a copy that's
3408
     * under control of this AttStatsSlot.
3409
     */
3410
0
    statarray = DatumGetArrayTypePCopy(val);
3411
3412
    /*
3413
     * Extract the actual array element type, and pass it back in case the
3414
     * caller needs it.
3415
     */
3416
0
    sslot->valuetype = arrayelemtype = ARR_ELEMTYPE(statarray);
3417
3418
    /* Need info about element type */
3419
0
    typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
3420
0
    if (!HeapTupleIsValid(typeTuple))
3421
0
      elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
3422
0
    typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
3423
3424
    /* Deconstruct array into Datum elements; NULLs not expected */
3425
0
    deconstruct_array(statarray,
3426
0
              arrayelemtype,
3427
0
              typeForm->typlen,
3428
0
              typeForm->typbyval,
3429
0
              typeForm->typalign,
3430
0
              &sslot->values, NULL, &sslot->nvalues);
3431
3432
    /*
3433
     * If the element type is pass-by-reference, we now have a bunch of
3434
     * Datums that are pointers into the statarray, so we need to keep
3435
     * that until free_attstatsslot.  Otherwise, all the useful info is in
3436
     * sslot->values[], so we can free the array object immediately.
3437
     */
3438
0
    if (!typeForm->typbyval)
3439
0
      sslot->values_arr = statarray;
3440
0
    else
3441
0
      pfree(statarray);
3442
3443
0
    ReleaseSysCache(typeTuple);
3444
0
  }
3445
3446
0
  if (flags & ATTSTATSSLOT_NUMBERS)
3447
0
  {
3448
0
    val = SysCacheGetAttrNotNull(STATRELATTINH, statstuple,
3449
0
                   Anum_pg_statistic_stanumbers1 + i);
3450
3451
    /*
3452
     * Detoast the array if needed, and in any case make a copy that's
3453
     * under control of this AttStatsSlot.
3454
     */
3455
0
    statarray = DatumGetArrayTypePCopy(val);
3456
3457
    /*
3458
     * We expect the array to be a 1-D float4 array; verify that. We don't
3459
     * need to use deconstruct_array() since the array data is just going
3460
     * to look like a C array of float4 values.
3461
     */
3462
0
    narrayelem = ARR_DIMS(statarray)[0];
3463
0
    if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
3464
0
      ARR_HASNULL(statarray) ||
3465
0
      ARR_ELEMTYPE(statarray) != FLOAT4OID)
3466
0
      elog(ERROR, "stanumbers is not a 1-D float4 array");
3467
3468
    /* Give caller a pointer directly into the statarray */
3469
0
    sslot->numbers = (float4 *) ARR_DATA_PTR(statarray);
3470
0
    sslot->nnumbers = narrayelem;
3471
3472
    /* We'll free the statarray in free_attstatsslot */
3473
0
    sslot->numbers_arr = statarray;
3474
0
  }
3475
3476
0
  return true;
3477
0
}
3478
3479
/*
3480
 * free_attstatsslot
3481
 *    Free data allocated by get_attstatsslot
3482
 */
3483
void
3484
free_attstatsslot(AttStatsSlot *sslot)
3485
0
{
3486
  /* The values[] array was separately palloc'd by deconstruct_array */
3487
0
  if (sslot->values)
3488
0
    pfree(sslot->values);
3489
  /* The numbers[] array points into numbers_arr, do not pfree it */
3490
  /* Free the detoasted array objects, if any */
3491
0
  if (sslot->values_arr)
3492
0
    pfree(sslot->values_arr);
3493
0
  if (sslot->numbers_arr)
3494
0
    pfree(sslot->numbers_arr);
3495
0
}
3496
3497
/*        ---------- PG_NAMESPACE CACHE ----------         */
3498
3499
/*
3500
 * get_namespace_name
3501
 *    Returns the name of a given namespace
3502
 *
3503
 * Returns a palloc'd copy of the string, or NULL if no such namespace.
3504
 */
3505
char *
3506
get_namespace_name(Oid nspid)
3507
0
{
3508
0
  HeapTuple tp;
3509
3510
0
  tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
3511
0
  if (HeapTupleIsValid(tp))
3512
0
  {
3513
0
    Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
3514
0
    char     *result;
3515
3516
0
    result = pstrdup(NameStr(nsptup->nspname));
3517
0
    ReleaseSysCache(tp);
3518
0
    return result;
3519
0
  }
3520
0
  else
3521
0
    return NULL;
3522
0
}
3523
3524
/*
3525
 * get_namespace_name_or_temp
3526
 *    As above, but if it is this backend's temporary namespace, return
3527
 *    "pg_temp" instead.
3528
 */
3529
char *
3530
get_namespace_name_or_temp(Oid nspid)
3531
0
{
3532
0
  if (isTempNamespace(nspid))
3533
0
    return pstrdup("pg_temp");
3534
0
  else
3535
0
    return get_namespace_name(nspid);
3536
0
}
3537
3538
/*        ---------- PG_RANGE CACHES ----------        */
3539
3540
/*
3541
 * get_range_subtype
3542
 *    Returns the subtype of a given range type
3543
 *
3544
 * Returns InvalidOid if the type is not a range type.
3545
 */
3546
Oid
3547
get_range_subtype(Oid rangeOid)
3548
0
{
3549
0
  HeapTuple tp;
3550
3551
0
  tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3552
0
  if (HeapTupleIsValid(tp))
3553
0
  {
3554
0
    Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3555
0
    Oid     result;
3556
3557
0
    result = rngtup->rngsubtype;
3558
0
    ReleaseSysCache(tp);
3559
0
    return result;
3560
0
  }
3561
0
  else
3562
0
    return InvalidOid;
3563
0
}
3564
3565
/*
3566
 * get_range_collation
3567
 *    Returns the collation of a given range type
3568
 *
3569
 * Returns InvalidOid if the type is not a range type,
3570
 * or if its subtype is not collatable.
3571
 */
3572
Oid
3573
get_range_collation(Oid rangeOid)
3574
0
{
3575
0
  HeapTuple tp;
3576
3577
0
  tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3578
0
  if (HeapTupleIsValid(tp))
3579
0
  {
3580
0
    Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3581
0
    Oid     result;
3582
3583
0
    result = rngtup->rngcollation;
3584
0
    ReleaseSysCache(tp);
3585
0
    return result;
3586
0
  }
3587
0
  else
3588
0
    return InvalidOid;
3589
0
}
3590
3591
/*
3592
 * get_range_multirange
3593
 *    Returns the multirange type of a given range type
3594
 *
3595
 * Returns InvalidOid if the type is not a range type.
3596
 */
3597
Oid
3598
get_range_multirange(Oid rangeOid)
3599
0
{
3600
0
  HeapTuple tp;
3601
3602
0
  tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
3603
0
  if (HeapTupleIsValid(tp))
3604
0
  {
3605
0
    Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3606
0
    Oid     result;
3607
3608
0
    result = rngtup->rngmultitypid;
3609
0
    ReleaseSysCache(tp);
3610
0
    return result;
3611
0
  }
3612
0
  else
3613
0
    return InvalidOid;
3614
0
}
3615
3616
/*
3617
 * get_multirange_range
3618
 *    Returns the range type of a given multirange
3619
 *
3620
 * Returns InvalidOid if the type is not a multirange.
3621
 */
3622
Oid
3623
get_multirange_range(Oid multirangeOid)
3624
0
{
3625
0
  HeapTuple tp;
3626
3627
0
  tp = SearchSysCache1(RANGEMULTIRANGE, ObjectIdGetDatum(multirangeOid));
3628
0
  if (HeapTupleIsValid(tp))
3629
0
  {
3630
0
    Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
3631
0
    Oid     result;
3632
3633
0
    result = rngtup->rngtypid;
3634
0
    ReleaseSysCache(tp);
3635
0
    return result;
3636
0
  }
3637
0
  else
3638
0
    return InvalidOid;
3639
0
}
3640
3641
/*        ---------- PG_INDEX CACHE ----------         */
3642
3643
/*
3644
 * get_index_column_opclass
3645
 *
3646
 *    Given the index OID and column number,
3647
 *    return opclass of the index column
3648
 *      or InvalidOid if the index was not found
3649
 *        or column is non-key one.
3650
 */
3651
Oid
3652
get_index_column_opclass(Oid index_oid, int attno)
3653
0
{
3654
0
  HeapTuple tuple;
3655
0
  Form_pg_index rd_index;
3656
0
  Datum   datum;
3657
0
  oidvector  *indclass;
3658
0
  Oid     opclass;
3659
3660
  /* First we need to know the column's opclass. */
3661
3662
0
  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3663
0
  if (!HeapTupleIsValid(tuple))
3664
0
    return InvalidOid;
3665
3666
0
  rd_index = (Form_pg_index) GETSTRUCT(tuple);
3667
3668
  /* caller is supposed to guarantee this */
3669
0
  Assert(attno > 0 && attno <= rd_index->indnatts);
3670
3671
  /* Non-key attributes don't have an opclass */
3672
0
  if (attno > rd_index->indnkeyatts)
3673
0
  {
3674
0
    ReleaseSysCache(tuple);
3675
0
    return InvalidOid;
3676
0
  }
3677
3678
0
  datum = SysCacheGetAttrNotNull(INDEXRELID, tuple, Anum_pg_index_indclass);
3679
0
  indclass = ((oidvector *) DatumGetPointer(datum));
3680
3681
0
  Assert(attno <= indclass->dim1);
3682
0
  opclass = indclass->values[attno - 1];
3683
3684
0
  ReleaseSysCache(tuple);
3685
3686
0
  return opclass;
3687
0
}
3688
3689
/*
3690
 * get_index_isreplident
3691
 *
3692
 *    Given the index OID, return pg_index.indisreplident.
3693
 */
3694
bool
3695
get_index_isreplident(Oid index_oid)
3696
0
{
3697
0
  HeapTuple tuple;
3698
0
  Form_pg_index rd_index;
3699
0
  bool    result;
3700
3701
0
  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3702
0
  if (!HeapTupleIsValid(tuple))
3703
0
    return false;
3704
3705
0
  rd_index = (Form_pg_index) GETSTRUCT(tuple);
3706
0
  result = rd_index->indisreplident;
3707
0
  ReleaseSysCache(tuple);
3708
3709
0
  return result;
3710
0
}
3711
3712
/*
3713
 * get_index_isvalid
3714
 *
3715
 *    Given the index OID, return pg_index.indisvalid.
3716
 */
3717
bool
3718
get_index_isvalid(Oid index_oid)
3719
0
{
3720
0
  bool    isvalid;
3721
0
  HeapTuple tuple;
3722
0
  Form_pg_index rd_index;
3723
3724
0
  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3725
0
  if (!HeapTupleIsValid(tuple))
3726
0
    elog(ERROR, "cache lookup failed for index %u", index_oid);
3727
3728
0
  rd_index = (Form_pg_index) GETSTRUCT(tuple);
3729
0
  isvalid = rd_index->indisvalid;
3730
0
  ReleaseSysCache(tuple);
3731
3732
0
  return isvalid;
3733
0
}
3734
3735
/*
3736
 * get_index_isclustered
3737
 *
3738
 *    Given the index OID, return pg_index.indisclustered.
3739
 */
3740
bool
3741
get_index_isclustered(Oid index_oid)
3742
0
{
3743
0
  bool    isclustered;
3744
0
  HeapTuple tuple;
3745
0
  Form_pg_index rd_index;
3746
3747
0
  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
3748
0
  if (!HeapTupleIsValid(tuple))
3749
0
    elog(ERROR, "cache lookup failed for index %u", index_oid);
3750
3751
0
  rd_index = (Form_pg_index) GETSTRUCT(tuple);
3752
0
  isclustered = rd_index->indisclustered;
3753
0
  ReleaseSysCache(tuple);
3754
3755
0
  return isclustered;
3756
0
}
3757
3758
/*
3759
 * get_publication_oid - given a publication name, look up the OID
3760
 *
3761
 * If missing_ok is false, throw an error if name not found.  If true, just
3762
 * return InvalidOid.
3763
 */
3764
Oid
3765
get_publication_oid(const char *pubname, bool missing_ok)
3766
0
{
3767
0
  Oid     oid;
3768
3769
0
  oid = GetSysCacheOid1(PUBLICATIONNAME, Anum_pg_publication_oid,
3770
0
              CStringGetDatum(pubname));
3771
0
  if (!OidIsValid(oid) && !missing_ok)
3772
0
    ereport(ERROR,
3773
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
3774
0
         errmsg("publication \"%s\" does not exist", pubname)));
3775
0
  return oid;
3776
0
}
3777
3778
/*
3779
 * get_publication_name - given a publication Oid, look up the name
3780
 *
3781
 * If missing_ok is false, throw an error if name not found.  If true, just
3782
 * return NULL.
3783
 */
3784
char *
3785
get_publication_name(Oid pubid, bool missing_ok)
3786
0
{
3787
0
  HeapTuple tup;
3788
0
  char     *pubname;
3789
0
  Form_pg_publication pubform;
3790
3791
0
  tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
3792
3793
0
  if (!HeapTupleIsValid(tup))
3794
0
  {
3795
0
    if (!missing_ok)
3796
0
      elog(ERROR, "cache lookup failed for publication %u", pubid);
3797
0
    return NULL;
3798
0
  }
3799
3800
0
  pubform = (Form_pg_publication) GETSTRUCT(tup);
3801
0
  pubname = pstrdup(NameStr(pubform->pubname));
3802
3803
0
  ReleaseSysCache(tup);
3804
3805
0
  return pubname;
3806
0
}
3807
3808
/*
3809
 * get_subscription_oid - given a subscription name, look up the OID
3810
 *
3811
 * If missing_ok is false, throw an error if name not found.  If true, just
3812
 * return InvalidOid.
3813
 */
3814
Oid
3815
get_subscription_oid(const char *subname, bool missing_ok)
3816
0
{
3817
0
  Oid     oid;
3818
3819
0
  oid = GetSysCacheOid2(SUBSCRIPTIONNAME, Anum_pg_subscription_oid,
3820
0
              ObjectIdGetDatum(MyDatabaseId), CStringGetDatum(subname));
3821
0
  if (!OidIsValid(oid) && !missing_ok)
3822
0
    ereport(ERROR,
3823
0
        (errcode(ERRCODE_UNDEFINED_OBJECT),
3824
0
         errmsg("subscription \"%s\" does not exist", subname)));
3825
0
  return oid;
3826
0
}
3827
3828
/*
3829
 * get_subscription_name - given a subscription OID, look up the name
3830
 *
3831
 * If missing_ok is false, throw an error if name not found.  If true, just
3832
 * return NULL.
3833
 */
3834
char *
3835
get_subscription_name(Oid subid, bool missing_ok)
3836
0
{
3837
0
  HeapTuple tup;
3838
0
  char     *subname;
3839
0
  Form_pg_subscription subform;
3840
3841
0
  tup = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid));
3842
3843
0
  if (!HeapTupleIsValid(tup))
3844
0
  {
3845
0
    if (!missing_ok)
3846
0
      elog(ERROR, "cache lookup failed for subscription %u", subid);
3847
0
    return NULL;
3848
0
  }
3849
3850
0
  subform = (Form_pg_subscription) GETSTRUCT(tup);
3851
0
  subname = pstrdup(NameStr(subform->subname));
3852
3853
0
  ReleaseSysCache(tup);
3854
3855
0
  return subname;
3856
0
}