Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * conversioncmds.c
4 : * conversion creation command support code
5 : *
6 : * Portions Copyright (c) 1996-2017, 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_conversion_fn.h"
22 : #include "catalog/pg_type.h"
23 : #include "commands/alter.h"
24 : #include "commands/conversioncmds.h"
25 : #include "mb/pg_wchar.h"
26 : #include "miscadmin.h"
27 : #include "parser/parse_func.h"
28 : #include "utils/builtins.h"
29 : #include "utils/lsyscache.h"
30 : #include "utils/rel.h"
31 : #include "utils/syscache.h"
32 :
33 : /*
34 : * CREATE CONVERSION
35 : */
36 : ObjectAddress
37 142 : CreateConversionCommand(CreateConversionStmt *stmt)
38 : {
39 : Oid namespaceId;
40 : char *conversion_name;
41 : AclResult aclresult;
42 : int from_encoding;
43 : int to_encoding;
44 : Oid funcoid;
45 142 : const char *from_encoding_name = stmt->for_encoding_name;
46 142 : const char *to_encoding_name = stmt->to_encoding_name;
47 142 : List *func_name = stmt->func_name;
48 : static const Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, INTERNALOID, INT4OID};
49 : char result[1];
50 :
51 : /* Convert list of names to a name and namespace */
52 142 : namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name,
53 : &conversion_name);
54 :
55 : /* Check we have creation rights in target namespace */
56 142 : aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
57 142 : if (aclresult != ACLCHECK_OK)
58 0 : aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
59 0 : get_namespace_name(namespaceId));
60 :
61 : /* Check the encoding names */
62 142 : from_encoding = pg_char_to_encoding(from_encoding_name);
63 142 : if (from_encoding < 0)
64 0 : ereport(ERROR,
65 : (errcode(ERRCODE_UNDEFINED_OBJECT),
66 : errmsg("source encoding \"%s\" does not exist",
67 : from_encoding_name)));
68 :
69 142 : to_encoding = pg_char_to_encoding(to_encoding_name);
70 142 : if (to_encoding < 0)
71 0 : ereport(ERROR,
72 : (errcode(ERRCODE_UNDEFINED_OBJECT),
73 : errmsg("destination encoding \"%s\" does not exist",
74 : to_encoding_name)));
75 :
76 : /*
77 : * Check the existence of the conversion function. Function name could be
78 : * a qualified name.
79 : */
80 142 : funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid),
81 : funcargs, false);
82 :
83 : /* Check it returns VOID, else it's probably the wrong function */
84 142 : if (get_func_rettype(funcoid) != VOIDOID)
85 0 : ereport(ERROR,
86 : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
87 : errmsg("encoding conversion function %s must return type %s",
88 : NameListToString(func_name), "void")));
89 :
90 : /* Check we have EXECUTE rights for the function */
91 142 : aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE);
92 142 : if (aclresult != ACLCHECK_OK)
93 0 : aclcheck_error(aclresult, ACL_KIND_PROC,
94 0 : NameListToString(func_name));
95 :
96 : /*
97 : * Check that the conversion function is suitable for the requested source
98 : * and target encodings. We do that by calling the function with an empty
99 : * string; the conversion function should throw an error if it can't
100 : * perform the requested conversion.
101 : */
102 142 : OidFunctionCall5(funcoid,
103 : Int32GetDatum(from_encoding),
104 : Int32GetDatum(to_encoding),
105 : CStringGetDatum(""),
106 : CStringGetDatum(result),
107 : Int32GetDatum(0));
108 :
109 : /*
110 : * All seem ok, go ahead (possible failure would be a duplicate conversion
111 : * name)
112 : */
113 142 : return ConversionCreate(conversion_name, namespaceId, GetUserId(),
114 142 : from_encoding, to_encoding, funcoid, stmt->def);
115 : }
|