From 0345f58496f9bdd462afafd8e97dac229720d663 Mon Sep 17 00:00:00 2001
From: Tatsuo Ishii <ishii@postgresql.org>
Date: Thu, 25 Jul 2002 10:07:13 +0000
Subject: [PATCH] Implement DROP CONVERSION Add regression test

---
 src/backend/catalog/dependency.c         |  30 +-
 src/backend/catalog/pg_conversion.c      | 121 +++++-
 src/backend/commands/conversioncmds.c    |   6 +-
 src/backend/tcop/utility.c               |   5 +-
 src/backend/utils/cache/syscache.c       |  22 +-
 src/backend/utils/init/miscinit.c        |  52 +--
 src/backend/utils/mb/mbutils.c           |  13 +-
 src/include/catalog/catversion.h         |   4 +-
 src/include/catalog/indexing.h           |   5 +-
 src/include/catalog/pg_conversion.h      |   7 +-
 src/include/commands/conversioncmds.h    |   4 +-
 src/include/utils/syscache.h             |  46 +--
 src/test/regress/expected/conversion.out | 478 +++++++++++++++++++++++
 src/test/regress/parallel_schedule       |   4 +-
 src/test/regress/serial_schedule         |   3 +-
 src/test/regress/sql/conversion.sql      | 156 ++++++++
 16 files changed, 852 insertions(+), 104 deletions(-)
 create mode 100644 src/test/regress/expected/conversion.out
 create mode 100644 src/test/regress/sql/conversion.sql

diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 638843c3e07..8330fe42a62 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.5 2002/07/18 23:11:27 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.6 2002/07/25 10:07:10 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,7 @@
 #include "catalog/indexing.h"
 #include "catalog/pg_attrdef.h"
 #include "catalog/pg_constraint.h"
+#include "catalog/pg_conversion.h"
 #include "catalog/pg_depend.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_namespace.h"
@@ -52,6 +53,7 @@ typedef enum ObjectClasses
 	OCLASS_PROC,				/* pg_proc */
 	OCLASS_TYPE,				/* pg_type */
 	OCLASS_CONSTRAINT,			/* pg_constraint */
+	OCLASS_CONVERSION,			/* pg_conversion */
 	OCLASS_DEFAULT,				/* pg_attrdef */
 	OCLASS_LANGUAGE,			/* pg_language */
 	OCLASS_OPERATOR,			/* pg_operator */
@@ -581,6 +583,10 @@ doDeletion(const ObjectAddress *object)
 			RemoveConstraintById(object->objectId);
 			break;
 
+		case OCLASS_CONVERSION:
+			RemoveConversionById(object->objectId);
+			break;
+
 		case OCLASS_DEFAULT:
 			RemoveAttrDefaultById(object->objectId);
 			break;
@@ -989,6 +995,7 @@ init_object_classes(void)
 	object_classes[OCLASS_PROC] = RelOid_pg_proc;
 	object_classes[OCLASS_TYPE] = RelOid_pg_type;
 	object_classes[OCLASS_CONSTRAINT] = get_system_catalog_relid(ConstraintRelationName);
+	object_classes[OCLASS_CONVERSION] = get_system_catalog_relid(ConversionRelationName);
 	object_classes[OCLASS_DEFAULT] = get_system_catalog_relid(AttrDefaultRelationName);
 	object_classes[OCLASS_LANGUAGE] = get_system_catalog_relid(LanguageRelationName);
 	object_classes[OCLASS_OPERATOR] = get_system_catalog_relid(OperatorRelationName);
@@ -1039,6 +1046,11 @@ getObjectClass(const ObjectAddress *object)
 		Assert(object->objectSubId == 0);
 		return OCLASS_CONSTRAINT;
 	}
+	if (object->classId == object_classes[OCLASS_CONVERSION])
+	{
+		Assert(object->objectSubId == 0);
+		return OCLASS_CONVERSION;
+	}
 	if (object->classId == object_classes[OCLASS_DEFAULT])
 	{
 		Assert(object->objectSubId == 0);
@@ -1165,6 +1177,22 @@ getObjectDescription(const ObjectAddress *object)
 			break;
 		}
 
