PostgreSQL Source Code  git master
conversioncmds.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * conversioncmds.c
4  * conversion creation command support code
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/commands/conversioncmds.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/htup_details.h"
18 #include "catalog/dependency.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_conversion.h"
21 #include "catalog/pg_type.h"
22 #include "commands/alter.h"
24 #include "mb/pg_wchar.h"
25 #include "miscadmin.h"
26 #include "parser/parse_func.h"
27 #include "utils/builtins.h"
28 #include "utils/lsyscache.h"
29 #include "utils/rel.h"
30 #include "utils/syscache.h"
31 
32 /*
33  * CREATE CONVERSION
34  */
37 {
38  Oid namespaceId;
39  char *conversion_name;
40  AclResult aclresult;
41  int from_encoding;
42  int to_encoding;
43  Oid funcoid;
44  const char *from_encoding_name = stmt->for_encoding_name;
45  const char *to_encoding_name = stmt->to_encoding_name;
46  List *func_name = stmt->func_name;
47  static const Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, INTERNALOID, INT4OID};
48  char result[1];
49 
50  /* Convert list of names to a name and namespace */
52  &conversion_name);
53 
54  /* Check we have creation rights in target namespace */
55  aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
56  if (aclresult != ACLCHECK_OK)
57  aclcheck_error(aclresult, OBJECT_SCHEMA,
58  get_namespace_name(namespaceId));
59 
60  /* Check the encoding names */
61  from_encoding = pg_char_to_encoding(from_encoding_name);
62  if (from_encoding < 0)
63  ereport(ERROR,
64  (errcode(ERRCODE_UNDEFINED_OBJECT),
65  errmsg("source encoding \"%s\" does not exist",
66  from_encoding_name)));
67 
68  to_encoding = pg_char_to_encoding(to_encoding_name);
69  if (to_encoding < 0)
70  ereport(ERROR,
71  (errcode(ERRCODE_UNDEFINED_OBJECT),
72  errmsg("destination encoding \"%s\" does not exist",
73  to_encoding_name)));
74 
75  /*
76  * We consider conversions to or from SQL_ASCII to be meaningless. (If
77  * you wish to change this, note that pg_do_encoding_conversion() and its
78  * sister functions have hard-wired fast paths for any conversion in which
79  * the source or target encoding is SQL_ASCII, so that an encoding
80  * conversion function declared for such a case will never be used.)
81  */
82  if (from_encoding == PG_SQL_ASCII || to_encoding == PG_SQL_ASCII)
83  ereport(ERROR,
84  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
85  errmsg("encoding conversion to or from \"SQL_ASCII\" is not supported")));
86 
87  /*
88  * Check the existence of the conversion function. Function name could be
89  * a qualified name.
90  */
91  funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid),
92  funcargs, false);
93 
94  /* Check it returns VOID, else it's probably the wrong function */
95  if (get_func_rettype(funcoid) != VOIDOID)
96  ereport(ERROR,
97  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
98  errmsg("encoding conversion function %s must return type %s",
99  NameListToString(func_name), "void")));
100 
101  /* Check we have EXECUTE rights for the function */
102  aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
103  if (aclresult != ACLCHECK_OK)
104  aclcheck_error(aclresult, OBJECT_FUNCTION,
105  NameListToString(func_name));
106 
107  /*
108  * Check that the conversion function is suitable for the requested source
109  * and target encodings. We do that by calling the function with an empty
110  * string; the conversion function should throw an error if it can't
111  * perform the requested conversion.
112  */
113  OidFunctionCall5(funcoid,
114  Int32GetDatum(from_encoding),
115  Int32GetDatum(to_encoding),
116  CStringGetDatum(""),
117  CStringGetDatum(result),
118  Int32GetDatum(0));
119 
120  /*
121  * All seem ok, go ahead (possible failure would be a duplicate conversion
122  * name)
123  */
124  return ConversionCreate(conversion_name, namespaceId, GetUserId(),
125  from_encoding, to_encoding, funcoid, stmt->def);
126 }
int pg_char_to_encoding(const char *name)
Definition: encnames.c:551
Oid GetUserId(void)
Definition: miscinit.c:380
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2987
int errcode(int sqlerrcode)
Definition: elog.c:570
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4693
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1457
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2100
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel, rest)
Definition: elog.h:141
char * NameListToString(List *names)
Definition: namespace.c:3094
ObjectAddress ConversionCreate(const char *conname, Oid connamespace, Oid conowner, int32 conforencoding, int32 contoencoding, Oid conproc, bool def)
Definition: pg_conversion.c:41
AclResult
Definition: acl.h:177
ObjectAddress CreateConversionCommand(CreateConversionStmt *stmt)
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define ACL_EXECUTE
Definition: parsenodes.h:81
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4655
Definition: pg_list.h:50
#define OidFunctionCall5(functionId, arg1, arg2, arg3, arg4, arg5)
Definition: fmgr.h:663