Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd367f62

Browse files
committed
Add permissions check: now one must be the Postgres superuser or the
table owner in order to vacuum a table. This is mainly to preventdenial-of-service attacks via repeated vacuums. Allow VACUUM to gatherstatistics about system relations, except for pg_statistic itself ---not clear that it's worth the trouble to make that case work cleanly.Cope with possible tuple size overflow in pg_statistic tuples; I'msurprised we never realized that could happen. Hold a couple of locksa little longer to try to prevent deadlocks between concurrent VACUUMs.There still seem to be some problems in that last area though :-(
1 parent8a7f31a commitd367f62

File tree

1 file changed

+105
-45
lines changed

1 file changed

+105
-45
lines changed

‎src/backend/commands/vacuum.c

Lines changed: 105 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.127 1999/11/28 02:10:01 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.128 1999/11/29 04:43:15 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -35,6 +35,7 @@
3535
#include"storage/sinval.h"
3636
#include"storage/smgr.h"
3737
#include"tcop/tcopprot.h"
38+
#include"utils/acl.h"
3839
#include"utils/builtins.h"
3940
#include"utils/inval.h"
4041
#include"utils/portal.h"
@@ -393,15 +394,35 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
393394
}
394395

395396
/*
396-
* Open the class, get an exclusive lock on it, and vacuum it
397+
* Open the class, get an exclusive lock on it, and check permissions.
398+
*
399+
* Note we choose to treat permissions failure as a NOTICE and keep
400+
* trying to vacuum the rest of the DB --- is this appropriate?
397401
*/
398402
onerel=heap_open(relid,AccessExclusiveLock);
399403

404+
#ifndefNO_SECURITY
405+
if (!pg_ownercheck(GetPgUserName(),RelationGetRelationName(onerel),
406+
RELNAME))
407+
{
408+
elog(NOTICE,"Skipping \"%s\" --- only table owner can VACUUM it",
409+
RelationGetRelationName(onerel));
410+
heap_close(onerel,AccessExclusiveLock);
411+
CommitTransactionCommand();
412+
return;
413+
}
414+
#endif
415+
416+
/*
417+
* Set up statistics-gathering machinery.
418+
*/
400419
vacrelstats= (VRelStats*)palloc(sizeof(VRelStats));
401420
vacrelstats->relid=relid;
402421
vacrelstats->num_pages=vacrelstats->num_tuples=0;
403422
vacrelstats->hasindex= false;
404-
if (analyze&& !IsSystemRelationName(RelationGetRelationName(onerel)))
423+
/* we can VACUUM ANALYZE any table except pg_statistic; see vc_updstats */
424+
if (analyze&&
425+
strcmp(RelationGetRelationName(onerel),StatisticRelationName)!=0)
405426
{
406427
intattr_cnt,
407428
*attnums=NULL;
@@ -498,7 +519,7 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
498519
stats->outfunc=InvalidOid;
499520
}
500521
vacrelstats->va_natts=attr_cnt;
501-
/* delete existingpg_statistics rows for relation */
522+
/* delete existingpg_statistic rows for relation */
502523
vc_delstats(relid, ((attnums) ?attr_cnt :0),attnums);
503524
if (attnums)
504525
pfree(attnums);
@@ -2248,19 +2269,38 @@ vc_bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len
22482269
}
22492270

