Re: pg_conversion seems rather strangely defined - Mailing list pgsql-hackers

From Tom Lane
Subject Re: pg_conversion seems rather strangely defined
Date
Msg-id 29191.1452042136@sss.pgh.pa.us
Whole thread Raw
In response to Re: pg_conversion seems rather strangely defined  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
I wrote:
> I still think however that search-path-based lookup of default encoding
> conversions is a Bad Idea, and that we only ought to allow one default
> conversion to exist for any pair of encodings.

> I realized that we could implement that without too much trouble by
> redefining pg_conversion.condefault as being true for default conversions
> and NULL (not false) for non-default ones.  With this definition, a
> unique index on pg_conversion (conforencoding, contoencoding, condefault)
> would have the behavior we want --- sort of a poor man's partial unique
> index, except that it would work correctly on a system catalog whereas
> a true partial index wouldn't.

Turns out that indeed that works just fine.  See attached draft patch.

            regards, tom lane

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 97ef618..dcb8b8e 100644
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 2538,2544 ****
        <entry><structfield>condefault</structfield></entry>
        <entry><type>bool</type></entry>
        <entry></entry>
!       <entry>True if this is the default conversion</entry>
       </row>

      </tbody>
--- 2538,2545 ----
        <entry><structfield>condefault</structfield></entry>
        <entry><type>bool</type></entry>
        <entry></entry>
!       <entry>True if this is the default conversion for these two encodings,
!        else NULL</entry>
       </row>

      </tbody>
diff --git a/doc/src/sgml/charset.sgml b/doc/src/sgml/charset.sgml
index f8c7ac3..eb39a9f 100644
*** a/doc/src/sgml/charset.sgml
--- b/doc/src/sgml/charset.sgml
*************** $ <userinput>psql -l</userinput>
*** 1102,1108 ****
       <literal>pg_conversion</> system catalog.  <productname>PostgreSQL</>
       comes with some predefined conversions, as shown in <xref
       linkend="multibyte-translation-table">. You can create a new
!      conversion using the SQL command <command>CREATE CONVERSION</command>.
      </para>

       <table id="multibyte-translation-table">
--- 1102,1108 ----
       <literal>pg_conversion</> system catalog.  <productname>PostgreSQL</>
       comes with some predefined conversions, as shown in <xref
       linkend="multibyte-translation-table">. You can create a new
!      conversion using the SQL command <xref linkend="sql-createconversion">.
      </para>

       <table id="multibyte-translation-table">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index a0b42c2..f57d891 100644
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 1488,1494 ****
          original encoding is specified by
          <parameter>src_encoding</parameter>. The
          <parameter>string</parameter> must be valid in this encoding.
!         Conversions can be defined by <command>CREATE CONVERSION</command>.
          Also there are some predefined conversions. See <xref
          linkend="conversion-names"> for available conversions.
         </entry>
--- 1488,1494 ----
          original encoding is specified by
          <parameter>src_encoding</parameter>. The
          <parameter>string</parameter> must be valid in this encoding.
!         Conversions can be defined with <xref linkend="sql-createconversion">.
          Also there are some predefined conversions. See <xref
          linkend="conversion-names"> for available conversions.
         </entry>
***************
*** 1525,1534 ****
         </entry>
         <entry><type>bytea</type></entry>
         <entry>
!         Convert string to <parameter>dest_encoding</parameter>.
         </entry>
         <entry><literal>convert_to('some text', 'UTF8')</literal></entry>
!        <entry><literal>some text</literal> represented in the UTF8 encoding</entry>
        </row>

        <row>
--- 1525,1535 ----
         </entry>
         <entry><type>bytea</type></entry>
         <entry>
!         Convert string from the database encoding
!         to <parameter>dest_encoding</parameter>.
         </entry>
         <entry><literal>convert_to('some text', 'UTF8')</literal></entry>
!        <entry><literal>some text</literal> represented in UTF8 encoding</entry>
        </row>

        <row>
