1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-16 15:02:33 +03:00

Add SQL99 CONVERT() function.

This commit is contained in:
Tatsuo Ishii
2002-08-06 05:40:47 +00:00
parent 34f03b1630
commit 6206a880cf
15 changed files with 1237 additions and 211 deletions

View File

@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.27 2002/07/29 23:46:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.28 2002/08/06 05:40:44 ishii Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1238,6 +1238,43 @@ PopSpecialNamespace(Oid namespaceId)
namespaceSearchPathValid = false;
}
/*
* FindConversionByName - find a conversion by possibly qualified name
*/
Oid FindConversionByName(List *name)
{
char *conversion_name;
Oid namespaceId;
Oid conoid;
List *lptr;
/* Convert list of names to a name and namespace */
namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name);
if (length(name) > 1)
{
/* Check we have usage rights in target namespace */
if (pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
return InvalidOid;
return FindConversion(conversion_name, namespaceId);
}
recomputeNamespacePath();
foreach(lptr, namespaceSearchPath)
{
Oid namespaceId = (Oid) lfirsti(lptr);
conoid = FindConversion(conversion_name, namespaceId);
if (OidIsValid(conoid))
return conoid;
}
/* Not found in path */
return InvalidOid;
}
/*
* FindDefaultConversionProc - find default encoding cnnversion proc
*/

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.4 2002/08/05 03:29:16 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.5 2002/08/06 05:40:45 ishii Exp $
*
*-------------------------------------------------------------------------
*/
@@ -221,7 +221,7 @@ RemoveConversionById(Oid conversionOid)
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
simple_heap_delete(rel, &tuple->t_self);
else
elog(ERROR, "Conversion %u does not exist", conversionOid);
elog(ERROR, "conversion %u does not exist", conversionOid);
heap_endscan(scan);
heap_close(rel, RowExclusiveLock);
}
@@ -233,47 +233,6 @@ RemoveConversionById(Oid conversionOid)
* If found, returns the procedure's oid, otherwise InvalidOid.
* ---------------
*/
#ifdef NOT_USED
Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
{
Relation rel;
HeapScanDesc scan;
ScanKeyData scanKeyData;
HeapTuple tuple;
Form_pg_conversion body;
Oid proc = InvalidOid;
/* Check we have usage rights in target namespace */
if (pg_namespace_aclcheck(name_space, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
return InvalidOid;
ScanKeyEntryInitialize(&scanKeyData,
0,
Anum_pg_conversion_connamespace,
F_OIDEQ,
ObjectIdGetDatum(name_space));
rel = heap_openr(ConversionRelationName, AccessShareLock);
scan = heap_beginscan(rel, SnapshotNow,
1, &scanKeyData);
while (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
{
body = (Form_pg_conversion)GETSTRUCT(tuple);
if (body->conforencoding == for_encoding &&
body->contoencoding == to_encoding &&
body->condefault == TRUE)
{
proc = body->conproc;
break;
}
}
heap_endscan(scan);
heap_close(rel, AccessShareLock);
return proc;
}
#endif
Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
{
CatCList *catlist;
@@ -309,34 +268,27 @@ Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
/* ----------------
* FindConversionByName
*
* Find conversion proc by possibly qualified conversion name.
* Find conversion by namespace and conversion name.
* Returns conversion oid.
* ---------------
*/
Oid FindConversionByName(List *name)
Oid FindConversion(const char *conname, Oid connamespace)
{
HeapTuple tuple;
char *conversion_name;
Oid namespaceId;
Oid procoid;
Oid conoid;
AclResult aclresult;
/* Convert list of names to a name and namespace */
namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name);
/* Check we have usage rights in target namespace */
if (pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
return InvalidOid;
/* search pg_conversion by namespaceId and conversion name */
/* search pg_conversion by connamespace and conversion name */
tuple = SearchSysCache(CONNAMESP,
PointerGetDatum(conversion_name),
ObjectIdGetDatum(namespaceId),
PointerGetDatum(conname),
ObjectIdGetDatum(connamespace),
0,0);
if (!HeapTupleIsValid(tuple))
return InvalidOid;
procoid = ((Form_pg_conversion)GETSTRUCT(tuple))->conproc;
conoid = HeapTupleGetOid(tuple);
ReleaseSysCache(tuple);
@@ -345,6 +297,69 @@ Oid FindConversionByName(List *name)
if (aclresult != ACLCHECK_OK)
return InvalidOid;
return procoid;
return conoid;
}
/*
* Execute SQL99's CONVERT function.
*
* CONVERT <left paren> <character value expression>
* USING <form-of-use conversion name> <right paren>
*
* TEXT convert3(TEXT string, OID conversion_oid);
*/
Datum
pg_convert3(PG_FUNCTION_ARGS)
{
text *string = PG_GETARG_TEXT_P(0);
Oid convoid = PG_GETARG_OID(1);
HeapTuple tuple;
Form_pg_conversion body;
text *retval;
unsigned char *str;
unsigned char *result;
int len;
if (!OidIsValid(convoid))
elog(ERROR, "Conversion does not exist");
/* make sure that source string is null terminated */
len = VARSIZE(string) - VARHDRSZ;
str = palloc(len + 1);
memcpy(str, VARDATA(string), len);
*(str + len) = '\0';
tuple = SearchSysCache(CONOID,
ObjectIdGetDatum(convoid),
0,0,0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "Conversion %u search from syscache failed", convoid);
result = palloc(len * 4 + 1);
body = (Form_pg_conversion)GETSTRUCT(tuple);
OidFunctionCall5(body->conproc,
Int32GetDatum(body->conforencoding),
Int32GetDatum(body->contoencoding),
CStringGetDatum(str),
CStringGetDatum(result),
Int32GetDatum(len));
ReleaseSysCache(tuple);
/* build text data type structre. we cannot use textin() here,
since textin assumes that input string encoding is same as
database encoding. */
len = strlen(result) + VARHDRSZ;
retval = palloc(len);
VARATT_SIZEP(retval) = len;
memcpy(VARDATA(retval), result, len - VARHDRSZ);
pfree(result);
pfree(str);
/* free memory if allocated by the toaster */
PG_FREE_IF_COPY(string, 0);
PG_RETURN_TEXT_P(retval);
}

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.356 2002/08/05 02:30:50 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.357 2002/08/06 05:40:45 ishii Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -53,6 +53,7 @@
#include "access/htup.h"
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/params.h"
@@ -216,7 +217,8 @@ static void doNegateFloat(Value *v);
insert_target_list, def_list, opt_indirection,
group_clause, TriggerFuncArgs, select_limit,
opt_select_limit, opclass_item_list, trans_options,
TableFuncElementList, OptTableFuncElementList
TableFuncElementList, OptTableFuncElementList,
convert_args
%type <range> into_clause, OptTempTableName
@@ -232,7 +234,7 @@ static void doNegateFloat(Value *v);
%type <jtype> join_type
%type <list> extract_list, overlay_list, position_list
%type <list> substr_list, trim_list
%type <list> substr_list, trim_list, convert_list
%type <ival> opt_interval
%type <node> overlay_placing, substr_from, substr_for
@@ -329,7 +331,7 @@ static void doNegateFloat(Value *v);
CACHE, CALLED, CASCADE, CASE, CAST, CHAIN, CHAR_P,
CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLASS, CLOSE,
CLUSTER, COALESCE, COLLATE, COLUMN, COMMENT, COMMIT,
COMMITTED, CONSTRAINT, CONSTRAINTS, CONVERSION_P, COPY, CREATE, CREATEDB,
COMMITTED, CONSTRAINT, CONSTRAINTS, CONVERSION_P, CONVERT, COPY, CREATE, CREATEDB,
CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME,
CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, CYCLE,
@@ -6253,6 +6255,15 @@ c_expr: columnref { $$ = (Node *) $1; }
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| CONVERT '(' convert_list ')'
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("convert");
n->args = $3;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = (Node *)n;
}
| select_with_parens %prec UMINUS
{
SubLink *n = makeNode(SubLink);
@@ -6418,6 +6429,48 @@ trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); }
| expr_list { $$ = $1; }
;
/* CONVERT() arguments. We accept followings:
* SQL99 syntax
* o CONVERT(TEXT string USING conversion_name)
*
* Function calls
* o CONVERT(TEXT string, NAME src_encoding_name, NAME dest_encoding_name)
* o CONVERT(TEXT string, NAME encoding_name)
*/
convert_list:
a_expr USING any_name
{
Oid oid = FindConversionByName($3);
Const *convoid = makeNode(Const);
if (!OidIsValid(oid))
{
elog(ERROR, "Conversion \"%s\" does not exist",
NameListToString($3));
}
convoid->consttype = OIDOID;
convoid->constlen = sizeof(Oid);
convoid->constvalue = oid;
convoid->constisnull = FALSE;
convoid->constbyval = TRUE;
convoid->constisset = FALSE;
convoid->constiscast = FALSE;
$$ = makeList2($1, convoid);
}
| convert_args
{
$$ = $1;
}
| /*EMPTY*/
{ $$ = NIL; }
;
convert_args: a_expr { $$ = makeList1($1); }
| convert_args ',' a_expr { $$ = lappend($1, $3); }
;
in_expr: select_with_parens
{
SubLink *n = makeNode(SubLink);

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.123 2002/07/29 22:14:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.124 2002/08/06 05:40:45 ishii Exp $
*
*-------------------------------------------------------------------------
*/
@@ -80,6 +80,7 @@ static const ScanKeyword ScanKeywords[] = {
{"constraint", CONSTRAINT},
{"constraints", CONSTRAINTS},
{"conversion", CONVERSION_P},
{"convert", CONVERT},
{"copy", COPY},
{"create", CREATE},
{"createdb", CREATEDB},

View File

@@ -4,7 +4,7 @@
# Makefile for utils/mb
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/utils/mb/Makefile,v 1.18 2002/07/18 02:02:30 ishii Exp $
# $Header: /cvsroot/pgsql/src/backend/utils/mb/Makefile,v 1.19 2002/08/06 05:40:45 ishii Exp $
#
#-------------------------------------------------------------------------
@@ -24,7 +24,7 @@ clean distclean maintainer-clean:
SUBSYS.o: $(OBJS)
@for dir in $(DIRS); do $(MAKE) -C $$dir all || exit; done
$(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS)
$(LD) $(LDREL) $(LDOUT) $@ $^
depend dep:
$(CC) -MM $(CFLAGS) *.c >depend

View File

@@ -4,7 +4,7 @@
# Makefile for utils/mb/conversion_procs
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/utils/mb/conversion_procs/Makefile,v 1.2 2002/07/18 22:58:08 petere Exp $
# $Header: /cvsroot/pgsql/src/backend/utils/mb/conversion_procs/Makefile,v 1.3 2002/08/06 05:40:45 ishii Exp $
#
#-------------------------------------------------------------------------
@@ -14,6 +14,9 @@ include $(top_builddir)/src/Makefile.global
SQLSCRIPT = conversion_create.sql
# This file can be placed as src/test/regress/conversion.sql
REGRESSION_SCRIPT = conversion.sql
DIRS = \
utf8_and_ascii utf8_and_iso8859_1 \
utf8_and_euc_jp utf8_and_euc_kr utf8_and_euc_cn utf8_and_euc_tw \
@@ -21,9 +24,7 @@ DIRS = \
utf8_and_uhc utf8_and_johab utf8_and_tcvn utf8_and_iso8859 \
euc_jp_and_sjis euc_tw_and_big5
# conversion_name source_encoding destination_encoding function object
$(SQLSCRIPT): Makefile
@set \
CONVERSIONS = \
utf8_to_ascii UNICODE SQL_ASCII utf8_to_ascii utf8_and_ascii \
ascii_to_utf8 SQL_ASCII UNICODE ascii_to_utf8 utf8_and_ascii \
utf8_to_iso8859_1 UNICODE LATIN1 utf8_to_iso8859_1 utf8_and_iso8859_1 \
@@ -87,8 +88,11 @@ $(SQLSCRIPT): Makefile
euc_tw_to_mic EUC_TW MULE_INTERNAL euc_tw_to_mic euc_tw_and_big5 \
big5_to_mic BIG5 MULE_INTERNAL big5_to_mic euc_tw_and_big5 \
mic_to_euc_tw MULE_INTERNAL EUC_TW mic_to_euc_tw euc_tw_and_big5 \
mic_to_big5 MULE_INTERNAL BIG5 mic_to_big5 euc_tw_and_big5 \
; \
mic_to_big5 MULE_INTERNAL BIG5 mic_to_big5 euc_tw_and_big5
# conversion_name source_encoding destination_encoding function object
$(SQLSCRIPT): Makefile
@set $(CONVERSIONS) ; \
while [ "$$#" -gt 0 ] ; \
do \
name=$$1;shift; \
@@ -102,6 +106,22 @@ $(SQLSCRIPT): Makefile
echo "CREATE DEFAULT CONVERSION pg_catalog.$$name FOR '$$se' TO '$$de' FROM $$func;"; \
done > $@
$(REGRESSION_SCRIPT): Makefile
@cp regress_prolog $@; \
set $(CONVERSIONS) ; \
while [ "$$#" -gt 0 ] ; \
do \
name=$$1;shift; \
se=$$1;shift; \
de=$$1; shift; \
func=$$1; shift; \
obj=$$1; shift; \
echo "-- $$se --> $$de"; \
echo "SELECT CONVERT('foo' USING $$name);"; \
echo "SELECT CONVERT('foo', '$$se', '$$de');"; \
done >> $@; \
cat regress_epilogue >> $@;
install: all installdirs
$(INSTALL_DATA) $(SQLSCRIPT) $(DESTDIR)$(datadir)
@for dir in $(DIRS); do $(MAKE) -C $$dir $@ || exit; done

View File

@@ -0,0 +1,5 @@
--
-- return to the super user
--
RESET SESSION AUTHORIZATION;
DROP USER foo;

View File

@@ -0,0 +1,25 @@
--
-- create user defined conversion
--
CREATE USER foo WITH NOCREATEDB NOCREATEUSER;
SET SESSION AUTHORIZATION foo;
CREATE CONVERSION myconv FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_to_utf8;
--
-- cannot make same name conversion in same schema
--
CREATE CONVERSION myconv FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_to_utf8;
--
-- create default conversion with qualified name
--
CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_to_utf8;
--
-- cannot make default conversion with same shcema/for_encoding/to_encoding
--
CREATE DEFAULT CONVERSION public.mydef2 FOR 'LATIN1' TO 'UNICODE' FROM iso8859_1_to_utf8;
--
-- drop user defined conversion
--
DROP CONVERSION myconv;
DROP CONVERSION mydef;
--
-- make sure all pre-defined conversions are fine.