]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/lockfuncs.c
pgindent run.
[postgresql] / src / backend / utils / adt / lockfuncs.c
1 /*-------------------------------------------------------------------------
2  *
3  * lockfuncs.c
4  *              Set-returning functions to view the state of locks within the DB.
5  *
6  * Copyright (c) 2002, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  *              $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.7 2002/09/04 20:31:28 momjian Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14
15 #include "funcapi.h"
16 #include "access/heapam.h"
17 #include "catalog/pg_type.h"
18 #include "storage/lock.h"
19 #include "storage/proc.h"
20 #include "utils/builtins.h"
21
22
23 /* Working status for pg_lock_status */
24 typedef struct
25 {
26         LockData   *lockData;           /* state data from lmgr */
27         int                     currIdx;                /* current PROCLOCK index */
28 } PG_Lock_Status;
29
30 /*
31  * pg_lock_status - produce a view with one row per held or awaited lock mode
32  */
33 Datum
34 pg_lock_status(PG_FUNCTION_ARGS)
35 {
36         FuncCallContext *funcctx;
37         PG_Lock_Status *mystatus;
38         LockData   *lockData;
39
40         if (SRF_IS_FIRSTCALL())
41         {
42                 TupleDesc       tupdesc;
43                 MemoryContext oldcontext;
44
45                 /* create a function context for cross-call persistence */
46                 funcctx = SRF_FIRSTCALL_INIT();
47
48                 /*
49                  * switch to memory context appropriate for multiple function
50                  * calls
51                  */
52                 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
53
54                 /* build tupdesc for result tuples */
55                 /* this had better match pg_locks view in initdb.sh */
56                 tupdesc = CreateTemplateTupleDesc(6, false);
57                 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation",
58                                                    OIDOID, -1, 0, false);
59                 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
60                                                    OIDOID, -1, 0, false);
61                 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction",
62                                                    XIDOID, -1, 0, false);
63                 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid",
64                                                    INT4OID, -1, 0, false);
65                 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode",
66                                                    TEXTOID, -1, 0, false);
67                 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted",
68                                                    BOOLOID, -1, 0, false);
69
70                 funcctx->slot = TupleDescGetSlot(tupdesc);
71
72                 /*
73                  * Collect all the locking information that we will format and
74                  * send out as a result set.
75                  */
76                 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
77                 funcctx->user_fctx = (void *) mystatus;
78
79                 mystatus->lockData = GetLockStatusData();
80                 mystatus->currIdx = 0;
81
82                 MemoryContextSwitchTo(oldcontext);
83         }
84
85         funcctx = SRF_PERCALL_SETUP();
86         mystatus = (PG_Lock_Status *) funcctx->user_fctx;
87         lockData = mystatus->lockData;
88
89         while (mystatus->currIdx < lockData->nelements)
90         {
91                 PROCLOCK   *holder;
92                 LOCK       *lock;
93                 PGPROC     *proc;
94                 bool            granted;
95                 LOCKMODE        mode;
96                 Datum           values[6];
97                 char            nulls[6];
98                 HeapTuple       tuple;
99                 Datum           result;
100
101                 holder = &(lockData->holders[mystatus->currIdx]);
102                 lock = &(lockData->locks[mystatus->currIdx]);
103                 proc = &(lockData->procs[mystatus->currIdx]);
104
105                 /*
106                  * Look to see if there are any held lock modes in this PROCLOCK.
107                  * If so, report, and destructively modify lockData so we don't
108                  * report again.
109                  */
110                 granted = false;
111                 for (mode = 0; mode < MAX_LOCKMODES; mode++)
112                 {
113                         if (holder->holding[mode] > 0)
114                         {
115                                 granted = true;
116                                 holder->holding[mode] = 0;
117                                 break;
118                         }
119                 }
120
121                 /*
122                  * If no (more) held modes to report, see if PROC is waiting for a
123                  * lock on this lock.
124                  */
125                 if (!granted)
126                 {
127                         if (proc->waitLock == (LOCK *) MAKE_PTR(holder->tag.lock))
128                         {
129                                 /* Yes, so report it with proper mode */
130                                 mode = proc->waitLockMode;
131
132                                 /*
133                                  * We are now done with this PROCLOCK, so advance pointer
134                                  * to continue with next one on next call.
135                                  */
136                                 mystatus->currIdx++;
137                         }
138                         else
139                         {
140                                 /*
141                                  * Okay, we've displayed all the locks associated with
142                                  * this PROCLOCK, proceed to the next one.
143                                  */
144                                 mystatus->currIdx++;
145                                 continue;
146                         }
147                 }
148
149                 /*
150                  * Form tuple with appropriate data.
151                  */
152                 MemSet(values, 0, sizeof(values));
153                 MemSet(nulls, ' ', sizeof(nulls));
154
155                 if (lock->tag.relId == XactLockTableId && lock->tag.dbId == 0)
156                 {
157                         /* Lock is for transaction ID */
158                         nulls[0] = 'n';
159                         nulls[1] = 'n';
160                         values[2] = TransactionIdGetDatum(lock->tag.objId.xid);
161                 }
162                 else
163                 {
164                         /* Lock is for a relation */
165                         values[0] = ObjectIdGetDatum(lock->tag.relId);
166                         values[1] = ObjectIdGetDatum(lock->tag.dbId);
167                         nulls[2] = 'n';
168
169                 }
170
171                 values[3] = Int32GetDatum(proc->pid);
172                 values[4] = DirectFunctionCall1(textin,
173                                                                  CStringGetDatum(GetLockmodeName(mode)));
174                 values[5] = BoolGetDatum(granted);
175
176                 tuple = heap_formtuple(funcctx->slot->ttc_tupleDescriptor,
177                                                            values, nulls);
178                 result = TupleGetDatum(funcctx->slot, tuple);
179                 SRF_RETURN_NEXT(funcctx, result);
180         }
181
182         SRF_RETURN_DONE(funcctx);
183 }