diff --git a/doc/src/sgml/ref/create_conversion.sgml b/doc/src/sgml/ref/create_conversion.sgml
index d2e2c01..1933107 100644
*** a/doc/src/sgml/ref/create_conversion.sgml
--- b/doc/src/sgml/ref/create_conversion.sgml
*************** CREATE [ DEFAULT ] CONVERSION <replaceab
*** 28,34 ****

    <para>
     <command>CREATE CONVERSION</command> defines a new conversion between
!    character set encodings.  Also, conversions that
     are marked <literal>DEFAULT</> can be used for automatic encoding
     conversion between
     client and server. For this purpose, two conversions, from encoding A to
--- 28,34 ----

    <para>
     <command>CREATE CONVERSION</command> defines a new conversion between
!    character set encodings.  Conversions that
     are marked <literal>DEFAULT</> can be used for automatic encoding
     conversion between
     client and server. For this purpose, two conversions, from encoding A to
*************** CREATE [ DEFAULT ] CONVERSION <replaceab
*** 53,59 ****
        <para>
         The <literal>DEFAULT</> clause indicates that this conversion
         is the default for this particular source to destination
!        encoding. There should be only one default encoding in a schema
         for the encoding pair.
        </para>
       </listitem>
--- 53,59 ----
        <para>
         The <literal>DEFAULT</> clause indicates that this conversion
         is the default for this particular source to destination
!        encoding. There can be only one default conversion in a database
         for the encoding pair.
        </para>
       </listitem>
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 8b105fe..98977f6 100644
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
***************
*** 28,34 ****
  #include "catalog/pg_authid.h"
  #include "catalog/pg_collation.h"
  #include "catalog/pg_conversion.h"
- #include "catalog/pg_conversion_fn.h"
  #include "catalog/pg_namespace.h"
  #include "catalog/pg_opclass.h"
  #include "catalog/pg_operator.h"
--- 28,33 ----
*************** get_conversion_oid(List *name, bool miss
*** 3416,3448 ****
  }

  /*
-  * FindDefaultConversionProc - find default encoding conversion proc
-  */
- Oid
- FindDefaultConversionProc(int32 for_encoding, int32 to_encoding)
- {
-     Oid            proc;
-     ListCell   *l;
-
-     recomputeNamespacePath();
-
-     foreach(l, activeSearchPath)
-     {
-         Oid            namespaceId = lfirst_oid(l);
-
-         if (namespaceId == myTempNamespace)
-             continue;            /* do not look in temp namespace */
-
-         proc = FindDefaultConversion(namespaceId, for_encoding, to_encoding);
-         if (OidIsValid(proc))
-             return proc;
-     }
-
-     /* Not found in path */
-     return InvalidOid;
- }
-
- /*
   * recomputeNamespacePath - recompute path derived variables if needed.
   */
  static void
--- 3415,3420 ----
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index e2feb17..89b1ccf 100644
*** a/src/backend/catalog/pg_conversion.c
--- b/src/backend/catalog/pg_conversion.c
***************
*** 14,19 ****
--- 14,20 ----
   */
  #include "postgres.h"

+ #include "access/genam.h"
  #include "access/heapam.h"
  #include "access/htup_details.h"
  #include "access/sysattr.h"
