PostgreSQL Source Code git master
Loading...
Searching...
No Matches
ddlutils.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_database.h"
#include "catalog/pg_db_role_setting.h"
#include "catalog/pg_tablespace.h"
#include "commands/tablespace.h"
#include "common/relpath.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/pg_locale.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/syscache.h"
#include "utils/timestamp.h"
#include "utils/varlena.h"
Include dependency graph for ddlutils.c:

Go to the source code of this file.

Data Structures

struct  DdlOption
 

Typedefs

typedef struct DdlOption DdlOption
 

Enumerations

enum  DdlOptType { DDL_OPT_BOOL , DDL_OPT_TEXT , DDL_OPT_INT }
 

Functions

static void parse_ddl_options (FunctionCallInfo fcinfo, int variadic_start, DdlOption *opts, int nopts)
 
static void append_ddl_option (StringInfo buf, bool pretty, int indent, const char *fmt,...) pg_attribute_printf(4
 
static void static void append_guc_value (StringInfo buf, const char *name, const char *value)
 
static Listpg_get_role_ddl_internal (Oid roleid, bool pretty, bool memberships)
 
static Listpg_get_tablespace_ddl_internal (Oid tsid, bool pretty, bool no_owner)
 
static Datum pg_get_tablespace_ddl_srf (FunctionCallInfo fcinfo, Oid tsid, bool isnull)
 
static Listpg_get_database_ddl_internal (Oid dbid, bool pretty, bool no_owner, bool no_tablespace)
 
Datum pg_get_role_ddl (PG_FUNCTION_ARGS)
 
Datum pg_get_tablespace_ddl_oid (PG_FUNCTION_ARGS)
 
Datum pg_get_tablespace_ddl_name (PG_FUNCTION_ARGS)
 
Datum pg_get_database_ddl (PG_FUNCTION_ARGS)
 

Typedef Documentation

◆ DdlOption

Enumeration Type Documentation

◆ DdlOptType

Enumerator
DDL_OPT_BOOL 
DDL_OPT_TEXT 
DDL_OPT_INT 

Definition at line 50 of file ddlutils.c.

51{
DdlOptType
Definition ddlutils.c:51
@ DDL_OPT_TEXT
Definition ddlutils.c:53
@ DDL_OPT_INT
Definition ddlutils.c:54
@ DDL_OPT_BOOL
Definition ddlutils.c:52

Function Documentation

◆ append_ddl_option()

static void append_ddl_option ( StringInfo  buf,
bool  pretty,
int  indent,
const char fmt,
  ... 
)
static

Definition at line 234 of file ddlutils.c.

236{
237 if (pretty)
238 {
241 }
242 else
244
245 for (;;)
246 {
248 int needed;
249
250 va_start(args, fmt);
252 va_end(args);
253 if (needed == 0)
254 break;
256 }
257}
static char buf[DEFAULT_XLOG_SEG_SIZE]
static int fb(int x)
int appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
Definition stringinfo.c:187
void enlargeStringInfo(StringInfo str, int needed)
Definition stringinfo.c:337
void appendStringInfoSpaces(StringInfo str, int count)
Definition stringinfo.c:260
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242

References appendStringInfoChar(), appendStringInfoSpaces(), appendStringInfoVA(), buf, enlargeStringInfo(), and fb().

Referenced by pg_get_database_ddl_internal(), pg_get_role_ddl_internal(), and pg_get_tablespace_ddl_internal().

◆ append_guc_value()

static void append_guc_value ( StringInfo  buf,
const char name,
const char value 
)
static

Definition at line 271 of file ddlutils.c.

272{
273 char *rawval;
274
276
278 {
279 List *namelist;
280 bool first = true;
281
282 /* Parse string into list of identifiers */
283 if (!SplitGUCList(rawval, ',', &namelist))
284 {
285 /* this shouldn't fail really */
286 elog(ERROR, "invalid list syntax in setconfig item");
287 }
288 /* Special case: represent an empty list as NULL */
289 if (namelist == NIL)
292 {
293 if (first)
294 first = false;
295 else
298 }
300 }
301 else
303
304 pfree(rawval);
305}
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:227
int GetConfigOptionFlags(const char *name, bool missing_ok)
Definition guc.c:4348
#define GUC_LIST_QUOTE
Definition guc.h:215
static struct @177 value
void list_free(List *list)
Definition list.c:1546
char * pstrdup(const char *in)
Definition mcxt.c:1781
void pfree(void *pointer)
Definition mcxt.c:1616
#define NIL
Definition pg_list.h:68
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
char * quote_literal_cstr(const char *rawstr)
Definition quote.c:101
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
Definition pg_list.h:54
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition varlena.c:3025
const char * name

References appendStringInfoString(), buf, elog, ERROR, fb(), foreach_ptr, GetConfigOptionFlags(), GUC_LIST_QUOTE, list_free(), name, NIL, pfree(), pstrdup(), quote_literal_cstr(), SplitGUCList(), and value.

Referenced by pg_get_database_ddl_internal(), and pg_get_role_ddl_internal().

◆ parse_ddl_options()

static void parse_ddl_options ( FunctionCallInfo  fcinfo,
int  variadic_start,
DdlOption opts,
int  nopts 
)
static

Definition at line 102 of file ddlutils.c.

104{
105 Datum *args;
106 bool *nulls;
107 Oid *types;
108 int nargs;
109
110 /* Clear all output fields */
111 for (int i = 0; i < nopts; i++)
112 {
113 opts[i].isset = false;
114 switch (opts[i].type)
115 {
116 case DDL_OPT_BOOL:
117 opts[i].boolval = false;
118 break;
119 case DDL_OPT_TEXT:
120 opts[i].textval = NULL;
121 break;
122 case DDL_OPT_INT:
123 opts[i].intval = 0;
124 break;
125 }
126 }
127
128 nargs = extract_variadic_args(fcinfo, variadic_start, true,
129 &args, &types, &nulls);
130
131 if (nargs <= 0)
132 return;
133
134 /* Handle DEFAULT NULL case */
135 if (nargs == 1 && nulls[0])
136 return;
137
138 if (nargs % 2 != 0)
141 errmsg("variadic arguments must be name/value pairs"),
142 errhint("Provide an even number of variadic arguments that can be divided into pairs.")));
143
144 /*
145 * For each option name/value pair, find corresponding positional option
146 * for the option name, and assign the option value.
147 */
148 for (int i = 0; i < nargs; i += 2)
149 {
150 char *name;
151 char *valstr;
152 DdlOption *opt = NULL;
153
154 if (nulls[i])
157 errmsg("option name at variadic position %d is null", i + 1)));
158
159 name = TextDatumGetCString(args[i]);
160
161 if (nulls[i + 1])
164 errmsg("value for option \"%s\" must not be null", name)));
165
166 /* Find matching option descriptor */
167 for (int j = 0; j < nopts; j++)
168 {
169 if (pg_strcasecmp(name, opts[j].name) == 0)
170 {
171 opt = &opts[j];
172 break;
173 }
174 }
175
176 if (opt == NULL)
179 errmsg("unrecognized option: \"%s\"", name)));
180
181 if (opt->isset)
184 errmsg("option \"%s\" is specified more than once",
185 name)));
186
187 valstr = TextDatumGetCString(args[i + 1]);
188
189 switch (opt->type)
190 {
191 case DDL_OPT_BOOL:
192 if (!parse_bool(valstr, &opt->boolval))
195 errmsg("invalid value for boolean option \"%s\": %s",
196 name, valstr)));
197 break;
198
199 case DDL_OPT_TEXT:
200 opt->textval = valstr;
201 valstr = NULL; /* don't pfree below */
202 break;
203
204 case DDL_OPT_INT:
205 {
206 char *endp;
207 long val;
208
209 errno = 0;
210 val = strtol(valstr, &endp, 10);
211 if (*endp != '\0' || errno == ERANGE ||
215 errmsg("invalid value for integer option \"%s\": %s",
216 name, valstr)));
217 opt->intval = (int) val;
218 }
219 break;
220 }
221
222 opt->isset = true;
223
224 if (valstr)
225 pfree(valstr);
226 pfree(name);
227 }
228}
bool parse_bool(const char *value, bool *result)
Definition bool.c:31
#define TextDatumGetCString(d)
Definition builtins.h:99
#define PG_INT32_MAX
Definition c.h:673
struct typedefs * types
Definition ecpg.c:30
int errcode(int sqlerrcode)
Definition elog.c:874
int errhint(const char *fmt,...) pg_attribute_printf(1
#define ereport(elevel,...)
Definition elog.h:151
int extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start, bool convert_unknown, Datum **args, Oid **types, bool **nulls)
Definition funcapi.c:2011
long val
Definition informix.c:689
int j
Definition isn.c:78
int i
Definition isn.c:77
static char * errmsg
static AmcheckOptions opts
Definition pg_amcheck.c:112
int pg_strcasecmp(const char *s1, const char *s2)
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
char * textval
Definition ddlutils.c:70
bool isset
Definition ddlutils.c:65
bool boolval
Definition ddlutils.c:69
int intval
Definition ddlutils.c:71
DdlOptType type
Definition ddlutils.c:64
const char * type

