From e87c68524f64611ca639fe57138a16c924c53584 Mon Sep 17 00:00:00 2001 From: tonybelloni Date: Thu, 21 Dec 2017 00:42:04 -0200 Subject: [PATCH 1/6] Add built-in function pg_objs_per_tablespace prototype --- src/include/catalog/pg_proc.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index c9693759811f7..ac16ef34061df 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4279,6 +4279,9 @@ DATA(insert OID = 2550 ( integer_pl_date PGNSP PGUID 14 1 0 0 0 f f f f t f i DATA(insert OID = 2556 ( pg_tablespace_databases PGNSP PGUID 12 1 1000 0 0 f f f f t t s s 1 0 26 "26" _null_ _null_ _null_ _null_ _null_ pg_tablespace_databases _null_ _null_ _null_ )); DESCR("get OIDs of databases in a tablespace"); +DATA(insert OID = 2579 ( pg_obj_per_tablespace PGNSP PGUID 12 0 0 0 0 f f f f t t s s 1 0 22 "" _null_ _null_ _null_ _null_ _null_ pg_objs_per_tablespace _null_ _null_ _null_ )); +DESCR("get OIDs objects per database and tablespace"); + DATA(insert OID = 2557 ( bool PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 16 "23" _null_ _null_ _null_ _null_ _null_ int4_bool _null_ _null_ _null_ )); DESCR("convert int4 to boolean"); DATA(insert OID = 2558 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "16" _null_ _null_ _null_ _null_ _null_ bool_int4 _null_ _null_ _null_ )); From fc8723892df4581da162b0174842751d8339c99a Mon Sep 17 00:00:00 2001 From: tonybelloni Date: Thu, 21 Dec 2017 00:58:30 -0200 Subject: [PATCH 2/6] Add sample code for bult-in function pg_objs_per_tablespace --- src/backend/utils/adt/misc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index f53d411ad1dd7..34f9f15c5ef6c 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -369,6 +369,13 @@ typedef struct DIR *dirdesc; } ts_db_fctx; +Datum +pg_objs_per_tablespace(PG_FUNCTION_ARGS) +{ + int teste = 1; + return teste; +} + Datum pg_tablespace_databases(PG_FUNCTION_ARGS) { From a6f9dc079d568fba3f77a4c3ede2368f3c935477 Mon Sep 17 00:00:00 2001 From: tonybelloni Date: Thu, 21 Dec 2017 18:10:02 -0200 Subject: [PATCH 3/6] WIP 0.0.1 --- src/backend/utils/adt/misc.c | 41 +++++++++++++++++++++++++++++++++-- src/include/catalog/pg_proc.h | 2 +- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 34f9f15c5ef6c..0102130f4bd0b 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -372,8 +372,45 @@ typedef struct Datum pg_objs_per_tablespace(PG_FUNCTION_ARGS) { - int teste = 1; - return teste; + FuncCallContext *funcctx; + char *values[3]; + HeapTuple tuple; + + if (SRF_IS_FIRSTCALL()) + { + MemoryContext oldcontext; + TupleDesc tupdesc; + + funcctx = SRF_FIRSTCALL_INIT(); + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + tupdesc = CreateTemplateTupleDesc(3, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode", + CHAROID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc", + TEXTOID, -1, 0); + + funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); + + MemoryContextSwitchTo(oldcontext); + } + + funcctx = SRF_PERCALL_SETUP(); + + if (funcctx->call_cntr < 10) + { + values[0] = "Teste"; + values[1] = "C"; + values[2] = "Testando"; + + tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); + + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } + + SRF_RETURN_DONE(funcctx); } Datum diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index ac16ef34061df..a9c84e8358303 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4279,7 +4279,7 @@ DATA(insert OID = 2550 ( integer_pl_date PGNSP PGUID 14 1 0 0 0 f f f f t f i DATA(insert OID = 2556 ( pg_tablespace_databases PGNSP PGUID 12 1 1000 0 0 f f f f t t s s 1 0 26 "26" _null_ _null_ _null_ _null_ _null_ pg_tablespace_databases _null_ _null_ _null_ )); DESCR("get OIDs of databases in a tablespace"); -DATA(insert OID = 2579 ( pg_obj_per_tablespace PGNSP PGUID 12 0 0 0 0 f f f f t t s s 1 0 22 "" _null_ _null_ _null_ _null_ _null_ pg_objs_per_tablespace _null_ _null_ _null_ )); +DATA(insert OID = 2579 ( pg_objs_per_tablespace PGNSP PGUID 12 1 0 0 0 f f f f t t s s 1 0 2249 "26" _null_ _null_ _null_ _null_ _null_ pg_objs_per_tablespace _null_ _null_ _null_ )); DESCR("get OIDs objects per database and tablespace"); DATA(insert OID = 2557 ( bool PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 16 "23" _null_ _null_ _null_ _null_ _null_ int4_bool _null_ _null_ _null_ )); From b0c8d9e8cd2fbca37a7ab99f89d31c901946c05c Mon Sep 17 00:00:00 2001 From: tonybelloni Date: Fri, 22 Dec 2017 17:25:58 -0200 Subject: [PATCH 4/6] WIP 20171222 --- src/backend/utils/adt/misc.c | 51 ++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 0102130f4bd0b..820c23d2588a2 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -45,7 +45,6 @@ #include "utils/builtins.h" #include "utils/timestamp.h" - /* * Common subroutine for num_nulls() and num_nonnulls(). * Returns true if successful, false if function should return NULL. @@ -361,58 +360,72 @@ pg_rotate_logfile(PG_FUNCTION_ARGS) PG_RETURN_BOOL(true); } -/* Function to find out which databases make use of a tablespace */ - typedef struct { - char *location; - DIR *dirdesc; + char *location; + DIR *dirdesc; } ts_db_fctx; Datum pg_objs_per_tablespace(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; - char *values[3]; - HeapTuple tuple; + ts_db_fctx *fctx; + char *values[2]; + HeapTuple tuple; + struct dirent *direntry; if (SRF_IS_FIRSTCALL()) { + MemoryContext oldcontext; TupleDesc tupdesc; +elog(LOG, "%s\n", "Inicio SRF_IS_FIRSTCALL"); + funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - tupdesc = CreateTemplateTupleDesc(3, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word", + fctx = palloc(sizeof(ts_db_fctx)); + + tupdesc = CreateTemplateTupleDesc(2, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "database", TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catcode", - CHAROID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "catdesc", + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relation", TEXTOID, -1, 0); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); + fctx->location = psprintf("base"); + fctx->dirdesc = AllocateDir(fctx->location); + + funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); +elog(LOG, "FIM SRF_IS_FIRSTCALL - %s\n", "pg_objs_per_tablespace"); } funcctx = SRF_PERCALL_SETUP(); + fctx = (ts_db_fctx *) funcctx->user_fctx; - if (funcctx->call_cntr < 10) - { - values[0] = "Teste"; - values[1] = "C"; - values[2] = "Testando"; + if (!fctx->dirdesc) /* not a tablespace */ + SRF_RETURN_DONE(funcctx); - tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); +elog(LOG,"Uma Execucao : %s\n", "PG_OBJ_PER_TABLESPACE"); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + while ((direntry = ReadDir(fctx->dirdesc, fctx->location)) != NULL) + { + values[0] = "base" ; //databaseOid; + values[1] = direntry->d_name; //subdirentry->d_name; + + tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); } + FreeDir(fctx->dirdesc); SRF_RETURN_DONE(funcctx); } +/* Function to find out which databases make use of a tablespace */ Datum pg_tablespace_databases(PG_FUNCTION_ARGS) { From 8dbecd5f4790a8a0afd1cd363ec8b9d07a645717 Mon Sep 17 00:00:00 2001 From: tonybelloni Date: Tue, 26 Dec 2017 16:13:53 -0200 Subject: [PATCH 5/6] WIP 26122017 --- src/backend/utils/adt/misc.c | 105 +++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 24 deletions(-) diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 820c23d2588a2..0103e81836e14 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -362,18 +362,38 @@ pg_rotate_logfile(PG_FUNCTION_ARGS) typedef struct { - char *location; - DIR *dirdesc; -} ts_db_fctx; + char *databaseOid; + char *relationOid; +} tbsp_record; + +typedef struct +{ + tbsp_record *records; + int reccount; +} tbsp_fctx; + +int MyFNatoi(const char *numArray, int *value) +{ + int n = 0; + return sscanf(numArray, "%d%n", value, &n) > 0 /* integer was converted */ + && numArray[n] == '\0'; /* all input got consumed */ +} Datum pg_objs_per_tablespace(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; - ts_db_fctx *fctx; char *values[2]; + DIR *subdirdesc; + DIR *dirdesc; + char *location; HeapTuple tuple; struct dirent *direntry; + struct dirent *subdirentry; + tbsp_record *records = NULL; + int maxrecords = 0; + tbsp_fctx *fctx; + int t; if (SRF_IS_FIRSTCALL()) { @@ -381,13 +401,9 @@ pg_objs_per_tablespace(PG_FUNCTION_ARGS) MemoryContext oldcontext; TupleDesc tupdesc; -elog(LOG, "%s\n", "Inicio SRF_IS_FIRSTCALL"); - funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - fctx = palloc(sizeof(ts_db_fctx)); - tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "database", TEXTOID, -1, 0); @@ -396,36 +412,77 @@ elog(LOG, "%s\n", "Inicio SRF_IS_FIRSTCALL"); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); - fctx->location = psprintf("base"); - fctx->dirdesc = AllocateDir(fctx->location); + location = psprintf("base"); + dirdesc = AllocateDir(location); + while ((direntry = ReadDir(dirdesc, location)) != NULL) + { + char *subdir; + + if (direntry->d_name[0] == '.') + continue; + + if (direntry->d_type == DT_DIR) + { + subdir = psprintf("base/%s", direntry->d_name); + subdirdesc = AllocateDir(subdir); + while ((subdirentry = ReadDir(subdirdesc, subdir)) != NULL) + { + if (subdirentry->d_name[0] == '.') + continue; + + if (!MyFNatoi(subdirentry->d_name, &t)) + continue; + + if (maxrecords == 0) + { + records = (tbsp_record*) malloc(sizeof(tbsp_record)); + records[0].databaseOid = get_database_name(atoi(direntry->d_name)); + records[0].relationOid = strdup(subdirentry->d_name); + maxrecords++; + } + else + { + records = (tbsp_record*) realloc(records, (maxrecords+1) * sizeof(tbsp_record)); + records[maxrecords].databaseOid = get_database_name(atoi(direntry->d_name)); + records[maxrecords].relationOid = strdup(subdirentry->d_name); + maxrecords++; + } + } + FreeDir(subdirdesc); + } + } + FreeDir(dirdesc); + + fctx = palloc(sizeof(tbsp_fctx)); + + fctx->records = records; + fctx->reccount = maxrecords; funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); -elog(LOG, "FIM SRF_IS_FIRSTCALL - %s\n", "pg_objs_per_tablespace"); } funcctx = SRF_PERCALL_SETUP(); - fctx = (ts_db_fctx *) funcctx->user_fctx; - - if (!fctx->dirdesc) /* not a tablespace */ - SRF_RETURN_DONE(funcctx); - -elog(LOG,"Uma Execucao : %s\n", "PG_OBJ_PER_TABLESPACE"); + fctx = (tbsp_fctx *) funcctx->user_fctx; - while ((direntry = ReadDir(fctx->dirdesc, fctx->location)) != NULL) + if (funcctx->call_cntr < fctx->reccount) { - values[0] = "base" ; //databaseOid; - values[1] = direntry->d_name; //subdirentry->d_name; + values[0] = fctx->records[funcctx->call_cntr].databaseOid; + values[1] = fctx->records[funcctx->call_cntr].relationOid; - tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); - SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); } - - FreeDir(fctx->dirdesc); SRF_RETURN_DONE(funcctx); } /* Function to find out which databases make use of a tablespace */ +typedef struct +{ + char *location; + DIR *dirdesc; +} ts_db_fctx; + Datum pg_tablespace_databases(PG_FUNCTION_ARGS) { From 71808f5e1cf81923b024cb82a64a0abf495f245e Mon Sep 17 00:00:00 2001 From: tonybelloni Date: Tue, 26 Dec 2017 18:00:17 -0200 Subject: [PATCH 6/6] WIP 26122017 --- src/backend/utils/adt/misc.c | 90 ++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 8 deletions(-) diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 0103e81836e14..a5464e0a27872 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -360,6 +360,7 @@ pg_rotate_logfile(PG_FUNCTION_ARGS) PG_RETURN_BOOL(true); } +/* Structures used in pg_objs_per_tablespace */ typedef struct { char *databaseOid; @@ -372,13 +373,25 @@ typedef struct int reccount; } tbsp_fctx; -int MyFNatoi(const char *numArray, int *value) +/* + * Check if a char* array is a number. I don't know if there is + * something that does the same thing in the codebase, so I wrote + * my own function. + */ +static int +check_is_digit(const char *numArray, int *value) { int n = 0; return sscanf(numArray, "%d%n", value, &n) > 0 /* integer was converted */ && numArray[n] == '\0'; /* all input got consumed */ } +/* + * Function to report which objects are in which tablespace. + * It follows a similar approach as pg_tablespace_databases, ie, + * reads the tablespace's directory and list all OIDs in it. + * + */ Datum pg_objs_per_tablespace(PG_FUNCTION_ARGS) { @@ -397,9 +410,37 @@ pg_objs_per_tablespace(PG_FUNCTION_ARGS) if (SRF_IS_FIRSTCALL()) { - MemoryContext oldcontext; TupleDesc tupdesc; + Oid tablespaceOid = PG_GETARG_OID(0); + + /* If user is not superuser, return a error message and block execution */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to execute this function")))); + + /* + * Global tablespace does not hold databases. If OID passed is from global tablespace + * return a error and block execution. + */ + if (tablespaceOid == GLOBALTABLESPACE_OID) + { + ereport(ERROR, + (errcode(ERRCODE_NO_DATA), + (errmsg("global tablespace never has databases")))); + } + else + { + /* if OID passed is from default tablespace point location to base directory. + * Otherwise point location to tablespace's directory. + */ + if (tablespaceOid == DEFAULTTABLESPACE_OID) + location = psprintf("base"); + else + location = psprintf("pg_tblspc/%u/%s", tablespaceOid, + TABLESPACE_VERSION_DIRECTORY); + } funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); @@ -412,38 +453,68 @@ pg_objs_per_tablespace(PG_FUNCTION_ARGS) funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); - location = psprintf("base"); + /* allocate directory descriptor. If directory descriptor is null, tablespace does not exists. + * In this case, return a error and block execution. + */ dirdesc = AllocateDir(location); + if (!dirdesc) + ereport(ERROR, + (errcode(ERRCODE_NO_DATA), + (errmsg("%u is not a valid tablespace Oid", tablespaceOid)))); + + /* Reads the tablespace's directory. If it's a tablespace it will contain subdirectories for each + * database, each one with their own objects. + */ while ((direntry = ReadDir(dirdesc, location)) != NULL) { char *subdir; - + + /* ignore parent directories */ if (direntry->d_name[0] == '.') continue; + /* if directory entry is a directory then it is a database OID. Iterate over it go get the + * objects in the database. + */ if (direntry->d_type == DT_DIR) { - subdir = psprintf("base/%s", direntry->d_name); + /* point subdir location to tablespace/database directory */ + subdir = psprintf("%s/%s", location, direntry->d_name); + + /* allocate a descriptor to the tablespace/database location + * TODO : Test if directory is invalid or does not exists + */ subdirdesc = AllocateDir(subdir); + + /* iterate over tablespace/database directory and get the objects */ while ((subdirentry = ReadDir(subdirdesc, subdir)) != NULL) { + + /* ignore parent directories */ if (subdirentry->d_name[0] == '.') continue; - if (!MyFNatoi(subdirentry->d_name, &t)) + /* check if entry is a number. Do not consider _vm, _fsm and other files */ + if (!check_is_digit(subdirentry->d_name, &t)) continue; + /* If it's the first time, allocate one record into the records array and + * add a database/object value pair. + */ if (maxrecords == 0) { records = (tbsp_record*) malloc(sizeof(tbsp_record)); - records[0].databaseOid = get_database_name(atoi(direntry->d_name)); + records[0].databaseOid = get_database_name(atooid(direntry->d_name)); records[0].relationOid = strdup(subdirentry->d_name); maxrecords++; } else { + /* If the records array is already initialized, realloc one more record and + * add a database/object value pair into it. + */ records = (tbsp_record*) realloc(records, (maxrecords+1) * sizeof(tbsp_record)); - records[maxrecords].databaseOid = get_database_name(atoi(direntry->d_name)); + records[maxrecords].databaseOid = get_database_name(atooid(direntry->d_name)); records[maxrecords].relationOid = strdup(subdirentry->d_name); maxrecords++; } @@ -453,8 +524,10 @@ pg_objs_per_tablespace(PG_FUNCTION_ARGS) } FreeDir(dirdesc); + /* Initialize the context struct used over SRF_PERCALL iterations */ fctx = palloc(sizeof(tbsp_fctx)); + /* assign values to the context struct used to maintain the status over SRF_PERCALL iterations */ fctx->records = records; fctx->reccount = maxrecords; @@ -465,6 +538,7 @@ pg_objs_per_tablespace(PG_FUNCTION_ARGS) funcctx = SRF_PERCALL_SETUP(); fctx = (tbsp_fctx *) funcctx->user_fctx; + /* iterate over the array of records and return a tuple to each database/object value pair */ if (funcctx->call_cntr < fctx->reccount) { values[0] = fctx->records[funcctx->call_cntr].databaseOid; 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