22502271
/*
2251-
*vc_updstats() -- update pg_class statistics for one relation
2272+
*vc_updstats() -- update statistics for one relation
2273+
*
2274+
*Statistics are stored in several places: the pg_class row for the
2275+
*relation has stats about the whole relation, the pg_attribute rows
2276+
*for each attribute store "disbursion", and there is a pg_statistic
2277+
*row for each (non-system) attribute. (Disbursion probably ought to
2278+
*be moved to pg_statistic, but it's not worth doing unless there's
2279+
*another reason to have to change pg_attribute.) Disbursion and
2280+
*pg_statistic values are only updated by VACUUM ANALYZE, but we
2281+
*always update the stats in pg_class.
22522282
*
22532283
*This routine works for both index and heap relation entries in
22542284
*pg_class. We violate no-overwrite semantics here by storing new
2255-
*values fornum_tuples, num_pages, and hasindexdirectlyin the pg_class
2285+
*values forthe statistics columnsdirectlyinto the pg_class
22562286
*tuple that's already on the page. The reason for this is that if
2257-
*we updated these tuples in the usual way, then every tuple in pg_class
2258-
*would be replaced every day. This would make planning and executing
2259-
*historical queries very expensive. Note that we also don't use
2260-
*any locking while doing updation.
2287+
*we updated these tuples in the usual way, vacuuming pg_class itself
2288+
*wouldn't work very well --- by the time we got done with a vacuum
2289+
*cycle, most of the tuples in pg_class would've been obsoleted.
2290+
*Updating pg_class's own statistics would be especially tricky.
2291+
*Of course, this only works for fixed-size never-null columns, but
2292+
*these are.
2293+
*
2294+
*Updates of pg_attribute statistics are handled in the same way
2295+
*for the same reasons.
2296+
*
2297+
*To keep things simple, we punt for pg_statistic, and don't try
2298+
*to compute or store rows for pg_statistic itself in pg_statistic.
2299+
*This could possibly be made to work, but it's not worth the trouble.
22612300
*/
22622301
staticvoid
2263-
vc_updstats(Oidrelid,intnum_pages,intnum_tuples,boolhasindex,VRelStats*vacrelstats)
2302+
vc_updstats(Oidrelid,intnum_pages,intnum_tuples,boolhasindex,
2303+
VRelStats*vacrelstats)
22642304
{
22652305
Relationrd,
22662306
ad,
@@ -2298,13 +2338,21 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
22982338
pgcform->relpages=num_pages;
22992339
pgcform->relhasindex=hasindex;
23002340

2341+
/* invalidate the tuple in the cache and write the buffer */
2342+
RelationInvalidateHeapTuple(rd,&rtup);
2343+
WriteBuffer(buffer);
2344+
2345+
heap_close(rd,RowExclusiveLock);
2346+
23012347
if (vacrelstats!=NULL&&vacrelstats->va_natts>0)
23022348
{
23032349
VacAttrStats*vacattrstats=vacrelstats->vacattrstats;
23042350
intnatts=vacrelstats->va_natts;
23052351

23062352
ad=heap_openr(AttributeRelationName,RowExclusiveLock);
23072353
sd=heap_openr(StatisticRelationName,RowExclusiveLock);
2354+
2355+
/* Find pg_attribute rows for this relation */
23082356
ScanKeyEntryInitialize(&askey,0,Anum_pg_attribute_attrelid,
23092357
F_INT4EQ,relid);
23102358

@@ -2313,15 +2361,10 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
23132361
while (HeapTupleIsValid(atup=heap_getnext(scan,0)))
23142362
{
23152363
inti;
2316-
float32dataselratio;/* average ratio of rows selected
2317-
* for a random constant */
23182364
VacAttrStats*stats;
2319-
Datumvalues[Natts_pg_statistic];
2320-
charnulls[Natts_pg_statistic];
23212365

23222366
attp= (Form_pg_attribute)GETSTRUCT(atup);
2323-
if (attp->attnum <=0)/* skip system attributes for now, */
2324-
/* they are unique anyway */
2367+
if (attp->attnum <=0)/* skip system attributes for now */
23252368
continue;
23262369

23272370
for (i=0;i<natts;i++)
@@ -2330,12 +2373,15 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
23302373
break;
23312374
}
23322375
if (i >=natts)
2333-
continue;
2376+
continue;/* skip attr if no stats collected */
23342377
stats=&(vacattrstats[i]);
23352378

2336-
/* overwrite the existing statistics in the tuple */
23372379
if (VacAttrStatsEqValid(stats))
23382380
{
2381+
float32dataselratio;/* average ratio of rows selected
2382+
* for a random constant */
2383+
2384+
/* Compute disbursion */
23392385
if (stats->nonnull_cnt==0&&stats->null_cnt==0)
23402386
{
23412387
/* empty relation, so put a dummy value in attdisbursion */
@@ -2383,23 +2429,24 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
23832429
elseif (selratio>1.0)
23842430
selratio=1.0;
23852431
}
2432+
2433+
/* overwrite the existing statistics in the tuple */
23862434
attp->attdisbursion=selratio;
23872435

2388-
/*
2389-
* Invalidate the cache for the tuple and write the buffer
2390-
*/
2436+
/* invalidate the tuple in the cache and write the buffer */
23912437
RelationInvalidateHeapTuple(ad,atup);
23922438
WriteNoReleaseBuffer(scan->rs_cbuf);
23932439

2394-
/* DO PG_STATISTIC INSERTS */
2395-
23962440
/*
2397-
* doing system relations, especially pg_statistic is a
2398-
* problem
2441+
* Create pg_statistic tuples for the relation, if we have
2442+
* gathered the right data. vc_delstats() previously
2443+
* deleted all the pg_statistic tuples for the rel, so we
2444+
* just have to insert new ones here.
2445+
*
2446+
* Note vc_vacone() has seen to it that we won't come here
2447+
* when vacuuming pg_statistic itself.
23992448
*/
2400-
if (VacAttrStatsLtGtValid(stats)&&stats->initialized
2401-
/* && !IsSystemRelationName(NameData(pgcform->relname))
2402-
*/ )
2449+
if (VacAttrStatsLtGtValid(stats)&&stats->initialized)
24032450
{
24042451
float32datanullratio;
24052452
float32databestratio;
@@ -2408,6 +2455,8 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
24082455
doublebest_cnt_d=stats->best_cnt,
24092456
null_cnt_d=stats->null_cnt,
24102457
nonnull_cnt_d=stats->nonnull_cnt;/* prevent overflow */
2458+
Datumvalues[Natts_pg_statistic];
2459+
charnulls[Natts_pg_statistic];
24112460

24122461
nullratio=null_cnt_d / (nonnull_cnt_d+null_cnt_d);
24132462
bestratio=best_cnt_d / (nonnull_cnt_d+null_cnt_d);
@@ -2441,13 +2490,26 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
24412490
stup=heap_formtuple(sd->rd_att,values,nulls);
24422491

24432492
/* ----------------
2444-
*insert the tuple in the relation.
2493+
*Watch out for oversize tuple, which can happen if
2494+
*all three of the saved data values are long.
2495+
*Our fallback strategy is just to not store the
2496+
*pg_statistic tuple at all in that case. (We could
2497+
*replace the values by NULLs and still store the
2498+
*numeric stats, but presently selfuncs.c couldn't
2499+
*do anything useful with that case anyway.)
2500+
*
2501+
*We could reduce the probability of overflow, but not
2502+
*prevent it, by storing the data values as compressed
2503+
*text; is that worth doing? The problem should go
2504+
*away whenever long tuples get implemented...
24452505
* ----------------
24462506
*/
2447-
heap_insert(sd,stup);
2448-
2507+
if (MAXALIGN(stup->t_len) <=MaxTupleSize)
24492508
{
2509+
/* OK, store tuple and update indexes too */
24502510
Relationirelations[Num_pg_statistic_indices];
2511+
2512+
heap_insert(sd,stup);
24512513
CatalogOpenIndices(Num_pg_statistic_indices,Name_pg_statistic_indices,irelations);
24522514
CatalogIndexInsert(irelations,Num_pg_statistic_indices,sd,stup);
24532515
CatalogCloseIndices(Num_pg_statistic_indices,irelations);
@@ -2462,22 +2524,14 @@ vc_updstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *
24622524
}
24632525
}
24642526
heap_endscan(scan);
2465-
heap_close(ad,RowExclusiveLock);
2466-
heap_close(sd,RowExclusiveLock);
2527+
/* close rels, but hold locks till upcoming commit */
2528+
heap_close(ad,NoLock);
2529+
heap_close(sd,NoLock);
24672530
}
2468-
2469-
/*
2470-
* Invalidate the cached pg_class tuple and write the buffer
2471-
*/
2472-
RelationInvalidateHeapTuple(rd,&rtup);
2473-
2474-
WriteBuffer(buffer);
2475-
2476-
heap_close(rd,RowExclusiveLock);
24772531
}
24782532

24792533
/*
2480-
*vc_delstats() -- deletepg_statistics rows for a relation
2534+
*vc_delstats() -- deletepg_statistic rows for a relation
24812535
*
24822536
*If a list of attribute numbers is given, only zap stats for those attrs.
24832537
*/
@@ -2514,7 +2568,13 @@ vc_delstats(Oid relid, int attcnt, int *attnums)
25142568
}
25152569

25162570
heap_endscan(scan);
2517-
heap_close(pgstatistic,RowExclusiveLock);
2571+
/*
2572+
* Close rel, but *keep* lock; we will need to reacquire it later,
2573+
* so there's a possibility of deadlock against another VACUUM process
2574+
* if we let go now. Keeping the lock shouldn't delay any common
2575+
* operation other than an attempted VACUUM of pg_statistic itself.
2576+
*/
2577+
heap_close(pgstatistic,NoLock);
25182578
}
25192579

25202580
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp