|
1 | 1 | /*-------------------------------------------------------------------------
|
2 | 2 | *
|
3 | 3 | * lsyscache.c
|
4 |
| - * Routines to access information within system caches |
| 4 | + * Convenience routines for common queries in the system catalog cache. |
5 | 5 | *
|
6 | 6 | * Copyright (c) 1994, Regents of the University of California
|
7 | 7 | *
|
8 |
| - * |
9 | 8 | * IDENTIFICATION
|
10 |
| - * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.31 1999/07/17 20:18:01 momjian Exp $ |
| 9 | + * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.32 1999/08/09 03:13:30 tgl Exp $ |
11 | 10 | *
|
12 | 11 | * NOTES
|
13 | 12 | * Eventually, the index information should go through here, too.
|
14 | 13 | *-------------------------------------------------------------------------
|
15 | 14 | */
|
16 | 15 | #include "postgres.h"
|
17 | 16 |
|
18 |
| - |
19 | 17 | #include "catalog/pg_operator.h"
|
20 | 18 | #include "catalog/pg_type.h"
|
21 | 19 | #include "utils/lsyscache.h"
|
@@ -166,6 +164,77 @@ get_atttypmod(Oid relid, AttrNumber attnum)
|
166 | 164 | return -1;
|
167 | 165 | }
|
168 | 166 |
|
| 167 | +/* |
| 168 | + * get_attdisbursion |
| 169 | + * |
| 170 | + * Retrieve the disbursion statistic for an attribute, |
| 171 | + * or produce an estimate if no info is available. |
| 172 | + * |
| 173 | + * min_estimate is the minimum estimate to return if insufficient data |
| 174 | + * is available to produce a reliable value. This value may vary |
| 175 | + * depending on context. (For example, when deciding whether it is |
| 176 | + * safe to use a hashjoin, we want to be more conservative than when |
| 177 | + * estimating the number of tuples produced by an equijoin.) |
| 178 | + */ |
| 179 | +double |
| 180 | +get_attdisbursion(Oid relid, AttrNumber attnum, double min_estimate) |
| 181 | +{ |
| 182 | + HeapTuple atp; |
| 183 | + double disbursion; |
| 184 | + int32 ntuples; |
| 185 | + |
| 186 | + atp = SearchSysCacheTuple(ATTNUM, |
| 187 | + ObjectIdGetDatum(relid), |
| 188 | + Int16GetDatum(attnum), |
| 189 | + 0, 0); |
| 190 | + if (!HeapTupleIsValid(atp)) |
| 191 | + { |
| 192 | + /* this should not happen */ |
| 193 | + elog(ERROR, "get_attdisbursion: no attribute tuple %u %d", |
| 194 | + relid, attnum); |
| 195 | + return min_estimate; |
| 196 | + } |
| 197 | + |
| 198 | + disbursion = ((Form_pg_attribute) GETSTRUCT(atp))->attdisbursion; |
| 199 | + if (disbursion > 0.0) |
| 200 | + return disbursion; /* we have a specific estimate */ |
| 201 | + |
| 202 | + /* |
| 203 | + * Disbursion is either 0 (no data available) or -1 (disbursion |
| 204 | + * is 1/numtuples). Either way, we need the relation size. |
| 205 | + */ |
| 206 | + |
| 207 | + atp = SearchSysCacheTuple(RELOID, |
| 208 | + ObjectIdGetDatum(relid), |
| 209 | + 0, 0, 0); |
| 210 | + if (!HeapTupleIsValid(atp)) |
| 211 | + { |
| 212 | + /* this should not happen */ |
| 213 | + elog(ERROR, "get_attdisbursion: no relation tuple %u", relid); |
| 214 | + return min_estimate; |
| 215 | + } |
| 216 | + |
| 217 | + ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples; |
| 218 | + |
| 219 | + if (ntuples == 0) |
| 220 | + return min_estimate; /* no data available */ |
| 221 | + |
| 222 | + if (disbursion < 0.0) /* VACUUM thinks there are no duplicates */ |
| 223 | + return 1.0 / (double) ntuples; |
| 224 | + |
| 225 | + /* |
| 226 | + * VACUUM ANALYZE has not been run for this table. |
| 227 | + * Produce an estimate = 1/numtuples. This may produce |
| 228 | + * unreasonably small estimates for large tables, so limit |
| 229 | + * the estimate to no less than min_estimate. |
| 230 | + */ |
| 231 | + disbursion = 1.0 / (double) ntuples; |
| 232 | + if (disbursion < min_estimate) |
| 233 | + disbursion = min_estimate; |
| 234 | + |
| 235 | + return disbursion; |
| 236 | +} |
| 237 | + |
169 | 238 | /* ---------- INDEX CACHE ---------- */
|
170 | 239 |
|
171 | 240 | /* watch this space...
|
@@ -504,15 +573,110 @@ get_typalign(Oid typid)
|
504 | 573 | /*
|
505 | 574 | * get_typdefault -
|
506 | 575 | *
|
507 |
| - * Given the type OID, return the default value of the ADT. |
508 |
| - * |
| 576 | + * Given a type OID, return the typdefault field associated with that |
| 577 | + * type, or Datum(NULL) if there is no typdefault. (This implies |
| 578 | + * that pass-by-value types can't have a default value that has |
| 579 | + * a representation of zero. Not worth fixing now.) |
| 580 | + * The result points to palloc'd storage for non-pass-by-value types. |
509 | 581 | */
|
510 |
| -struct varlena * |
| 582 | +Datum |
511 | 583 | get_typdefault(Oid typid)
|
512 | 584 | {
|
513 |
| - struct varlena *typdefault = (struct varlena *) TypeDefaultRetrieve(typid); |
| 585 | + struct varlena *typDefault; |
| 586 | + int32 dataSize; |
| 587 | + HeapTuple typeTuple; |
| 588 | + Form_pg_type type; |
| 589 | + int32 typLen; |
| 590 | + bool typByVal; |
| 591 | + Datum returnValue; |
| 592 | + |
| 593 | + /* |
| 594 | + * First, see if there is a non-null typdefault field (usually there isn't) |
| 595 | + */ |
| 596 | + typDefault = (struct varlena *) |
| 597 | + SearchSysCacheGetAttribute(TYPOID, |
| 598 | + Anum_pg_type_typdefault, |
| 599 | + ObjectIdGetDatum(typid), |
| 600 | + 0, 0, 0); |
| 601 | + |
| 602 | + if (typDefault == NULL) |
| 603 | + return PointerGetDatum(NULL); |
| 604 | + |
| 605 | + dataSize = VARSIZE(typDefault) - VARHDRSZ; |
| 606 | + |
| 607 | + /* |
| 608 | + * Need the type's length and byVal fields. |
| 609 | + * |
| 610 | + * XXX silly to repeat the syscache search that SearchSysCacheGetAttribute |
| 611 | + * just did --- but at present this path isn't taken often enough to |
| 612 | + * make it worth fixing. |
| 613 | + */ |
| 614 | + typeTuple = SearchSysCacheTuple(TYPOID, |
| 615 | + ObjectIdGetDatum(typid), |
| 616 | + 0, 0, 0); |
| 617 | + |
| 618 | + if (!HeapTupleIsValid(typeTuple)) |
| 619 | + elog(ERROR, "get_typdefault: failed to lookup type %u", typid); |
| 620 | + |
| 621 | + type = (Form_pg_type) GETSTRUCT(typeTuple); |
| 622 | + typLen = type->typlen; |
| 623 | + typByVal = type->typbyval; |
| 624 | + |
| 625 | + if (typByVal) |
| 626 | + { |
| 627 | + int8 i8; |
| 628 | + int16 i16; |
| 629 | + int32 i32 = 0; |
| 630 | + |
| 631 | + if (dataSize == typLen) |
| 632 | + { |
| 633 | + switch (typLen) |
| 634 | + { |
| 635 | + case sizeof(int8): |
| 636 | + memcpy((char *) &i8, VARDATA(typDefault), sizeof(int8)); |
| 637 | + i32 = i8; |
| 638 | + break; |
| 639 | + case sizeof(int16): |
| 640 | + memcpy((char *) &i16, VARDATA(typDefault), sizeof(int16)); |
| 641 | + i32 = i16; |
| 642 | + break; |
| 643 | + case sizeof(int32): |
| 644 | + memcpy((char *) &i32, VARDATA(typDefault), sizeof(int32)); |
| 645 | + break; |
| 646 | + } |
| 647 | + returnValue = Int32GetDatum(i32); |
| 648 | + } |
| 649 | + else |
| 650 | + returnValue = PointerGetDatum(NULL); |
| 651 | + } |
| 652 | + else if (typLen < 0) |
| 653 | + { |
| 654 | + /* variable-size type */ |
| 655 | + if (dataSize < 0) |
| 656 | + returnValue = PointerGetDatum(NULL); |
| 657 | + else |
| 658 | + { |
| 659 | + returnValue = PointerGetDatum(palloc(VARSIZE(typDefault))); |
| 660 | + memcpy((char *) DatumGetPointer(returnValue), |
| 661 | + (char *) typDefault, |
| 662 | + (int) VARSIZE(typDefault)); |
| 663 | + } |
| 664 | + } |
| 665 | + else |
| 666 | + { |
| 667 | + /* fixed-size pass-by-ref type */ |
| 668 | + if (dataSize != typLen) |
| 669 | + returnValue = PointerGetDatum(NULL); |
| 670 | + else |
| 671 | + { |
| 672 | + returnValue = PointerGetDatum(palloc(dataSize)); |
| 673 | + memcpy((char *) DatumGetPointer(returnValue), |
| 674 | + VARDATA(typDefault), |
| 675 | + (int) dataSize); |
| 676 | + } |
| 677 | + } |
514 | 678 |
|
515 |
| - return typdefault; |
| 679 | + return returnValue; |
516 | 680 | }
|
517 | 681 |
|
518 | 682 | /*
|
|
0 commit comments