00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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
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
00114 snprintf(buf, sizeof(buf), "(%u,%u)", blockNumber, offsetNumber);
00115
00116 PG_RETURN_CSTRING(pstrdup(buf));
00117 }
00118
00119
00120
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
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
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
00250
00251
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
00264
00265
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 }