References DdlOption::boolval, DDL_OPT_BOOL, DDL_OPT_INT, DDL_OPT_TEXT, ereport, errcode(), errhint(), errmsg, ERROR, extract_variadic_args(), fb(), i, DdlOption::intval, DdlOption::isset, j, name, opts, parse_bool(), pfree(), PG_INT32_MAX, pg_strcasecmp(), TextDatumGetCString, DdlOption::textval, type, DdlOption::type, types, and val.

Referenced by pg_get_database_ddl(), pg_get_role_ddl(), and pg_get_tablespace_ddl_srf().

◆ pg_get_database_ddl()

Datum pg_get_database_ddl ( PG_FUNCTION_ARGS  )

Definition at line 1117 of file ddlutils.c.

1118{
1121
1122 if (SRF_IS_FIRSTCALL())
1123 {
1124 MemoryContext oldcontext;
1125 Oid dbid;
1126 DdlOption opts[] = {
1127 {"pretty", DDL_OPT_BOOL},
1128 {"owner", DDL_OPT_BOOL},
1129 {"tablespace", DDL_OPT_BOOL},
1130 };
1131
1133 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1134
1135 if (PG_ARGISNULL(0))
1136 {
1137 MemoryContextSwitchTo(oldcontext);
1139 }
1140
1141 dbid = PG_GETARG_OID(0);
1142 parse_ddl_options(fcinfo, 1, opts, lengthof(opts));
1143
1145 opts[0].isset && opts[0].boolval,
1146 opts[1].isset && !opts[1].boolval,
1147 opts[2].isset && !opts[2].boolval);
1148 funcctx->user_fctx = statements;
1149 funcctx->max_calls = list_length(statements);
1150
1151 MemoryContextSwitchTo(oldcontext);
1152 }
1153
1155 statements = (List *) funcctx->user_fctx;
1156
1157 if (funcctx->call_cntr < funcctx->max_calls)
1158 {
1159 char *stmt;
1160
1161 stmt = list_nth(statements, funcctx->call_cntr);
1162
1164 }
1165 else
1166 {
1169 }
1170}
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define lengthof(array)
Definition c.h:873
static List * pg_get_database_ddl_internal(Oid dbid, bool pretty, bool no_owner, bool no_tablespace)
Definition ddlutils.c:857
static void parse_ddl_options(FunctionCallInfo fcinfo, int variadic_start, DdlOption *opts, int nopts)
Definition ddlutils.c:102
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_ARGISNULL(n)
Definition fmgr.h:209
#define SRF_IS_FIRSTCALL()
Definition funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition funcapi.h:328
#define stmt
void list_free_deep(List *list)
Definition list.c:1560
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static int list_length(const List *l)
Definition pg_list.h:152
static void * list_nth(const List *list, int n)
Definition pg_list.h:331

References CStringGetTextDatum, DDL_OPT_BOOL, fb(), lengthof, list_free_deep(), list_length(), list_nth(), MemoryContextSwitchTo(), opts, parse_ddl_options(), PG_ARGISNULL, pg_get_database_ddl_internal(), PG_GETARG_OID, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and stmt.

◆ pg_get_database_ddl_internal()

static List * pg_get_database_ddl_internal ( Oid  dbid,
bool  pretty,
bool  no_owner,
bool  no_tablespace 
)
static

Definition at line 857 of file ddlutils.c.

859{
860 HeapTuple tuple;
863 bool isnull;
864 Datum datum;
865 const char *encoding;
866 char *dbname;
867 char *collate;
868 char *ctype;
869 Relation rel;
871 SysScanDesc scan;
874
876 if (!HeapTupleIsValid(tuple))
879 errmsg("database with OID %u does not exist", dbid)));
880
881 /* User must have connect privilege for target database. */
883 if (aclresult != ACLCHECK_OK)
885 get_database_name(dbid));
886
888 dbname = pstrdup(NameStr(dbform->datname));
889
890 /*
891 * We don't support generating DDL for system databases. The primary
892 * reason for this is that users shouldn't be recreating them.
893 */
894 if (strcmp(dbname, "template0") == 0 || strcmp(dbname, "template1") == 0)
897 errmsg("database \"%s\" is a system database", dbname),
898 errdetail("DDL generation is not supported for template0 and template1.")));
899
901
902 /* --- Build CREATE DATABASE statement --- */
903 appendStringInfo(&buf, "CREATE DATABASE %s", quote_identifier(dbname));
904
905 /*
906 * Always use template0: the target database already contains the catalog
907 * data from whatever template was used originally, so we must start from
908 * the pristine template to avoid duplication.
909 */
910 append_ddl_option(&buf, pretty, 4, "WITH TEMPLATE = template0");
911
912 /* ENCODING */
914 if (strlen(encoding) > 0)
915 append_ddl_option(&buf, pretty, 4, "ENCODING = %s",
917
918 /* LOCALE_PROVIDER */
919 if (dbform->datlocprovider == COLLPROVIDER_BUILTIN ||
920 dbform->datlocprovider == COLLPROVIDER_ICU ||
921 dbform->datlocprovider == COLLPROVIDER_LIBC)
922 append_ddl_option(&buf, pretty, 4, "LOCALE_PROVIDER = %s",
923 collprovider_name(dbform->datlocprovider));
924 else
927 errmsg("unrecognized locale provider: %c",
928 dbform->datlocprovider)));
929
930 /* LOCALE, LC_COLLATE, LC_CTYPE */
931 datum = SysCacheGetAttr(DATABASEOID, tuple,
933 collate = isnull ? NULL : TextDatumGetCString(datum);
934 datum = SysCacheGetAttr(DATABASEOID, tuple,
936 ctype = isnull ? NULL : TextDatumGetCString(datum);
937 if (collate != NULL && ctype != NULL && strcmp(collate, ctype) == 0)
938 {
939 append_ddl_option(&buf, pretty, 4, "LOCALE = %s",
940 quote_literal_cstr(collate));
941 }
942 else
943 {
944 if (collate != NULL)
945 append_ddl_option(&buf, pretty, 4, "LC_COLLATE = %s",
946 quote_literal_cstr(collate));
947 if (ctype != NULL)
948 append_ddl_option(&buf, pretty, 4, "LC_CTYPE = %s",
949 quote_literal_cstr(ctype));
950 }
951
952 /* LOCALE (provider-specific) */
953 datum = SysCacheGetAttr(DATABASEOID, tuple,
955 if (!isnull)
956 {
957 const char *locale = TextDatumGetCString(datum);
958
959 if (dbform->datlocprovider == COLLPROVIDER_BUILTIN)
960 append_ddl_option(&buf, pretty, 4, "BUILTIN_LOCALE = %s",
961 quote_literal_cstr(locale));
962 else if (dbform->datlocprovider == COLLPROVIDER_ICU)
963 append_ddl_option(&buf, pretty, 4, "ICU_LOCALE = %s",
964 quote_literal_cstr(locale));
965 }
966
967 /* ICU_RULES */
968 datum = SysCacheGetAttr(DATABASEOID, tuple,
970 if (!isnull && dbform->datlocprovider == COLLPROVIDER_ICU)
971 append_ddl_option(&buf, pretty, 4, "ICU_RULES = %s",
973
974 /* TABLESPACE */
975 if (!no_tablespace && OidIsValid(dbform->dattablespace))
976 {
977 char *spcname = get_tablespace_name(dbform->dattablespace);
978
979 if (pg_strcasecmp(spcname, "pg_default") != 0)
980 append_ddl_option(&buf, pretty, 4, "TABLESPACE = %s",
982 }
983
986
987 /* OWNER */
988 if (!no_owner && OidIsValid(dbform->datdba))
989 {
990 char *owner = GetUserNameFromId(dbform->datdba, false);
991
993 appendStringInfo(&buf, "ALTER DATABASE %s OWNER TO %s;",
995 pfree(owner);
997 }
998
999 /* CONNECTION LIMIT */
1000 if (dbform->datconnlimit != -1)
1001 {
1003 appendStringInfo(&buf, "ALTER DATABASE %s CONNECTION LIMIT = %d;",
1004 quote_identifier(dbname), dbform->datconnlimit);
1006 }
1007
1008 /* IS_TEMPLATE */
1009 if (dbform->datistemplate)
1010 {
1012 appendStringInfo(&buf, "ALTER DATABASE %s IS_TEMPLATE = true;",
1015 }
1016
1017 /* ALLOW_CONNECTIONS */
1018 if (!dbform->datallowconn)
1019 {
1021 appendStringInfo(&buf, "ALTER DATABASE %s ALLOW_CONNECTIONS = false;",
1024 }
1025
1026 ReleaseSysCache(tuple);
1027
1028 /*
1029 * Now scan pg_db_role_setting for ALTER DATABASE SET configurations.
1030 *
1031 * It is only database-wide (setrole = 0). It generates one ALTER
1032 * statement per setting.
1033 */
1035 ScanKeyInit(&scankey[0],
1038 ObjectIdGetDatum(dbid));
1039 ScanKeyInit(&scankey[1],
1043
1045 NULL, 2, scankey);
1046
1047 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1048 {
1050 Datum *settings;
1051 bool *nulls;
1052 int nsettings;
1053
1054 /*
1055 * The setconfig column is a text array in "name=value" format. It
1056 * should never be null for a valid row, but be defensive.
1057 */
1059 RelationGetDescr(rel), &isnull);
1060 if (isnull)
1061 continue;
1062
1064
1065 deconstruct_array_builtin(dbconfig, TEXTOID, &settings, &nulls, &nsettings);
1066
1067 for (int i = 0; i < nsettings; i++)
1068 {
1069 char *s,
1070 *p;
1071
1072 if (nulls[i])
1073 continue;
1074
1075 s = TextDatumGetCString(settings[i]);
1076 p = strchr(s, '=');
1077 if (p == NULL)
1078 {
1079 pfree(s);
1080 continue;
1081 }
1082 *p++ = '\0';
1083
1085 appendStringInfo(&buf, "ALTER DATABASE %s SET %s TO ",
1087 quote_identifier(s));
1088
1089 append_guc_value(&buf, s, p);
1090
1092
1094
1095 pfree(s);
1096 }
1097
1098 pfree(settings);
1099 pfree(nulls);
1100 pfree(dbconfig);
1101 }
1102
1103 systable_endscan(scan);
1105
1106 pfree(buf.data);
1107 pfree(dbname);
1108
1109 return statements;
1110}
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3879
#define DatumGetArrayTypeP(X)
Definition array.h:261
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
char * get_tablespace_name(Oid spc_oid)
#define NameStr(name)
Definition c.h:835
#define OidIsValid(objectId)
Definition c.h:858
static void append_ddl_option(StringInfo buf, bool pretty, int indent, const char *fmt,...) pg_attribute_printf(4
Definition ddlutils.c:234
static void static void append_guc_value(StringInfo buf, const char *name, const char *value)
Definition ddlutils.c:271
int errdetail(const char *fmt,...) pg_attribute_printf(1
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static void * GETSTRUCT(const HeapTupleData *tuple)
static char * encoding
Definition initdb.c:139
List * lappend(List *list, void *datum)
Definition list.c:339
#define AccessShareLock
Definition lockdefs.h:36
char * get_database_name(Oid dbid)
Definition lsyscache.c:1312
Oid GetUserId(void)
Definition miscinit.c:470
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition miscinit.c:990
@ OBJECT_DATABASE
#define ACL_CONNECT
Definition parsenodes.h:87
END_CATALOG_STRUCT typedef FormData_pg_database * Form_pg_database
#define pg_encoding_to_char
Definition pg_wchar.h:630
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
#define InvalidOid
#define RelationGetDescr(relation)
Definition rel.h:540
const char * quote_identifier(const char *ident)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define BTEqualStrategyNumber
Definition stratnum.h:31
char * dbname
Definition streamutil.c:49
void resetStringInfo(StringInfo str)
Definition stringinfo.c:126
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40

References AccessShareLock, ACL_CONNECT, aclcheck_error(), ACLCHECK_OK, append_ddl_option(), append_guc_value(), appendStringInfo(), appendStringInfoChar(), BTEqualStrategyNumber, buf, DatumGetArrayTypeP, dbname, deconstruct_array_builtin(), encoding, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), Form_pg_database, get_database_name(), get_tablespace_name(), GETSTRUCT(), GetUserId(), GetUserNameFromId(), heap_getattr(), HeapTupleIsValid, i, initStringInfo(), InvalidOid, lappend(), NameStr, NIL, object_aclcheck(), OBJECT_DATABASE, ObjectIdGetDatum(), OidIsValid, pfree(), pg_encoding_to_char, pg_strcasecmp(), pstrdup(), quote_identifier(), quote_literal_cstr(), RelationGetDescr, ReleaseSysCache(), resetStringInfo(), ScanKeyInit(), SearchSysCache1(), SysCacheGetAttr(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and TextDatumGetCString.

Referenced by pg_get_database_ddl().

◆ pg_get_role_ddl()

Datum pg_get_role_ddl ( PG_FUNCTION_ARGS  )

Definition at line 596 of file ddlutils.c.

597{
600
601 if (SRF_IS_FIRSTCALL())
602 {
603 MemoryContext oldcontext;
604 Oid roleid;
605 DdlOption opts[] = {
606 {"pretty", DDL_OPT_BOOL},
607 {"memberships", DDL_OPT_BOOL},
608 };
609
611 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
612
613 if (PG_ARGISNULL(0))
614 {
615 MemoryContextSwitchTo(oldcontext);
617 }
618
619 roleid = PG_GETARG_OID(0);
620 parse_ddl_options(fcinfo, 1, opts, lengthof(opts));
621
623 opts[0].isset && opts[0].boolval,
624 !opts[1].isset || opts[1].boolval);
625 funcctx->user_fctx = statements;
626 funcctx->max_calls = list_length(statements);
627
628 MemoryContextSwitchTo(oldcontext);
629 }
630
632 statements = (List *) funcctx->user_fctx;
633
634 if (funcctx->call_cntr < funcctx->max_calls)
635 {
636 char *stmt;
637
638 stmt = list_nth(statements, funcctx->call_cntr);
639
641 }
642 else
643 {
646 }
647}
static List * pg_get_role_ddl_internal(Oid roleid, bool pretty, bool memberships)
Definition ddlutils.c:318

References CStringGetTextDatum, DDL_OPT_BOOL, fb(), lengthof, list_free_deep(), list_length(), list_nth(), MemoryContextSwitchTo(), opts, parse_ddl_options(), PG_ARGISNULL, pg_get_role_ddl_internal(), PG_GETARG_OID, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and stmt.

◆ pg_get_role_ddl_internal()

static List * pg_get_role_ddl_internal ( Oid  roleid,
bool  pretty,
bool  memberships 
)
static

Definition at line 318 of file ddlutils.c.

319{
320 HeapTuple tuple;
323 char *rolname;
325 bool isnull;
326 Relation rel;
328 SysScanDesc scan;
330
331 tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
332 if (!HeapTupleIsValid(tuple))
335 errmsg("role with OID %u does not exist", roleid)));
336
338 rolname = pstrdup(NameStr(roleform->rolname));
339
340 /* User must have SELECT privilege on pg_authid. */
342 {
343 ReleaseSysCache(tuple);
346 errmsg("permission denied for role %s", rolname)));
347 }
348
349 /*
350 * We don't support generating DDL for system roles. The primary reason
351 * for this is that users shouldn't be recreating them.
352 */
356 errmsg("role name \"%s\" is reserved", rolname),
357 errdetail("Role names starting with \"pg_\" are reserved for system roles.")));
358
360 appendStringInfo(&buf, "CREATE ROLE %s", quote_identifier(rolname));
361
362 /*
363 * Append role attributes. The order here follows the same sequence as
364 * you'd typically write them in a CREATE ROLE command, though any order
365 * is actually acceptable to the parser.
366 */
367 append_ddl_option(&buf, pretty, 4, "%s",
368 roleform->rolsuper ? "SUPERUSER" : "NOSUPERUSER");
369
370 append_ddl_option(&buf, pretty, 4, "%s",
371 roleform->rolinherit ? "INHERIT" : "NOINHERIT");
372
373 append_ddl_option(&buf, pretty, 4, "%s",
374 roleform->rolcreaterole ? "CREATEROLE" : "NOCREATEROLE");
375
376 append_ddl_option(&buf, pretty, 4, "%s",
377 roleform->rolcreatedb ? "CREATEDB" : "NOCREATEDB");
378
379 append_ddl_option(&buf, pretty, 4, "%s",
380 roleform->rolcanlogin ? "LOGIN" : "NOLOGIN");
381
382 append_ddl_option(&buf, pretty, 4, "%s",
383 roleform->rolreplication ? "REPLICATION" : "NOREPLICATION");
384
385 append_ddl_option(&buf, pretty, 4, "%s",
386 roleform->rolbypassrls ? "BYPASSRLS" : "NOBYPASSRLS");
387
388 /*
389 * CONNECTION LIMIT is only interesting if it's not -1 (the default,
390 * meaning no limit).
391 */
392 if (roleform->rolconnlimit >= 0)
393 append_ddl_option(&buf, pretty, 4, "CONNECTION LIMIT %d",
394 roleform->rolconnlimit);
395
398 &isnull);
399 if (!isnull)
400 {
401 TimestampTz ts;
402 int tz;
403 struct pg_tm tm;
404 fsec_t fsec;
405 const char *tzn;
406 char ts_str[MAXDATELEN + 1];
407
409 if (TIMESTAMP_NOT_FINITE(ts))
411 else if (timestamp2tm(ts, &tz, &tm, &fsec, &tzn, NULL) == 0)
412 EncodeDateTime(&tm, fsec, true, tz, tzn, USE_ISO_DATES, ts_str);
413 else
416 errmsg("timestamp out of range")));
417
418 append_ddl_option(&buf, pretty, 4, "VALID UNTIL %s",
420 }
421
422 ReleaseSysCache(tuple);
423
424 /*
425 * We intentionally omit PASSWORD. There's no way to retrieve the
426 * original password text from the stored hash, and even if we could,
427 * exposing passwords through a SQL function would be a security issue.
428 * Users must set passwords separately after recreating roles.
429 */
430
432
434
435 /*
436 * Now scan pg_db_role_setting for ALTER ROLE SET configurations.
437 *
438 * These can be role-wide (setdatabase = 0) or specific to a particular
439 * database (setdatabase = a valid DB OID). It generates one ALTER
440 * statement per setting.
441 */
446 ObjectIdGetDatum(roleid));
448 NULL, 1, &scankey);
449
450 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
451 {
453 Oid datid = setting->setdatabase;
454 Datum datum;
456 Datum *settings;
457 bool *nulls;
458 int nsettings;
459 char *datname = NULL;
460
461 /*
462 * If setdatabase is valid, this is a role-in-database setting;
463 * otherwise it's a role-wide setting. Look up the database name once
464 * for all settings in this row.
465 */
466 if (OidIsValid(datid))
467 {
469 /* Database has been dropped; skip all settings in this row. */
470 if (datname == NULL)
471 continue;
472 }
473
474 /*
475 * The setconfig column is a text array in "name=value" format. It
476 * should never be null for a valid row, but be defensive.
477 */
479 RelationGetDescr(rel), &isnull);
480 if (isnull)
481 continue;
482
484
486
487 for (int i = 0; i < nsettings; i++)
488 {
489 char *s,
490 *p;
491
492 if (nulls[i])
493 continue;
494
495 s = TextDatumGetCString(settings[i]);
496 p = strchr(s, '=');
497 if (p == NULL)
498 {
499 pfree(s);
500 continue;
501 }
502 *p++ = '\0';
503
504 /* Build a fresh ALTER ROLE statement for this setting */
506 appendStringInfo(&buf, "ALTER ROLE %s", quote_identifier(rolname));
507
508 if (datname != NULL)
509 appendStringInfo(&buf, " IN DATABASE %s",
511
512 appendStringInfo(&buf, " SET %s TO ",
514
515 append_guc_value(&buf, s, p);
516
518
520
521 pfree(s);
522 }
523
524 pfree(settings);
525 pfree(nulls);
527
528 if (datname != NULL)
529 pfree(datname);
530 }
531
532 systable_endscan(scan);
534
535 /*
536 * Scan pg_auth_members for role memberships. We look for rows where
537 * member = roleid, meaning this role has been granted membership in other
538 * roles.
539 */
540 if (memberships)
541 {
546 ObjectIdGetDatum(roleid));
548 NULL, 1, &scankey);
549
550 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
551 {
553 char *granted_role;
554 char *grantor;
555
556 granted_role = GetUserNameFromId(memform->roleid, false);
557 grantor = GetUserNameFromId(memform->grantor, false);
558
560 appendStringInfo(&buf, "GRANT %s TO %s",
563 appendStringInfo(&buf, " WITH ADMIN %s, INHERIT %s, SET %s",
564 memform->admin_option ? "TRUE" : "FALSE",
565 memform->inherit_option ? "TRUE" : "FALSE",
566 memform->set_option ? "TRUE" : "FALSE");
567 appendStringInfo(&buf, " GRANTED BY %s;",
568 quote_identifier(grantor));
569
571
573 pfree(grantor);
574 }
575
576 systable_endscan(scan);
578 }
579
580 pfree(buf.data);
581 pfree(rolname);
582
583 return statements;
584}
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition aclchk.c:4082
void set_option(char *arg)
Definition args.c:261
void EncodeDateTime(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
Definition datetime.c:4465
void EncodeSpecialTimestamp(Timestamp dt, char *str)
Definition timestamp.c:1581
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition timestamp.c:1904
bool IsReservedName(const char *name)
Definition catalog.c:278
int64 TimestampTz
Definition timestamp.h:39
int32 fsec_t
Definition timestamp.h:41
#define TIMESTAMP_NOT_FINITE(j)
Definition timestamp.h:169
#define MAXDATELEN
Definition datetime.h:200
static struct pg_tm tm
Definition localtime.c:104
#define USE_ISO_DATES
Definition miscadmin.h:237
#define ACL_SELECT
Definition parsenodes.h:77
END_CATALOG_STRUCT typedef FormData_pg_auth_members * Form_pg_auth_members
NameData rolname
Definition pg_authid.h:36
END_CATALOG_STRUCT typedef FormData_pg_authid * Form_pg_authid
Definition pg_authid.h:60
NameData datname
Definition pg_database.h:37
END_CATALOG_STRUCT typedef FormData_pg_db_role_setting * Form_pg_db_role_setting
Definition pgtime.h:35
static TimestampTz DatumGetTimestampTz(Datum X)
Definition timestamp.h:34

References AccessShareLock, ACL_SELECT, ACLCHECK_OK, append_ddl_option(), append_guc_value(), appendStringInfo(), appendStringInfoChar(), BTEqualStrategyNumber, buf, datname, DatumGetArrayTypeP, DatumGetTimestampTz(), deconstruct_array_builtin(), EncodeDateTime(), EncodeSpecialTimestamp(), ereport, errcode(), errdetail(), errmsg, ERROR, fb(), Form_pg_auth_members, Form_pg_authid, Form_pg_db_role_setting, get_database_name(), GETSTRUCT(), GetUserId(), GetUserNameFromId(), heap_getattr(), HeapTupleIsValid, i, initStringInfo(), IsReservedName(), lappend(), MAXDATELEN, NameStr, NIL, ObjectIdGetDatum(), OidIsValid, pfree(), pg_class_aclcheck(), pstrdup(), quote_identifier(), quote_literal_cstr(), RelationGetDescr, ReleaseSysCache(), resetStringInfo(), rolname, ScanKeyInit(), SearchSysCache1(), SysCacheGetAttr(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, and USE_ISO_DATES.

Referenced by pg_get_role_ddl().

◆ pg_get_tablespace_ddl_internal()

static List * pg_get_tablespace_ddl_internal ( Oid  tsid,
bool  pretty,
bool  no_owner 
)
static

Definition at line 658 of file ddlutils.c.

659{
660 HeapTuple tuple;
663 char *spcname;
664 char *spcowner;
665 char *path;
666 bool isNull;
667 Datum datum;
669
671 if (!HeapTupleIsValid(tuple))
674 errmsg("tablespace with OID %u does not exist",
675 tsid)));
676
678 spcname = pstrdup(NameStr(tspForm->spcname));
679
680 /* User must have SELECT privilege on pg_tablespace. */
682 {
683 ReleaseSysCache(tuple);
685 }
686
687 /*
688 * We don't support generating DDL for system tablespaces. The primary
689 * reason for this is that users shouldn't be recreating them.
690 */
694 errmsg("tablespace name \"%s\" is reserved", spcname),
695 errdetail("Tablespace names starting with \"pg_\" are reserved for system tablespaces.")));
696
698
699 /* Start building the CREATE TABLESPACE statement */
700 appendStringInfo(&buf, "CREATE TABLESPACE %s", quote_identifier(spcname));
701
702 /* Add OWNER clause */
703 if (!no_owner)
704 {
705 spcowner = GetUserNameFromId(tspForm->spcowner, false);
706 append_ddl_option(&buf, pretty, 4, "OWNER %s",
709 }
710
711 /* Find tablespace directory path */
712 path = get_tablespace_location(tsid);
713
714 /* Add directory LOCATION (path), if it exists */
715 if (path[0] != '\0')
716 {
717 /*
718 * Special case: if the tablespace was created with GUC
719 * "allow_in_place_tablespaces = true" and "LOCATION ''", path will
720 * begin with "pg_tblspc/". In that case, show "LOCATION ''" as the
721 * user originally specified.
722 */
724 append_ddl_option(&buf, pretty, 4, "LOCATION ''");
725 else
726 append_ddl_option(&buf, pretty, 4, "LOCATION %s",
727 quote_literal_cstr(path));
728 }
729 pfree(path);
730
733
734 /* Check for tablespace options */
735 datum = SysCacheGetAttr(TABLESPACEOID, tuple,
737 if (!isNull)
738 {
740 appendStringInfo(&buf, "ALTER TABLESPACE %s SET (",
742 get_reloptions(&buf, datum);
745 }
746
747 ReleaseSysCache(tuple);
748 pfree(spcname);
749 pfree(buf.data);
750
751 return statements;
752}
@ ACLCHECK_NO_PRIV
Definition acl.h:185
@ OBJECT_TABLESPACE
char * get_tablespace_location(Oid tablespaceOid)
END_CATALOG_STRUCT typedef FormData_pg_tablespace * Form_pg_tablespace
#define PG_TBLSPC_DIR_SLASH
Definition relpath.h:42
void get_reloptions(StringInfo buf, Datum reloptions)

References ACL_SELECT, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_OK, append_ddl_option(), appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), buf, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), Form_pg_tablespace, get_reloptions(), get_tablespace_location(), GETSTRUCT(), GetUserId(), GetUserNameFromId(), HeapTupleIsValid, initStringInfo(), IsReservedName(), lappend(), NameStr, NIL, OBJECT_TABLESPACE, ObjectIdGetDatum(), pfree(), pg_class_aclcheck(), PG_TBLSPC_DIR_SLASH, pstrdup(), quote_identifier(), quote_literal_cstr(), ReleaseSysCache(), resetStringInfo(), SearchSysCache1(), and SysCacheGetAttr().

Referenced by pg_get_tablespace_ddl_srf().

◆ pg_get_tablespace_ddl_name()

Datum pg_get_tablespace_ddl_name ( PG_FUNCTION_ARGS  )

Definition at line 831 of file ddlutils.c.

832{
833 Oid tsid = InvalidOid;
835 bool isnull;
836
837 isnull = PG_ARGISNULL(0);
838
839 if (!isnull)
840 {
842 tsid = get_tablespace_oid(NameStr(*tspname), false);
843 }
844
845 return pg_get_tablespace_ddl_srf(fcinfo, tsid, isnull);
846}
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
static Datum pg_get_tablespace_ddl_srf(FunctionCallInfo fcinfo, Oid tsid, bool isnull)
Definition ddlutils.c:758
#define PG_GETARG_NAME(n)
Definition fmgr.h:279
Definition c.h:830

References fb(), get_tablespace_oid(), InvalidOid, NameStr, PG_ARGISNULL, pg_get_tablespace_ddl_srf(), and PG_GETARG_NAME.

◆ pg_get_tablespace_ddl_oid()

Datum pg_get_tablespace_ddl_oid ( PG_FUNCTION_ARGS  )

Definition at line 814 of file ddlutils.c.

815{
816 Oid tsid = InvalidOid;
817 bool isnull;
818
819 isnull = PG_ARGISNULL(0);
820 if (!isnull)
821 tsid = PG_GETARG_OID(0);
822
823 return pg_get_tablespace_ddl_srf(fcinfo, tsid, isnull);
824}

References InvalidOid, PG_ARGISNULL, pg_get_tablespace_ddl_srf(), and PG_GETARG_OID.

◆ pg_get_tablespace_ddl_srf()

static Datum pg_get_tablespace_ddl_srf ( FunctionCallInfo  fcinfo,
Oid  tsid,
bool  isnull 
)
static

Definition at line 758 of file ddlutils.c.

759{
762
763 if (SRF_IS_FIRSTCALL())
764 {
765 MemoryContext oldcontext;
766 DdlOption opts[] = {
767 {"pretty", DDL_OPT_BOOL},
768 {"owner", DDL_OPT_BOOL},
769 };
770
772 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
773
774 if (isnull)
775 {
776 MemoryContextSwitchTo(oldcontext);
778 }
779
780 parse_ddl_options(fcinfo, 1, opts, lengthof(opts));
781
783 opts[0].isset && opts[0].boolval,
784 opts[1].isset && !opts[1].boolval);
785 funcctx->user_fctx = statements;
786 funcctx->max_calls = list_length(statements);
787
788 MemoryContextSwitchTo(oldcontext);
789 }
790
792 statements = (List *) funcctx->user_fctx;
793
794 if (funcctx->call_cntr < funcctx->max_calls)
795 {
796 char *stmt;
797
798 stmt = (char *) list_nth(statements, funcctx->call_cntr);
799
801 }
802 else
803 {
806 }
807}
static List * pg_get_tablespace_ddl_internal(Oid tsid, bool pretty, bool no_owner)
Definition ddlutils.c:658

References CStringGetTextDatum, DDL_OPT_BOOL, fb(), lengthof, list_free_deep(), list_length(), list_nth(), MemoryContextSwitchTo(), opts, parse_ddl_options(), pg_get_tablespace_ddl_internal(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and stmt.

Referenced by pg_get_tablespace_ddl_name(), and pg_get_tablespace_ddl_oid().