Skip to content

Commit 71808f5

Browse files
committed
WIP 26122017
1 parent f3c9cd5 commit 71808f5

File tree

1 file changed

+82
-8
lines changed

1 file changed

+82
-8
lines changed

src/backend/utils/adt/misc.c

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ pg_rotate_logfile(PG_FUNCTION_ARGS)
360360
PG_RETURN_BOOL(true);
361361
}
362362

363+
/* Structures used in pg_objs_per_tablespace */
363364
typedef struct
364365
{
365366
char *databaseOid;
@@ -372,13 +373,25 @@ typedef struct
372373
int reccount;
373374
} tbsp_fctx;
374375

375-
int MyFNatoi(const char *numArray, int *value)
376+
/*
377+
* Check if a char* array is a number. I don't know if there is
378+
* something that does the same thing in the codebase, so I wrote
379+
* my own function.
380+
*/
381+
static int
382+
check_is_digit(const char *numArray, int *value)
376383
{
377384
int n = 0;
378385
return sscanf(numArray, "%d%n", value, &n) > 0 /* integer was converted */
379386
&& numArray[n] == '\0'; /* all input got consumed */
380387
}
381388

389+
/*
390+
* Function to report which objects are in which tablespace.
391+
* It follows a similar approach as pg_tablespace_databases, ie,
392+
* reads the tablespace's directory and list all OIDs in it.
393+
*
394+
*/
382395
Datum
383396
pg_objs_per_tablespace(PG_FUNCTION_ARGS)
384397
{
@@ -397,9 +410,37 @@ pg_objs_per_tablespace(PG_FUNCTION_ARGS)
397410

398411
if (SRF_IS_FIRSTCALL())
399412
{
400-
401413
MemoryContext oldcontext;
402414
TupleDesc tupdesc;
415+
Oid tablespaceOid = PG_GETARG_OID(0);
416+
417+
/* If user is not superuser, return a error message and block execution */
418+
if (!superuser())
419+
ereport(ERROR,
420+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
421+
(errmsg("must be superuser to execute this function"))));
422+
423+
/*
424+
* Global tablespace does not hold databases. If OID passed is from global tablespace
425+
* return a error and block execution.
426+
*/
427+
if (tablespaceOid == GLOBALTABLESPACE_OID)
428+
{
429+
ereport(ERROR,
430+
(errcode(ERRCODE_NO_DATA),
431+
(errmsg("global tablespace never has databases"))));
432+
}
433+
else
434+
{
435+
/* if OID passed is from default tablespace point location to base directory.
436+
* Otherwise point location to tablespace's directory.
437+
*/
438+
if (tablespaceOid == DEFAULTTABLESPACE_OID)
439+
location = psprintf("base");
440+
else
441+
location = psprintf("pg_tblspc/%u/%s", tablespaceOid,
442+
TABLESPACE_VERSION_DIRECTORY);
443+
}
403444

404445
funcctx = SRF_FIRSTCALL_INIT();
405446
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
@@ -412,38 +453,68 @@ pg_objs_per_tablespace(PG_FUNCTION_ARGS)
412453

413454
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
414455

415-
location = psprintf("base");
456+
/* allocate directory descriptor. If directory descriptor is null, tablespace does not exists.
457+
* In this case, return a error and block execution.
458+
*/
416459
dirdesc = AllocateDir(location);
460+
if (!dirdesc)
461+
ereport(ERROR,
462+
(errcode(ERRCODE_NO_DATA),
463+
(errmsg("%u is not a valid tablespace Oid", tablespaceOid))));
464+
465+
/* Reads the tablespace's directory. If it's a tablespace it will contain subdirectories for each
466+
* database, each one with their own objects.
467+
*/
417468
while ((direntry = ReadDir(dirdesc, location)) != NULL)
418469
{
419470
char *subdir;
420-
471+
472+
/* ignore parent directories */
421473
if (direntry->d_name[0] == '.')
422474
continue;
423475

476+
/* if directory entry is a directory then it is a database OID. Iterate over it go get the
477+
* objects in the database.
478+
*/
424479
if (direntry->d_type == DT_DIR)
425480
{
426-
subdir = psprintf("base/%s", direntry->d_name);
481+
/* point subdir location to tablespace/database directory */
482+
subdir = psprintf("%s/%s", location, direntry->d_name);
483+
484+
/* allocate a descriptor to the tablespace/database location
485+
* TODO : Test if directory is invalid or does not exists
486+
*/
427487
subdirdesc = AllocateDir(subdir);
488+
489+
/* iterate over tablespace/database directory and get the objects */
428490
while ((subdirentry = ReadDir(subdirdesc, subdir)) != NULL)
429491
{
492+
493+
/* ignore parent directories */
430494
if (subdirentry->d_name[0] == '.')
431495
continue;
432496

433-
if (!MyFNatoi(subdirentry->d_name, &t))
497+
/* check if entry is a number. Do not consider _vm, _fsm and other files */
498+
if (!check_is_digit(subdirentry->d_name, &t))
434499
continue;
435500

501+
/* If it's the first time, allocate one record into the records array and
502+
* add a database/object value pair.
503+
*/
436504
if (maxrecords == 0)
437505
{
438506
records = (tbsp_record*) malloc(sizeof(tbsp_record));
439-
records[0].databaseOid = get_database_name(atoi(direntry->d_name));
507+
records[0].databaseOid = get_database_name(atooid(direntry->d_name));
440508
records[0].relationOid = strdup(subdirentry->d_name);
441509
maxrecords++;
442510
}
443511
else
444512
{
513+
/* If the records array is already initialized, realloc one more record and
514+
* add a database/object value pair into it.
515+
*/
445516
records = (tbsp_record*) realloc(records, (maxrecords+1) * sizeof(tbsp_record));
446-
records[maxrecords].databaseOid = get_database_name(atoi(direntry->d_name));
517+
records[maxrecords].databaseOid = get_database_name(atooid(direntry->d_name));
447518
records[maxrecords].relationOid = strdup(subdirentry->d_name);
448519
maxrecords++;
449520
}
@@ -453,8 +524,10 @@ pg_objs_per_tablespace(PG_FUNCTION_ARGS)
453524
}
454525
FreeDir(dirdesc);
455526

527+
/* Initialize the context struct used over SRF_PERCALL iterations */
456528
fctx = palloc(sizeof(tbsp_fctx));
457529

530+
/* assign values to the context struct used to maintain the status over SRF_PERCALL iterations */
458531
fctx->records = records;
459532
fctx->reccount = maxrecords;
460533

@@ -465,6 +538,7 @@ pg_objs_per_tablespace(PG_FUNCTION_ARGS)
465538
funcctx = SRF_PERCALL_SETUP();
466539
fctx = (tbsp_fctx *) funcctx->user_fctx;
467540

541+
/* iterate over the array of records and return a tuple to each database/object value pair */
468542
if (funcctx->call_cntr < fctx->reccount)
469543
{
470544
values[0] = fctx->records[funcctx->call_cntr].databaseOid;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy