*** pgsql/contrib/dblink/dblink.c 2010/06/09 01:00:13 1.48.2.8 --- pgsql/contrib/dblink/dblink.c 2010/06/14 20:49:57 1.48.2.9 *************** *** 51,56 **** --- 51,57 ---- #include "tcop/tcopprot.h" #include "utils/builtins.h" #include "utils/fmgroids.h" + #include "utils/acl.h" #include "utils/array.h" #include "utils/lsyscache.h" #include "utils/syscache.h" *************** static remoteConn *getConnectionByName(c *** 74,92 **** static HTAB *createConnHash(void); static void createNewConnection(const char *name, remoteConn * rconn); static void deleteConnection(const char *name); ! static char **get_pkey_attnames(Oid relid, int16 *numatts); ! static char *get_sql_insert(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals); ! static char *get_sql_delete(Oid relid, int2vector *pkattnums, int16 pknumatts, char **tgt_pkattvals); ! static char *get_sql_update(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals); static char *quote_literal_cstr(char *rawstr); static char *quote_ident_cstr(char *rawstr); static int16 get_attnum_pk_pos(int2vector *pkattnums, int16 pknumatts, int16 key); ! static HeapTuple get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals); ! static Oid get_relid_from_relname(text *relname_text); ! static char *generate_relation_name(Oid relid); static char *connstr_strip_password(const char *connstr); static void dblink_security_check(PGconn *conn, remoteConn *rconn, const char *connstr); ! static int get_nondropped_natts(Oid relid); /* Global */ static remoteConn *pconn = NULL; --- 75,93 ---- static HTAB *createConnHash(void); static void createNewConnection(const char *name, remoteConn * rconn); static void deleteConnection(const char *name); ! static char **get_pkey_attnames(Relation rel, int16 *numatts); ! static char *get_sql_insert(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals); ! static char *get_sql_delete(Relation rel, int2vector *pkattnums, int16 pknumatts, char **tgt_pkattvals); ! static char *get_sql_update(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals); static char *quote_literal_cstr(char *rawstr); static char *quote_ident_cstr(char *rawstr); static int16 get_attnum_pk_pos(int2vector *pkattnums, int16 pknumatts, int16 key); ! static HeapTuple get_tuple_of_interest(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals); ! static Relation get_rel_from_relname(text *relname_text, LOCKMODE lockmode, AclMode aclmode); ! static char *generate_relation_name(Relation rel); static char *connstr_strip_password(const char *connstr); static void dblink_security_check(PGconn *conn, remoteConn *rconn, const char *connstr); ! static int get_nondropped_natts(Relation rel); /* Global */ static remoteConn *pconn = NULL; *************** Datum *** 1021,1027 **** dblink_get_pkey(PG_FUNCTION_ARGS) { int16 numatts; - Oid relid; char **results; FuncCallContext *funcctx; int32 call_cntr; --- 1022,1027 ---- *************** dblink_get_pkey(PG_FUNCTION_ARGS) *** 1032,1038 **** /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { ! TupleDesc tupdesc = NULL; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); --- 1032,1039 ---- /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { ! Relation rel; ! TupleDesc tupdesc; /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); *************** dblink_get_pkey(PG_FUNCTION_ARGS) *** 1042,1054 **** */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); ! /* convert relname to rel Oid */ ! relid = get_relid_from_relname(PG_GETARG_TEXT_P(0)); ! if (!OidIsValid(relid)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_TABLE), ! errmsg("relation \"%s\" does not exist", ! GET_STR(PG_GETARG_TEXT_P(0))))); /* * need a tuple descriptor representing one INT and one TEXT column --- 1043,1055 ---- */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); ! /* open target relation */ ! rel = get_rel_from_relname(PG_GETARG_TEXT_P(0), AccessShareLock, ACL_SELECT); ! ! /* get the array of attnums */ ! results = get_pkey_attnames(rel, &numatts); ! ! relation_close(rel, AccessShareLock); /* * need a tuple descriptor representing one INT and one TEXT column *************** dblink_get_pkey(PG_FUNCTION_ARGS) *** 1066,1074 **** attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = attinmeta; - /* get an array of attnums */ - results = get_pkey_attnames(relid, &numatts); - if ((results != NULL) && (numatts > 0)) { funcctx->max_calls = numatts; --- 1067,1072 ---- *************** PG_FUNCTION_INFO_V1(dblink_build_sql_ins *** 1150,1156 **** Datum dblink_build_sql_insert(PG_FUNCTION_ARGS) { ! Oid relid; text *relname_text; int2vector *pkattnums; int pknumatts_tmp; --- 1148,1154 ---- Datum dblink_build_sql_insert(PG_FUNCTION_ARGS) { ! Relation rel; text *relname_text; int2vector *pkattnums; int pknumatts_tmp; *************** dblink_build_sql_insert(PG_FUNCTION_ARGS *** 1176,1189 **** relname_text = PG_GETARG_TEXT_P(0); /* ! * Convert relname to rel OID. */ ! relid = get_relid_from_relname(relname_text); ! if (!OidIsValid(relid)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_TABLE), ! errmsg("relation \"%s\" does not exist", ! GET_STR(relname_text)))); pkattnums = (int2vector *) PG_GETARG_POINTER(1); pknumatts_tmp = PG_GETARG_INT32(2); --- 1174,1182 ---- relname_text = PG_GETARG_TEXT_P(0); /* ! * Open target relation. */ ! rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT); pkattnums = (int2vector *) PG_GETARG_POINTER(1); pknumatts_tmp = PG_GETARG_INT32(2); *************** dblink_build_sql_insert(PG_FUNCTION_ARGS *** 1210,1216 **** * ensure we don't ask for more pk attributes than we have * non-dropped columns */ ! nondropped_natts = get_nondropped_natts(relid); if (pknumatts > nondropped_natts) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("number of primary key fields exceeds number of specified relation attributes"))); --- 1203,1209 ---- * ensure we don't ask for more pk attributes than we have * non-dropped columns */ ! nondropped_natts = get_nondropped_natts(rel); if (pknumatts > nondropped_natts) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("number of primary key fields exceeds number of specified relation attributes"))); *************** dblink_build_sql_insert(PG_FUNCTION_ARGS *** 1284,1290 **** /* * Prep work is finally done. Go get the SQL string. */ ! sql = get_sql_insert(relid, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals); /* * And send it --- 1277,1288 ---- /* * Prep work is finally done. Go get the SQL string. */ ! sql = get_sql_insert(rel, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals); ! ! /* ! * Now we can close the relation. ! */ ! relation_close(rel, AccessShareLock); /* * And send it *************** PG_FUNCTION_INFO_V1(dblink_build_sql_del *** 1312,1318 **** Datum dblink_build_sql_delete(PG_FUNCTION_ARGS) { ! Oid relid; text *relname_text; int2vector *pkattnums; int pknumatts_tmp; --- 1310,1316 ---- Datum dblink_build_sql_delete(PG_FUNCTION_ARGS) { ! Relation rel; text *relname_text; int2vector *pkattnums; int pknumatts_tmp; *************** dblink_build_sql_delete(PG_FUNCTION_ARGS *** 1333,1346 **** relname_text = PG_GETARG_TEXT_P(0); /* ! * Convert relname to rel OID. */ ! relid = get_relid_from_relname(relname_text); ! if (!OidIsValid(relid)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_TABLE), ! errmsg("relation \"%s\" does not exist", ! GET_STR(relname_text)))); pkattnums = (int2vector *) PG_GETARG_POINTER(1); pknumatts_tmp = PG_GETARG_INT32(2); --- 1331,1339 ---- relname_text = PG_GETARG_TEXT_P(0); /* ! * Open target relation. */ ! rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT); pkattnums = (int2vector *) PG_GETARG_POINTER(1); pknumatts_tmp = PG_GETARG_INT32(2); *************** dblink_build_sql_delete(PG_FUNCTION_ARGS *** 1366,1372 **** * ensure we don't ask for more pk attributes than we have * non-dropped columns */ ! nondropped_natts = get_nondropped_natts(relid); if (pknumatts > nondropped_natts) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("number of primary key fields exceeds number of specified relation attributes"))); --- 1359,1365 ---- * ensure we don't ask for more pk attributes than we have * non-dropped columns */ ! nondropped_natts = get_nondropped_natts(rel); if (pknumatts > nondropped_natts) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("number of primary key fields exceeds number of specified relation attributes"))); *************** dblink_build_sql_delete(PG_FUNCTION_ARGS *** 1407,1413 **** /* * Prep work is finally done. Go get the SQL string. */ ! sql = get_sql_delete(relid, pkattnums, pknumatts, tgt_pkattvals); /* * And send it --- 1400,1411 ---- /* * Prep work is finally done. Go get the SQL string. */ ! sql = get_sql_delete(rel, pkattnums, pknumatts, tgt_pkattvals); ! ! /* ! * Now we can close the relation. ! */ ! relation_close(rel, AccessShareLock); /* * And send it *************** PG_FUNCTION_INFO_V1(dblink_build_sql_upd *** 1439,1445 **** Datum dblink_build_sql_update(PG_FUNCTION_ARGS) { ! Oid relid; text *relname_text; int2vector *pkattnums; int pknumatts_tmp; --- 1437,1443 ---- Datum dblink_build_sql_update(PG_FUNCTION_ARGS) { ! Relation rel; text *relname_text; int2vector *pkattnums; int pknumatts_tmp; *************** dblink_build_sql_update(PG_FUNCTION_ARGS *** 1465,1478 **** relname_text = PG_GETARG_TEXT_P(0); /* ! * Convert relname to rel OID. */ ! relid = get_relid_from_relname(relname_text); ! if (!OidIsValid(relid)) ! ereport(ERROR, ! (errcode(ERRCODE_UNDEFINED_TABLE), ! errmsg("relation \"%s\" does not exist", ! GET_STR(relname_text)))); pkattnums = (int2vector *) PG_GETARG_POINTER(1); pknumatts_tmp = PG_GETARG_INT32(2); --- 1463,1471 ---- relname_text = PG_GETARG_TEXT_P(0); /* ! * Open target relation. */ ! rel = get_rel_from_relname(relname_text, AccessShareLock, ACL_SELECT); pkattnums = (int2vector *) PG_GETARG_POINTER(1); pknumatts_tmp = PG_GETARG_INT32(2); *************** dblink_build_sql_update(PG_FUNCTION_ARGS *** 1499,1505 **** * ensure we don't ask for more pk attributes than we have * non-dropped columns */ ! nondropped_natts = get_nondropped_natts(relid); if (pknumatts > nondropped_natts) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("number of primary key fields exceeds number of specified relation attributes"))); --- 1492,1498 ---- * ensure we don't ask for more pk attributes than we have * non-dropped columns */ ! nondropped_natts = get_nondropped_natts(rel); if (pknumatts > nondropped_natts) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("number of primary key fields exceeds number of specified relation attributes"))); *************** dblink_build_sql_update(PG_FUNCTION_ARGS *** 1573,1579 **** /* * Prep work is finally done. Go get the SQL string. */ ! sql = get_sql_update(relid, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals); /* * And send it --- 1566,1577 ---- /* * Prep work is finally done. Go get the SQL string. */ ! sql = get_sql_update(rel, pkattnums, pknumatts, src_pkattvals, tgt_pkattvals); ! ! /* ! * Now we can close the relation. ! */ ! relation_close(rel, AccessShareLock); /* * And send it *************** dblink_current_query(PG_FUNCTION_ARGS) *** 1607,1613 **** * Return NULL, and set numatts = 0, if no primary key exists. */ static char ** ! get_pkey_attnames(Oid relid, int16 *numatts) { Relation indexRelation; ScanKeyData entry; --- 1605,1611 ---- * Return NULL, and set numatts = 0, if no primary key exists. */ static char ** ! get_pkey_attnames(Relation rel, int16 *numatts) { Relation indexRelation; ScanKeyData entry; *************** get_pkey_attnames(Oid relid, int16 *numa *** 1615,1636 **** HeapTuple indexTuple; int i; char **result = NULL; - Relation rel; TupleDesc tupdesc; - /* open relation using relid, get tupdesc */ - rel = relation_open(relid, AccessShareLock); - tupdesc = rel->rd_att; - /* initialize numatts to 0 in case no primary key exists */ *numatts = 0; /* use relid to get all related indexes */ indexRelation = heap_open(IndexRelationId, AccessShareLock); ScanKeyInit(&entry, Anum_pg_index_indrelid, BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(relid)); scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry); while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL) --- 1613,1631 ---- HeapTuple indexTuple; int i; char **result = NULL; TupleDesc tupdesc; /* initialize numatts to 0 in case no primary key exists */ *numatts = 0; + tupdesc = rel->rd_att; + /* use relid to get all related indexes */ indexRelation = heap_open(IndexRelationId, AccessShareLock); ScanKeyInit(&entry, Anum_pg_index_indrelid, BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(RelationGetRelid(rel))); scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry); while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL) *************** get_pkey_attnames(Oid relid, int16 *numa *** 1653,1667 **** } heap_endscan(scan); heap_close(indexRelation, AccessShareLock); - relation_close(rel, AccessShareLock); return result; } static char * ! get_sql_insert(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals) { - Relation rel; char *relname; HeapTuple tuple; TupleDesc tupdesc; --- 1648,1660 ---- } heap_endscan(scan); heap_close(indexRelation, AccessShareLock); return result; } static char * ! get_sql_insert(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals) { char *relname; HeapTuple tuple; TupleDesc tupdesc; *************** get_sql_insert(Oid relid, int2vector *pk *** 1674,1689 **** bool needComma; /* get relation name including any needed schema prefix and quoting */ ! relname = generate_relation_name(relid); - /* - * Open relation using relid - */ - rel = relation_open(relid, AccessShareLock); tupdesc = rel->rd_att; natts = tupdesc->natts; ! tuple = get_tuple_of_interest(relid, pkattnums, pknumatts, src_pkattvals); if (!tuple) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), --- 1667,1678 ---- bool needComma; /* get relation name including any needed schema prefix and quoting */ ! relname = generate_relation_name(rel); tupdesc = rel->rd_att; natts = tupdesc->natts; ! tuple = get_tuple_of_interest(rel, pkattnums, pknumatts, src_pkattvals); if (!tuple) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), *************** get_sql_insert(Oid relid, int2vector *pk *** 1743,1757 **** sql = pstrdup(str->data); pfree(str->data); pfree(str); - relation_close(rel, AccessShareLock); return (sql); } static char * ! get_sql_delete(Oid relid, int2vector *pkattnums, int16 pknumatts, char **tgt_pkattvals) { - Relation rel; char *relname; TupleDesc tupdesc; int natts; --- 1732,1744 ---- sql = pstrdup(str->data); pfree(str->data); pfree(str); return (sql); } static char * ! get_sql_delete(Relation rel, int2vector *pkattnums, int16 pknumatts, char **tgt_pkattvals) { char *relname; TupleDesc tupdesc; int natts; *************** get_sql_delete(Oid relid, int2vector *pk *** 1761,1772 **** int i; /* get relation name including any needed schema prefix and quoting */ ! relname = generate_relation_name(relid); - /* - * Open relation using relid - */ - rel = relation_open(relid, AccessShareLock); tupdesc = rel->rd_att; natts = tupdesc->natts; --- 1748,1755 ---- int i; /* get relation name including any needed schema prefix and quoting */ ! relname = generate_relation_name(rel); tupdesc = rel->rd_att; natts = tupdesc->natts; *************** get_sql_delete(Oid relid, int2vector *pk *** 1799,1813 **** sql = pstrdup(str->data); pfree(str->data); pfree(str); - relation_close(rel, AccessShareLock); return (sql); } static char * ! get_sql_update(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals) { - Relation rel; char *relname; HeapTuple tuple; TupleDesc tupdesc; --- 1782,1794 ---- sql = pstrdup(str->data); pfree(str->data); pfree(str); return (sql); } static char * ! get_sql_update(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals) { char *relname; HeapTuple tuple; TupleDesc tupdesc; *************** get_sql_update(Oid relid, int2vector *pk *** 1820,1835 **** bool needComma; /* get relation name including any needed schema prefix and quoting */ ! relname = generate_relation_name(relid); - /* - * Open relation using relid - */ - rel = relation_open(relid, AccessShareLock); tupdesc = rel->rd_att; natts = tupdesc->natts; ! tuple = get_tuple_of_interest(relid, pkattnums, pknumatts, src_pkattvals); if (!tuple) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), --- 1801,1812 ---- bool needComma; /* get relation name including any needed schema prefix and quoting */ ! relname = generate_relation_name(rel); tupdesc = rel->rd_att; natts = tupdesc->natts; ! tuple = get_tuple_of_interest(rel, pkattnums, pknumatts, src_pkattvals); if (!tuple) ereport(ERROR, (errcode(ERRCODE_CARDINALITY_VIOLATION), *************** get_sql_update(Oid relid, int2vector *pk *** 1898,1904 **** sql = pstrdup(str->data); pfree(str->data); pfree(str); - relation_close(rel, AccessShareLock); return (sql); } --- 1875,1880 ---- *************** get_attnum_pk_pos(int2vector *pkattnums, *** 1955,1963 **** } static HeapTuple ! get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals) { - Relation rel; char *relname; TupleDesc tupdesc; StringInfo str = makeStringInfo(); --- 1931,1938 ---- } static HeapTuple ! get_tuple_of_interest(Relation rel, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals) { char *relname; TupleDesc tupdesc; StringInfo str = makeStringInfo(); *************** get_tuple_of_interest(Oid relid, int2vec *** 1968,1981 **** char *val = NULL; /* get relation name including any needed schema prefix and quoting */ ! relname = generate_relation_name(relid); ! /* ! * Open relation using relid ! */ ! rel = relation_open(relid, AccessShareLock); ! tupdesc = CreateTupleDescCopy(rel->rd_att); ! relation_close(rel, AccessShareLock); /* * Connect to SPI manager --- 1943,1951 ---- char *val = NULL; /* get relation name including any needed schema prefix and quoting */ ! relname = generate_relation_name(rel); ! tupdesc = rel->rd_att; /* * Connect to SPI manager *************** get_tuple_of_interest(Oid relid, int2vec *** 2053,2104 **** return NULL; } ! static Oid ! get_relid_from_relname(text *relname_text) { RangeVar *relvar; Relation rel; ! Oid relid; relvar = makeRangeVarFromNameList(textToQualifiedNameList(relname_text)); ! rel = heap_openrv(relvar, AccessShareLock); ! relid = RelationGetRelid(rel); ! relation_close(rel, AccessShareLock); ! return relid; } /* * generate_relation_name - copied from ruleutils.c ! * Compute the name to display for a relation specified by OID * * The result includes all necessary quoting and schema-prefixing. */ static char * ! generate_relation_name(Oid relid) { - HeapTuple tp; - Form_pg_class reltup; char *nspname; char *result; - tp = SearchSysCache(RELOID, - ObjectIdGetDatum(relid), - 0, 0, 0); - if (!HeapTupleIsValid(tp)) - elog(ERROR, "cache lookup failed for relation %u", relid); - - reltup = (Form_pg_class) GETSTRUCT(tp); - /* Qualify the name if not visible in search path */ ! if (RelationIsVisible(relid)) nspname = NULL; else ! nspname = get_namespace_name(reltup->relnamespace); ! result = quote_qualified_identifier(nspname, NameStr(reltup->relname)); ! ! ReleaseSysCache(tp); return result; } --- 2023,2071 ---- return NULL; } ! /* ! * Open the relation named by relname_text, acquire specified type of lock, ! * verify we have specified permissions. ! * Caller must close rel when done with it. ! */ ! static Relation ! get_rel_from_relname(text *relname_text, LOCKMODE lockmode, AclMode aclmode) { RangeVar *relvar; Relation rel; ! AclResult aclresult; relvar = makeRangeVarFromNameList(textToQualifiedNameList(relname_text)); ! rel = heap_openrv(relvar, lockmode); ! aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ! aclmode); ! if (aclresult != ACLCHECK_OK) ! aclcheck_error(aclresult, ACL_KIND_CLASS, ! RelationGetRelationName(rel)); ! ! return rel; } /* * generate_relation_name - copied from ruleutils.c ! * Compute the name to display for a relation * * The result includes all necessary quoting and schema-prefixing. */ static char * ! generate_relation_name(Relation rel) { char *nspname; char *result; /* Qualify the name if not visible in search path */ ! if (RelationIsVisible(RelationGetRelid(rel))) nspname = NULL; else ! nspname = get_namespace_name(rel->rd_rel->relnamespace); ! result = quote_qualified_identifier(nspname, RelationGetRelationName(rel)); return result; } *************** dblink_security_check(PGconn *conn, remo *** 2342,2356 **** } static int ! get_nondropped_natts(Oid relid) { int nondropped_natts = 0; TupleDesc tupdesc; - Relation rel; int natts; int i; - rel = relation_open(relid, AccessShareLock); tupdesc = rel->rd_att; natts = tupdesc->natts; --- 2309,2321 ---- } static int ! get_nondropped_natts(Relation rel) { int nondropped_natts = 0; TupleDesc tupdesc; int natts; int i; tupdesc = rel->rd_att; natts = tupdesc->natts; *************** get_nondropped_natts(Oid relid) *** 2361,2367 **** nondropped_natts++; } - relation_close(rel, AccessShareLock); return nondropped_natts; } --- 2326,2331 ----