00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/heapam.h"
00018 #include "catalog/namespace.h"
00019 #include "catalog/pg_inherits_fn.h"
00020 #include "commands/lockcmds.h"
00021 #include "miscadmin.h"
00022 #include "parser/parse_clause.h"
00023 #include "storage/lmgr.h"
00024 #include "utils/acl.h"
00025 #include "utils/lsyscache.h"
00026 #include "utils/syscache.h"
00027
00028 static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait);
00029 static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode);
00030 static void RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid,
00031 Oid oldrelid, void *arg);
00032
00033
00034
00035
00036 void
00037 LockTableCommand(LockStmt *lockstmt)
00038 {
00039 ListCell *p;
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 if (lockstmt->mode > RowExclusiveLock)
00050 PreventCommandDuringRecovery("LOCK TABLE");
00051
00052
00053
00054
00055 foreach(p, lockstmt->relations)
00056 {
00057 RangeVar *rv = (RangeVar *) lfirst(p);
00058 bool recurse = interpretInhOption(rv->inhOpt);
00059 Oid reloid;
00060
00061 reloid = RangeVarGetRelidExtended(rv, lockstmt->mode, false,
00062 lockstmt->nowait,
00063 RangeVarCallbackForLockTable,
00064 (void *) &lockstmt->mode);
00065
00066 if (recurse)
00067 LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
00068 }
00069 }
00070
00071
00072
00073
00074
00075 static void
00076 RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
00077 void *arg)
00078 {
00079 LOCKMODE lockmode = *(LOCKMODE *) arg;
00080 char relkind;
00081 AclResult aclresult;
00082
00083 if (!OidIsValid(relid))
00084 return;
00085 relkind = get_rel_relkind(relid);
00086 if (!relkind)
00087 return;
00088
00089
00090
00091 if (relkind != RELKIND_RELATION)
00092 ereport(ERROR,
00093 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00094 errmsg("\"%s\" is not a table",
00095 rv->relname)));
00096
00097
00098 aclresult = LockTableAclCheck(relid, lockmode);
00099 if (aclresult != ACLCHECK_OK)
00100 aclcheck_error(aclresult, ACL_KIND_CLASS, rv->relname);
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110 static void
00111 LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
00112 {
00113 List *children;
00114 ListCell *lc;
00115
00116 children = find_inheritance_children(reloid, NoLock);
00117
00118 foreach(lc, children)
00119 {
00120 Oid childreloid = lfirst_oid(lc);
00121 AclResult aclresult;
00122
00123
00124 aclresult = LockTableAclCheck(childreloid, lockmode);
00125 if (aclresult != ACLCHECK_OK)
00126 {
00127 char *relname = get_rel_name(childreloid);
00128
00129 if (!relname)
00130 continue;
00131 aclcheck_error(aclresult, ACL_KIND_CLASS, relname);
00132 }
00133
00134
00135 if (!nowait)
00136 LockRelationOid(childreloid, lockmode);
00137 else if (!ConditionalLockRelationOid(childreloid, lockmode))
00138 {
00139
00140 char *relname = get_rel_name(childreloid);
00141
00142 if (!relname)
00143 continue;
00144 ereport(ERROR,
00145 (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
00146 errmsg("could not obtain lock on relation \"%s\"",
00147 relname)));
00148 }
00149
00150
00151
00152
00153
00154 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(childreloid)))
00155 {
00156
00157 UnlockRelationOid(childreloid, lockmode);
00158 continue;
00159 }
00160
00161 LockTableRecurse(childreloid, lockmode, nowait);
00162 }
00163 }
00164
00165
00166
00167
00168 static AclResult
00169 LockTableAclCheck(Oid reloid, LOCKMODE lockmode)
00170 {
00171 AclResult aclresult;
00172
00173
00174 if (lockmode == AccessShareLock)
00175 aclresult = pg_class_aclcheck(reloid, GetUserId(),
00176 ACL_SELECT);
00177 else
00178 aclresult = pg_class_aclcheck(reloid, GetUserId(),
00179 ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE);
00180 return aclresult;
00181 }