📄 tid.c
字号:
/*------------------------------------------------------------------------- * * tid.c * Functions for the built-in type tuple id * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/adt/tid.c,v 1.59 2008/01/01 19:45:52 momjian Exp $ * * NOTES * input routine largely stolen from boxin(). * *------------------------------------------------------------------------- */#include "postgres.h"#include <math.h>#include <limits.h>#include "access/heapam.h"#include "catalog/namespace.h"#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "miscadmin.h"#include "parser/parsetree.h"#include "utils/acl.h"#include "utils/builtins.h"#define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))#define ItemPointerGetDatum(X) PointerGetDatum(X)#define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))#define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)#define LDELIM '('#define RDELIM ')'#define DELIM ','#define NTIDARGS 2/* ---------------------------------------------------------------- * tidin * ---------------------------------------------------------------- */Datumtidin(PG_FUNCTION_ARGS){ char *str = PG_GETARG_CSTRING(0); char *p, *coord[NTIDARGS]; int i; ItemPointer result; BlockNumber blockNumber; OffsetNumber offsetNumber; char *badp; int hold_offset; for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++) if (*p == DELIM || (*p == LDELIM && !i)) coord[i++] = p + 1; if (i < NTIDARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type tid: \"%s\"", str))); errno = 0; blockNumber = strtoul(coord[0], &badp, 10); if (errno || *badp != DELIM) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type tid: \"%s\"", str))); hold_offset = strtol(coord[1], &badp, 10); if (errno || *badp != RDELIM || hold_offset > USHRT_MAX || hold_offset < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type tid: \"%s\"", str))); offsetNumber = hold_offset; result = (ItemPointer) palloc(sizeof(ItemPointerData)); ItemPointerSet(result, blockNumber, offsetNumber); PG_RETURN_ITEMPOINTER(result);}/* ---------------------------------------------------------------- * tidout * ---------------------------------------------------------------- */Datumtidout(PG_FUNCTION_ARGS){ ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0); BlockNumber blockNumber; OffsetNumber offsetNumber; char buf[32]; blockNumber = BlockIdGetBlockNumber(&(itemPtr->ip_blkid)); offsetNumber = itemPtr->ip_posid; /* Perhaps someday we should output this as a record. */ snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber); PG_RETURN_CSTRING(pstrdup(buf));}/* * tidrecv - converts external binary format to tid */Datumtidrecv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); ItemPointer result; BlockNumber blockNumber; OffsetNumber offsetNumber; blockNumber = pq_getmsgint(buf, sizeof(blockNumber)); offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber)); result = (ItemPointer) palloc(sizeof(ItemPointerData)); ItemPointerSet(result, blockNumber, offsetNumber); PG_RETURN_ITEMPOINTER(result);}/* * tidsend - converts tid to binary format */Datumtidsend(PG_FUNCTION_ARGS){ ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0); BlockId blockId; BlockNumber blockNumber; OffsetNumber offsetNumber; StringInfoData buf; blockId = &(itemPtr->ip_blkid); blockNumber = BlockIdGetBlockNumber(blockId); offsetNumber = itemPtr->ip_posid; pq_begintypsend(&buf); pq_sendint(&buf, blockNumber, sizeof(blockNumber)); pq_sendint(&buf, offsetNumber, sizeof(offsetNumber)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/***************************************************************************** * PUBLIC ROUTINES * *****************************************************************************/Datumtideq(PG_FUNCTION_ARGS){ ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0); ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1); PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);}Datumtidne(PG_FUNCTION_ARGS){ ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0); ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1); PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);}Datumtidlt(PG_FUNCTION_ARGS){ ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0); ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1); PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);}Datumtidle(PG_FUNCTION_ARGS){ ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0); ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1); PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);}Datumtidgt(PG_FUNCTION_ARGS){ ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0); ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1); PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);}Datumtidge(PG_FUNCTION_ARGS){ ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0); ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1); PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);}Datumbttidcmp(PG_FUNCTION_ARGS){ ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0); ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1); PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));}Datumtidlarger(PG_FUNCTION_ARGS){ ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0); ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1); PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);}Datumtidsmaller(PG_FUNCTION_ARGS){ ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0); ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1); PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);}/* * Functions to get latest tid of a specified tuple. * * Maybe these implementations should be moved to another place */static ItemPointerData Current_last_tid = {{0, 0}, 0};voidsetLastTid(const ItemPointer tid){ Current_last_tid = *tid;}/* * Handle CTIDs of views. * CTID should be defined in the view and it must * correspond to the CTID of a base relation. */static Datumcurrtid_for_view(Relation viewrel, ItemPointer tid){ TupleDesc att = RelationGetDescr(viewrel); RuleLock *rulelock; RewriteRule *rewrite; int i, natts = att->natts, tididx = -1; for (i = 0; i < natts; i++) { if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0) { if (att->attrs[i]->atttypid != TIDOID) elog(ERROR, "ctid isn't of type TID"); tididx = i; break; } } if (tididx < 0) elog(ERROR, "currtid cannot handle views with no CTID"); rulelock = viewrel->rd_rules; if (!rulelock) elog(ERROR, "the view has no rules"); for (i = 0; i < rulelock->numLocks; i++) { rewrite = rulelock->rules[i]; if (rewrite->event == CMD_SELECT) { Query *query; TargetEntry *tle; if (list_length(rewrite->actions) != 1) elog(ERROR, "only one select rule is allowed in views"); query = (Query *) linitial(rewrite->actions); tle = get_tle_by_resno(query->targetList, tididx + 1); if (tle && tle->expr && IsA(tle->expr, Var)) { Var *var = (Var *) tle->expr; RangeTblEntry *rte; if (var->varno > 0 && var->varno < INNER && var->varattno == SelfItemPointerAttributeNumber) { rte = rt_fetch(var->varno, query->rtable); if (rte) { heap_close(viewrel, AccessShareLock); return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid)); } } } break; } } elog(ERROR, "currtid cannot handle this view"); return (Datum) 0;}Datumcurrtid_byreloid(PG_FUNCTION_ARGS){ Oid reloid = PG_GETARG_OID(0); ItemPointer tid = PG_GETARG_ITEMPOINTER(1); ItemPointer result; Relation rel; AclResult aclresult; result = (ItemPointer) palloc(sizeof(ItemPointerData)); if (!reloid) { *result = Current_last_tid; PG_RETURN_ITEMPOINTER(result); } rel = heap_open(reloid, AccessShareLock); aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_SELECT); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, RelationGetRelationName(rel)); if (rel->rd_rel->relkind == RELKIND_VIEW) return currtid_for_view(rel, tid); ItemPointerCopy(tid, result); heap_get_latest_tid(rel, SnapshotNow, result); heap_close(rel, AccessShareLock); PG_RETURN_ITEMPOINTER(result);}Datumcurrtid_byrelname(PG_FUNCTION_ARGS){ text *relname = PG_GETARG_TEXT_P(0); ItemPointer tid = PG_GETARG_ITEMPOINTER(1); ItemPointer result; RangeVar *relrv; Relation rel; AclResult aclresult; relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = heap_openrv(relrv, AccessShareLock); aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_SELECT); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, RelationGetRelationName(rel)); if (rel->rd_rel->relkind == RELKIND_VIEW) return currtid_for_view(rel, tid); result = (ItemPointer) palloc(sizeof(ItemPointerData)); ItemPointerCopy(tid, result); heap_get_latest_tid(rel, SnapshotNow, result); heap_close(rel, AccessShareLock); PG_RETURN_ITEMPOINTER(result);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -