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"
23#include "commands/conversioncmds.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 */
35ObjectAddress
36CreateConversionCommand(CreateConversionStmt *stmt)
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 */
51 namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name,
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 * Check the existence of the conversion function. Function name could be
77 * a qualified name.
78 */
79 funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid),
80 funcargs, false);
81
82 /* Check it returns VOID, else it's probably the wrong function */
83 if (get_func_rettype(funcoid) != VOIDOID)
84 ereport(ERROR,
85 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
86 errmsg("encoding conversion function %s must return type %s",
87 NameListToString(func_name), "void")));
88
89 /* Check we have EXECUTE rights for the function */
90 aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
91 if (aclresult != ACLCHECK_OK)
92 aclcheck_error(aclresult, OBJECT_FUNCTION,
93 NameListToString(func_name));
94
95 /*
96 * Check that the conversion function is suitable for the requested source
97 * and target encodings. We do that by calling the function with an empty
98 * string; the conversion function should throw an error if it can't
99 * perform the requested conversion.
100 */
101 OidFunctionCall5(funcoid,
102 Int32GetDatum(from_encoding),
103 Int32GetDatum(to_encoding),
104 CStringGetDatum(""),
105 CStringGetDatum(result),
106 Int32GetDatum(0));
107
108 /*
109 * All seem ok, go ahead (possible failure would be a duplicate conversion
110 * name)
111 */
112 return ConversionCreate(conversion_name, namespaceId, GetUserId(),
113 from_encoding, to_encoding, funcoid, stmt->def);
114}
115