4 * Copyright (c) 2005-2006 Tatsuo Ishii
6 * Permission to use, copy, modify, and distribute this software and
7 * its documentation for any purpose, without fee, and without a
8 * written agreement is hereby granted, provided that the above
9 * copyright notice and this paragraph and the following two
10 * paragraphs appear in all copies.
12 * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
13 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
14 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
15 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
16 * OF THE POSSIBILITY OF SUCH DAMAGE.
18 * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
21 * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
22 * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
27 #include "access/heapam.h"
28 #include "access/multixact.h"
29 #include "access/relscan.h"
30 #include "access/xact.h"
31 #include "catalog/namespace.h"
33 #include "miscadmin.h"
34 #include "storage/bufmgr.h"
35 #include "storage/procarray.h"
36 #include "utils/acl.h"
37 #include "utils/builtins.h"
38 #include "utils/tqual.h"
43 PG_FUNCTION_INFO_V1(pgrowlocks
);
45 extern Datum
pgrowlocks(PG_FUNCTION_ARGS
);
49 * returns tids of rows being locked
63 pgrowlocks(PG_FUNCTION_ARGS
)
65 FuncCallContext
*funcctx
;
69 AttInMetadata
*attinmeta
;
74 if (SRF_IS_FIRSTCALL())
78 MemoryContext oldcontext
;
81 funcctx
= SRF_FIRSTCALL_INIT();
82 oldcontext
= MemoryContextSwitchTo(funcctx
->multi_call_memory_ctx
);
84 /* Build a tuple descriptor for our result type */
85 if (get_call_result_type(fcinfo
, NULL
, &tupdesc
) != TYPEFUNC_COMPOSITE
)
86 elog(ERROR
, "return type must be a row type");
88 attinmeta
= TupleDescGetAttInMetadata(tupdesc
);
89 funcctx
->attinmeta
= attinmeta
;
91 relname
= PG_GETARG_TEXT_P(0);
92 relrv
= makeRangeVarFromNameList(textToQualifiedNameList(relname
));
93 rel
= heap_openrv(relrv
, AccessShareLock
);
95 /* check permissions: must have SELECT on table */
96 aclresult
= pg_class_aclcheck(RelationGetRelid(rel
), GetUserId(),
98 if (aclresult
!= ACLCHECK_OK
)
99 aclcheck_error(aclresult
, ACL_KIND_CLASS
,
100 RelationGetRelationName(rel
));
102 scan
= heap_beginscan(rel
, SnapshotNow
, 0, NULL
);
103 mydata
= palloc(sizeof(*mydata
));
106 mydata
->ncolumns
= tupdesc
->natts
;
107 funcctx
->user_fctx
= mydata
;
109 MemoryContextSwitchTo(oldcontext
);
112 funcctx
= SRF_PERCALL_SETUP();
113 attinmeta
= funcctx
->attinmeta
;
114 mydata
= (MyData
*) funcctx
->user_fctx
;
117 /* scan the relation */
118 while ((tuple
= heap_getnext(scan
, ForwardScanDirection
)) != NULL
)
120 /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
121 LockBuffer(scan
->rs_cbuf
, BUFFER_LOCK_SHARE
);
123 if (HeapTupleSatisfiesUpdate(tuple
->t_data
,
124 GetCurrentCommandId(false),
125 scan
->rs_cbuf
) == HeapTupleBeingUpdated
)
131 values
= (char **) palloc(mydata
->ncolumns
* sizeof(char *));
134 values
[i
++] = (char *) DirectFunctionCall1(tidout
, PointerGetDatum(&tuple
->t_self
));
136 if (tuple
->t_data
->t_infomask
& HEAP_XMAX_SHARED_LOCK
)
137 values
[i
++] = pstrdup("Shared");
139 values
[i
++] = pstrdup("Exclusive");
140 values
[i
] = palloc(NCHARS
* sizeof(char));
141 snprintf(values
[i
++], NCHARS
, "%d", HeapTupleHeaderGetXmax(tuple
->t_data
));
142 if (tuple
->t_data
->t_infomask
& HEAP_XMAX_IS_MULTI
)
147 int isValidXid
= 0; /* any valid xid ever exists? */
149 values
[i
++] = pstrdup("true");
150 nxids
= GetMultiXactIdMembers(HeapTupleHeaderGetXmax(tuple
->t_data
), &xids
);
153 elog(ERROR
, "GetMultiXactIdMembers returns error");
156 values
[i
] = palloc(NCHARS
* nxids
);
157 values
[i
+ 1] = palloc(NCHARS
* nxids
);
158 strcpy(values
[i
], "{");
159 strcpy(values
[i
+ 1], "{");
161 for (j
= 0; j
< nxids
; j
++)
165 if (TransactionIdIsInProgress(xids
[j
]))
169 strcat(values
[i
], ",");
170 strcat(values
[i
+ 1], ",");
172 snprintf(buf
, NCHARS
, "%d", xids
[j
]);
173 strcat(values
[i
], buf
);
174 snprintf(buf
, NCHARS
, "%d", BackendXidGetPid(xids
[j
]));
175 strcat(values
[i
+ 1], buf
);
181 strcat(values
[i
], "}");
182 strcat(values
[i
+ 1], "}");
187 values
[i
++] = pstrdup("false");
188 values
[i
] = palloc(NCHARS
* sizeof(char));
189 snprintf(values
[i
++], NCHARS
, "{%d}", HeapTupleHeaderGetXmax(tuple
->t_data
));
191 values
[i
] = palloc(NCHARS
* sizeof(char));
192 snprintf(values
[i
++], NCHARS
, "{%d}", BackendXidGetPid(HeapTupleHeaderGetXmax(tuple
->t_data
)));
195 LockBuffer(scan
->rs_cbuf
, BUFFER_LOCK_UNLOCK
);
198 tuple
= BuildTupleFromCStrings(attinmeta
, values
);
200 /* make the tuple into a datum */
201 result
= HeapTupleGetDatum(tuple
);
204 for (i
= 0; i
< mydata
->ncolumns
; i
++)
208 SRF_RETURN_NEXT(funcctx
, result
);
212 LockBuffer(scan
->rs_cbuf
, BUFFER_LOCK_UNLOCK
);
217 heap_close(mydata
->rel
, AccessShareLock
);
219 SRF_RETURN_DONE(funcctx
);