Move routines to manipulate WAL into PostgreSQL::Test::Cluster
[pgsql.git] / src / backend / commands / conversioncmds.c
blobd3ecc76d97b14d13c0cd2c293cdc7bf587073d31
1 /*-------------------------------------------------------------------------
3 * conversioncmds.c
4 * conversion creation command support code
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/commands/conversioncmds.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include "catalog/pg_conversion.h"
18 #include "catalog/pg_namespace.h"
19 #include "catalog/pg_proc.h"
20 #include "catalog/pg_type.h"
21 #include "commands/conversioncmds.h"
22 #include "mb/pg_wchar.h"
23 #include "miscadmin.h"
24 #include "parser/parse_func.h"
25 #include "utils/acl.h"
26 #include "utils/lsyscache.h"
29 * CREATE CONVERSION
31 ObjectAddress
32 CreateConversionCommand(CreateConversionStmt *stmt)
34 Oid namespaceId;
35 char *conversion_name;
36 AclResult aclresult;
37 int from_encoding;
38 int to_encoding;
39 Oid funcoid;
40 const char *from_encoding_name = stmt->for_encoding_name;
41 const char *to_encoding_name = stmt->to_encoding_name;
42 List *func_name = stmt->func_name;
43 static const Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, INTERNALOID, INT4OID, BOOLOID};
44 char result[1];
45 Datum funcresult;
47 /* Convert list of names to a name and namespace */
48 namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name,
49 &conversion_name);
51 /* Check we have creation rights in target namespace */
52 aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(), ACL_CREATE);
53 if (aclresult != ACLCHECK_OK)
54 aclcheck_error(aclresult, OBJECT_SCHEMA,
55 get_namespace_name(namespaceId));
57 /* Check the encoding names */
58 from_encoding = pg_char_to_encoding(from_encoding_name);
59 if (from_encoding < 0)
60 ereport(ERROR,
61 (errcode(ERRCODE_UNDEFINED_OBJECT),
62 errmsg("source encoding \"%s\" does not exist",
63 from_encoding_name)));
65 to_encoding = pg_char_to_encoding(to_encoding_name);
66 if (to_encoding < 0)
67 ereport(ERROR,
68 (errcode(ERRCODE_UNDEFINED_OBJECT),
69 errmsg("destination encoding \"%s\" does not exist",
70 to_encoding_name)));
73 * We consider conversions to or from SQL_ASCII to be meaningless. (If
74 * you wish to change this, note that pg_do_encoding_conversion() and its
75 * sister functions have hard-wired fast paths for any conversion in which
76 * the source or target encoding is SQL_ASCII, so that an encoding
77 * conversion function declared for such a case will never be used.)
79 if (from_encoding == PG_SQL_ASCII || to_encoding == PG_SQL_ASCII)
80 ereport(ERROR,
81 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
82 errmsg("encoding conversion to or from \"SQL_ASCII\" is not supported")));
85 * Check the existence of the conversion function. Function name could be
86 * a qualified name.
88 funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid),
89 funcargs, false);
91 /* Check it returns int4, else it's probably the wrong function */
92 if (get_func_rettype(funcoid) != INT4OID)
93 ereport(ERROR,
94 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
95 errmsg("encoding conversion function %s must return type %s",
96 NameListToString(func_name), "integer")));
98 /* Check we have EXECUTE rights for the function */
99 aclresult = object_aclcheck(ProcedureRelationId, funcoid, GetUserId(), ACL_EXECUTE);
100 if (aclresult != ACLCHECK_OK)
101 aclcheck_error(aclresult, OBJECT_FUNCTION,
102 NameListToString(func_name));
105 * Check that the conversion function is suitable for the requested source
106 * and target encodings. We do that by calling the function with an empty
107 * string; the conversion function should throw an error if it can't
108 * perform the requested conversion.
110 funcresult = OidFunctionCall6(funcoid,
111 Int32GetDatum(from_encoding),
112 Int32GetDatum(to_encoding),
113 CStringGetDatum(""),
114 CStringGetDatum(result),
115 Int32GetDatum(0),
116 BoolGetDatum(false));
119 * The function should return 0 for empty input. Might as well check that,
120 * too.
122 if (DatumGetInt32(funcresult) != 0)
123 ereport(ERROR,
124 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
125 errmsg("encoding conversion function %s returned incorrect result for empty input",
126 NameListToString(func_name))));
129 * All seem ok, go ahead (possible failure would be a duplicate conversion
130 * name)
132 return ConversionCreate(conversion_name, namespaceId, GetUserId(),
133 from_encoding, to_encoding, funcoid, stmt->def);