Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * conversioncmds.c
4 : * conversion creation command support code
5 : *
6 : * Portions Copyright (c) 1996-2023, 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_namespace.h"
22 : #include "catalog/pg_proc.h"
23 : #include "catalog/pg_type.h"
24 : #include "commands/alter.h"
25 : #include "commands/conversioncmds.h"
26 : #include "mb/pg_wchar.h"
27 : #include "miscadmin.h"
28 : #include "parser/parse_func.h"
29 : #include "utils/acl.h"
30 : #include "utils/builtins.h"
31 : #include "utils/lsyscache.h"
32 : #include "utils/rel.h"
33 : #include "utils/syscache.h"
34 :
35 : /*
36 : * CREATE CONVERSION
37 : */
38 : ObjectAddress
7577 ishii 39 GIC 32 : CreateConversionCommand(CreateConversionStmt *stmt)
40 : {
7577 ishii 41 ECB : Oid namespaceId;
42 : char *conversion_name;
43 : AclResult aclresult;
44 : int from_encoding;
45 : int to_encoding;
46 : Oid funcoid;
7203 tgl 47 GIC 32 : const char *from_encoding_name = stmt->for_encoding_name;
7577 ishii 48 32 : const char *to_encoding_name = stmt->to_encoding_name;
7522 bruce 49 CBC 32 : List *func_name = stmt->func_name;
738 heikki.linnakangas 50 ECB : static const Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, INTERNALOID, INT4OID, BOOLOID};
5154 51 : char result[1];
52 : Datum funcresult;
53 :
54 : /* Convert list of names to a name and namespace */
7463 tgl 55 GIC 32 : namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name,
56 : &conversion_name);
7577 ishii 57 ECB :
58 : /* Check we have creation rights in target namespace */
147 peter 59 GNC 32 : aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(), ACL_CREATE);
7577 ishii 60 GIC 32 : if (aclresult != ACLCHECK_OK)
1954 peter_e 61 LBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
7191 tgl 62 0 : get_namespace_name(namespaceId));
7577 ishii 63 EUB :
64 : /* Check the encoding names */
7203 tgl 65 GIC 32 : from_encoding = pg_char_to_encoding(from_encoding_name);
66 32 : if (from_encoding < 0)
7203 tgl 67 LBC 0 : ereport(ERROR,
7203 tgl 68 ECB : (errcode(ERRCODE_UNDEFINED_OBJECT),
7203 tgl 69 EUB : errmsg("source encoding \"%s\" does not exist",
70 : from_encoding_name)));
71 :
7577 ishii 72 GIC 32 : to_encoding = pg_char_to_encoding(to_encoding_name);
73 32 : if (to_encoding < 0)
7203 tgl 74 LBC 0 : ereport(ERROR,
7203 tgl 75 ECB : (errcode(ERRCODE_UNDEFINED_OBJECT),
7203 tgl 76 EUB : errmsg("destination encoding \"%s\" does not exist",
77 : to_encoding_name)));
78 :
79 : /*
80 : * We consider conversions to or from SQL_ASCII to be meaningless. (If
81 : * you wish to change this, note that pg_do_encoding_conversion() and its
82 : * sister functions have hard-wired fast paths for any conversion in which
83 : * the source or target encoding is SQL_ASCII, so that an encoding
84 : * conversion function declared for such a case will never be used.)
85 : */
1374 tgl 86 GIC 32 : if (from_encoding == PG_SQL_ASCII || to_encoding == PG_SQL_ASCII)
1374 tgl 87 UIC 0 : ereport(ERROR,
1374 tgl 88 ECB : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1374 tgl 89 EUB : errmsg("encoding conversion to or from \"SQL_ASCII\" is not supported")));
90 :
91 : /*
92 : * Check the existence of the conversion function. Function name could be
93 : * a qualified name.
94 : */
7219 tgl 95 GIC 32 : funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid),
96 : funcargs, false);
7577 ishii 97 ECB :
98 : /* Check it returns int4, else it's probably the wrong function */
738 heikki.linnakangas 99 GIC 32 : if (get_func_rettype(funcoid) != INT4OID)
5259 tgl 100 UIC 0 : ereport(ERROR,
5259 tgl 101 ECB : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2495 rhaas 102 EUB : errmsg("encoding conversion function %s must return type %s",
103 : NameListToString(func_name), "integer")));
104 :
105 : /* Check we have EXECUTE rights for the function */
147 peter 106 GNC 32 : aclresult = object_aclcheck(ProcedureRelationId, funcoid, GetUserId(), ACL_EXECUTE);
7577 ishii 107 GIC 32 : if (aclresult != ACLCHECK_OK)
1954 peter_e 108 LBC 0 : aclcheck_error(aclresult, OBJECT_FUNCTION,
7191 tgl 109 0 : NameListToString(func_name));
7522 bruce 110 EUB :
5154 heikki.linnakangas 111 : /*
112 : * Check that the conversion function is suitable for the requested source
113 : * and target encodings. We do that by calling the function with an empty
114 : * string; the conversion function should throw an error if it can't
115 : * perform the requested conversion.
116 : */
738 heikki.linnakangas 117 GIC 32 : funcresult = OidFunctionCall6(funcoid,
118 : Int32GetDatum(from_encoding),
738 heikki.linnakangas 119 ECB : Int32GetDatum(to_encoding),
120 : CStringGetDatum(""),
121 : CStringGetDatum(result),
122 : Int32GetDatum(0),
123 : BoolGetDatum(false));
124 :
125 : /*
126 : * The function should return 0 for empty input. Might as well check that,
127 : * too.
128 : */
738 heikki.linnakangas 129 GIC 32 : if (DatumGetInt32(funcresult) != 0)
738 heikki.linnakangas 130 UIC 0 : ereport(ERROR,
738 heikki.linnakangas 131 ECB : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
738 heikki.linnakangas 132 EUB : errmsg("encoding conversion function %s returned incorrect result for empty input",
133 : NameListToString(func_name))));
134 :
135 : /*
136 : * All seem ok, go ahead (possible failure would be a duplicate conversion
137 : * name)
138 : */
3759 rhaas 139 GIC 32 : return ConversionCreate(conversion_name, namespaceId, GetUserId(),
140 32 : from_encoding, to_encoding, funcoid, stmt->def);
7577 ishii 141 ECB : }
|