*************** ConversionCreate(const char *conname, Oi
*** 68,79 ****
      if (def)
      {
          /*
!          * make sure there is no existing default <for encoding><to encoding>
!          * pair in this name space
           */
!         if (FindDefaultConversion(connamespace,
!                                   conforencoding,
!                                   contoencoding))
              ereport(ERROR,
                      (errcode(ERRCODE_DUPLICATE_OBJECT),
                       errmsg("default conversion for %s to %s already exists",
--- 69,79 ----
      if (def)
      {
          /*
!          * make sure there is no existing default conversion for same
!          * encodings
           */
!         if (OidIsValid(FindDefaultConversionProc(conforencoding,
!                                                  contoencoding)))
              ereport(ERROR,
                      (errcode(ERRCODE_DUPLICATE_OBJECT),
                       errmsg("default conversion for %s to %s already exists",
*************** ConversionCreate(const char *conname, Oi
*** 100,106 ****
      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);

      tup = heap_form_tuple(tupDesc, values, nulls);

--- 100,109 ----
      values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
      values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
      values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
!     if (def)
!         values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(true);
!     else
!         nulls[Anum_pg_conversion_condefault - 1] = true;

      tup = heap_form_tuple(tupDesc, values, nulls);

*************** ConversionCreate(const char *conname, Oi
*** 145,159 ****
  /*
   * RemoveConversionById
   *
!  * Remove a tuple from pg_conversion by Oid. This function is solely
!  * called inside catalog/dependency.c
   */
  void
  RemoveConversionById(Oid conversionOid)
  {
      Relation    rel;
      HeapTuple    tuple;
!     HeapScanDesc scan;
      ScanKeyData scanKeyData;

      ScanKeyInit(&scanKeyData,
--- 148,162 ----
  /*
   * RemoveConversionById
   *
!  * Remove a tuple from pg_conversion by Oid.
!  * This function is solely called inside catalog/dependency.c.
   */
  void
  RemoveConversionById(Oid conversionOid)
  {
      Relation    rel;
      HeapTuple    tuple;
!     SysScanDesc scan;
      ScanKeyData scanKeyData;

      ScanKeyInit(&scanKeyData,
*************** RemoveConversionById(Oid conversionOid)
*** 161,213 ****
                  BTEqualStrategyNumber, F_OIDEQ,
                  ObjectIdGetDatum(conversionOid));

-     /* open pg_conversion */
      rel = heap_open(ConversionRelationId, RowExclusiveLock);

!     scan = heap_beginscan_catalog(rel, 1, &scanKeyData);

!     /* search for the target tuple */
!     if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
          simple_heap_delete(rel, &tuple->t_self);
      else
          elog(ERROR, "could not find tuple for conversion %u", conversionOid);
!     heap_endscan(scan);
      heap_close(rel, RowExclusiveLock);
  }

  /*
!  * FindDefaultConversion
   *
!  * Find "default" conversion proc by for_encoding and to_encoding in the
!  * given namespace.
   *
   * If found, returns the procedure's oid, otherwise InvalidOid.  Note that
   * you get the procedure's OID not the conversion's OID!
   */
  Oid
! FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
  {
!     CatCList   *catlist;
!     HeapTuple    tuple;
!     Form_pg_conversion body;
!     Oid            proc = InvalidOid;
!     int            i;

!     catlist = SearchSysCacheList3(CONDEFAULT,
!                                   ObjectIdGetDatum(name_space),
!                                   Int32GetDatum(for_encoding),
!                                   Int32GetDatum(to_encoding));

!     for (i = 0; i < catlist->n_members; i++)
      {
!         tuple = &catlist->members[i]->tuple;
!         body = (Form_pg_conversion) GETSTRUCT(tuple);
!         if (body->condefault)
!         {
!             proc = body->conproc;
!             break;
!         }
      }
!     ReleaseSysCacheList(catlist);
!     return proc;
  }
--- 164,229 ----
                  BTEqualStrategyNumber, F_OIDEQ,
                  ObjectIdGetDatum(conversionOid));

      rel = heap_open(ConversionRelationId, RowExclusiveLock);

!     scan = systable_beginscan(rel, ConversionOidIndexId, true,
!                               NULL, 1, &scanKeyData);

!     if (HeapTupleIsValid(tuple = systable_getnext(scan)))
          simple_heap_delete(rel, &tuple->t_self);
      else
          elog(ERROR, "could not find tuple for conversion %u", conversionOid);
!
!     systable_endscan(scan);
      heap_close(rel, RowExclusiveLock);
  }

  /*
!  * FindDefaultConversionProc
   *
!  * Find "default" conversion proc converting from for_encoding to to_encoding.
   *
   * If found, returns the procedure's oid, otherwise InvalidOid.  Note that
   * you get the procedure's OID not the conversion's OID!
   */
  Oid
! FindDefaultConversionProc(int32 for_encoding, int32 to_encoding)
  {
!     Oid            result = InvalidOid;
!     Relation    conRel;
!     ScanKeyData key[3];
!     SysScanDesc conScan;
!     HeapTuple    conTup;

!     conRel = heap_open(ConversionRelationId, AccessShareLock);

!     ScanKeyInit(&key[0],
!                 Anum_pg_conversion_conforencoding,
!                 BTEqualStrategyNumber, F_INT4EQ,
!                 Int32GetDatum(for_encoding));
!     ScanKeyInit(&key[1],
!                 Anum_pg_conversion_contoencoding,
!                 BTEqualStrategyNumber, F_INT4EQ,
!                 Int32GetDatum(to_encoding));
!     ScanKeyInit(&key[2],
!                 Anum_pg_conversion_condefault,
!                 BTEqualStrategyNumber, F_BOOLEQ,
!                 BoolGetDatum(true));
!
!     conScan = systable_beginscan(conRel, ConversionDefaultIndexId, true,
!                                  NULL, 3, key);
!
!     /* Assume there can be at most one match */
!     if (HeapTupleIsValid(conTup = systable_getnext(conScan)))
      {
!         Form_pg_conversion conForm = (Form_pg_conversion) GETSTRUCT(conTup);
!
!         result = conForm->conproc;
      }
!
!     systable_endscan(conScan);
!
!     relation_close(conRel, AccessShareLock);
!
!     return result;
  }
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 6eb2ac6..3d6f82b 100644
*** a/src/backend/utils/cache/syscache.c
--- b/src/backend/utils/cache/syscache.c
*************** static const struct cachedesc cacheinfo[
*** 303,319 ****
          },
          8
      },
-     {ConversionRelationId,        /* CONDEFAULT */
-         ConversionDefaultIndexId,
-         4,
-         {
-             Anum_pg_conversion_connamespace,
-             Anum_pg_conversion_conforencoding,
-             Anum_pg_conversion_contoencoding,
-             ObjectIdAttributeNumber,
-         },
-         8
-     },
      {ConversionRelationId,        /* CONNAMENSP */
          ConversionNameNspIndexId,
          2,
--- 303,308 ----
diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c
index 7f1c881..b9a9686 100644
*** a/src/backend/utils/mb/mbutils.c
--- b/src/backend/utils/mb/mbutils.c
***************
*** 35,41 ****
  #include "postgres.h"

  #include "access/xact.h"
! #include "catalog/namespace.h"
  #include "mb/pg_wchar.h"
  #include "utils/builtins.h"
  #include "utils/memutils.h"
--- 35,41 ----
  #include "postgres.h"

  #include "access/xact.h"
! #include "catalog/pg_conversion_fn.h"
  #include "mb/pg_wchar.h"
  #include "utils/builtins.h"
  #include "utils/memutils.h"
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 56c0528..3421b12 100644
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
*************** dumpConversion(Archive *fout, DumpOption
*** 12178,12183 ****
--- 12178,12184 ----
      conforencoding = PQgetvalue(res, 0, i_conforencoding);
      contoencoding = PQgetvalue(res, 0, i_contoencoding);
      conproc = PQgetvalue(res, 0, i_conproc);
+     /* condefault might be true, false, or null; this works regardless */
      condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');

      /*
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index ab2c1a8..25a465b 100644
*** a/src/include/catalog/indexing.h
--- b/src/include/catalog/indexing.h
*************** DECLARE_INDEX(pg_constraint_contypid_ind
*** 123,129 ****
  DECLARE_UNIQUE_INDEX(pg_constraint_oid_index, 2667, on pg_constraint using btree(oid oid_ops));
  #define ConstraintOidIndexId  2667

! DECLARE_UNIQUE_INDEX(pg_conversion_default_index, 2668, on pg_conversion using btree(connamespace oid_ops,
conforencodingint4_ops, contoencoding int4_ops, oid oid_ops)); 
  #define ConversionDefaultIndexId  2668
  DECLARE_UNIQUE_INDEX(pg_conversion_name_nsp_index, 2669, on pg_conversion using btree(conname name_ops, connamespace
oid_ops));
  #define ConversionNameNspIndexId  2669
--- 123,130 ----
  DECLARE_UNIQUE_INDEX(pg_constraint_oid_index, 2667, on pg_constraint using btree(oid oid_ops));
  #define ConstraintOidIndexId  2667

! /* NB: this index will not enforce uniqueness for rows with null condefault */
! DECLARE_UNIQUE_INDEX(pg_conversion_default_index, 2668, on pg_conversion using btree(conforencoding int4_ops,
contoencodingint4_ops, condefault bool_ops)); 
  #define ConversionDefaultIndexId  2668
  DECLARE_UNIQUE_INDEX(pg_conversion_name_nsp_index, 2669, on pg_conversion using btree(conname name_ops, connamespace
oid_ops));
  #define ConversionNameNspIndexId  2669
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 2ccb3a7..35b0369 100644
*** a/src/include/catalog/namespace.h
--- b/src/include/catalog/namespace.h
*************** extern void PopOverrideSearchPath(void);
*** 135,141 ****

  extern Oid    get_collation_oid(List *collname, bool missing_ok);
  extern Oid    get_conversion_oid(List *conname, bool missing_ok);
- extern Oid    FindDefaultConversionProc(int32 for_encoding, int32 to_encoding);

  /* initialization & transaction cleanup code */
  extern void InitializeSearchPath(void);
--- 135,140 ----
diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h
index 1cfe57c..7b8fff0 100644
*** a/src/include/catalog/pg_conversion.h
--- b/src/include/catalog/pg_conversion.h
***************
*** 32,38 ****
   *    conforencoding        FOR encoding id
   *    contoencoding        TO encoding id
   *    conproc                OID of the conversion proc
!  *    condefault            TRUE if this is a default conversion
   * ----------------------------------------------------------------
   */
  #define ConversionRelationId  2607
--- 32,41 ----
   *    conforencoding        FOR encoding id
   *    contoencoding        TO encoding id
   *    conproc                OID of the conversion proc
!  *    condefault            TRUE if this is a default conversion, else NULL
!  *
!  * (The odd definition of condefault allows us to make a poor man's
!  * partial unique index on conforencoding/contoencoding.)
   * ----------------------------------------------------------------
   */
  #define ConversionRelationId  2607
*************** CATALOG(pg_conversion,2607)
*** 45,51 ****
      int32        conforencoding;
      int32        contoencoding;
      regproc        conproc;
!     bool        condefault;
  } FormData_pg_conversion;

  /* ----------------
--- 48,57 ----
      int32        conforencoding;
      int32        contoencoding;
      regproc        conproc;
!
! #ifdef CATALOG_VARLEN            /* variable-length fields start here */
!     bool condefault BKI_FORCE_NULL;
! #endif
  } FormData_pg_conversion;

  /* ----------------
diff --git a/src/include/catalog/pg_conversion_fn.h b/src/include/catalog/pg_conversion_fn.h
index 9fcdde6..fb4eef7 100644
*** a/src/include/catalog/pg_conversion_fn.h
--- b/src/include/catalog/pg_conversion_fn.h
*************** extern ObjectAddress ConversionCreate(co
*** 22,27 ****
                   int32 conforencoding, int32 contoencoding,
                   Oid conproc, bool def);
  extern void RemoveConversionById(Oid conversionOid);
! extern Oid    FindDefaultConversion(Oid connamespace, int32 for_encoding, int32 to_encoding);

  #endif   /* PG_CONVERSION_FN_H */
--- 22,27 ----
                   int32 conforencoding, int32 contoencoding,
                   Oid conproc, bool def);
  extern void RemoveConversionById(Oid conversionOid);
! extern Oid    FindDefaultConversionProc(int32 for_encoding, int32 to_encoding);

  #endif   /* PG_CONVERSION_FN_H */
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 256615b..cd390b0 100644
*** a/src/include/utils/syscache.h
--- b/src/include/utils/syscache.h
*************** enum SysCacheIdentifier
*** 48,54 ****
      CLAOID,
      COLLNAMEENCNSP,
      COLLOID,
-     CONDEFAULT,
      CONNAMENSP,
      CONSTROID,
      CONVOID,
--- 48,53 ----
diff --git a/src/test/regress/expected/conversion.out b/src/test/regress/expected/conversion.out
index 37965ae..7260ed2 100644
*** a/src/test/regress/expected/conversion.out
--- b/src/test/regress/expected/conversion.out
*************** CREATE CONVERSION myconv FOR 'LATIN1' TO
*** 10,23 ****
  CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
  ERROR:  conversion "myconv" already exists
  --
! -- create default conversion with qualified name
  --
! CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
  --
! -- cannot make default conversion with same schema/for_encoding/to_encoding
  --
! CREATE DEFAULT CONVERSION public.mydef2 FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
! ERROR:  default conversion for LATIN1 to UTF8 already exists
  -- test comments
  COMMENT ON CONVERSION myconv_bad IS 'foo';
  ERROR:  conversion "myconv_bad" does not exist
--- 10,29 ----
  CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
  ERROR:  conversion "myconv" already exists
  --
! -- create a default conversion --- has to not match any built-in default,
! -- so we use a dummy function from regress.c
  --
! CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'BIG5' FROM iso8859_1_to_big5;
  --
! -- cannot make two default conversions for same encodings
  --
! CREATE DEFAULT CONVERSION mydef2 FOR 'LATIN1' TO 'BIG5' FROM iso8859_1_to_big5;
! ERROR:  default conversion for LATIN1 to BIG5 already exists
! --
! -- verify that we notice if wrong conversion function is specified
! --
! CREATE CONVERSION bogus FOR 'BIG5' TO 'UTF8' FROM iso8859_1_to_utf8;
! ERROR:  expected source encoding "LATIN1", but got "BIG5"
  -- test comments
  COMMENT ON CONVERSION myconv_bad IS 'foo';
  ERROR:  conversion "myconv_bad" does not exist
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 616e674..2618f69 100644
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p.oid = c.conproc AND
*** 853,859 ****
  -- there is no way to ask convert() to invoke them, and we cannot call
  -- them directly from SQL.  But there are no non-default built-in
  -- conversions anyway.
- -- (Similarly, this doesn't cope with any search path issues.)
  SELECT p1.oid, p1.conname
  FROM pg_conversion as p1
  WHERE condefault AND
--- 853,858 ----
diff --git a/src/test/regress/input/create_function_1.source b/src/test/regress/input/create_function_1.source
index f2b1561..6ed53a5 100644
*** a/src/test/regress/input/create_function_1.source
--- b/src/test/regress/input/create_function_1.source
*************** CREATE FUNCTION test_atomic_ops()
*** 62,67 ****
--- 62,72 ----
      AS '@libdir@/regress@DLSUFFIX@'
      LANGUAGE C;

+ CREATE FUNCTION iso8859_1_to_big5(int4, int4, cstring, internal, int4)
+     RETURNS void
+     AS '@libdir@/regress@DLSUFFIX@'
+     LANGUAGE C STRICT;
+
  -- Things that shouldn't work:

  CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
diff --git a/src/test/regress/output/create_function_1.source b/src/test/regress/output/create_function_1.source
index 30c2936..603499c 100644
*** a/src/test/regress/output/create_function_1.source
--- b/src/test/regress/output/create_function_1.source
*************** CREATE FUNCTION test_atomic_ops()
*** 55,60 ****
--- 55,64 ----
      RETURNS bool
      AS '@libdir@/regress@DLSUFFIX@'
      LANGUAGE C;
+ CREATE FUNCTION iso8859_1_to_big5(int4, int4, cstring, internal, int4)
+     RETURNS void
+     AS '@libdir@/regress@DLSUFFIX@'
+     LANGUAGE C STRICT;
  -- Things that shouldn't work:
  CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
      AS 'SELECT ''not an integer'';';
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index bb30629..294cdc4 100644
*** a/src/test/regress/regress.c
--- b/src/test/regress/regress.c
***************
*** 29,34 ****
--- 29,35 ----
  #include "commands/trigger.h"
  #include "executor/executor.h"
  #include "executor/spi.h"
+ #include "mb/pg_wchar.h"
  #include "miscadmin.h"
  #include "port/atomics.h"
  #include "utils/builtins.h"
*************** test_atomic_ops(PG_FUNCTION_ARGS)
*** 1120,1122 ****
--- 1121,1153 ----

      PG_RETURN_BOOL(true);
  }
+
+
+ PG_FUNCTION_INFO_V1(iso8859_1_to_big5);
+ Datum
+ iso8859_1_to_big5(PG_FUNCTION_ARGS)
+ {
+     unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
+     unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
+     int            len = PG_GETARG_INT32(4);
+     unsigned short c;
+
+     CHECK_ENCODING_CONVERSION_ARGS(PG_LATIN1, PG_BIG5);
+
+     /*
+      * Since this is a dummy implementation, just throw error for non-ASCII
+      * characters.
+      */
+     while (len > 0)
+     {
+         c = *src;
+         if (c == 0 || IS_HIGHBIT_SET(c))
+             report_invalid_encoding(PG_LATIN1, (const char *) src, len);
+         *dest++ = c;
+         src++;
+         len--;
+     }
+     *dest = '\0';
+
+     PG_RETURN_VOID();
+ }
diff --git a/src/test/regress/sql/conversion.sql b/src/test/regress/sql/conversion.sql
index e31876b..68fb6e2 100644
*** a/src/test/regress/sql/conversion.sql
--- b/src/test/regress/sql/conversion.sql
***************
*** 3,21 ****
  --
  CREATE USER conversion_test_user WITH NOCREATEDB NOCREATEROLE;
  SET SESSION AUTHORIZATION conversion_test_user;
  CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
  --
  -- cannot make same name conversion in same schema
  --
  CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
  --
! -- create default conversion with qualified name
  --
! CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
  --
! -- cannot make default conversion with same schema/for_encoding/to_encoding
  --
! CREATE DEFAULT CONVERSION public.mydef2 FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
  -- test comments
  COMMENT ON CONVERSION myconv_bad IS 'foo';
  COMMENT ON CONVERSION myconv IS 'bar';
--- 3,28 ----
  --
  CREATE USER conversion_test_user WITH NOCREATEDB NOCREATEROLE;
  SET SESSION AUTHORIZATION conversion_test_user;
+
  CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
  --
  -- cannot make same name conversion in same schema
  --
  CREATE CONVERSION myconv FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
  --
! -- create a default conversion --- has to not match any built-in default,
! -- so we use a dummy function from regress.c
  --
! CREATE DEFAULT CONVERSION public.mydef FOR 'LATIN1' TO 'BIG5' FROM iso8859_1_to_big5;
  --
! -- cannot make two default conversions for same encodings
  --
! CREATE DEFAULT CONVERSION mydef2 FOR 'LATIN1' TO 'BIG5' FROM iso8859_1_to_big5;
! --
! -- verify that we notice if wrong conversion function is specified
! --
! CREATE CONVERSION bogus FOR 'BIG5' TO 'UTF8' FROM iso8859_1_to_utf8;
!
  -- test comments
  COMMENT ON CONVERSION myconv_bad IS 'foo';
  COMMENT ON CONVERSION myconv IS 'bar';
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index d6aa2e8..6216083 100644
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p.oid = c.conproc AND
*** 488,494 ****
  -- there is no way to ask convert() to invoke them, and we cannot call
  -- them directly from SQL.  But there are no non-default built-in
  -- conversions anyway.
- -- (Similarly, this doesn't cope with any search path issues.)

  SELECT p1.oid, p1.conname
  FROM pg_conversion as p1
--- 488,493 ----

pgsql-hackers by date:

Previous
From: Petr Korobeinikov
Date:
Subject: Add schema-qualified relnames in constraint error messages.
Next
From: Haribabu Kommi
Date:
Subject: Re: Multi-tenancy with RLS