Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * conversioncmds.c
4 : : * conversion creation command support code
5 : : *
6 : : * Portions Copyright (c) 1996-2024, 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 "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"
27 : :
28 : : /*
29 : : * CREATE CONVERSION
30 : : */
31 : : ObjectAddress
7948 ishii@postgresql.org 32 :CBC 32 : CreateConversionCommand(CreateConversionStmt *stmt)
33 : : {
34 : : Oid namespaceId;
35 : : char *conversion_name;
36 : : AclResult aclresult;
37 : : int from_encoding;
38 : : int to_encoding;
39 : : Oid funcoid;
7574 tgl@sss.pgh.pa.us 40 : 32 : const char *from_encoding_name = stmt->for_encoding_name;
7948 ishii@postgresql.org 41 : 32 : const char *to_encoding_name = stmt->to_encoding_name;
7893 bruce@momjian.us 42 : 32 : List *func_name = stmt->func_name;
43 : : static const Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, INTERNALOID, INT4OID, BOOLOID};
44 : : char result[1];
45 : : Datum funcresult;
46 : :
47 : : /* Convert list of names to a name and namespace */
7834 tgl@sss.pgh.pa.us 48 : 32 : namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name,
49 : : &conversion_name);
50 : :
51 : : /* Check we have creation rights in target namespace */
518 peter@eisentraut.org 52 : 32 : aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(), ACL_CREATE);
7948 ishii@postgresql.org 53 [ - + ]: 32 : if (aclresult != ACLCHECK_OK)
2325 peter_e@gmx.net 54 :UBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
7562 tgl@sss.pgh.pa.us 55 : 0 : get_namespace_name(namespaceId));
56 : :
57 : : /* Check the encoding names */
7574 tgl@sss.pgh.pa.us 58 :CBC 32 : from_encoding = pg_char_to_encoding(from_encoding_name);
59 [ - + ]: 32 : if (from_encoding < 0)
7574 tgl@sss.pgh.pa.us 60 [ # # ]:UBC 0 : ereport(ERROR,
61 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
62 : : errmsg("source encoding \"%s\" does not exist",
63 : : from_encoding_name)));
64 : :
7948 ishii@postgresql.org 65 :CBC 32 : to_encoding = pg_char_to_encoding(to_encoding_name);
66 [ - + ]: 32 : if (to_encoding < 0)
7574 tgl@sss.pgh.pa.us 67 [ # # ]:UBC 0 : ereport(ERROR,
68 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
69 : : errmsg("destination encoding \"%s\" does not exist",
70 : : to_encoding_name)));
71 : :
72 : : /*
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.)
78 : : */
1745 tgl@sss.pgh.pa.us 79 [ + - - + ]:CBC 32 : if (from_encoding == PG_SQL_ASCII || to_encoding == PG_SQL_ASCII)
1745 tgl@sss.pgh.pa.us 80 [ # # ]:UBC 0 : ereport(ERROR,
81 : : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
82 : : errmsg("encoding conversion to or from \"SQL_ASCII\" is not supported")));
83 : :
84 : : /*
85 : : * Check the existence of the conversion function. Function name could be
86 : : * a qualified name.
87 : : */
7590 tgl@sss.pgh.pa.us 88 :CBC 32 : funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid),
89 : : funcargs, false);
90 : :
91 : : /* Check it returns int4, else it's probably the wrong function */
1109 heikki.linnakangas@i 92 [ - + ]: 32 : if (get_func_rettype(funcoid) != INT4OID)
5630 tgl@sss.pgh.pa.us 93 [ # # ]:UBC 0 : ereport(ERROR,
94 : : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
95 : : errmsg("encoding conversion function %s must return type %s",
96 : : NameListToString(func_name), "integer")));
97 : :
98 : : /* Check we have EXECUTE rights for the function */
518 peter@eisentraut.org 99 :CBC 32 : aclresult = object_aclcheck(ProcedureRelationId, funcoid, GetUserId(), ACL_EXECUTE);
7948 ishii@postgresql.org 100 [ - + ]: 32 : if (aclresult != ACLCHECK_OK)
2325 peter_e@gmx.net 101 :UBC 0 : aclcheck_error(aclresult, OBJECT_FUNCTION,
7562 tgl@sss.pgh.pa.us 102 : 0 : NameListToString(func_name));
103 : :
104 : : /*
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.
109 : : */
1109 heikki.linnakangas@i 110 :CBC 32 : funcresult = OidFunctionCall6(funcoid,
111 : : Int32GetDatum(from_encoding),
112 : : Int32GetDatum(to_encoding),
113 : : CStringGetDatum(""),
114 : : CStringGetDatum(result),
115 : : Int32GetDatum(0),
116 : : BoolGetDatum(false));
117 : :
118 : : /*
119 : : * The function should return 0 for empty input. Might as well check that,
120 : : * too.
121 : : */
122 [ - + ]: 32 : if (DatumGetInt32(funcresult) != 0)
1109 heikki.linnakangas@i 123 [ # # ]:UBC 0 : ereport(ERROR,
124 : : (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
125 : : errmsg("encoding conversion function %s returned incorrect result for empty input",
126 : : NameListToString(func_name))));
127 : :
128 : : /*
129 : : * All seem ok, go ahead (possible failure would be a duplicate conversion
130 : : * name)
131 : : */
4130 rhaas@postgresql.org 132 :CBC 32 : return ConversionCreate(conversion_name, namespaceId, GetUserId(),
133 : 32 : from_encoding, to_encoding, funcoid, stmt->def);
134 : : }
|