Header And Logo

PostgreSQL
| The world's most advanced open source database.

tid.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * tid.c
00004  *    Functions for the built-in type tuple id
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/utils/adt/tid.c
00012  *
00013  * NOTES
00014  *    input routine largely stolen from boxin().
00015  *
00016  *-------------------------------------------------------------------------
00017  */
00018 #include "postgres.h"
00019 
00020 #include <math.h>
00021 #include <limits.h>
00022 
00023 #include "access/heapam.h"
00024 #include "access/sysattr.h"
00025 #include "catalog/namespace.h"
00026 #include "catalog/pg_type.h"
00027 #include "libpq/pqformat.h"
00028 #include "miscadmin.h"
00029 #include "parser/parsetree.h"
00030 #include "utils/acl.h"
00031 #include "utils/builtins.h"
00032 #include "utils/rel.h"
00033 #include "utils/tqual.h"
00034 
00035 
00036 #define DatumGetItemPointer(X)   ((ItemPointer) DatumGetPointer(X))
00037 #define ItemPointerGetDatum(X)   PointerGetDatum(X)
00038 #define PG_GETARG_ITEMPOINTER(n) DatumGetItemPointer(PG_GETARG_DATUM(n))
00039 #define PG_RETURN_ITEMPOINTER(x) return ItemPointerGetDatum(x)
00040 
00041 #define LDELIM          '('
00042 #define RDELIM          ')'
00043 #define DELIM           ','
00044 #define NTIDARGS        2
00045 
00046 /* ----------------------------------------------------------------
00047  *      tidin
00048  * ----------------------------------------------------------------
00049  */
00050 Datum
00051 tidin(PG_FUNCTION_ARGS)
00052 {
00053     char       *str = PG_GETARG_CSTRING(0);
00054     char       *p,
00055                *coord[NTIDARGS];
00056     int         i;
00057     ItemPointer result;
00058     BlockNumber blockNumber;
00059     OffsetNumber offsetNumber;
00060     char       *badp;
00061     int         hold_offset;
00062 
00063     for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
00064         if (*p == DELIM || (*p == LDELIM && !i))
00065             coord[i++] = p + 1;
00066 
00067     if (i < NTIDARGS)
00068         ereport(ERROR,
00069                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00070                  errmsg("invalid input syntax for type tid: \"%s\"",
00071                         str)));
00072 
00073     errno = 0;
00074     blockNumber = strtoul(coord[0], &badp, 10);
00075     if (errno || *badp != DELIM)
00076         ereport(ERROR,
00077                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00078                  errmsg("invalid input syntax for type tid: \"%s\"",
00079                         str)));
00080 
00081     hold_offset = strtol(coord[1], &badp, 10);
00082     if (errno || *badp != RDELIM ||
00083         hold_offset > USHRT_MAX || hold_offset < 0)
00084         ereport(ERROR,
00085                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00086                  errmsg("invalid input syntax for type tid: \"%s\"",
00087                         str)));
00088 
00089     offsetNumber = hold_offset;
00090 
00091     result = (ItemPointer) palloc(sizeof(ItemPointerData));
00092 
00093     ItemPointerSet(result, blockNumber, offsetNumber);
00094 
00095     PG_RETURN_ITEMPOINTER(result);
00096 }
00097 
00098 /* ----------------------------------------------------------------
00099  *      tidout
00100  * ----------------------------------------------------------------
00101  */
00102 Datum
00103 tidout(PG_FUNCTION_ARGS)
00104 {
00105     ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
00106     BlockNumber blockNumber;
00107     OffsetNumber offsetNumber;
00108     char        buf[32];
00109 
00110     blockNumber = BlockIdGetBlockNumber(&(itemPtr->ip_blkid));
00111     offsetNumber = itemPtr->ip_posid;
00112 
00113     /* Perhaps someday we should output this as a record. */
00114     snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
00115 
00116     PG_RETURN_CSTRING(pstrdup(buf));
00117 }
00118 
00119 /*
00120  *      tidrecv         - converts external binary format to tid
00121  */
00122 Datum
00123 tidrecv(PG_FUNCTION_ARGS)
00124 {
00125     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00126     ItemPointer result;
00127     BlockNumber blockNumber;
00128     OffsetNumber offsetNumber;
00129 
00130     blockNumber = pq_getmsgint(buf, sizeof(blockNumber));
00131     offsetNumber = pq_getmsgint(buf, sizeof(offsetNumber));
00132 
00133     result = (ItemPointer) palloc(sizeof(ItemPointerData));
00134 
00135     ItemPointerSet(result, blockNumber, offsetNumber);
00136 
00137     PG_RETURN_ITEMPOINTER(result);
00138 }
00139 
00140 /*
00141  *      tidsend         - converts tid to binary format
00142  */
00143 Datum
00144 tidsend(PG_FUNCTION_ARGS)
00145 {
00146     ItemPointer itemPtr = PG_GETARG_ITEMPOINTER(0);
00147     BlockId     blockId;
00148     BlockNumber blockNumber;
00149     OffsetNumber offsetNumber;
00150     StringInfoData buf;
00151 
00152     blockId = &(itemPtr->ip_blkid);
00153     blockNumber = BlockIdGetBlockNumber(blockId);
00154     offsetNumber = itemPtr->ip_posid;
00155 
00156     pq_begintypsend(&buf);
00157     pq_sendint(&buf, blockNumber, sizeof(blockNumber));
00158     pq_sendint(&buf, offsetNumber, sizeof(offsetNumber));
00159     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00160 }
00161 
00162 /*****************************************************************************
00163  *   PUBLIC ROUTINES                                                         *
00164  *****************************************************************************/
00165 
00166 Datum
00167 tideq(PG_FUNCTION_ARGS)
00168 {
00169     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
00170     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
00171 
00172     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) == 0);
00173 }
00174 
00175 Datum
00176 tidne(PG_FUNCTION_ARGS)
00177 {
00178     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
00179     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
00180 
00181     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) != 0);
00182 }
00183 
00184 Datum
00185 tidlt(PG_FUNCTION_ARGS)
00186 {
00187     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
00188     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
00189 
00190     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) < 0);
00191 }
00192 
00193 Datum
00194 tidle(PG_FUNCTION_ARGS)
00195 {
00196     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
00197     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
00198 
00199     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) <= 0);
00200 }
00201 
00202 Datum
00203 tidgt(PG_FUNCTION_ARGS)
00204 {
00205     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
00206     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
00207 
00208     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) > 0);
00209 }
00210 
00211 Datum
00212 tidge(PG_FUNCTION_ARGS)
00213 {
00214     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
00215     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
00216 
00217     PG_RETURN_BOOL(ItemPointerCompare(arg1, arg2) >= 0);
00218 }
00219 
00220 Datum
00221 bttidcmp(PG_FUNCTION_ARGS)
00222 {
00223     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
00224     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
00225 
00226     PG_RETURN_INT32(ItemPointerCompare(arg1, arg2));
00227 }
00228 
00229 Datum
00230 tidlarger(PG_FUNCTION_ARGS)
00231 {
00232     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
00233     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
00234 
00235     PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) >= 0 ? arg1 : arg2);
00236 }
00237 
00238 Datum
00239 tidsmaller(PG_FUNCTION_ARGS)
00240 {
00241     ItemPointer arg1 = PG_GETARG_ITEMPOINTER(0);
00242     ItemPointer arg2 = PG_GETARG_ITEMPOINTER(1);
00243 
00244     PG_RETURN_ITEMPOINTER(ItemPointerCompare(arg1, arg2) <= 0 ? arg1 : arg2);
00245 }
00246 
00247 
00248 /*
00249  *  Functions to get latest tid of a specified tuple.
00250  *
00251  *  Maybe these implementations should be moved to another place
00252  */
00253 
00254 static ItemPointerData Current_last_tid = {{0, 0}, 0};
00255 
00256 void
00257 setLastTid(const ItemPointer tid)
00258 {
00259     Current_last_tid = *tid;
00260 }
00261 
00262 /*
00263  *  Handle CTIDs of views.
00264  *      CTID should be defined in the view and it must
00265  *      correspond to the CTID of a base relation.
00266  */
00267 static Datum
00268 currtid_for_view(Relation viewrel, ItemPointer tid)
00269 {
00270     TupleDesc   att = RelationGetDescr(viewrel);
00271     RuleLock   *rulelock;
00272     RewriteRule *rewrite;
00273     int         i,
00274                 natts = att->natts,
00275                 tididx = -1;
00276 
00277     for (i = 0; i < natts; i++)
00278     {
00279         if (strcmp(NameStr(att->attrs[i]->attname), "ctid") == 0)
00280         {
00281             if (att->attrs[i]->atttypid != TIDOID)
00282                 elog(ERROR, "ctid isn't of type TID");
00283             tididx = i;
00284             break;
00285         }
00286     }
00287     if (tididx < 0)
00288         elog(ERROR, "currtid cannot handle views with no CTID");
00289     rulelock = viewrel->rd_rules;
00290     if (!rulelock)
00291         elog(ERROR, "the view has no rules");
00292     for (i = 0; i < rulelock->numLocks; i++)
00293     {
00294         rewrite = rulelock->rules[i];
00295         if (rewrite->event == CMD_SELECT)
00296         {
00297             Query      *query;
00298             TargetEntry *tle;
00299 
00300             if (list_length(rewrite->actions) != 1)
00301                 elog(ERROR, "only one select rule is allowed in views");
00302             query = (Query *) linitial(rewrite->actions);
00303             tle = get_tle_by_resno(query->targetList, tididx + 1);
00304             if (tle && tle->expr && IsA(tle->expr, Var))
00305             {
00306                 Var        *var = (Var *) tle->expr;
00307                 RangeTblEntry *rte;
00308 
00309                 if (!IS_SPECIAL_VARNO(var->varno) &&
00310                     var->varattno == SelfItemPointerAttributeNumber)
00311                 {
00312                     rte = rt_fetch(var->varno, query->rtable);
00313                     if (rte)
00314                     {
00315                         heap_close(viewrel, AccessShareLock);
00316                         return DirectFunctionCall2(currtid_byreloid, ObjectIdGetDatum(rte->relid), PointerGetDatum(tid));
00317                     }
00318                 }
00319             }
00320             break;
00321         }
00322     }
00323     elog(ERROR, "currtid cannot handle this view");
00324     return (Datum) 0;
00325 }
00326 
00327 Datum
00328 currtid_byreloid(PG_FUNCTION_ARGS)
00329 {
00330     Oid         reloid = PG_GETARG_OID(0);
00331     ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
00332     ItemPointer result;
00333     Relation    rel;
00334     AclResult   aclresult;
00335 
00336     result = (ItemPointer) palloc(sizeof(ItemPointerData));
00337     if (!reloid)
00338     {
00339         *result = Current_last_tid;
00340         PG_RETURN_ITEMPOINTER(result);
00341     }
00342 
00343     rel = heap_open(reloid, AccessShareLock);
00344 
00345     aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
00346                                   ACL_SELECT);
00347     if (aclresult != ACLCHECK_OK)
00348         aclcheck_error(aclresult, ACL_KIND_CLASS,
00349                        RelationGetRelationName(rel));
00350 
00351     if (rel->rd_rel->relkind == RELKIND_VIEW)
00352         return currtid_for_view(rel, tid);
00353 
00354     ItemPointerCopy(tid, result);
00355     heap_get_latest_tid(rel, SnapshotNow, result);
00356 
00357     heap_close(rel, AccessShareLock);
00358 
00359     PG_RETURN_ITEMPOINTER(result);
00360 }
00361 
00362 Datum
00363 currtid_byrelname(PG_FUNCTION_ARGS)
00364 {
00365     text       *relname = PG_GETARG_TEXT_P(0);
00366     ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
00367     ItemPointer result;
00368     RangeVar   *relrv;
00369     Relation    rel;
00370     AclResult   aclresult;
00371 
00372     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
00373     rel = heap_openrv(relrv, AccessShareLock);
00374 
00375     aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
00376                                   ACL_SELECT);
00377     if (aclresult != ACLCHECK_OK)
00378         aclcheck_error(aclresult, ACL_KIND_CLASS,
00379                        RelationGetRelationName(rel));
00380 
00381     if (rel->rd_rel->relkind == RELKIND_VIEW)
00382         return currtid_for_view(rel, tid);
00383 
00384     result = (ItemPointer) palloc(sizeof(ItemPointerData));
00385     ItemPointerCopy(tid, result);
00386 
00387     heap_get_latest_tid(rel, SnapshotNow, result);
00388 
00389     heap_close(rel, AccessShareLock);
00390 
00391     PG_RETURN_ITEMPOINTER(result);
00392 }