+		case OCLASS_CONVERSION:
+		{
+			HeapTuple		conTup;
+
+			conTup = SearchSysCache(CONOID,
+									 ObjectIdGetDatum(object->objectId),
+									 0, 0, 0);
+			if (!HeapTupleIsValid(conTup))
+				elog(ERROR, "getObjectDescription: Conversion %u does not exist",
+					 object->objectId);
+			appendStringInfo(&buffer, "conversion %s",
+							 NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
+			ReleaseSysCache(conTup);
+			break;
+		}
+
 		case OCLASS_DEFAULT:
 		{
 			Relation		attrdefDesc;
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 065d3c3aa56..3e316e3a291 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.2 2002/07/16 06:58:44 ishii Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.3 2002/07/25 10:07:10 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,11 +16,15 @@
 
 #include "access/heapam.h"
 #include "catalog/catname.h"
+#include "catalog/dependency.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_class.h"
 #include "catalog/pg_conversion.h"
 #include "catalog/namespace.h"
 #include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
+#include "utils/catcache.h"
 #include "mb/pg_wchar.h"
 #include "utils/fmgroids.h"
 #include "utils/acl.h"
@@ -28,6 +32,8 @@
 
 /* ----------------
  * ConversionCreate
+ *
+ * Add a new tuple to pg_coversion.
  * ---------------
  */
 Oid	ConversionCreate(const char *conname, Oid connamespace,
@@ -43,6 +49,8 @@ Oid	ConversionCreate(const char *conname, Oid connamespace,
 	Datum		values[Natts_pg_conversion];
 	NameData	cname;
 	Oid			oid;
+	ObjectAddress	myself,
+					referenced;
 
 	/* sanity checks */
 	if (!conname)
@@ -85,7 +93,10 @@ Oid	ConversionCreate(const char *conname, Oid connamespace,
 	values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
 	values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
 	values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
-	values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
+	if (def == true)
+		values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
+	else
+		nulls[Anum_pg_conversion_condefault - 1] = 'n';
 
 	tup = heap_formtuple(tupDesc, values, nulls);
 
@@ -103,6 +114,17 @@ Oid	ConversionCreate(const char *conname, Oid connamespace,
 		CatalogCloseIndices(Num_pg_conversion_indices, idescs);
 	}
 
+	myself.classId = get_system_catalog_relid(ConversionRelationName);
+	myself.objectId = HeapTupleGetOid(tup);
+	myself.objectSubId = 0;
+
+	/* dependency on conversion procedure */
+	referenced.classId = RelOid_pg_proc;
+	referenced.objectId = conproc;
+	referenced.objectSubId = 0;
+	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+	heap_freetuple(tup);
 	heap_close(rel, RowExclusiveLock);
 
 	return oid;
@@ -110,9 +132,12 @@ Oid	ConversionCreate(const char *conname, Oid connamespace,
 
 /* ----------------
  * ConversionDrop
+ *
+ * Drop a conversion and do dependency check.
  * ---------------
  */
-void	ConversionDrop(const char *conname, Oid connamespace, int32 conowner)
+void	ConversionDrop(const char *conname, Oid connamespace,
+					   int32 conowner, DropBehavior behavior)
 {
 	Relation	rel;
 	TupleDesc	tupDesc;
@@ -120,6 +145,8 @@ void	ConversionDrop(const char *conname, Oid connamespace, int32 conowner)
 	HeapScanDesc scan;
 	ScanKeyData scanKeyData;
 	Form_pg_conversion body;
+	ObjectAddress	object;
+	Oid	myoid;
 
 	/* sanity checks */
 	if (!conname)
@@ -132,7 +159,7 @@ void	ConversionDrop(const char *conname, Oid connamespace, int32 conowner)
 						   ObjectIdGetDatum(connamespace));
 
 	/* open pg_conversion */
-	rel = heap_openr(ConversionRelationName, RowExclusiveLock);
+	rel = heap_openr(ConversionRelationName, AccessShareLock);
 	tupDesc = rel->rd_att;
 
 	scan = heap_beginscan(rel, SnapshotNow,
@@ -155,8 +182,53 @@ void	ConversionDrop(const char *conname, Oid connamespace, int32 conowner)
 	if (!superuser() && ((Form_pg_conversion)GETSTRUCT(tuple))->conowner != GetUserId())
 		elog(ERROR, "permission denied");
 
-	simple_heap_delete(rel, &tuple->t_self);
+	myoid = HeapTupleGetOid(tuple);
+	heap_endscan(scan);
+ 	heap_close(rel, AccessShareLock);
+
+	/*
+	 * Do the deletion
+	 */
+	object.classId = get_system_catalog_relid(ConversionRelationName);
+	object.objectId = myoid;
+	object.objectSubId = 0;
+
+	performDeletion(&object, behavior);
+}
+
+/* ----------------
+ * RemoveConversionById
+ *
+ * Remove a tuple from pg_conversion by Oid. This function is soley
+ * called inside catalog/dependency.c
+ * --------------- */
+void
+RemoveConversionById(Oid conversionOid)
+{
+	Relation	rel;
+	TupleDesc	tupDesc;
+	HeapTuple	tuple;
+	HeapScanDesc scan;
+	ScanKeyData scanKeyData;
+
+	ScanKeyEntryInitialize(&scanKeyData,
+						   0,
+						   ObjectIdAttributeNumber,
+						   F_OIDEQ,
+						   ObjectIdGetDatum(conversionOid));
 
+	/* open pg_conversion */
+	rel = heap_openr(ConversionRelationName, RowExclusiveLock);
+	tupDesc = rel->rd_att;
+
+	scan = heap_beginscan(rel, SnapshotNow,
+							  1, &scanKeyData);
+
+	/* search for the target tuple */
+	if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
+		simple_heap_delete(rel, &tuple->t_self);
+	else
+		elog(ERROR, "Conversion %u does not exist", conversionOid);
 	heap_endscan(scan);
 	heap_close(rel, RowExclusiveLock);
 }
@@ -164,9 +236,11 @@ void	ConversionDrop(const char *conname, Oid connamespace, int32 conowner)
 /* ----------------
  * FindDefaultConversion
  *
- * find default conversion proc by for_encoding and to_encoding in this name space
+ * Find "default" conversion proc by for_encoding and to_encoding in this name space.
+ * 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;
@@ -205,11 +279,44 @@ Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
 	heap_close(rel, AccessShareLock);
 	return proc;
 }
+#endif
+
+Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
+{
+	CatCList	*catlist;
+	HeapTuple	tuple;
+	Form_pg_conversion body;
+	Oid proc = InvalidOid;
+	int	i;
+
+	/* Check we have usage rights in target namespace */
+	if (pg_namespace_aclcheck(name_space, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
+		return proc;
+
+	catlist = SearchSysCacheList(CONDEFAULT, 3,
+							   ObjectIdGetDatum(name_space),
+							   Int32GetDatum(for_encoding),
+							   Int32GetDatum(to_encoding),
+							   0);
+
+	for (i = 0; i < catlist->n_members; i++)
+	{
+		tuple = &catlist->members[i]->tuple;
+		body = (Form_pg_conversion)GETSTRUCT(tuple);
+		if (body->condefault == TRUE)
+		{
+			proc = body->conproc;
+			break;
+		}
+	}
+	ReleaseSysCacheList(catlist);
+	return proc;
+}
 
 /* ----------------
  * FindConversionByName
  *
- * find conversion proc by possibly qualified conversion name.
+ * Find conversion proc by possibly qualified conversion name.
  * ---------------
  */
 Oid FindConversionByName(List *name)
diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c
index 077fe9d8d87..a8785d76862 100644
--- a/src/backend/commands/conversioncmds.c
+++ b/src/backend/commands/conversioncmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.1 2002/07/11 07:39:27 ishii Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.2 2002/07/25 10:07:11 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -90,7 +90,7 @@ CreateConversionCommand(CreateConversionStmt *stmt)
  * DROP CONVERSION
  */
 void
-DropConversionCommand(List *name)
+DropConversionCommand(List *name, DropBehavior behavior)
 {
 	Oid			namespaceId;
 	char		*conversion_name;
@@ -108,5 +108,5 @@ DropConversionCommand(List *name)
 	 * none existing conversion
 	 * not ower of this conversion
 	 */
-	ConversionDrop(conversion_name, namespaceId, GetUserId());
+	ConversionDrop(conversion_name, namespaceId, GetUserId(), behavior);
 }
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 54eeab77cd1..2ec5f427d3f 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.164 2002/07/18 23:11:28 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.165 2002/07/25 10:07:11 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -318,8 +318,7 @@ ProcessUtility(Node *parsetree,
 							break;
 
 						case DROP_CONVERSION:
-							/* does its own permissions checks */
-							DropConversionCommand(names);
+							DropConversionCommand(names, stmt->behavior);
 							break;
 
 						case DROP_SCHEMA:
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 9966a8d881f..0e114f36968 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.83 2002/07/20 05:16:58 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.84 2002/07/25 10:07:12 ishii Exp $
  *
  * NOTES
  *	  These routines allow the parser/planner/executor to perform
@@ -206,6 +206,16 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0
 	}},
+	{ConversionRelationName, /* CONDEFAULT */
+		ConversionDefaultIndex,
+		0,
+		4,
+		{
+			Anum_pg_conversion_connamespace,
+			Anum_pg_conversion_conforencoding,
+			Anum_pg_conversion_contoencoding,
+			ObjectIdAttributeNumber,
+	}},
 	{ConversionRelationName, /* CONNAMENSP */
 		ConversionNameNspIndex,
 		0,
@@ -216,6 +226,16 @@ static const struct cachedesc cacheinfo[] = {
 			0,
 			0
 	}},
+	{ConversionRelationName, /* CONOID */
+		ConversionOidIndex,
+		0,
+		1,
+		{
+			ObjectIdAttributeNumber,
+			0,
+			0,
+			0
+	}},
 	{GroupRelationName,			/* GRONAME */
 		GroupNameIndex,
 		0,
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index b32fdc80335..367d9c2acab 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.93 2002/06/20 20:29:40 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.94 2002/07/25 10:07:12 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -185,56 +185,6 @@ SetDataDir(const char *dir)
 	DataDir = new;
 }
 
-
-/* ----------------------------------------------------------------
- *				MULTIBYTE stub code
- *
- * Even if MULTIBYTE is not enabled, these functions are necessary
- * since pg_proc.h has references to them.
- * ----------------------------------------------------------------
- */
-
-#ifndef MULTIBYTE
-
-Datum
-getdatabaseencoding(PG_FUNCTION_ARGS)
-{
-	return DirectFunctionCall1(namein, CStringGetDatum("SQL_ASCII"));
-}
-
-Datum
-pg_client_encoding(PG_FUNCTION_ARGS)
-{
-	return DirectFunctionCall1(namein, CStringGetDatum("SQL_ASCII"));
-}
-
-Datum
-PG_encoding_to_char(PG_FUNCTION_ARGS)
-{
-	return DirectFunctionCall1(namein, CStringGetDatum("SQL_ASCII"));
-}
-
-Datum
-PG_char_to_encoding(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_INT32(0);
-}
-
-Datum
-pg_convert(PG_FUNCTION_ARGS)
-{
-	elog(ERROR, "convert is not supported. To use convert, you need to enable multibyte capability");
-	return DirectFunctionCall1(textin, CStringGetDatum(""));
-}
-
-Datum
-pg_convert2(PG_FUNCTION_ARGS)
-{
-	elog(ERROR, "convert is not supported. To use convert, you need to enable multibyte capability");
-	return DirectFunctionCall1(textin, CStringGetDatum(""));
-}
-#endif
-
 /* ----------------------------------------------------------------
  *				CYR_RECODE support
  * ----------------------------------------------------------------
diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c
index 63d7398d774..1ebe13ea77e 100644
--- a/src/backend/utils/mb/mbutils.c
+++ b/src/backend/utils/mb/mbutils.c
@@ -3,10 +3,10 @@
  * client encoding and server internal encoding.
  * (currently mule internal code (mic) is used)
  * Tatsuo Ishii
- * $Id: mbutils.c,v 1.28 2002/07/18 02:02:30 ishii Exp $
+ * $Id: mbutils.c,v 1.29 2002/07/25 10:07:12 ishii Exp $
  */
 #include "postgres.h"
-
+#include "access/xact.h"
 #include "miscadmin.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
@@ -35,7 +35,8 @@ SetClientEncoding(int encoding, bool doit)
 	if (!PG_VALID_FE_ENCODING(encoding))
 		return (-1);
 
-	if (current_server_encoding == encoding)
+	if (current_server_encoding == encoding ||
+		(current_server_encoding == PG_SQL_ASCII || encoding == PG_SQL_ASCII))
 	{
 		ClientEncoding = &pg_enc2name_tbl[encoding];
 		return 0;
@@ -102,9 +103,15 @@ pg_do_encoding_conversion(unsigned char *src, int len,
 	unsigned char *result;
 	Oid	proc;
 
+	if (!IsTransactionState())
+		return src;
+	
 	if (src_encoding == dest_encoding)
 		return src;
 
+	if (src_encoding == PG_SQL_ASCII || dest_encoding == PG_SQL_ASCII)
+		return src;
+
 	proc = FindDefaultConversionProc(src_encoding, dest_encoding);
 	if (!OidIsValid(proc))
 	{
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 65facda7530..9dcd646e6f3 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.142 2002/07/24 19:11:12 petere Exp $
+ * $Id: catversion.h,v 1.143 2002/07/25 10:07:12 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200207241
+#define CATALOG_VERSION_NO	200207251
 
 #endif
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index db14ae6bd68..4928eda6b65 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: indexing.h,v 1.72 2002/07/22 20:23:19 petere Exp $
+ * $Id: indexing.h,v 1.73 2002/07/25 10:07:12 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -179,8 +179,7 @@ DECLARE_INDEX(pg_constraint_conname_nsp_index on pg_constraint using btree(conna
 /* This following index is not used for a cache and is not unique */
 DECLARE_INDEX(pg_constraint_conrelid_index on pg_constraint using btree(conrelid oid_ops));
 DECLARE_UNIQUE_INDEX(pg_constraint_oid_index on pg_constraint using btree(oid oid_ops));
-/* This following index is not used for a cache and is not unique */
-DECLARE_INDEX(pg_conversion_default_index on pg_conversion using btree(connamespace oid_ops, conforencoding int4_ops, contoencoding int4_ops));
+DECLARE_UNIQUE_INDEX(pg_conversion_default_index on pg_conversion using btree(connamespace oid_ops, conforencoding int4_ops, contoencoding int4_ops, oid oid_ops));
 DECLARE_UNIQUE_INDEX(pg_conversion_name_nsp_index on pg_conversion using btree(conname name_ops, connamespace oid_ops));
 DECLARE_UNIQUE_INDEX(pg_conversion_oid_index on pg_conversion using btree(oid oid_ops));
 DECLARE_UNIQUE_INDEX(pg_database_datname_index on pg_database using btree(datname name_ops));
diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h
index d4c406b8ee1..2867843a9b2 100644
--- a/src/include/catalog/pg_conversion.h
+++ b/src/include/catalog/pg_conversion.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_conversion.h,v 1.1 2002/07/11 07:39:27 ishii Exp $
+ * $Id: pg_conversion.h,v 1.2 2002/07/25 10:07:13 ishii Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -81,12 +81,15 @@ typedef FormData_pg_conversion *Form_pg_conversion;
  * prototypes for functions in pg_conversion.c
  */
 #include "nodes/pg_list.h"
+#include "nodes/parsenodes.h"
 
 extern Oid	ConversionCreate(const char *conname, Oid connamespace,
 							 int32 conowner,
 							 int4 conforencoding, int4 contoencoding,
 							 Oid conproc, bool def);
-extern void ConversionDrop(const char *conname, Oid connamespace, int32 conowner);
+extern void ConversionDrop(const char *conname, Oid connamespace,
+						   int32 conowner, DropBehavior behavior);
+extern void RemoveConversionById(Oid conversionOid);
 extern Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding);
 extern Oid FindConversionByName(List *conname);
 
diff --git a/src/include/commands/conversioncmds.h b/src/include/commands/conversioncmds.h
index fc4e5e6f51b..87c8c8f54ae 100644
--- a/src/include/commands/conversioncmds.h
+++ b/src/include/commands/conversioncmds.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: conversioncmds.h,v 1.1 2002/07/11 07:39:27 ishii Exp $
+ * $Id: conversioncmds.h,v 1.2 2002/07/25 10:07:13 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,6 @@
 #include "nodes/parsenodes.h"
 
 extern void CreateConversionCommand(CreateConversionStmt *parsetree);
-extern void DropConversionCommand(List *conversion_name);
+extern void DropConversionCommand(List *conversion_name, DropBehavior behavior);
 
 #endif  /* CONVERSIONCMDS_H */
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 5d964bb5668..e8c70fa00be 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: syscache.h,v 1.50 2002/07/18 23:11:32 petere Exp $
+ * $Id: syscache.h,v 1.51 2002/07/25 10:07:13 ishii Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,27 +39,29 @@
 #define CASTSOURCETARGET 8
 #define CLAAMNAMENSP	9
 #define CLAOID			10
-#define CONNAMESP		11
-#define GRONAME			12
-#define GROSYSID		13
-#define INDEXRELID		14
-#define INHRELID		15
-#define LANGNAME		16
-#define LANGOID			17
-#define NAMESPACENAME	18
-#define NAMESPACEOID	19
-#define OPERNAMENSP		20
-#define OPEROID			21
-#define PROCNAMENSP		22
-#define PROCOID			23
-#define RELNAMENSP		24
-#define RELOID			25
-#define RULERELNAME		26
-#define SHADOWNAME		27
-#define SHADOWSYSID		28
-#define STATRELATT		29
-#define TYPENAMENSP		30
-#define TYPEOID			31
+#define CONDEFAULT		11
+#define CONNAMESP		12
+#define CONOID			13
+#define GRONAME			14
+#define GROSYSID		15
+#define INDEXRELID		16
+#define INHRELID		17
+#define LANGNAME		18
+#define LANGOID			19
+#define NAMESPACENAME	20
+#define NAMESPACEOID	21
+#define OPERNAMENSP		22
+#define OPEROID			23
+#define PROCNAMENSP		24
+#define PROCOID			25
+#define RELNAMENSP		26
+#define RELOID			27
+#define RULERELNAME		28
+#define SHADOWNAME		29
+#define SHADOWSYSID		30
+#define STATRELATT		31
+#define TYPENAMENSP		32
+#define TYPEOID			33
 
 extern void InitCatalogCache(void);
 extern void InitCatalogCachePhase2(void);
diff --git a/src/test/regress/expected/conversion.out b/src/test/regress/expected/conversion.out
new file mode 100644
index 00000000000..d1b3cdfba87
--- /dev/null
+++ b/src/test/regress/expected/conversion.out
@@ -0,0 +1,478 @@
+--
+-- 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;
+ERROR:  conversion name "myconv" already exists
+--
+-- 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;
+ERROR:  default conversion for LATIN1 to UNICODE already exists
+--
+-- drop user defined conversion
+--
+DROP CONVERSION myconv;
+DROP CONVERSION mydef;
+--
+-- make sure all pre-defined conversions are fine.
+--
+-- UNICODE -> SQL_ASCII
+SELECT CONVERT('foo', 'UNICODE', 'SQL_ASCII');
+ convert 
+---------
+ foo
+(1 row)
+
+-- SQL_ASCII -> UNICODE
+SELECT CONVERT('foo', 'SQL_ASCII', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN1
+SELECT CONVERT('foo', 'UNICODE', 'LATIN1');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN1 -> UNICODE
+SELECT CONVERT('foo', 'LATIN1', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- EUC_JP -> UNICODE
+SELECT CONVERT('foo', 'EUC_JP', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> EUC_JP
+SELECT CONVERT('foo', 'UNICODE', 'EUC_JP');
+ convert 
+---------
+ foo
+(1 row)
+
+-- EUC_KR -> UNICODE
+SELECT CONVERT('foo', 'EUC_KR', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> EUC_KR
+SELECT CONVERT('foo', 'UNICODE', 'EUC_KR');
+ convert 
+---------
+ foo
+(1 row)
+
+-- EUC_CN -> UNICODE
+SELECT CONVERT('foo', 'EUC_CN', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> EUC_CN
+SELECT CONVERT('foo', 'UNICODE', 'EUC_CN');
+ convert 
+---------
+ foo
+(1 row)
+
+-- EUC_TW -> UNICODE
+SELECT CONVERT('foo', 'EUC_TW', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> EUC_TW
+SELECT CONVERT('foo', 'UNICODE', 'EUC_TW');
+ convert 
+---------
+ foo
+(1 row)
+
+-- SJIS -> UNICODE
+SELECT CONVERT('foo', 'SJIS', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> SJIS
+SELECT CONVERT('foo', 'UNICODE', 'SJIS');
+ convert 
+---------
+ foo
+(1 row)
+
+-- BIG5 -> UNICODE
+SELECT CONVERT('foo', 'BIG5', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> BIG5
+SELECT CONVERT('foo', 'UNICODE', 'BIG5');
+ convert 
+---------
+ foo
+(1 row)
+
+-- GBK -> UNICODE
+SELECT CONVERT('foo', 'GBK', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> GBK
+SELECT CONVERT('foo', 'UNICODE', 'GBK');
+ convert 
+---------
+ foo
+(1 row)
+
+-- GB18030 -> UNICODE
+SELECT CONVERT('foo', 'GB18030', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> GB18030
+SELECT CONVERT('foo', 'UNICODE', 'GB18030');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UHC -> UNICODE
+SELECT CONVERT('foo', 'UHC', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> UHC
+SELECT CONVERT('foo', 'UNICODE', 'UHC');
+ convert 
+---------
+ foo
+(1 row)
+
+-- JOHAB -> UNICODE
+SELECT CONVERT('foo', 'JOHAB', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> JOHAB
+SELECT CONVERT('foo', 'UNICODE', 'JOHAB');
+ convert 
+---------
+ foo
+(1 row)
+
+-- TCVN -> UNICODE
+SELECT CONVERT('foo', 'TCVN', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> TCVN
+SELECT CONVERT('foo', 'UNICODE', 'TCVN');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN2
+SELECT CONVERT('foo', 'UNICODE', 'LATIN2');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN2 -> UNICODE
+SELECT CONVERT('foo', 'LATIN2', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN3
+SELECT CONVERT('foo', 'UNICODE', 'LATIN3');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN3 -> UNICODE
+SELECT CONVERT('foo', 'LATIN3', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN4
+SELECT CONVERT('foo', 'UNICODE', 'LATIN4');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN4 -> UNICODE
+SELECT CONVERT('foo', 'LATIN4', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN5
+SELECT CONVERT('foo', 'UNICODE', 'LATIN5');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN5 -> UNICODE
+SELECT CONVERT('foo', 'LATIN5', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN6
+SELECT CONVERT('foo', 'UNICODE', 'LATIN6');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN6 -> UNICODE
+SELECT CONVERT('foo', 'LATIN6', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN7
+SELECT CONVERT('foo', 'UNICODE', 'LATIN7');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN7 -> UNICODE
+SELECT CONVERT('foo', 'LATIN7', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN8
+SELECT CONVERT('foo', 'UNICODE', 'LATIN8');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN8 -> UNICODE
+SELECT CONVERT('foo', 'LATIN8', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN9
+SELECT CONVERT('foo', 'UNICODE', 'LATIN9');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN9 -> UNICODE
+SELECT CONVERT('foo', 'LATIN9', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> LATIN10
+SELECT CONVERT('foo', 'UNICODE', 'LATIN10');
+ convert 
+---------
+ foo
+(1 row)
+
+-- LATIN10 -> UNICODE
+SELECT CONVERT('foo', 'LATIN10', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> ISO-8859-5
+SELECT CONVERT('foo', 'UNICODE', 'ISO-8859-5');
+ convert 
+---------
+ foo
+(1 row)
+
+-- ISO-8859-5 -> UNICODE
+SELECT CONVERT('foo', 'ISO-8859-5', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> ISO-8859-6
+SELECT CONVERT('foo', 'UNICODE', 'ISO-8859-6');
+ convert 
+---------
+ foo
+(1 row)
+
+-- ISO-8859-6 -> UNICODE
+SELECT CONVERT('foo', 'ISO-8859-6', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> ISO-8859-7
+SELECT CONVERT('foo', 'UNICODE', 'ISO-8859-7');
+ convert 
+---------
+ foo
+(1 row)
+
+-- ISO-8859-7 -> UNICODE
+SELECT CONVERT('foo', 'ISO-8859-7', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- UNICODE -> ISO-8859-8
+SELECT CONVERT('foo', 'UNICODE', 'ISO-8859-8');
+ convert 
+---------
+ foo
+(1 row)
+
+-- ISO-8859-8 -> UNICODE
+SELECT CONVERT('foo', 'ISO-8859-8', 'UNICODE');
+ convert 
+---------
+ foo
+(1 row)
+
+-- EUC_JP -> SJIS
+SELECT CONVERT('foo', 'EUC_JP', 'SJIS');
+ convert 
+---------
+ foo
+(1 row)
+
+-- SJIS -> EUC_JP
+SELECT CONVERT('foo', 'SJIS', 'EUC_JP');
+ convert 
+---------
+ foo
+(1 row)
+
+-- EUC_JP -> MULE_INTERNAL
+SELECT CONVERT('foo', 'EUC_JP', 'MULE_INTERNAL');
+ convert 
+---------
+ foo
+(1 row)
+
+-- SJIS -> MULE_INTERNAL
+SELECT CONVERT('foo', 'SJIS', 'MULE_INTERNAL');
+ convert 
+---------
+ foo
+(1 row)
+
+-- MULE_INTERNAL -> EUC_JP
+SELECT CONVERT('foo', 'MULE_INTERNAL', 'EUC_JP');
+ convert 
+---------
+ foo
+(1 row)
+
+-- MULE_INTERNAL -> SJIS
+SELECT CONVERT('foo', 'MULE_INTERNAL', 'SJIS');
+ convert 
+---------
+ foo
+(1 row)
+
+-- EUC_TW -> BIG5
+SELECT CONVERT('foo', 'EUC_TW', 'BIG5');
+ convert 
+---------
+ foo
+(1 row)
+
+-- BIG5 -> EUC_TW
+SELECT CONVERT('foo', 'BIG5', 'EUC_TW');
+ convert 
+---------
+ foo
+(1 row)
+
+-- EUC_TW -> MULE_INTERNAL
+SELECT CONVERT('foo', 'EUC_TW', 'MULE_INTERNAL');
+ convert 
+---------
+ foo
+(1 row)
+
+-- BIG5 -> MULE_INTERNAL
+SELECT CONVERT('foo', 'BIG5', 'MULE_INTERNAL');
+ convert 
+---------
+ foo
+(1 row)
+
+-- MULE_INTERNAL -> EUC_TW
+SELECT CONVERT('foo', 'MULE_INTERNAL', 'EUC_TW');
+ convert 
+---------
+ foo
+(1 row)
+
+-- MULE_INTERNAL -> BIG5
+SELECT CONVERT('foo', 'MULE_INTERNAL', 'BIG5');
+ convert 
+---------
+ foo
+(1 row)
+
+RESET SESSION AUTHORIZATION;
+DROP USER foo;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index fd9ae6c89a1..513bdf8c430 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -74,7 +74,5 @@ test: select_views alter_table portals_p2 rules foreign_key
 # The sixth group of parallel test
 # ----------
 # "plpgsql" cannot run concurrently with "rules"
-test: limit plpgsql temp domain rangefuncs copy2
-
+test: limit plpgsql temp domain rangefuncs copy2 conversion
 test: without_oid
-
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 566b3962299..271c5123d70 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -1,4 +1,4 @@
-# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.13 2002/07/20 05:16:59 momjian Exp $
+# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.14 2002/07/25 10:07:13 ishii Exp $
 # This should probably be in an order similar to parallel_schedule.
 test: boolean
 test: char
@@ -86,3 +86,4 @@ test: temp
 test: domain
 test: rangefuncs
 test: without_oid
+test: conversion
diff --git a/src/test/regress/sql/conversion.sql b/src/test/regress/sql/conversion.sql
new file mode 100644
index 00000000000..7be4916fec0
--- /dev/null
+++ b/src/test/regress/sql/conversion.sql
@@ -0,0 +1,156 @@
+--
+-- 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.
+--
+-- UNICODE -> SQL_ASCII
+SELECT CONVERT('foo', 'UNICODE', 'SQL_ASCII');
+-- SQL_ASCII -> UNICODE
+SELECT CONVERT('foo', 'SQL_ASCII', 'UNICODE');
+-- UNICODE -> LATIN1
+SELECT CONVERT('foo', 'UNICODE', 'LATIN1');
+-- LATIN1 -> UNICODE
+SELECT CONVERT('foo', 'LATIN1', 'UNICODE');
+-- EUC_JP -> UNICODE
+SELECT CONVERT('foo', 'EUC_JP', 'UNICODE');
+-- UNICODE -> EUC_JP
+SELECT CONVERT('foo', 'UNICODE', 'EUC_JP');
+-- EUC_KR -> UNICODE
+SELECT CONVERT('foo', 'EUC_KR', 'UNICODE');
+-- UNICODE -> EUC_KR
+SELECT CONVERT('foo', 'UNICODE', 'EUC_KR');
+-- EUC_CN -> UNICODE
+SELECT CONVERT('foo', 'EUC_CN', 'UNICODE');
+-- UNICODE -> EUC_CN
+SELECT CONVERT('foo', 'UNICODE', 'EUC_CN');
+-- EUC_TW -> UNICODE
+SELECT CONVERT('foo', 'EUC_TW', 'UNICODE');
+-- UNICODE -> EUC_TW
+SELECT CONVERT('foo', 'UNICODE', 'EUC_TW');
+-- SJIS -> UNICODE
+SELECT CONVERT('foo', 'SJIS', 'UNICODE');
+-- UNICODE -> SJIS
+SELECT CONVERT('foo', 'UNICODE', 'SJIS');
+-- BIG5 -> UNICODE
+SELECT CONVERT('foo', 'BIG5', 'UNICODE');
+-- UNICODE -> BIG5
+SELECT CONVERT('foo', 'UNICODE', 'BIG5');
+-- GBK -> UNICODE
+SELECT CONVERT('foo', 'GBK', 'UNICODE');
+-- UNICODE -> GBK
+SELECT CONVERT('foo', 'UNICODE', 'GBK');
+-- GB18030 -> UNICODE
+SELECT CONVERT('foo', 'GB18030', 'UNICODE');
+-- UNICODE -> GB18030
+SELECT CONVERT('foo', 'UNICODE', 'GB18030');
+-- UHC -> UNICODE
+SELECT CONVERT('foo', 'UHC', 'UNICODE');
+-- UNICODE -> UHC
+SELECT CONVERT('foo', 'UNICODE', 'UHC');
+-- JOHAB -> UNICODE
+SELECT CONVERT('foo', 'JOHAB', 'UNICODE');
+-- UNICODE -> JOHAB
+SELECT CONVERT('foo', 'UNICODE', 'JOHAB');
+-- TCVN -> UNICODE
+SELECT CONVERT('foo', 'TCVN', 'UNICODE');
+-- UNICODE -> TCVN
+SELECT CONVERT('foo', 'UNICODE', 'TCVN');
+-- UNICODE -> LATIN2
+SELECT CONVERT('foo', 'UNICODE', 'LATIN2');
+-- LATIN2 -> UNICODE
+SELECT CONVERT('foo', 'LATIN2', 'UNICODE');
+-- UNICODE -> LATIN3
+SELECT CONVERT('foo', 'UNICODE', 'LATIN3');
+-- LATIN3 -> UNICODE
+SELECT CONVERT('foo', 'LATIN3', 'UNICODE');
+-- UNICODE -> LATIN4
+SELECT CONVERT('foo', 'UNICODE', 'LATIN4');
+-- LATIN4 -> UNICODE
+SELECT CONVERT('foo', 'LATIN4', 'UNICODE');
+-- UNICODE -> LATIN5
+SELECT CONVERT('foo', 'UNICODE', 'LATIN5');
+-- LATIN5 -> UNICODE
+SELECT CONVERT('foo', 'LATIN5', 'UNICODE');
+-- UNICODE -> LATIN6
+SELECT CONVERT('foo', 'UNICODE', 'LATIN6');
+-- LATIN6 -> UNICODE
+SELECT CONVERT('foo', 'LATIN6', 'UNICODE');
+-- UNICODE -> LATIN7
+SELECT CONVERT('foo', 'UNICODE', 'LATIN7');
+-- LATIN7 -> UNICODE
+SELECT CONVERT('foo', 'LATIN7', 'UNICODE');
+-- UNICODE -> LATIN8
+SELECT CONVERT('foo', 'UNICODE', 'LATIN8');
+-- LATIN8 -> UNICODE
+SELECT CONVERT('foo', 'LATIN8', 'UNICODE');
+-- UNICODE -> LATIN9
+SELECT CONVERT('foo', 'UNICODE', 'LATIN9');
+-- LATIN9 -> UNICODE
+SELECT CONVERT('foo', 'LATIN9', 'UNICODE');
+-- UNICODE -> LATIN10
+SELECT CONVERT('foo', 'UNICODE', 'LATIN10');
+-- LATIN10 -> UNICODE
+SELECT CONVERT('foo', 'LATIN10', 'UNICODE');
+-- UNICODE -> ISO-8859-5
+SELECT CONVERT('foo', 'UNICODE', 'ISO-8859-5');
+-- ISO-8859-5 -> UNICODE
+SELECT CONVERT('foo', 'ISO-8859-5', 'UNICODE');
+-- UNICODE -> ISO-8859-6
+SELECT CONVERT('foo', 'UNICODE', 'ISO-8859-6');
+-- ISO-8859-6 -> UNICODE
+SELECT CONVERT('foo', 'ISO-8859-6', 'UNICODE');
+-- UNICODE -> ISO-8859-7
+SELECT CONVERT('foo', 'UNICODE', 'ISO-8859-7');
+-- ISO-8859-7 -> UNICODE
+SELECT CONVERT('foo', 'ISO-8859-7', 'UNICODE');
+-- UNICODE -> ISO-8859-8
+SELECT CONVERT('foo', 'UNICODE', 'ISO-8859-8');
+-- ISO-8859-8 -> UNICODE
+SELECT CONVERT('foo', 'ISO-8859-8', 'UNICODE');
+-- EUC_JP -> SJIS
+SELECT CONVERT('foo', 'EUC_JP', 'SJIS');
+-- SJIS -> EUC_JP
+SELECT CONVERT('foo', 'SJIS', 'EUC_JP');
+-- EUC_JP -> MULE_INTERNAL
+SELECT CONVERT('foo', 'EUC_JP', 'MULE_INTERNAL');
+-- SJIS -> MULE_INTERNAL
+SELECT CONVERT('foo', 'SJIS', 'MULE_INTERNAL');
+-- MULE_INTERNAL -> EUC_JP
+SELECT CONVERT('foo', 'MULE_INTERNAL', 'EUC_JP');
+-- MULE_INTERNAL -> SJIS
+SELECT CONVERT('foo', 'MULE_INTERNAL', 'SJIS');
+-- EUC_TW -> BIG5
+SELECT CONVERT('foo', 'EUC_TW', 'BIG5');
+-- BIG5 -> EUC_TW
+SELECT CONVERT('foo', 'BIG5', 'EUC_TW');
+-- EUC_TW -> MULE_INTERNAL
+SELECT CONVERT('foo', 'EUC_TW', 'MULE_INTERNAL');
+-- BIG5 -> MULE_INTERNAL
+SELECT CONVERT('foo', 'BIG5', 'MULE_INTERNAL');
+-- MULE_INTERNAL -> EUC_TW
+SELECT CONVERT('foo', 'MULE_INTERNAL', 'EUC_TW');
+-- MULE_INTERNAL -> BIG5
+SELECT CONVERT('foo', 'MULE_INTERNAL', 'BIG5');
+RESET SESSION AUTHORIZATION;
+DROP USER foo;
-- 
GitLab