public inbox for [email protected]  
help / color / mirror / Atom feed
From: Boguk, Maksym <[email protected]>
To: [email protected]
Subject: UTF8 national character data type support WIP patch and list of open issues.
Date: Tue, 3 Sep 2013 12:28:45 +1000
Message-ID: <[email protected]> (raw)
List-Unsubscribe: <mailto:[email protected]?body=unsub%20pgsql-hackers>

Hi,

As part of my job I started developing in-core support for the UTF8
National Character types (national character/national character
variable).
I attached current WIP patch (against HEAD) to community review.

Target usage:  ability to store UTF8 national characters in some
selected fields inside a single-byte encoded database.
For sample if I have a ru-RU.koi8r encoded database with mostly Russian
text inside,  it would be nice to be able store an Japanese text in one
field without converting the whole database to UTF8 (convert such
database to UTF8 easily could almost double the database size even if
only one field in whole database will use any symbols outside of
ru-RU.koi8r encoding).

What has been done:

1)Addition of new string data types NATIONAL CHARACTER and NATIONAL
CHARACTER VARIABLE. 
These types differ from the char/varchar data types in one important
respect:  NATIONAL string types are always have UTF8 encoding even
(independent from used database encoding).
Of course that lead to encoding conversion overhead when comparing
NATIONAL string types with common string types (that is expected and
unavoidable).
2)Some ECPG support for these types
3)Some documentation patch (not finished)

What need to be done:

1)Full set of string functions and operators for NATIONAL types (we
could not use generic text functions because they assume that the stings
will have database encoding).
Now only basic set implemented.
2)Need implement some way to define default collation for a NATIONAL
types.
3)Need implement some way to input UTF8 characters into NATIONAL types
via SQL  (there are serious open problem... it will be defined later in
the text).

Most serious open problem that the patch in current state doesn't allow
input/output UTF8 symbols which could not be represented in used
database encoding into NATIONAL fields.
It happen because encoding conversion from the client_encoding to the
database encoding happens before syntax analyze/parse stage and throw an
error for symbols which could not be represented.
I don't see any good solution to this problem except made whole codebase
use an UTF8 encoding for the all internal operations with huge
performance hit.
May be someone have good idea how to deal with this issue.

That is really WIP patch (with lots things on todo list/required
polish).

Kindly please tell me what you think about this idea/patch in general.

PS: It is my first patch to PostgreSQL so there are a lot of space to
improvement/style for sure.


Kind Regards,
Maksym







-- 
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Attachments:

  [application/octet-stream] pgHEAD_UTF8NCHAR.patch (210.6K, ../[email protected]/2-pgHEAD_UTF8NCHAR.patch)
  download | inline diff:
diff -U 5 -N -r -w ../orig.HEAD/doc/src/sgml/datatype.sgml ./doc/src/sgml/datatype.sgml
--- ../orig.HEAD/doc/src/sgml/datatype.sgml	2013-08-19 20:22:06.000000000 -0400
+++ ./doc/src/sgml/datatype.sgml	2013-08-19 20:54:00.000000000 -0400
@@ -159,10 +159,22 @@
        <entry></entry>
        <entry>currency amount</entry>
       </row>
 
       <row>
+       <entry><type>national character varying [ (<replaceable>n</replaceable>) ]</type></entry>
+       <entry><type>nvarchar [ (<replaceable>n</replaceable>) ]</type></entry>
+       <entry>variable-length national character string</entry>
+      </row>
+
+      <row>
+       <entry><type>national character [ (<replaceable>n</replaceable>) ]</type></entry>
+       <entry><type>nchar [ (<replaceable>n</replaceable>) ]</type></entry>
+       <entry>fixed-length national character string</entry>
+      </row>
+
+      <row>
        <entry><type>numeric [ (<replaceable>p</replaceable>,
          <replaceable>s</replaceable>) ]</type></entry>
        <entry><type>decimal [ (<replaceable>p</replaceable>,
          <replaceable>s</replaceable>) ]</type></entry>
        <entry>exact numeric of selectable precision</entry>
@@ -4661,6 +4673,195 @@
     <type>internal</> argument.
    </para>
 
   </sect1>
 
+  <sect1 id="datatype-national-character">
+   <title>National Character Types</title>
+
+   <indexterm zone="datatype-national-character">
+    <primary>national character string</primary>
+    <secondary>data types</secondary>
+   </indexterm>
+
+   <indexterm>
+    <primary>string</primary>
+    <see>national character string</see>
+   </indexterm>
+
+   <indexterm zone="datatype-national-character">
+    <primary>national character</primary>
+   </indexterm>
+
+   <indexterm zone="datatype-national-character">
+    <primary>national character varying</primary>
+   </indexterm>
+
+   <indexterm zone="datatype-national-character">
+    <primary>nchar</primary>
+   </indexterm>
+
+   <indexterm zone="datatype-national-character">
+    <primary>nvarchar</primary>
+   </indexterm>
+
+    <table id="datatype-national-character-table">
+     <title>National Character Types</title>
+     <tgroup cols="2">
+      <thead>
+       <row>
+        <entry>Name</entry>
+        <entry>Description</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry><type>national character varying(<replaceable>n</>)</type>, <type>nvarchar(<replaceable>n</>)</type></entry>
+        <entry>variable-length with limit</entry>
+       </row>
+       <row>
+        <entry><type>national character(<replaceable>n</>)</type>, <type>nchar(<replaceable>n</>)</type></entry>
+        <entry>fixed-length, blank padded</entry>
+       </row>
+     </tbody>
+     </tgroup>
+    </table>
+
+   <para>
+    <xref linkend="datatype-national-character-table"> shows the
+    general-purpose national character types available in
+    <productname>PostgreSQL</productname>.
+   </para>
+
+   <para>
+    <acronym>SQL</acronym> defines two primary national character types:
+    <type>national character varying(<replaceable>n</>)</type> and
+    <type>national character(<replaceable>n</>)</type>, where <replaceable>n</>
+    is a positive integer.  Both of these types can store strings up to
+    <replaceable>n</> national characters (not bytes) in length.  An attempt to store a
+    longer string into a column of these types will result in an
+    error, unless the excess characters are all spaces, in which case
+    the string will be truncated to the maximum length. 
+    If the string to be stored is shorter than the declared
+    length, values of type <type>national character</type> will be space-padded;
+    values of type <type>national character varying</type> will simply store the
+    shorter
+    string.
+   </para>
+
+   <para>
+    If one explicitly casts a value to <type>national character
+    varying(<replaceable>n</>)</type> or
+    <type>national character(<replaceable>n</>)</type>, then an over-length
+    value will be truncated to <replaceable>n</> characters without
+    raising an error. (This too is required by the
+    <acronym>SQL</acronym> standard.)
+   </para>
+
+   <para>
+    The notations <type>nvarchar(<replaceable>n</>)</type> and
+    <type>nchar(<replaceable>n</>)</type> are aliases for <type>national character
+    varying(<replaceable>n</>)</type> and
+    <type>national character(<replaceable>n</>)</type>, respectively.
+    <type>national character</type> without length specifier is equivalent to
+    <type>national character(1)</type>. If <type>national character varying</type> is used
+    without length specifier, the type accepts strings of any size. The
+    latter is a <productname>PostgreSQL</> extension.
+   </para>
+
+   <para>
+    Values of type <type>national character</type> are physically padded
+    with spaces to the specified width <replaceable>n</>, and are
+    stored and displayed that way.  However, the padding spaces are
+    treated as semantically insignificant.  Trailing spaces are
+    disregarded when comparing two values of type <type>national character</type>,
+    and they will be removed when converting a <type>national character</type> value
+    to one of the other string types.  Note that trailing spaces
+    <emphasis>are</> semantically significant in
+    <type>national character varying</type> values, and
+    when using pattern matching, e.g. <literal>LIKE</>,
+    regular expressions.
+   </para>
+
+   <para>
+    The storage requirement for a short string (up to 126 bytes) is 1 byte
+    plus the actual string, which includes the space padding in the case of
+    <type>national character</type>.  Longer strings have 4 bytes of overhead instead
+    of 1.  Long strings are compressed by the system automatically, so
+    the physical requirement on disk might be less. Very long values are also
+    stored in background tables so that they do not interfere with rapid
+    access to shorter column values. In any case, the longest
+    possible character string that can be stored is about 1 GB. (The
+    maximum value that will be allowed for <replaceable>n</> in the data
+    type declaration is less than that. It wouldn't be useful to
+    change this because with multibyte character encodings the number of
+    characters and bytes can be quite different. If you desire to
+    store long strings with no specific upper limit, use
+    <type>text</type> or <type>national character varying</type> without a length
+    specifier, rather than making up an arbitrary length limit.)
+   </para>
+
+   <tip>
+    <para>
+     There is no performance difference among these two types,
+     apart from increased storage space when using the blank-padded
+     type, and a few extra CPU cycles to check the length when storing into
+     a length-constrained column.  While
+     <type>national character(<replaceable>n</>)</type> has performance
+     advantages in some other database systems, there is no such advantage in
+     <productname>PostgreSQL</productname>; in fact
+     <type>national character(<replaceable>n</>)</type> is usually the slowest of
+     the three because of its additional storage costs.  In most situations
+     <type>text</type> or <type>national character varying</type> should be used
+     instead.
+    </para>
+   </tip>
+
+   <para>
+    Refer to <xref linkend="sql-syntax-strings"> for information about
+    the syntax of string literals, and to <xref linkend="functions">
+    for information about available operators and functions. The
+    database character set determines the character set used to store
+    textual values. The <type>national character varying</type> or <type>national character</type> types are supported only when the database encoding is UTF-8; for more information on character set support,
+    refer to <xref linkend="multibyte">.
+   </para>
+
+   <example>
+    <title>Using the National Character Types</title>
+
+<programlisting>
+CREATE TABLE test1 (a national character(4));
+INSERT INTO test1 VALUES (N'ok');
+SELECT a, char_length(a) FROM test1; -- <co id="co.datatype-nchar">
+<computeroutput>
+  a   | char_length
+------+-------------
+ ok   |           2
+</computeroutput>
+
+CREATE TABLE test2 (b nvarchar(5));
+INSERT INTO test2 VALUES (N'ok');
+INSERT INTO test2 VALUES (N'good      ');
+INSERT INTO test2 VALUES (N'too long');
+<computeroutput>ERROR:  value too long for type national character varying(5)</computeroutput>
+INSERT INTO test2 VALUES ('too long'::nvarchar(5)); -- explicit truncation
+SELECT b, char_length(b) FROM test2;
+<computeroutput>
+   b   | char_length
+-------+-------------
+ ok    |           2
+ good  |           5
+ too l |           5
+</computeroutput>
+</programlisting>
+    <calloutlist>
+     <callout arearefs="co.datatype-nchar">
+      <para>
+       The <function>char_length</function> function is discussed in
+       <xref linkend="functions-string">.
+      </para>
+     </callout>
+    </calloutlist>
+   </example>
+
+  </sect1>
  </chapter>
diff -U 5 -N -r -w ../orig.HEAD/doc/src/sgml/ecpg.sgml ./doc/src/sgml/ecpg.sgml
--- ../orig.HEAD/doc/src/sgml/ecpg.sgml	2013-08-19 20:22:06.000000000 -0400
+++ ./doc/src/sgml/ecpg.sgml	2013-08-19 20:54:00.000000000 -0400
@@ -888,10 +888,20 @@
 
       <row>
        <entry><type>boolean</type></entry>
        <entry><type>bool</type><footnote><para>declared in <filename>ecpglib.h</filename> if not native</para></footnote></entry>
       </row>
+      
+      <row>
+       <entry><type>national character(<replaceable>n</>)</type>, <type>nvarchar(<replaceable>n</>)</type></entry>
+       <entry><type>NCHAR[<replaceable>n</>+1]</type>, <type>NVARCHAR[<replaceable>n</>+1]</type></entry>
+      </row>
+      
+      <row>
+       <entry><type>national character(<replaceable>n</>)</type>, <type>nvarchar(<replaceable>n</>)</type>, <type>character(<replaceable>n</>)</type>, <type>varchar(<replaceable>n</>)</type>, <type>text</type></entry>
+       <entry><type>UVARCHAR[<replaceable>2*n</>]</type></entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
 
    <sect3 id="ecpg-char">
@@ -966,10 +976,197 @@
      also hold values of other SQL types, which will be stored in
      their string forms.
     </para>
    </sect3>
 
+   <sect3 id="ecpg-nchar">
+    <title>Handling National Character Strings</title>
+
+    <para>
+     To handle SQL national character string data types, such
+     as <type>nvarchar</type> and <type>nchar</type>, there are two
+     possible ways to declare the host variables.
+    </para>
+
+    <para>
+     One way is using <type>NCHAR[]</type>, an array
+     of <type>NCHAR</type>, internally which is mapped to an array of <type>char</type> which is the most common way to handle
+     character data in C.
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+    NCHAR str[50];
+EXEC SQL END DECLARE SECTION;
+</programlisting>
+     Note that you have to take care of the length yourself.  If you
+     use this host variable as the target variable of a query which
+     returns a string with more than 49 characters, a buffer overflow
+     occurs.
+    </para>
+
+    <para>
+     The other way is using the <type>NVARCHAR</type> type, which is a
+     special type provided by ECPG.  The definition on an array of
+     type <type>NVARCHAR</type> is converted into a
+     named <type>struct</> for every variable. A declaration like:
+<programlisting>
+NVARCHAR var[180];
+</programlisting>
+     is converted into:
+<programlisting>
+struct varchar_var { int len; char arr[180]; } var;
+</programlisting>
+     The member <structfield>arr</structfield> hosts the string
+     including a terminating zero byte.  Thus, to store a string in
+     a <type>NVARCHAR</type> host variable, the host variable has to be
+     declared with the length including the zero byte terminator.  The
+     member <structfield>len</structfield> holds the length of the
+     string stored in the <structfield>arr</structfield> without the
+     terminating zero byte.  When a host variable is used as input for
+     a query, if <literal>strlen(arr)</literal>
+     and <structfield>len</structfield> are different, the shorter one
+     is used.
+    </para>
+
+    <para>
+     Two or more <type>NVARCHAR</type> host variables cannot be defined
+     in single line statement.  The following code will confuse
+     the <command>ecpg</command> preprocessor:
+<programlisting>
+NVARCHAR v1[128], v2[128];   /* WRONG */
+</programlisting>
+     Two variables should be defined in separate statements like this:
+<programlisting>
+NVARCHAR v1[128];
+NVARCHAR v2[128];
+</programlisting>
+    </para>
+
+    <para>
+     <type>NVARCHAR</type> and <type>NCHAR</type> can be written in upper or lower case, but
+     not in mixed case.
+    </para>
+
+    <para>
+     <type>NCHAR</type> and <type>NVARCHAR</type> host variables can
+     also hold values of other SQL types, which will be stored in
+     their string forms. NVARCHAR type is pretty similar to VARCHAR type 
+     and added mainly for SQL standard compatibility.
+    </para>
+   </sect3>
+
+   <sect3 id="ecpg-uvarchar">
+    <title>Handling Strings with UVARCHAR type</title>
+
+    <para>
+     ECPG contains a special type <type>UVARCHAR</type> for defining host variables to store 
+     character string and national character string values from respective SQL types. 
+
+     This type is preprocessed into a structure with length and buffer fields.
+
+     <programlisting>
+      struct uvarchar_var { int len; char arr[180]; } uvc;
+     </programlisting>
+
+    The data stored by <type>UVARCHAR</type> type structure is always in UTF-16 encoding. There is an implicit conversion from UTF-8 to UTF-16 when UVARCHAR type is created.
+    </para>
+    
+    <para>
+     The sample usage of UVARCHAR to handle string data
+     
+     <programlisting>
+      #include &lt;stdio.h>
+ 
+      EXEC SQL INCLUDE sqlca;
+      EXEC SQL WHENEVER SQLERROR   SQLPRINT;
+      
+      int main( int argc, char * argv[] )
+      {
+          EXEC SQL BEGIN DECLARE SECTION;
+          UVARCHAR uv[100];
+          EXEC SQL END DECLARE SECTION;
+      
+          EXEC SQL CONNECT TO postgres;
+          EXEC SQL CREATE TABLE test (a nvarchar);
+          EXEC SQL INSERT INTO test (a) values ('ok'),
+      ...
+          EXEC SQL SELECT a INTO :uv FROM test;
+          printf("value=%s length=%d\n", uv.arr, uv.len);
+      ...
+      ...
+      }
+     </programlisting>
+
+     The member <structfield>arr</structfield> hosts the string
+     without a terminating zero byte.  As the default encoding for 
+     <type>UVARCHAR</type> is UTF-16, to store a string in a 
+     <type>UVARCHAR</type> host variable, the host variable has to be
+     declared with the minimum length of 2*n. The member <structfield>len</structfield> 
+     holds the length of the string stored in the <structfield>arr</structfield>.
+     When a host variable is used as input for a query, 
+     if <literal>strlen(arr)</literal> and <structfield>len</structfield> 
+     are different, the shorter one is used.
+
+    </para>
+
+   </sect3>
+
+   <sect3 id="ecpg-datatype-comparison">
+    <title>Comparison between VARCHAR, NVARCHAR and UVARCHAR Types</title>
+    <para>
+    The host data types used for handling string values, differ in few aspects like memory usage, encoding, performance etc.
+    <xref linkend="ecpg-datatype-comaprison-table"> shows the comparison of 
+    host data types.
+ 
+    </para>
+    <table id="ecpg-datatype-comaprison-table">
+     <title>Comparison between VARCHAR, NVARCHAR and UVARCHAR Types</title>
+
+     <tgroup cols="4">
+      <thead>
+       <row>
+        <entry></entry>
+        <entry>VARCHAR</entry>
+        <entry>NVARCHAR</entry>
+        <entry>UVARCHAR</entry>
+       </row>
+      </thead>
+
+      <tbody>
+       <row>
+        <entry><type>Maximum Size for 'n' characters</type></entry>
+        <entry><type>4*n + 1</type></entry>
+        <entry><type>4*n + 1</type></entry>
+        <entry><type>4*n</type></entry>
+       </row>
+       <row>
+        <entry><type>Minimum Size for 'n' characters</type></entry>
+        <entry><type>n + 1</type></entry>
+        <entry><type>n + 1</type></entry>
+        <entry><type>2*n</type></entry>
+       </row>
+       <row>
+        <entry><type>Encoding Used</type></entry>
+        <entry><type>client encoding</type></entry>
+        <entry><type>client encoding</type></entry>
+        <entry><type>UTF-16</type></entry>
+       </row>
+       <row>
+        <entry><type>Zero Terminated</type></entry>
+        <entry><type>Yes</type></entry>
+        <entry><type>Yes</type></entry>
+        <entry><type>No</type></entry>
+       </row>
+
+      </tbody>
+     </tgroup>
+    </table>
+
+	<para>
+     Please note that the data conversion from UTF-8 encoding to UTF-16 encoding will incur a negligible performance overhead in case of UVARCHAR Type.
+    </para>
+   </sect3>
+
    <sect3 id="ecpg-special-types">
     <title>Accessing Special Data Types</title>
 
     <para>
      ECPG contains some special types that help you to interact easily
diff -U 5 -N -r -w ../orig.HEAD/doc/src/sgml/syntax.sgml ./doc/src/sgml/syntax.sgml
--- ../orig.HEAD/doc/src/sgml/syntax.sgml	2013-08-19 20:22:06.000000000 -0400
+++ ./doc/src/sgml/syntax.sgml	2013-08-19 20:54:00.000000000 -0400
@@ -551,10 +551,37 @@
      To include the escape character in the string literally, write it
      twice.
     </para>
    </sect3>
 
+   <sect3 id="sql-syntax-strings-N">
+    <title>String Constants with prefix N</title>
+
+    <indexterm  zone="sql-syntax-strings-N">
+     <primary>Prefix N</primary>
+     <secondary>in string constants</secondary>
+    </indexterm>
+
+    <para>
+    The standard syntax for specifying national character type string constants 
+    is to add a prefix 'N' to the string constant. This string constant syntax
+    is supported only when the database encoding is UTF-8.
+    
+    The following trivial example shows how to pass a national character type 
+    string constant with prefix 'N'
+    
+        <programlisting>
+			INSERT INTO test VALUES (N'ok');
+		</programlisting>
+    
+    </para>
+    <para>
+    Please note that this syntax is optional and national character type string constants can also be specified bounded by single quotes (<literal>'</literal>), for example
+     <literal>'ok'</literal>.
+    </para>
+   </sect3>
+
    <sect3 id="sql-syntax-dollar-quoting">
     <title>Dollar-quoted String Constants</title>
 
      <indexterm>
       <primary>dollar quoting</primary>
diff -U 5 -N -r -w ../orig.HEAD/src/backend/catalog/information_schema.sql ./src/backend/catalog/information_schema.sql
--- ../orig.HEAD/src/backend/catalog/information_schema.sql	2013-08-19 20:22:07.000000000 -0400
+++ ./src/backend/catalog/information_schema.sql	2013-08-19 20:54:00.000000000 -0400
@@ -77,11 +77,11 @@
     RETURNS NULL ON NULL INPUT
     AS
 $$SELECT
   CASE WHEN $2 = -1 /* default typmod */
        THEN null
-       WHEN $1 IN (1042, 1043) /* char, varchar */
+       WHEN $1 IN (1042, 1043, 5001, 6001) /* char, varchar, nchar, nvarchar */
        THEN $2 - 4
        WHEN $1 IN (1560, 1562) /* bit, varbit */
        THEN $2
        ELSE null
   END$$;
@@ -90,11 +90,11 @@
     LANGUAGE sql
     IMMUTABLE
     RETURNS NULL ON NULL INPUT
     AS
 $$SELECT
-  CASE WHEN $1 IN (25, 1042, 1043) /* text, char, varchar */
+  CASE WHEN $1 IN (25, 1042, 1043, 5001, 6001) /* text, char, varchar, nchar, nvarchar */
        THEN CASE WHEN $2 = -1 /* default typmod */
                  THEN CAST(2^30 AS integer)
                  ELSE information_schema._pg_char_max_length($1, $2) *
                       pg_catalog.pg_encoding_max_length((SELECT encoding FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database()))
             END
diff -U 5 -N -r -w ../orig.HEAD/src/backend/parser/gram.y ./src/backend/parser/gram.y
--- ../orig.HEAD/src/backend/parser/gram.y	2013-08-19 20:22:08.000000000 -0400
+++ ./src/backend/parser/gram.y	2013-08-19 21:42:23.000000000 -0400
@@ -439,13 +439,15 @@
 
 %type <typnam>	Typename SimpleTypename ConstTypename
 				GenericType Numeric opt_float
 				Character ConstCharacter
 				CharacterWithLength CharacterWithoutLength
+				NCharacterWithLength NCharacterWithoutLength
 				ConstDatetime ConstInterval
 				Bit ConstBit BitWithLength BitWithoutLength
 %type <str>		character
+%type <str>             ncharacter
 %type <str>		extract_arg
 %type <str>		opt_charset
 %type <boolean> opt_varying opt_timezone opt_no_inherit
 
 %type <ival>	Iconst SignedIconst
@@ -562,10 +564,11 @@
 	MAPPING MATCH MATERIALIZED MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
 
 	NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NONE
 	NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF
 	NULLS_P NUMERIC
+	NVARCHAR
 
 	OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR
 	ORDER ORDINALITY OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
 
 	PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POSITION
@@ -10277,13 +10280,22 @@
 				}
 			| CharacterWithoutLength
 				{
 					$$ = $1;
 				}
+			| NCharacterWithLength
+				{
+					$$ = $1;
+				}
+			| NCharacterWithoutLength
+				{
+					$$ = $1;
+				}
 		;
 
-ConstCharacter:  CharacterWithLength
+ConstCharacter:
+			CharacterWithLength
 				{
 					$$ = $1;
 				}
 			| CharacterWithoutLength
 				{
@@ -10294,13 +10306,79 @@
 					 * was not specified.
 					 */
 					$$ = $1;
 					$$->typmods = NIL;
 				}
+			| NCharacterWithLength
+				{
+					$$ = $1;
+				}
+			| NCharacterWithoutLength
+				{
+					/* Length was not specified so allow to be unrestricted.
+					* This handles problems with fixed-length (bpchar) strings
+					* which in column definitions must default to a length
+					* of one, but should not be constrained if the length
+					* was not specified.
+					*/
+					$$ = $1;
+					$$->typmods = NIL;
+				}
 		;
 
-CharacterWithLength:  character '(' Iconst ')' opt_charset
+NCharacterWithLength:
+			NATIONAL ncharacter '(' Iconst ')' opt_charset
+				{
+					if (($6 != NULL) && (strcmp($6, "sql_text") != 0))
+				{
+						char *type;
+
+						type = palloc(strlen($2) + 1 + strlen($2) + 1);
+						strcpy(type, $2);
+						strcat(type, "_");
+						strcat(type, $6);
+						$1 = type;
+					}
+					$$ = SystemTypeName($2);
+					$$->typmods = list_make1(makeIntConst($4, @4));
+					$$->location = @1;
+				}
+		;
+
+NCharacterWithoutLength:
+			NATIONAL ncharacter opt_charset
+				{
+					if (($3 != NULL) && (strcmp($3, "sql_text") != 0))
+					{
+						char *type;
+
+						type = palloc(strlen($2) + 1 + strlen($3) + 1);
+						strcpy(type, $2);
+						strcat(type, "_");
+						strcat(type, $3);
+						$2 = type;
+					}
+					$$ = SystemTypeName($2);
+					/* nchar defaults to char(1), varchar to no limit */
+					if (strcmp($2, "nbpchar") == 0)
+						$$->typmods = list_make1(makeIntConst(1, -1));
+
+					$$->location = @1;
+				}
+		;
+
+ncharacter:
+			CHARACTER opt_varying
+				{ $$ = $2 ? "nvarchar": "nbpchar"; }
+			| CHAR_P opt_varying
+				{ $$ = $2 ? "nvarchar": "nbpchar"; }
+			| VARCHAR
+				{ $$ = "nvarchar"; }
+		;
+
+CharacterWithLength:
+			  character '(' Iconst ')' opt_charset
 				{
 					if (($5 != NULL) && (strcmp($5, "sql_text") != 0))
 					{
 						char *type;
 
@@ -10315,11 +10393,12 @@
 					$$->typmods = list_make1(makeIntConst($3, @3));
 					$$->location = @1;
 				}
 		;
 
-CharacterWithoutLength:	 character opt_charset
+CharacterWithoutLength:
+			 character opt_charset
 				{
 					if (($2 != NULL) && (strcmp($2, "sql_text") != 0))
 					{
 						char *type;
 
@@ -10330,30 +10409,29 @@
 						$1 = type;
 					}
 
 					$$ = SystemTypeName($1);
 
-					/* char defaults to char(1), varchar to no limit */
-					if (strcmp($1, "bpchar") == 0)
+					/* [n]char defaults to [national ]char(1), varchar to no limit */
+					if ((strcmp($1, "bpchar") == 0) || (strcmp($1, "nbpchar") == 0))
 						$$->typmods = list_make1(makeIntConst(1, -1));
 
 					$$->location = @1;
 				}
 		;
 
-character:	CHARACTER opt_varying
+character:
+			CHARACTER opt_varying
 										{ $$ = $2 ? "varchar": "bpchar"; }
 			| CHAR_P opt_varying
 										{ $$ = $2 ? "varchar": "bpchar"; }
 			| VARCHAR
 										{ $$ = "varchar"; }
-			| NATIONAL CHARACTER opt_varying
-										{ $$ = $3 ? "varchar": "bpchar"; }
-			| NATIONAL CHAR_P opt_varying
-										{ $$ = $3 ? "varchar": "bpchar"; }
 			| NCHAR opt_varying
-										{ $$ = $2 ? "varchar": "bpchar"; }
+				{ $$ = $2 ? "nvarchar": "nbpchar"; }
+			| NVARCHAR
+				{ $$ = "nvarchar"; }
 		;
 
 opt_varying:
 			VARYING									{ $$ = TRUE; }
 			| /*EMPTY*/								{ $$ = FALSE; }
@@ -12739,10 +12817,11 @@
 			| NATIONAL
 			| NCHAR
 			| NONE
 			| NULLIF
 			| NUMERIC
+			| NVARCHAR
 			| OUT_P
 			| OVERLAY
 			| POSITION
 			| PRECISION
 			| REAL
diff -U 5 -N -r -w ../orig.HEAD/src/backend/parser/scan.l ./src/backend/parser/scan.l
--- ../orig.HEAD/src/backend/parser/scan.l	2013-08-19 20:22:08.000000000 -0400
+++ ./src/backend/parser/scan.l	2013-08-19 22:27:02.000000000 -0400
@@ -480,11 +480,11 @@
 					const ScanKeyword *keyword;
 
 					SET_YYLLOC();
 					yyless(1);				/* eat only 'n' this time */
 
-					keyword = ScanKeywordLookup("nchar",
+					keyword = ScanKeywordLookup("nvarchar",
 												yyextra->keywords,
 												yyextra->num_keywords);
 					if (keyword != NULL)
 					{
 						yylval->keyword = keyword->name;
diff -U 5 -N -r -w ../orig.HEAD/src/backend/utils/adt/format_type.c ./src/backend/utils/adt/format_type.c
--- ../orig.HEAD/src/backend/utils/adt/format_type.c	2013-08-19 20:22:09.000000000 -0400
+++ ./src/backend/utils/adt/format_type.c	2013-08-19 20:54:00.000000000 -0400
@@ -216,10 +216,25 @@
 			}
 			else
 				buf = pstrdup("character");
 			break;
 
+		case NBPCHAROID:
+			if (with_typemod)
+				buf = printTypmod("national character", typemod, typeform->typmodout);
+			else if (typemod_given)
+			{
+				/*
+				 * bpchar with typmod -1 is not the same as CHARACTER, which
+				 * means CHARACTER(1) per SQL spec.  Report it as bpchar so
+				 * that parser will not assign a bogus typmod.
+				 */
+			}
+			else
+				buf = pstrdup("national character");
+			break;
+
 		case FLOAT4OID:
 			buf = pstrdup("real");
 			break;
 
 		case FLOAT8OID:
@@ -291,10 +306,17 @@
 			if (with_typemod)
 				buf = printTypmod("character varying", typemod, typeform->typmodout);
 			else
 				buf = pstrdup("character varying");
 			break;
+
+		case NVARCHAROID:
+			if (with_typemod)
+				buf = printTypmod("national character varying", typemod, typeform->typmodout);
+			else
+				buf = pstrdup("national character varying");
+			break;
 	}
 
 	if (buf == NULL)
 	{
 		/*
@@ -381,11 +403,13 @@
 		return -1;
 
 	switch (type_oid)
 	{
 		case BPCHAROID:
+		case NBPCHAROID:
 		case VARCHAROID:
+		case NVARCHAROID:
 			/* typemod includes varlena header */
 
 			/* typemod is in characters not bytes */
 			return (typemod - VARHDRSZ) *
 				pg_encoding_max_length(GetDatabaseEncoding())
diff -U 5 -N -r -w ../orig.HEAD/src/backend/utils/adt/Makefile ./src/backend/utils/adt/Makefile
--- ../orig.HEAD/src/backend/utils/adt/Makefile	2013-08-19 20:22:09.000000000 -0400
+++ ./src/backend/utils/adt/Makefile	2013-08-20 04:53:45.000000000 -0400
@@ -18,11 +18,11 @@
 OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \
 	array_userfuncs.o arrayutils.o bool.o \
 	cash.o char.o date.o datetime.o datum.o domains.o \
 	enum.o float.o format_type.o \
 	geo_ops.o geo_selfuncs.o int.o int8.o json.o jsonfuncs.o like.o \
-	lockfuncs.o misc.o nabstime.o name.o numeric.o numutils.o \
+	lockfuncs.o misc.o nabstime.o name.o numeric.o numutils.o nvarchar.o \
 	oid.o oracle_compat.o pseudotypes.o rangetypes.o rangetypes_gist.o \
 	rowtypes.o regexp.o regproc.o ruleutils.o selfuncs.o \
 	tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
 	network.o mac.o inet_cidr_ntop.o inet_net_pton.o \
 	ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
diff -U 5 -N -r -w ../orig.HEAD/src/backend/utils/adt/nvarchar.c ./src/backend/utils/adt/nvarchar.c
--- ../orig.HEAD/src/backend/utils/adt/nvarchar.c	1969-12-31 19:00:00.000000000 -0500
+++ ./src/backend/utils/adt/nvarchar.c	2013-08-20 04:54:06.000000000 -0400
@@ -0,0 +1,421 @@
+/*-------------------------------------------------------------------------
+ *
+ * nvarchar.c
+ *	  Functions for the built-in types nchar(n) and nvarchar(n).
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/utils/adt/nvarchar.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+
+#include "access/hash.h"
+#include "access/tuptoaster.h"
+#include "libpq/pqformat.h"
+#include "nodes/nodeFuncs.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "mb/pg_wchar.h"
+#include "utils/formatting.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_collation.h"
+
+/*
+ *		====================
+ *		FORWARD DECLARATIONS
+ *		====================
+ */
+static int32 ntextcmp(text *left, text *right, Oid collid);
+
+// being really dumb for ntext collation initially 
+static const char *ntext_collation = "C.UTF-8";
+
+/*
+ *      ===================
+ *      TYPE CAST FUNCTIONS
+ *      ===================
+ */
+
+/*
+ * convert text to ntext (the database encoding to UTF8)
+ */
+Datum
+text2nvarchar(PG_FUNCTION_ARGS)
+{
+    text       *in_val = PG_GETARG_TEXT_PP(0);
+    char       *in_string;
+    text       *out_val;
+
+    in_string = text_to_cstring(in_val);
+    out_val = cstring_to_text(pg_server_to_any(in_string, strlen(in_string), PG_UTF8));
+
+    PG_RETURN_TEXT_P(out_val);
+}
+
+/*
+ * convert ntext to text (UTF8 to the database encoding)
+ */
+Datum
+nvarchar2text(PG_FUNCTION_ARGS)
+{
+    text       *in_val = PG_GETARG_TEXT_PP(0);
+    char       *in_string;
+    text       *out_val;
+
+    in_string = text_to_cstring(in_val);
+    out_val = cstring_to_text(pg_any_to_server(in_string, strlen(in_string), PG_UTF8));
+
+    PG_RETURN_TEXT_P(out_val);
+}
+
+/*
+ * convert rtrimmed text to ntext (the database encoding to UTF8)
+ * used for conversion from char type to nvarchar type
+ */
+Datum
+rtrimtext2nvarchar(PG_FUNCTION_ARGS)
+{
+    text       *in_val = PG_GETARG_TEXT_PP(0);
+    char       *in_string;
+    text       *out_val;
+    text       *trimmed_val;
+
+	trimmed_val = dotrim(VARDATA_ANY(in_val), VARSIZE_ANY_EXHDR(in_val),
+				" ", 1,
+				false, true);
+    in_string = text_to_cstring(trimmed_val);
+    out_val = cstring_to_text(pg_server_to_any(in_string, strlen(in_string), PG_UTF8));
+
+    PG_RETURN_TEXT_P(out_val);
+}
+
+/*
+ * convert ntext to rtrimmed text (UTF8 to the database encoding)
+ * used for conversion from nchar types to varchar/text types
+ */
+Datum
+nvarchar2rtrimtext(PG_FUNCTION_ARGS)
+{
+    text       *in_val = PG_GETARG_TEXT_PP(0);
+    char       *in_string;
+    text       *out_val;
+	text       *trimmed_val;
+
+    in_string = text_to_cstring(in_val);
+    out_val = cstring_to_text(pg_any_to_server(in_string, strlen(in_string), PG_UTF8));
+    trimmed_val = dotrim(VARDATA_ANY(out_val), VARSIZE_ANY_EXHDR(out_val),
+                " ", 1,
+                false, true);
+    PG_RETURN_TEXT_P(trimmed_val);
+}
+
+
+
+/*
+ *		=================
+ *		UTILITY FUNCTIONS
+ *		=================
+ */
+
+/*
+ *      ntextin          - converts "..." (assume that "..." using db encoding we need decode it to UTF8) to internal representation
+ */
+
+Datum
+ntextin(PG_FUNCTION_ARGS)
+{
+    char       *in_val = PG_GETARG_CSTRING(0);
+
+    PG_RETURN_TEXT_P(cstring_to_text(pg_server_to_any(in_val, strlen(in_val), PG_UTF8)));
+}
+
+/*
+ *      ntextout         - converts internal representation to "..." (assume that "..." using db encoding we need decode it from UTF8)
+ */
+
+Datum
+ntextout(PG_FUNCTION_ARGS)
+{
+    text       *in_val = PG_GETARG_TEXT_PP(0);
+    char       *in_string;
+
+    in_string = text_to_cstring(in_val);
+    PG_RETURN_CSTRING(pg_any_to_server(in_string, strlen(in_string), PG_UTF8));
+}
+
+
+/*
+ * Convert a C string to VARCHAR internal representation.  atttypmod
+ * is the declared length of the type plus VARHDRSZ.
+ */
+Datum
+nvarcharin(PG_FUNCTION_ARGS)
+{
+    char       *s = PG_GETARG_CSTRING(0);
+#ifdef NOT_USED
+    Oid         typelem = PG_GETARG_OID(1);
+#endif
+    int32       atttypmod = PG_GETARG_INT32(2);
+    VarChar    *result;
+
+//    result = varchar_input(s, strlen(s), atttypmod);
+//    PG_RETURN_VARCHAR_P(result);
+	PG_RETURN_VARCHAR_P(cstring_to_text(pg_server_to_any(s, strlen(s), PG_UTF8)));
+}
+
+
+/*
+ * Convert a VARCHAR value to a C string.
+ *
+ * Uses the text to C string conversion function, which is only appropriate
+ * if VarChar and text are equivalent types.
+ */
+Datum
+nvarcharout(PG_FUNCTION_ARGS)
+{
+    Datum       txt = PG_GETARG_DATUM(0);
+    char        *in_string;
+
+    in_string = text_to_cstring(txt);
+    PG_RETURN_CSTRING(pg_any_to_server(in_string, strlen(txt), PG_UTF8));
+}
+
+
+Datum
+ntextlower(PG_FUNCTION_ARGS)
+{
+    text       *in_string = PG_GETARG_TEXT_PP(0);
+    char       *out_string;
+    text       *result;
+
+    out_string = str_tolower(VARDATA_ANY(in_string),
+                             VARSIZE_ANY_EXHDR(in_string),
+                             CollationGetCollid(ntext_collation));
+    result = cstring_to_text(out_string);
+    pfree(out_string);
+
+    PG_RETURN_TEXT_P(result);
+}
+
+Datum
+ntextupper(PG_FUNCTION_ARGS)
+{
+    text       *in_string = PG_GETARG_TEXT_PP(0);
+    char       *out_string;
+    text       *result;
+
+    out_string = str_toupper(VARDATA_ANY(in_string),
+                             VARSIZE_ANY_EXHDR(in_string),
+                             CollationGetCollid(ntext_collation));
+    result = cstring_to_text(out_string);
+    pfree(out_string);
+
+    PG_RETURN_TEXT_P(result);
+}
+
+
+/*
+ * actual octet length of an utf8 text 
+ */
+Datum
+ntextoctetlen(PG_FUNCTION_ARGS)
+{
+//        Datum           arg = PG_GETARG_DATUM(0);
+//        /* We need not detoast the input at all */
+//        PG_RETURN_INT32(toast_raw_datum_size(arg) - VARHDRSZ);
+	text       *in_val = PG_GETARG_TEXT_PP(0);
+	char       *in_string;
+	int		   len;
+
+	in_string = text_to_cstring(in_val);
+	len = strlen(in_string);
+
+	PG_RETURN_INT32(len);
+}
+
+/*
+ * ntextcmp()
+ * Internal comparison function for ntext strings.
+ * Returns int32 negative, zero, or positive.
+ */
+static int32
+ntextcmp(text *left, text *right, Oid collid)
+{
+	return varstr_cmp(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left),
+						VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right),
+						collid);
+}
+
+/*
+ *		==================
+ *		INDEXING FUNCTIONS
+ *		==================
+ */
+Datum
+ntext_cmp(PG_FUNCTION_ARGS)
+{
+	text	   *left = PG_GETARG_TEXT_PP(0);
+	text	   *right = PG_GETARG_TEXT_PP(1);
+	int32		result;
+
+	result = ntextcmp(left, right, CollationGetCollid(ntext_collation));
+
+	PG_FREE_IF_COPY(left, 0);
+	PG_FREE_IF_COPY(right, 1);
+
+	PG_RETURN_INT32(result);
+}
+
+PG_FUNCTION_INFO_V1(ntext_hash);
+
+Datum
+ntext_hash(PG_FUNCTION_ARGS)
+{
+	text	    *txt = PG_GETARG_TEXT_PP(0);
+	Datum		result;
+
+	result = hash_any((unsigned char *) VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt));
+
+	/* Avoid leaking memory for toasted inputs */
+	PG_FREE_IF_COPY(txt, 0);
+
+	PG_RETURN_DATUM(result);
+}
+
+/*
+ *		==================
+ *		OPERATOR FUNCTIONS
+ *		==================
+ */
+Datum
+ntext_eq(PG_FUNCTION_ARGS)
+{
+	text	   *left = PG_GETARG_TEXT_PP(0);
+	text	   *right = PG_GETARG_TEXT_PP(1);
+	bool		result;
+
+	/*
+	 * Since we only care about equality or not-equality, we can avoid all the
+	 * expense of strcoll() here, and just do bitwise comparison.
+	 */
+	result = (strcmp(text_to_cstring(left), text_to_cstring(right)) == 0);
+
+	PG_FREE_IF_COPY(left, 0);
+	PG_FREE_IF_COPY(right, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+Datum
+ntext_ne(PG_FUNCTION_ARGS)
+{
+	text	   *left = PG_GETARG_TEXT_PP(0);
+	text	   *right = PG_GETARG_TEXT_PP(1);
+	bool		result;
+
+	/*
+	 * Since we only care about equality or not-equality, we can avoid all the
+	 * expense of strcoll() here, and just do bitwise comparison.
+	 */
+	result = (strcmp(text_to_cstring(left), text_to_cstring(right)) != 0);
+
+	PG_FREE_IF_COPY(left, 0);
+	PG_FREE_IF_COPY(right, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+Datum
+ntext_lt(PG_FUNCTION_ARGS)
+{
+	text	   *left = PG_GETARG_TEXT_PP(0);
+	text	   *right = PG_GETARG_TEXT_PP(1);
+	bool		result;
+
+	result = ntextcmp(left, right, CollationGetCollid(ntext_collation)) < 0;
+
+	PG_FREE_IF_COPY(left, 0);
+	PG_FREE_IF_COPY(right, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+Datum
+ntext_le(PG_FUNCTION_ARGS)
+{
+	text	   *left = PG_GETARG_TEXT_PP(0);
+	text	   *right = PG_GETARG_TEXT_PP(1);
+	bool		result;
+
+	result = ntextcmp(left, right, CollationGetCollid(ntext_collation)) <= 0;
+
+	PG_FREE_IF_COPY(left, 0);
+	PG_FREE_IF_COPY(right, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+Datum
+ntext_gt(PG_FUNCTION_ARGS)
+{
+	text	   *left = PG_GETARG_TEXT_PP(0);
+	text	   *right = PG_GETARG_TEXT_PP(1);
+	bool		result;
+
+	result = ntextcmp(left, right, CollationGetCollid(ntext_collation)) > 0;
+
+	PG_FREE_IF_COPY(left, 0);
+	PG_FREE_IF_COPY(right, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+Datum
+ntext_ge(PG_FUNCTION_ARGS)
+{
+	text	   *left = PG_GETARG_TEXT_PP(0);
+	text	   *right = PG_GETARG_TEXT_PP(1);
+	bool		result;
+
+	result = ntextcmp(left, right, CollationGetCollid(ntext_collation)) >= 0;
+
+	PG_FREE_IF_COPY(left, 0);
+	PG_FREE_IF_COPY(right, 1);
+
+	PG_RETURN_BOOL(result);
+}
+
+/*
+ *		===================
+ *		AGGREGATE FUNCTIONS
+ *		===================
+ */
+Datum
+ntext_smaller(PG_FUNCTION_ARGS)
+{
+	text	   *left = PG_GETARG_TEXT_PP(0);
+	text	   *right = PG_GETARG_TEXT_PP(1);
+	text	   *result;
+
+	result = ntextcmp(left, right, CollationGetCollid(ntext_collation)) < 0 ? left : right;
+	PG_RETURN_TEXT_P(result);
+}
+
+Datum
+ntext_larger(PG_FUNCTION_ARGS)
+{
+	text	   *left = PG_GETARG_TEXT_PP(0);
+	text	   *right = PG_GETARG_TEXT_PP(1);
+	text	   *result;
+
+	result = ntextcmp(left, right, CollationGetCollid(ntext_collation)) > 0 ? left : right;
+	PG_RETURN_TEXT_P(result);
+}
+
+
diff -U 5 -N -r -w ../orig.HEAD/src/backend/utils/adt/oracle_compat.c ./src/backend/utils/adt/oracle_compat.c
--- ../orig.HEAD/src/backend/utils/adt/oracle_compat.c	2013-08-19 20:22:09.000000000 -0400
+++ ./src/backend/utils/adt/oracle_compat.c	2013-08-19 20:54:00.000000000 -0400
@@ -18,15 +18,10 @@
 #include "utils/builtins.h"
 #include "utils/formatting.h"
 #include "mb/pg_wchar.h"
 
 
-static text *dotrim(const char *string, int stringlen,
-	   const char *set, int setlen,
-	   bool doltrim, bool dortrim);
-
-
 /********************************************************************
  *
  * lower
  *
  * Syntax:
@@ -365,11 +360,11 @@
 }
 
 /*
  * Common implementation for btrim, ltrim, rtrim
  */
-static text *
+text *
 dotrim(const char *string, int stringlen,
 	   const char *set, int setlen,
 	   bool doltrim, bool dortrim)
 {
 	int			i;
diff -U 5 -N -r -w ../orig.HEAD/src/backend/utils/adt/selfuncs.c ./src/backend/utils/adt/selfuncs.c
--- ../orig.HEAD/src/backend/utils/adt/selfuncs.c	2013-08-19 20:22:09.000000000 -0400
+++ ./src/backend/utils/adt/selfuncs.c	2013-08-19 20:54:00.000000000 -0400
@@ -3624,11 +3624,13 @@
 			/*
 			 * Built-in string types
 			 */
 		case CHAROID:
 		case BPCHAROID:
+		case NBPCHAROID:
 		case VARCHAROID:
+		case NVARCHAROID:
 		case TEXTOID:
 		case NAMEOID:
 			{
 				char	   *valstr = convert_string_datum(value, valuetypid);
 				char	   *lostr = convert_string_datum(lobound, boundstypid);
@@ -3886,11 +3888,13 @@
 			val = (char *) palloc(2);
 			val[0] = DatumGetChar(value);
 			val[1] = '\0';
 			break;
 		case BPCHAROID:
+		case NBPCHAROID:
 		case VARCHAROID:
+		case NVARCHAROID:
 		case TEXTOID:
 			val = TextDatumGetCString(value);
 			break;
 		case NAMEOID:
 			{
@@ -5873,11 +5877,13 @@
 	 */
 	switch (datatype)
 	{
 		case TEXTOID:
 		case VARCHAROID:
+		case NVARCHAROID:
 		case BPCHAROID:
+		case NBPCHAROID:
 			collation = DEFAULT_COLLATION_OID;
 			constlen = -1;
 			break;
 
 		case NAMEOID:
diff -U 5 -N -r -w ../orig.HEAD/src/include/catalog/pg_amop.h ./src/include/catalog/pg_amop.h
--- ../orig.HEAD/src/include/catalog/pg_amop.h	2013-08-19 20:22:12.000000000 -0400
+++ ./src/include/catalog/pg_amop.h	2013-08-19 20:54:00.000000000 -0400
@@ -251,10 +251,17 @@
 DATA(insert (	426   1042 1042 2 s 1059	403 0 ));
 DATA(insert (	426   1042 1042 3 s 1054	403 0 ));
 DATA(insert (	426   1042 1042 4 s 1061	403 0 ));
 DATA(insert (	426   1042 1042 5 s 1060	403 0 ));
 
+DATA(insert (   426   5001 5001 1 s 5058        403 0 ));
+DATA(insert (   426   5001 5001 2 s 5059        403 0 ));
+DATA(insert (   426   5001 5001 3 s 5054        403 0 ));
+DATA(insert (   426   5001 5001 4 s 5061        403 0 ));
+DATA(insert (   426   5001 5001 5 s 5060        403 0 ));
+
+
 /*
  *	btree bytea_ops
  */
 
 DATA(insert (	428   17 17 1 s 1957	403 0 ));
@@ -506,10 +513,14 @@
  *	hash index _ops
  */
 
 /* bpchar_ops */
 DATA(insert (	427   1042 1042 1 s 1054	405 0 ));
+
+/* nbpchar_ops */
+DATA(insert (   427   5001 5001 1 s 5054        405 0 ));
+
 /* char_ops */
 DATA(insert (	431   18 18 1 s 92	405 0 ));
 /* date_ops */
 DATA(insert (	435   1082 1082 1 s 1093	405 0 ));
 /* float_ops */
diff -U 5 -N -r -w ../orig.HEAD/src/include/catalog/pg_amproc.h ./src/include/catalog/pg_amproc.h
--- ../orig.HEAD/src/include/catalog/pg_amproc.h	2013-08-19 20:22:12.000000000 -0400
+++ ./src/include/catalog/pg_amproc.h	2013-08-19 20:54:00.000000000 -0400
@@ -78,10 +78,11 @@
 DATA(insert (	397   2277 2277 1 382 ));
 DATA(insert (	421   702 702 1 357 ));
 DATA(insert (	423   1560 1560 1 1596 ));
 DATA(insert (	424   16 16 1 1693 ));
 DATA(insert (	426   1042 1042 1 1078 ));
+DATA(insert (   426   5001 5001 1 1078 ));
 DATA(insert (	428   17 17 1 1954 ));
 DATA(insert (	429   18 18 1 358 ));
 DATA(insert (	434   1082 1082 1 1092 ));
 DATA(insert (	434   1082 1082 2 3136 ));
 DATA(insert (	434   1082 1114 1 2344 ));
@@ -126,20 +127,22 @@
 DATA(insert (	1996   1083 1083 1 1107 ));
 DATA(insert (	2000   1266 1266 1 1358 ));
 DATA(insert (	2002   1562 1562 1 1672 ));
 DATA(insert (	2095   25 25 1 2166 ));
 DATA(insert (	2097   1042 1042 1 2180 ));
+DATA(insert (   2097   5001 5001 1 2180 ));
 DATA(insert (	2099   790 790 1  377 ));
 DATA(insert (	2233   703 703 1  380 ));
 DATA(insert (	2234   704 704 1  381 ));
 DATA(insert (	2789   27 27 1 2794 ));
 DATA(insert (	2968   2950 2950 1 2960 ));
 DATA(insert (	3522   3500 3500 1 3514 ));
 
 
 /* hash */
 DATA(insert (	427   1042 1042 1 1080 ));
+DATA(insert (   427   5001 5001 1 1080 ));
 DATA(insert (	431   18 18 1 454 ));
 DATA(insert (	435   1082 1082 1 450 ));
 DATA(insert (	627   2277 2277 1 626 ));
 DATA(insert (	1971   700 700 1 451 ));
 DATA(insert (	1971   701 701 1 452 ));
@@ -165,10 +168,11 @@
 DATA(insert (	2226   29 29 1 450 ));
 DATA(insert (	2227   702 702 1 450 ));
 DATA(insert (	2228   703 703 1 450 ));
 DATA(insert (	2229   25 25 1 400 ));
 DATA(insert (	2231   1042 1042 1 1080 ));
+DATA(insert (   2231   5001 5001 1 1080 ));
 DATA(insert (	2235   1033 1033 1 329 ));
 DATA(insert (	2969   2950 2950 1 2963 ));
 DATA(insert (	3523   3500 3500 1 3515 ));
 
 
diff -U 5 -N -r -w ../orig.HEAD/src/include/catalog/pg_cast.h ./src/include/catalog/pg_cast.h
--- ../orig.HEAD/src/include/catalog/pg_cast.h	2013-08-19 20:22:12.000000000 -0400
+++ ./src/include/catalog/pg_cast.h	2013-08-19 20:54:00.000000000 -0400
@@ -212,16 +212,77 @@
 DATA(insert ( 1043 2205 1079 i f ));
 
 /*
  * String category
  */
-DATA(insert (	25 1042    0 i b ));
-DATA(insert (	25 1043    0 i b ));
+/*
+ * 501  UTF8 conversion to database encoding
+ * 502  database encoding to UTF8
+ * 401  rtrim
+ * 503  conversion from UTF8 + rtrim 
+ * 504  rtrim + conversion to UTF8
+ * national -> common is always 'a' = assigment autocasts (and they could fail if encoding error happen)
+ * common -> nactional is always 'i' = implicit (because they should work always)
+ * temporary assume rtrim not depend on actual encoding (which is definitely wrong assumption)
+*/
+
+/*
+ * char -> text
+ * char -> varchar
+ * char -> nchar
+ * char -> nvarchar
+*/
 DATA(insert ( 1042	 25  401 i f ));
 DATA(insert ( 1042 1043  401 i f ));
+DATA(insert ( 1042 5001  502 i f ));
+DATA(insert ( 1042 6001  504 i f ));
+
+/*
+ * varchar -> text
+ * varchar -> char
+ * varchar -> nvarchar
+ * varchar -> nchar
+*/
 DATA(insert ( 1043	 25    0 i b ));
 DATA(insert ( 1043 1042    0 i b ));
+DATA(insert ( 1043 6001 502 i f ));
+DATA(insert ( 1043 5001 502 i f ));
+
+/*
+ * text -> varchar
+ * text -> char
+ * text -> nchar
+ * text -> nvarchar
+*/
+DATA(insert (   25 1043   0 i b ));
+DATA(insert (   25 1042   0 i b ));
+DATA(insert (   25 5001 502 i f ));
+DATA(insert (   25 6001 502 i f ));
+
+/*
+ * nvarchar -> text
+ * nvarchar -> varchar
+ * nvarchar -> char
+ * nvarchar -> nchar
+*/
+DATA(insert ( 6001   25  501 a f ));
+DATA(insert ( 6001 1043  501 a f ));
+DATA(insert ( 6001 1042  501 a f ));
+DATA(insert ( 6001 5001  0   i f ));
+
+/*
+ * nchar -> text
+ * nchar -> varchar
+ * nchar -> char
+ * nchar -> nvarchar
+*/
+DATA(insert ( 5001   25  503 a f ));
+DATA(insert ( 5001 1042  503 a f ));
+DATA(insert ( 5001 1043  501 a f ));
+DATA(insert ( 5001 6001  401 i f ));
+
+
 DATA(insert (	18	 25  946 i f ));
 DATA(insert (	18 1042  860 a f ));
 DATA(insert (	18 1043  946 a f ));
 DATA(insert (	19	 25  406 i f ));
 DATA(insert (	19 1042  408 a f ));
@@ -347,11 +408,13 @@
 
 /*
  * Length-coercion functions
  */
 DATA(insert ( 1042 1042  668 i f ));
+DATA(insert ( 5001 5001 5668 i f ));
 DATA(insert ( 1043 1043  669 i f ));
+DATA(insert ( 6001 6001 5669 i f ));
 DATA(insert ( 1083 1083 1968 i f ));
 DATA(insert ( 1114 1114 1961 i f ));
 DATA(insert ( 1184 1184 1967 i f ));
 DATA(insert ( 1186 1186 1200 i f ));
 DATA(insert ( 1266 1266 1969 i f ));
diff -U 5 -N -r -w ../orig.HEAD/src/include/catalog/pg_opclass.h ./src/include/catalog/pg_opclass.h
--- ../orig.HEAD/src/include/catalog/pg_opclass.h	2013-08-19 20:22:12.000000000 -0400
+++ ./src/include/catalog/pg_opclass.h	2013-08-19 20:54:00.000000000 -0400
@@ -95,10 +95,12 @@
 DATA(insert (	405		array_ops			PGNSP PGUID  627 2277 t 0 ));
 DATA(insert (	403		bit_ops				PGNSP PGUID  423 1560 t 0 ));
 DATA(insert (	403		bool_ops			PGNSP PGUID  424   16 t 0 ));
 DATA(insert (	403		bpchar_ops			PGNSP PGUID  426 1042 t 0 ));
 DATA(insert (	405		bpchar_ops			PGNSP PGUID  427 1042 t 0 ));
+DATA(insert (	403				nbpchar_ops						PGNSP PGUID  426 5001 t 0 ));
+DATA(insert (	405				nbpchar_ops						PGNSP PGUID  427 5001 t 0 ));
 DATA(insert (	403		bytea_ops			PGNSP PGUID  428   17 t 0 ));
 DATA(insert (	403		char_ops			PGNSP PGUID  429   18 t 0 ));
 DATA(insert (	405		char_ops			PGNSP PGUID  431   18 t 0 ));
 DATA(insert (	403		cidr_ops			PGNSP PGUID 1974  869 f 0 ));
 DATA(insert (	405		cidr_ops			PGNSP PGUID 1975  869 f 0 ));
@@ -154,10 +156,12 @@
 DATA(insert (	403		timetz_ops			PGNSP PGUID 2000 1266 t 0 ));
 DATA(insert (	405		timetz_ops			PGNSP PGUID 2001 1266 t 0 ));
 DATA(insert (	403		varbit_ops			PGNSP PGUID 2002 1562 t 0 ));
 DATA(insert (	403		varchar_ops			PGNSP PGUID 1994   25 f 0 ));
 DATA(insert (	405		varchar_ops			PGNSP PGUID 1995   25 f 0 ));
+DATA(insert (	403				nvarchar_ops					PGNSP PGUID 1994   25 f 0 ));
+DATA(insert (	405				nvarchar_ops					PGNSP PGUID 1995   25 f 0 ));
 DATA(insert OID = 3128 ( 403	timestamp_ops	PGNSP PGUID  434 1114 t 0 ));
 #define TIMESTAMP_BTREE_OPS_OID 3128
 DATA(insert (	405		timestamp_ops		PGNSP PGUID 2040 1114 t 0 ));
 DATA(insert (	403		text_pattern_ops	PGNSP PGUID 2095   25 f 0 ));
 DATA(insert (	403		varchar_pattern_ops PGNSP PGUID 2095   25 f 0 ));
@@ -185,10 +189,11 @@
 DATA(insert (	2742	_text_ops			PGNSP PGUID 2745  1009 t 25 ));
 DATA(insert (	2742	_abstime_ops		PGNSP PGUID 2745  1023 t 702 ));
 DATA(insert (	2742	_bit_ops			PGNSP PGUID 2745  1561 t 1560 ));
 DATA(insert (	2742	_bool_ops			PGNSP PGUID 2745  1000 t 16 ));
 DATA(insert (	2742	_bpchar_ops			PGNSP PGUID 2745  1014 t 1042 ));
+DATA(insert (	2742	_nbpchar_ops					PGNSP PGUID 2745  5014 t 5001 ));
 DATA(insert (	2742	_bytea_ops			PGNSP PGUID 2745  1001 t 17 ));
 DATA(insert (	2742	_char_ops			PGNSP PGUID 2745  1002 t 18 ));
 DATA(insert (	2742	_cidr_ops			PGNSP PGUID 2745  651 t 650 ));
 DATA(insert (	2742	_date_ops			PGNSP PGUID 2745  1182 t 1082 ));
 DATA(insert (	2742	_float4_ops			PGNSP PGUID 2745  1021 t 700 ));
@@ -205,10 +210,11 @@
 DATA(insert (	2742	_time_ops			PGNSP PGUID 2745  1183 t 1083 ));
 DATA(insert (	2742	_timestamptz_ops	PGNSP PGUID 2745  1185 t 1184 ));
 DATA(insert (	2742	_timetz_ops			PGNSP PGUID 2745  1270 t 1266 ));
 DATA(insert (	2742	_varbit_ops			PGNSP PGUID 2745  1563 t 1562 ));
 DATA(insert (	2742	_varchar_ops		PGNSP PGUID 2745  1015 t 1043 ));
+DATA(insert (	2742	_nvarchar_ops			PGNSP PGUID 2745  5015 t 6001 ));
 DATA(insert (	2742	_timestamp_ops		PGNSP PGUID 2745  1115 t 1114 ));
 DATA(insert (	2742	_money_ops			PGNSP PGUID 2745  791 t 790 ));
 DATA(insert (	2742	_reltime_ops		PGNSP PGUID 2745  1024 t 703 ));
 DATA(insert (	2742	_tinterval_ops		PGNSP PGUID 2745  1025 t 704 ));
 DATA(insert (	403		uuid_ops			PGNSP PGUID 2968  2950 t 0 ));
diff -U 5 -N -r -w ../orig.HEAD/src/include/catalog/pg_operator.h ./src/include/catalog/pg_operator.h
--- ../orig.HEAD/src/include/catalog/pg_operator.h	2013-08-19 20:22:12.000000000 -0400
+++ ./src/include/catalog/pg_operator.h	2013-08-19 20:54:00.000000000 -0400
@@ -741,26 +741,50 @@
 DATA(insert OID =  971 (  "@@"	   PGNSP PGUID l f f	0  604	600    0  0 poly_center - - ));
 DESCR("center of");
 
 DATA(insert OID = 1054 ( "="	   PGNSP PGUID b t t 1042 1042	 16 1054 1057 bpchareq eqsel eqjoinsel ));
 DESCR("equal");
+DATA(insert OID = 5054 ( "="       PGNSP PGUID b t t 5001 5001   16 5054 5057 nbpchareq eqsel eqjoinsel ));
+DESCR("equal");
 
 DATA(insert OID = 1055 ( "~"	   PGNSP PGUID b f f 1042 25	 16    0 1056 bpcharregexeq regexeqsel regexeqjoinsel ));
 DESCR("matches regular expression, case-sensitive");
+DATA(insert OID = 5055 ( "~"       PGNSP PGUID b f f 5001 25     16    0 5056 nbpcharregexeq regexeqsel regexeqjoinsel ));
+DESCR("matches regular expression, case-sensitive");
+
 #define OID_BPCHAR_REGEXEQ_OP		1055
 DATA(insert OID = 1056 ( "!~"	   PGNSP PGUID b f f 1042 25	 16    0 1055 bpcharregexne regexnesel regexnejoinsel ));
 DESCR("does not match regular expression, case-sensitive");
+DATA(insert OID = 5056 ( "!~"      PGNSP PGUID b f f 5001 25     16    0 5055 nbpcharregexne regexnesel regexnejoinsel ));
+DESCR("does not match regular expression, case-sensitive");
+
 DATA(insert OID = 1057 ( "<>"	   PGNSP PGUID b f f 1042 1042	 16 1057 1054 bpcharne neqsel neqjoinsel ));
 DESCR("not equal");
+DATA(insert OID = 5057 ( "<>"      PGNSP PGUID b f f 5001 5001   16 5057 5054 nbpcharne neqsel neqjoinsel ));
+DESCR("not equal");
+
 DATA(insert OID = 1058 ( "<"	   PGNSP PGUID b f f 1042 1042	 16 1060 1061 bpcharlt scalarltsel scalarltjoinsel ));
 DESCR("less than");
+DATA(insert OID = 5058 ( "<"       PGNSP PGUID b f f 5001 5001   16 5060 5061 nbpcharlt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+
 DATA(insert OID = 1059 ( "<="	   PGNSP PGUID b f f 1042 1042	 16 1061 1060 bpcharle scalarltsel scalarltjoinsel ));
 DESCR("less than or equal");
+DATA(insert OID = 5059 ( "<="      PGNSP PGUID b f f 5001 5001   16 5061 5060 nbpcharle scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+
 DATA(insert OID = 1060 ( ">"	   PGNSP PGUID b f f 1042 1042	 16 1058 1059 bpchargt scalargtsel scalargtjoinsel ));
 DESCR("greater than");
+DATA(insert OID = 5060 ( ">"       PGNSP PGUID b f f 5001 5001   16 5058 5059 nbpchargt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+
+
 DATA(insert OID = 1061 ( ">="	   PGNSP PGUID b f f 1042 1042	 16 1059 1058 bpcharge scalargtsel scalargtjoinsel ));
 DESCR("greater than or equal");
+DATA(insert OID = 5061 ( ">="      PGNSP PGUID b f f 5001 5001   16 5059 5058 nbpcharge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
 
 /* generic array comparison operators */
 DATA(insert OID = 1070 (  "="	   PGNSP PGUID b t t 2277 2277 16 1070 1071 array_eq eqsel eqjoinsel ));
 DESCR("equal");
 #define ARRAY_EQ_OP 1070
@@ -885,13 +909,18 @@
 #define OID_TEXT_LIKE_OP		1209
 DATA(insert OID = 1210 (  "!~~"   PGNSP PGUID b f f  25 25	16 0 1209 textnlike nlikesel nlikejoinsel ));
 DESCR("does not match LIKE expression");
 DATA(insert OID = 1211 (  "~~"	  PGNSP PGUID b f f  1042 25	16 0 1212 bpcharlike likesel likejoinsel ));
 DESCR("matches LIKE expression");
+DATA(insert OID = 5211 (  "~~"    PGNSP PGUID b f f  5001 25    16 0 5212 nbpcharlike likesel likejoinsel ));
+DESCR("matches LIKE expression");
+
 #define OID_BPCHAR_LIKE_OP		1211
 DATA(insert OID = 1212 (  "!~~"   PGNSP PGUID b f f  1042 25	16 0 1211 bpcharnlike nlikesel nlikejoinsel ));
 DESCR("does not match LIKE expression");
+DATA(insert OID = 5212 (  "!~~"   PGNSP PGUID b f f  5001 25    16 0 5211 nbpcharnlike nlikesel nlikejoinsel ));
+DESCR("does not match LIKE expression");
 
 /* case-insensitive regex hacks */
 DATA(insert OID = 1226 (  "~*"		 PGNSP PGUID b f f	19	25	16 0 1227 nameicregexeq icregexeqsel icregexeqjoinsel ));
 DESCR("matches regular expression, case-insensitive");
 #define OID_NAME_ICREGEXEQ_OP		1226
@@ -902,13 +931,18 @@
 #define OID_TEXT_ICREGEXEQ_OP		1228
 DATA(insert OID = 1229 (  "!~*"		 PGNSP PGUID b f f	25	25	16 0 1228 texticregexne icregexnesel icregexnejoinsel ));
 DESCR("does not match regular expression, case-insensitive");
 DATA(insert OID = 1234 (  "~*"		PGNSP PGUID b f f  1042  25  16 0 1235 bpcharicregexeq icregexeqsel icregexeqjoinsel ));
 DESCR("matches regular expression, case-insensitive");
+DATA(insert OID = 5234 (  "~*"          PGNSP PGUID b f f  5001  25  16 0 5235 nbpcharicregexeq icregexeqsel icregexeqjoinsel ));
+DESCR("matches regular expression, case-insensitive");
+
 #define OID_BPCHAR_ICREGEXEQ_OP		1234
 DATA(insert OID = 1235 ( "!~*"		PGNSP PGUID b f f  1042  25  16 0 1234 bpcharicregexne icregexnesel icregexnejoinsel ));
 DESCR("does not match regular expression, case-insensitive");
+DATA(insert OID = 5235 ( "!~*"          PGNSP PGUID b f f  5001  25  16 0 5234 nbpcharicregexne icregexnesel icregexnejoinsel ));
+DESCR("does not match regular expression, case-insensitive");
 
 /* timestamptz operators */
 DATA(insert OID = 1320 (  "="	   PGNSP PGUID b t t 1184 1184	 16 1320 1321 timestamptz_eq eqsel eqjoinsel ));
 DESCR("equal");
 DATA(insert OID = 1321 (  "<>"	   PGNSP PGUID b f f 1184 1184	 16 1321 1320 timestamptz_ne neqsel neqjoinsel ));
@@ -1176,13 +1210,18 @@
 #define OID_TEXT_ICLIKE_OP		1627
 DATA(insert OID = 1628 (  "!~~*"  PGNSP PGUID b f f  25 25	16 0 1627 texticnlike icnlikesel icnlikejoinsel ));
 DESCR("does not match LIKE expression, case-insensitive");
 DATA(insert OID = 1629 (  "~~*"   PGNSP PGUID b f f  1042 25	16 0 1630 bpchariclike iclikesel iclikejoinsel ));
 DESCR("matches LIKE expression, case-insensitive");
+DATA(insert OID = 5629 (  "~~*"   PGNSP PGUID b f f  5001 25    16 0 5630 nbpchariclike iclikesel iclikejoinsel ));
+DESCR("matches LIKE expression, case-insensitive");
 #define OID_BPCHAR_ICLIKE_OP	1629
 DATA(insert OID = 1630 (  "!~~*"  PGNSP PGUID b f f  1042 25	16 0 1629 bpcharicnlike icnlikesel icnlikejoinsel ));
 DESCR("does not match LIKE expression, case-insensitive");
+DATA(insert OID = 5630 (  "!~~*"  PGNSP PGUID b f f  5001 25    16 0 5629 nbpcharicnlike icnlikesel icnlikejoinsel ));
+DESCR("does not match LIKE expression, case-insensitive");
+
 
 /* NUMERIC type - OID's 1700-1799 */
 DATA(insert OID = 1751 (  "-"	   PGNSP PGUID l f f	0 1700 1700    0	0 numeric_uminus - - ));
 DESCR("negate");
 DATA(insert OID = 1752 (  "="	   PGNSP PGUID b t t 1700 1700	 16 1752 1753 numeric_eq eqsel eqjoinsel ));
@@ -1395,16 +1434,27 @@
 DATA(insert OID = 2318 ( "~>~"	PGNSP PGUID b f f 25 25 16 2314 2315 text_pattern_gt scalargtsel scalargtjoinsel ));
 DESCR("greater than");
 
 DATA(insert OID = 2326 ( "~<~"	PGNSP PGUID b f f 1042 1042 16 2330 2329 bpchar_pattern_lt scalarltsel scalarltjoinsel ));
 DESCR("less than");
+DATA(insert OID = 5326 ( "~<~"  PGNSP PGUID b f f 5001 5001 16 5330 5329 nbpchar_pattern_lt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+
 DATA(insert OID = 2327 ( "~<=~" PGNSP PGUID b f f 1042 1042 16 2329 2330 bpchar_pattern_le scalarltsel scalarltjoinsel ));
 DESCR("less than or equal");
+DATA(insert OID = 5327 ( "~<=~" PGNSP PGUID b f f 5001 5001 16 5329 5330 nbpchar_pattern_le scalarltsel scalarltjoinsel ));
+DESCR("less than or equal");
+
 DATA(insert OID = 2329 ( "~>=~" PGNSP PGUID b f f 1042 1042 16 2327 2326 bpchar_pattern_ge scalargtsel scalargtjoinsel ));
 DESCR("greater than or equal");
+DATA(insert OID = 5329 ( "~>=~" PGNSP PGUID b f f 5001 5001 16 5327 5326 nbpchar_pattern_ge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
+
 DATA(insert OID = 2330 ( "~>~"	PGNSP PGUID b f f 1042 1042 16 2326 2327 bpchar_pattern_gt scalargtsel scalargtjoinsel ));
 DESCR("greater than");
+DATA(insert OID = 5330 ( "~>~"  PGNSP PGUID b f f 5001 5001 16 5326 5327 nbpchar_pattern_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
 
 /* crosstype operations for date vs. timestamp and timestamptz */
 
 DATA(insert OID = 2345 ( "<"	   PGNSP PGUID b f f	1082	1114   16 2375 2348 date_lt_timestamp scalarltsel scalarltjoinsel ));
 DESCR("less than");
diff -U 5 -N -r -w ../orig.HEAD/src/include/catalog/pg_proc.h ./src/include/catalog/pg_proc.h
--- ../orig.HEAD/src/include/catalog/pg_proc.h	2013-08-19 20:22:12.000000000 -0400
+++ ./src/include/catalog/pg_proc.h	2013-08-19 20:54:00.000000000 -0400
@@ -743,10 +743,19 @@
 DESCR("convert int8 to float8");
 DATA(insert OID = 483 (  int8			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 20 "701" _null_ _null_ _null_ _null_	dtoi8 _null_ _null_ _null_ ));
 DESCR("convert float8 to int8");
 
 /* OIDS 500 - 599 */
+/* national characters support functions */
+DATA(insert OID =  501 (  text             PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "6001" _null_ _null_ _null_ _null_   nvarchar2text _null_ _null_ _null_ ));
+DESCR("convert nvarchar to text");
+DATA(insert OID =  502 (  nvarchar         PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 6001 "25" _null_ _null_ _null_ _null_   text2nvarchar _null_ _null_ _null_ ));
+DESCR("convert text to nvarchar");
+DATA(insert OID =  503 (  text             PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "5001" _null_ _null_ _null_ _null_   nvarchar2rtrimtext _null_ _null_ _null_ ));
+DESCR("convert nbpvarchar to rtrimmed text");
+DATA(insert OID =  504 (  nvarchar         PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 6001 "1042" _null_ _null_ _null_ _null_   rtrimtext2nvarchar _null_ _null_ _null_ ));
+DESCR("convert trimmed text (bpchar) to nvarchar");
 
 /* OIDS 600 - 699 */
 
 DATA(insert OID = 626 (  hash_array		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "2277" _null_ _null_ _null_ _null_ hash_array _null_ _null_ _null_ ));
 DESCR("hash");
@@ -767,14 +776,23 @@
 DATA(insert OID = 658 (  namege			   PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "19 19" _null_ _null_ _null_ _null_ namege _null_ _null_ _null_ ));
 DATA(insert OID = 659 (  namene			   PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "19 19" _null_ _null_ _null_ _null_ namene _null_ _null_ _null_ ));
 
 DATA(insert OID = 668 (  bpchar			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1042 "1042 23 16" _null_ _null_ _null_ _null_ bpchar _null_ _null_ _null_ ));
 DESCR("adjust char() to typmod length");
+DATA(insert OID = 5668 (  nbpchar                    PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 5001 "5001 23 16" _null_ _null_ _null_ _null_ bpchar _null_ _null_ _null_ ));
+DESCR("adjust char() to typmod length");
+
 DATA(insert OID = 3097 ( varchar_transform PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ varchar_transform _null_ _null_ _null_ ));
 DESCR("transform a varchar length coercion");
+DATA(insert OID = 5097 ( nvarchar_transform PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ varchar_transform _null_ _null_ _null_ ));
+DESCR("transform a nvarchar length coercion");
+
 DATA(insert OID = 669 (  varchar		   PGNSP PGUID 12 1 0 0 varchar_transform f f f f t f i 3 0 1043 "1043 23 16" _null_ _null_ _null_ _null_ varchar _null_ _null_ _null_ ));
 DESCR("adjust varchar() to typmod length");
+DATA(insert OID = 5669 (  nvarchar                   PGNSP PGUID 12 1 0 0 nvarchar_transform f f f f t f i 3 0 6001 "6001 23 16" _null_ _null_ _null_ _null_ varchar _null_ _null_ _null_ ));
+DESCR("adjust nvarchar() to typmod length");
+
 
 DATA(insert OID = 676 (  mktinterval	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 704 "702 702" _null_ _null_ _null_ _null_ mktinterval _null_ _null_ _null_ ));
 
 DATA(insert OID = 619 (  oidvectorne	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "30 30" _null_ _null_ _null_ _null_ oidvectorne _null_ _null_ _null_ ));
 DATA(insert OID = 677 (  oidvectorlt	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "30 30" _null_ _null_ _null_ _null_ oidvectorlt _null_ _null_ _null_ ));
@@ -1118,38 +1136,79 @@
 DESCR("make ACL item");
 DATA(insert OID = 3943 (  acldefault	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1034 "18 26" _null_ _null_ _null_ _null_  acldefault_sql _null_ _null_ _null_ ));
 DESCR("TODO");
 DATA(insert OID = 1689 (  aclexplode	PGNSP PGUID 12 1 10 0 0 f f f f t t s 1 0 2249 "1034" "{1034,26,26,25,16}" "{i,o,o,o,o}" "{acl,grantor,grantee,privilege_type,is_grantable}" _null_ aclexplode _null_ _null_ _null_ ));
 DESCR("convert ACL item array to table, for use by information schema");
-DATA(insert OID = 1044 (  bpcharin		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1042 "2275 26 23" _null_ _null_ _null_ _null_ bpcharin _null_ _null_ _null_ ));
+
+DATA(insert OID = 1043 (  bpcharin		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1042 "2275 26 23" _null_ _null_ _null_ _null_ bpcharin _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 1045 (  bpcharout		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "1042" _null_ _null_ _null_ _null_ bpcharout _null_ _null_ _null_ ));
 DESCR("I/O");
+
+DATA(insert OID = 5101 (  nbpcharin                 PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 5001 "2275 26 23" _null_ _null_ _null_ _null_ bpcharin _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 5045 (  nbpcharout                PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "5001" _null_ _null_ _null_ _null_ bpcharout _null_ _null_ _null_ ));
+DESCR("I/O");
+
 DATA(insert OID = 2913 (  bpchartypmodin   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "1263" _null_ _null_ _null_ _null_	bpchartypmodin _null_ _null_ _null_ ));
 DESCR("I/O typmod");
 DATA(insert OID = 2914 (  bpchartypmodout  PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "23" _null_ _null_ _null_ _null_	bpchartypmodout _null_ _null_ _null_ ));
 DESCR("I/O typmod");
+
+DATA(insert OID = 5913 (  nbpchartypmodin   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "1263" _null_ _null_ _null_ _null_       bpchartypmodin _null_ _null_ _null_ ));
+DESCR("I/O typmod");
+DATA(insert OID = 5914 (  nbpchartypmodout  PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "23" _null_ _null_ _null_ _null_       bpchartypmodout _null_ _null_ _null_ ));
+DESCR("I/O typmod");
+
 DATA(insert OID = 1046 (  varcharin		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1043 "2275 26 23" _null_ _null_ _null_ _null_ varcharin _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 1047 (  varcharout	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "1043" _null_ _null_ _null_ _null_ varcharout _null_ _null_ _null_ ));
 DESCR("I/O");
+
+DATA(insert OID = 5046 (  nvarcharin       PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 6001 "2275 26 23" _null_ _null_ _null_ _null_ nvarcharin _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 5047 (  nvarcharout      PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "6001" _null_ _null_ _null_ _null_ nvarcharout _null_ _null_ _null_ ));
+DESCR("I/O");
+
 DATA(insert OID = 2915 (  varchartypmodin  PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "1263" _null_ _null_ _null_ _null_	varchartypmodin _null_ _null_ _null_ ));
 DESCR("I/O typmod");
 DATA(insert OID = 2916 (  varchartypmodout PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "23" _null_ _null_ _null_ _null_	varchartypmodout _null_ _null_ _null_ ));
 DESCR("I/O typmod");
+
+DATA(insert OID = 5915 (  nvarchartypmodin  PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "1263" _null_ _null_ _null_ _null_       varchartypmodin _null_ _null_ _null_ ));
+DESCR("I/O typmod");
+DATA(insert OID = 5916 (  nvarchartypmodout PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "23" _null_ _null_ _null_ _null_       varchartypmodout _null_ _null_ _null_ ));
+DESCR("I/O typmod");
+
 DATA(insert OID = 1048 (  bpchareq		   PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ bpchareq _null_ _null_ _null_ ));
 DATA(insert OID = 1049 (  bpcharlt		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ bpcharlt _null_ _null_ _null_ ));
 DATA(insert OID = 1050 (  bpcharle		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ bpcharle _null_ _null_ _null_ ));
 DATA(insert OID = 1051 (  bpchargt		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ bpchargt _null_ _null_ _null_ ));
 DATA(insert OID = 1052 (  bpcharge		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ bpcharge _null_ _null_ _null_ ));
 DATA(insert OID = 1053 (  bpcharne		   PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ bpcharne _null_ _null_ _null_ ));
+
+DATA(insert OID = 5048 (  nbpchareq                 PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpchareq _null_ _null_ _null_ ));
+DATA(insert OID = 5049 (  nbpcharlt                 PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpcharlt _null_ _null_ _null_ ));
+DATA(insert OID = 5050 (  nbpcharle                 PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpcharle _null_ _null_ _null_ ));
+DATA(insert OID = 5051 (  nbpchargt                 PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpchargt _null_ _null_ _null_ ));
+DATA(insert OID = 5052 (  nbpcharge                 PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpcharge _null_ _null_ _null_ ));
+DATA(insert OID = 5053 (  nbpcharne                 PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpcharne _null_ _null_ _null_ ));
+
 DATA(insert OID = 1063 (  bpchar_larger    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1042 "1042 1042" _null_ _null_ _null_ _null_ bpchar_larger _null_ _null_ _null_ ));
 DESCR("larger of two");
 DATA(insert OID = 1064 (  bpchar_smaller   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1042 "1042 1042" _null_ _null_ _null_ _null_ bpchar_smaller _null_ _null_ _null_ ));
 DESCR("smaller of two");
 DATA(insert OID = 1078 (  bpcharcmp		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "1042 1042" _null_ _null_ _null_ _null_ bpcharcmp _null_ _null_ _null_ ));
 DESCR("less-equal-greater");
+
+DATA(insert OID = 5063 (  nbpchar_larger    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 5001 "5001 5001" _null_ _null_ _null_ _null_ bpchar_larger _null_ _null_ _null_ ));
+DESCR("larger of two");
+DATA(insert OID = 5064 (  nbpchar_smaller   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 5001 "5001 5001" _null_ _null_ _null_ _null_ bpchar_smaller _null_ _null_ _null_ ));
+DESCR("smaller of two");
+DATA(insert OID = 5078 (  nbpcharcmp                PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "5001 5001" _null_ _null_ _null_ _null_ bpcharcmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+
 DATA(insert OID = 1080 (  hashbpchar	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "1042" _null_ _null_ _null_ _null_	hashbpchar _null_ _null_ _null_ ));
 DESCR("hash");
 DATA(insert OID = 1081 (  format_type	   PGNSP PGUID 12 1 0 0 0 f f f f f f s 2 0 25 "26 23" _null_ _null_ _null_ _null_ format_type _null_ _null_ _null_ ));
 DESCR("format a type oid and atttypmod to canonical SQL");
 DATA(insert OID = 1084 (  date_in		   PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 1082 "2275" _null_ _null_ _null_ _null_ date_in _null_ _null_ _null_ ));
@@ -1492,10 +1551,14 @@
 DESCR("character length");
 DATA(insert OID = 1374 (  octet_length			 PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "25" _null_ _null_ _null_ _null_	textoctetlen _null_ _null_ _null_ ));
 DESCR("octet length");
 DATA(insert OID = 1375 (  octet_length			 PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "1042" _null_ _null_ _null_ _null_ bpcharoctetlen _null_ _null_ _null_ ));
 DESCR("octet length");
+DATA(insert OID = 5374 (  octet_length                   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "5001" _null_ _null_ _null_ _null_ bpcharoctetlen _null_ _null_ _null_ ));
+DESCR("octet length");
+DATA(insert OID = 5375 (  octet_length                   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 23 "6001" _null_ _null_ _null_ _null_ textoctetlen _null_ _null_ _null_ ));
+DESCR("octet length");
 
 DATA(insert OID = 1377 (  time_larger	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1083 "1083 1083" _null_ _null_ _null_ _null_ time_larger _null_ _null_ _null_ ));
 DESCR("larger of two");
 DATA(insert OID = 1378 (  time_smaller	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1083 "1083 1083" _null_ _null_ _null_ _null_ time_smaller _null_ _null_ _null_ ));
 DESCR("smaller of two");
@@ -1547,10 +1610,15 @@
 DATA(insert OID = 1400 (  name		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 19 "1043" _null_ _null_ _null_ _null_	text_name _null_ _null_ _null_ ));
 DESCR("convert varchar to name");
 DATA(insert OID = 1401 (  varchar	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 1043 "19" _null_ _null_ _null_ _null_	name_text _null_ _null_ _null_ ));
 DESCR("convert name to varchar");
 
+DATA(insert OID = 5400 (  name             PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 19 "6001" _null_ _null_ _null_ _null_       text_name _null_ _null_ _null_ ));
+DESCR("convert nvarchar to name");
+DATA(insert OID = 5401 (  nvarchar         PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 6001 "19" _null_ _null_ _null_ _null_       name_text _null_ _null_ _null_ ));
+DESCR("convert name to nvarchar");
+
 DATA(insert OID = 1402 (  current_schema	PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 19 "" _null_ _null_ _null_ _null_ current_schema _null_ _null_ _null_ ));
 DESCR("current schema name");
 DATA(insert OID = 1403 (  current_schemas	PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 1003 "16" _null_ _null_ _null_ _null_	current_schemas _null_ _null_ _null_ ));
 DESCR("current schema search list");
 
@@ -1821,10 +1889,13 @@
 
 DATA(insert OID = 1624 (  mul_d_interval	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1186 "701 1186" _null_ _null_ _null_ _null_ mul_d_interval _null_ _null_ _null_ ));
 
 DATA(insert OID = 1631 (  bpcharlike	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 25" _null_ _null_ _null_ _null_ textlike _null_ _null_ _null_ ));
 DATA(insert OID = 1632 (  bpcharnlike	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 25" _null_ _null_ _null_ _null_ textnlike _null_ _null_ _null_ ));
+DATA(insert OID = 5631 (  nbpcharlike       PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 25" _null_ _null_ _null_ _null_ textlike _null_ _null_ _null_ ));
+DATA(insert OID = 5632 (  nbpcharnlike      PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 25" _null_ _null_ _null_ _null_ textnlike _null_ _null_ _null_ ));
+
 
 DATA(insert OID = 1633 (  texticlike		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ texticlike _null_ _null_ _null_ ));
 DATA(insert OID = 1634 (  texticnlike		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "25 25" _null_ _null_ _null_ _null_ texticnlike _null_ _null_ _null_ ));
 DATA(insert OID = 1635 (  nameiclike		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "19 25" _null_ _null_ _null_ _null_ nameiclike _null_ _null_ _null_ ));
 DATA(insert OID = 1636 (  nameicnlike		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "19 25" _null_ _null_ _null_ _null_ nameicnlike _null_ _null_ _null_ ));
@@ -1836,10 +1907,18 @@
 DATA(insert OID = 1658 (  bpcharregexeq    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 25" _null_ _null_ _null_ _null_ textregexeq _null_ _null_ _null_ ));
 DATA(insert OID = 1659 (  bpcharregexne    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 25" _null_ _null_ _null_ _null_ textregexne _null_ _null_ _null_ ));
 DATA(insert OID = 1660 (  bpchariclike		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 25" _null_ _null_ _null_ _null_ texticlike _null_ _null_ _null_ ));
 DATA(insert OID = 1661 (  bpcharicnlike		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 25" _null_ _null_ _null_ _null_ texticnlike _null_ _null_ _null_ ));
 
+DATA(insert OID = 5656 (  nbpcharicregexeq        PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 25" _null_ _null_ _null_ _null_ texticregexeq _null_ _null_ _null_ ));
+DATA(insert OID = 5657 (  nbpcharicregexne        PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 25" _null_ _null_ _null_ _null_ texticregexne _null_ _null_ _null_ ));
+DATA(insert OID = 5658 (  nbpcharregexeq    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 25" _null_ _null_ _null_ _null_ textregexeq _null_ _null_ _null_ ));
+DATA(insert OID = 5659 (  nbpcharregexne    PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 25" _null_ _null_ _null_ _null_ textregexne _null_ _null_ _null_ ));
+DATA(insert OID = 5660 (  nbpchariclike          PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 25" _null_ _null_ _null_ _null_ texticlike _null_ _null_ _null_ ));
+DATA(insert OID = 5661 (  nbpcharicnlike         PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 25" _null_ _null_ _null_ _null_ texticnlike _null_ _null_ _null_ ));
+
+
 /* Oracle Compatibility Related Functions - By Edmund Mergl <[email protected]> */
 DATA(insert OID =  868 (  strpos	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "25 25" _null_ _null_ _null_ _null_ textpos _null_ _null_ _null_ ));
 DESCR("position of substring");
 DATA(insert OID =  870 (  lower		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "25" _null_ _null_ _null_ _null_ lower _null_ _null_ _null_ ));
 DESCR("lowercase");
@@ -3256,10 +3335,18 @@
 DATA(insert OID = 2177 ( bpchar_pattern_ge	  PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ bpchar_pattern_ge _null_ _null_ _null_ ));
 DATA(insert OID = 2178 ( bpchar_pattern_gt	  PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "1042 1042" _null_ _null_ _null_ _null_ bpchar_pattern_gt _null_ _null_ _null_ ));
 DATA(insert OID = 2180 ( btbpchar_pattern_cmp PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "1042 1042" _null_ _null_ _null_ _null_ btbpchar_pattern_cmp _null_ _null_ _null_ ));
 DESCR("less-equal-greater");
 
+DATA(insert OID = 5174 ( nbpchar_pattern_lt        PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpchar_pattern_lt _null_ _null_ _null_ ));
+DATA(insert OID = 5175 ( nbpchar_pattern_le        PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpchar_pattern_le _null_ _null_ _null_ ));
+DATA(insert OID = 5177 ( nbpchar_pattern_ge        PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpchar_pattern_ge _null_ _null_ _null_ ));
+DATA(insert OID = 5178 ( nbpchar_pattern_gt        PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "5001 5001" _null_ _null_ _null_ _null_ bpchar_pattern_gt _null_ _null_ _null_ ));
+DATA(insert OID = 5180 ( nbtbpchar_pattern_cmp PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "5001 5001" _null_ _null_ _null_ _null_ btbpchar_pattern_cmp _null_ _null_ _null_ ));
+DESCR("less-equal-greater");
+
+
 DATA(insert OID = 2188 ( btint48cmp			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "23 20" _null_ _null_ _null_ _null_ btint48cmp _null_ _null_ _null_ ));
 DESCR("less-equal-greater");
 DATA(insert OID = 2189 ( btint84cmp			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "20 23" _null_ _null_ _null_ _null_ btint84cmp _null_ _null_ _null_ ));
 DESCR("less-equal-greater");
 DATA(insert OID = 2190 ( btint24cmp			PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "21 23" _null_ _null_ _null_ _null_ btint24cmp _null_ _null_ _null_ ));
@@ -3643,14 +3730,22 @@
 DESCR("I/O");
 DATA(insert OID = 2430 (  bpcharrecv		   PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 1042 "2281 26 23" _null_ _null_ _null_ _null_  bpcharrecv _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 2431 (  bpcharsend		   PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 17 "1042" _null_ _null_ _null_ _null_	bpcharsend _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 5430 (  nbpcharrecv              PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 5001 "2281 26 23" _null_ _null_ _null_ _null_  bpcharrecv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 5431 (  nbpcharsend              PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 17 "5001" _null_ _null_ _null_ _null_       bpcharsend _null_ _null_ _null_ ));
+DESCR("I/O");
 DATA(insert OID = 2432 (  varcharrecv		   PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 1043 "2281 26 23" _null_ _null_ _null_ _null_  varcharrecv _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 2433 (  varcharsend		   PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 17 "1043" _null_ _null_ _null_ _null_	varcharsend _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 5432 (  nvarcharrecv             PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 6001 "2281 26 23" _null_ _null_ _null_ _null_  varcharrecv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 5433 (  nvarcharsend             PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 17 "6001" _null_ _null_ _null_ _null_       varcharsend _null_ _null_ _null_ ));
+DESCR("I/O");
 DATA(insert OID = 2434 (  charrecv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 18 "2281" _null_ _null_ _null_ _null_	charrecv _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 2435 (  charsend			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "18" _null_ _null_ _null_ _null_ charsend _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 2436 (  boolrecv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 16 "2281" _null_ _null_ _null_ _null_	boolrecv _null_ _null_ _null_ ));
diff -U 5 -N -r -w ../orig.HEAD/src/include/catalog/pg_type.h ./src/include/catalog/pg_type.h
--- ../orig.HEAD/src/include/catalog/pg_type.h	2013-08-19 20:22:12.000000000 -0400
+++ ./src/include/catalog/pg_type.h	2013-08-19 20:54:00.000000000 -0400
@@ -457,11 +457,13 @@
 DATA(insert OID = 1010 (  _tid		 PGNSP PGUID -1 f b A f t \054 0	27 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1011 (  _xid		 PGNSP PGUID -1 f b A f t \054 0	28 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1012 (  _cid		 PGNSP PGUID -1 f b A f t \054 0	29 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1013 (  _oidvector PGNSP PGUID -1 f b A f t \054 0	30 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1014 (  _bpchar	 PGNSP PGUID -1 f b A f t \054 0 1042 0 array_in array_out array_recv array_send bpchartypmodin bpchartypmodout array_typanalyze i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DATA(insert OID = 5014 (  _nbpchar       PGNSP PGUID -1 f b A f t \054 0 5001 0 array_in array_out array_recv array_send nbpchartypmodin nbpchartypmodout array_typanalyze i x f 0 -1 0 100 _null_ _null_ _null_ ));
 DATA(insert OID = 1015 (  _varchar	 PGNSP PGUID -1 f b A f t \054 0 1043 0 array_in array_out array_recv array_send varchartypmodin varchartypmodout array_typanalyze i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DATA(insert OID = 5015 (  _nvarchar       PGNSP PGUID -1 f b A f t \054 0 6001 0 array_in array_out array_recv array_send nvarchartypmodin nvarchartypmodout array_typanalyze i x f 0 -1 0 100 _null_ _null_ _null_ ));
 DATA(insert OID = 1016 (  _int8		 PGNSP PGUID -1 f b A f t \054 0	20 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1017 (  _point	 PGNSP PGUID -1 f b A f t \054 0 600 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1018 (  _lseg		 PGNSP PGUID -1 f b A f t \054 0 601 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1019 (  _path		 PGNSP PGUID -1 f b A f t \054 0 602 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 1020 (  _box		 PGNSP PGUID -1 f b A f t \073 0 603 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
@@ -483,14 +485,23 @@
 #define CSTRINGARRAYOID		1263
 
 DATA(insert OID = 1042 ( bpchar		 PGNSP PGUID -1 f b S f t \054 0	0 1014 bpcharin bpcharout bpcharrecv bpcharsend bpchartypmodin bpchartypmodout - i x f 0 -1 0 100 _null_ _null_ _null_ ));
 DESCR("char(length), blank-padded string, fixed storage length");
 #define BPCHAROID		1042
+
+DATA(insert OID = 5001 ( nbpchar         PGNSP PGUID -1 f b S f t \054 0        0 5014 nbpcharin nbpcharout nbpcharrecv nbpcharsend nbpchartypmodin nbpchartypmodout - i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DESCR("nchar(length), blank-padded national string, fixed storage length");
+#define NBPCHAROID              5001
+
 DATA(insert OID = 1043 ( varchar	 PGNSP PGUID -1 f b S f t \054 0	0 1015 varcharin varcharout varcharrecv varcharsend varchartypmodin varchartypmodout - i x f 0 -1 0 100 _null_ _null_ _null_ ));
 DESCR("varchar(length), non-blank-padded string, variable storage length");
 #define VARCHAROID		1043
 
+DATA(insert OID = 6001 ( nvarchar         PGNSP PGUID -1 f b S f t \054 0        0 5015 nvarcharin nvarcharout nvarcharrecv nvarcharsend nvarchartypmodin nvarchartypmodout - i x f 0 -1 0 100 _null_ _null_ _null_ ));
+DESCR("nvarchar(length), non-blank-padded national string, variable storage length");
+#define NVARCHAROID		6001
+
 DATA(insert OID = 1082 ( date		 PGNSP PGUID	4 t b D f t \054 0	0 1182 date_in date_out date_recv date_send - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("date");
 #define DATEOID			1082
 DATA(insert OID = 1083 ( time		 PGNSP PGUID	8 FLOAT8PASSBYVAL b D f t \054 0	0 1183 time_in time_out time_recv time_send timetypmodin timetypmodout - d p f 0 -1 0 0 _null_ _null_ _null_ ));
 DESCR("time of day");
diff -U 5 -N -r -w ../orig.HEAD/src/include/parser/kwlist.h ./src/include/parser/kwlist.h
--- ../orig.HEAD/src/include/parser/kwlist.h	2013-08-19 20:22:12.000000000 -0400
+++ ./src/include/parser/kwlist.h	2013-08-19 20:54:00.000000000 -0400
@@ -255,10 +255,11 @@
 PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD)
 PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD)
 PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD)
 PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD)
+PG_KEYWORD("nvarchar", NVARCHAR, COL_NAME_KEYWORD)
 PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("of", OF, UNRESERVED_KEYWORD)
 PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD)
 PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD)
 PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD)
diff -U 5 -N -r -w ../orig.HEAD/src/include/utils/builtins.h ./src/include/utils/builtins.h
--- ../orig.HEAD/src/include/utils/builtins.h	2013-08-19 20:22:13.000000000 -0400
+++ ./src/include/utils/builtins.h	2013-08-19 20:54:00.000000000 -0400
@@ -324,10 +324,33 @@
 extern Datum btfloat4sortsupport(PG_FUNCTION_ARGS);
 extern Datum btfloat8sortsupport(PG_FUNCTION_ARGS);
 extern Datum btoidsortsupport(PG_FUNCTION_ARGS);
 extern Datum btnamesortsupport(PG_FUNCTION_ARGS);
 
+/* nvarchar.c */
+extern Datum ntextin(PG_FUNCTION_ARGS);
+extern Datum ntextout(PG_FUNCTION_ARGS);
+extern Datum nvarcharin(PG_FUNCTION_ARGS);
+extern Datum nvarcharout(PG_FUNCTION_ARGS);
+extern Datum ntextlower(PG_FUNCTION_ARGS);
+extern Datum ntextupper(PG_FUNCTION_ARGS);
+extern Datum ntextoctetlen(PG_FUNCTION_ARGS);
+extern Datum nvarchar2text(PG_FUNCTION_ARGS);
+extern Datum text2nvarchar(PG_FUNCTION_ARGS);
+extern Datum nvarchar2rtrimtext(PG_FUNCTION_ARGS);
+extern Datum rtrimtext2nvarchar(PG_FUNCTION_ARGS);
+extern Datum ntext_cmp(PG_FUNCTION_ARGS);
+extern Datum ntext_hash(PG_FUNCTION_ARGS);
+extern Datum ntext_eq(PG_FUNCTION_ARGS);
+extern Datum ntext_ne(PG_FUNCTION_ARGS);
+extern Datum ntext_gt(PG_FUNCTION_ARGS);
+extern Datum ntext_ge(PG_FUNCTION_ARGS);
+extern Datum ntext_lt(PG_FUNCTION_ARGS);
+extern Datum ntext_le(PG_FUNCTION_ARGS);
+extern Datum ntext_smaller(PG_FUNCTION_ARGS);
+extern Datum ntext_larger(PG_FUNCTION_ARGS);
+
 /* float.c */
 extern PGDLLIMPORT int extra_float_digits;
 
 extern double get_float8_infinity(void);
 extern float get_float4_infinity(void);
@@ -831,10 +854,13 @@
 extern Datum byteanlike(PG_FUNCTION_ARGS);
 extern Datum like_escape(PG_FUNCTION_ARGS);
 extern Datum like_escape_bytea(PG_FUNCTION_ARGS);
 
 /* oracle_compat.c */
+extern text *dotrim(const char *string, int stringlen,
+       const char *set, int setlen,
+       bool doltrim, bool dortrim);
 extern Datum lower(PG_FUNCTION_ARGS);
 extern Datum upper(PG_FUNCTION_ARGS);
 extern Datum initcap(PG_FUNCTION_ARGS);
 extern Datum lpad(PG_FUNCTION_ARGS);
 extern Datum rpad(PG_FUNCTION_ARGS);
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/ecpglib/data.c ./src/interfaces/ecpg/ecpglib/data.c
--- ../orig.HEAD/src/interfaces/ecpg/ecpglib/data.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/ecpglib/data.c	2013-08-20 05:02:12.000000000 -0400
@@ -225,12 +225,14 @@
 		}
 
 		switch (type)
 		{
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_varchar:
+			case ECPGt_nvarchar:
 			case ECPGt_string:
 				break;
 
 			default:
 				pval++;
@@ -448,10 +450,11 @@
 							   ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
 					return (false);
 					break;
 
 				case ECPGt_char:
+				case ECPGt_nchar:
 				case ECPGt_unsigned_char:
 				case ECPGt_string:
 					{
 						char	   *str = (char *) (var + offset * act_tuple);
 
@@ -506,10 +509,11 @@
 						pval += size;
 					}
 					break;
 
 				case ECPGt_varchar:
+				case ECPGt_nvarchar:
 					{
 						struct ECPGgeneric_varchar *variable =
 						(struct ECPGgeneric_varchar *) (var + offset * act_tuple);
 
 						variable->len = size;
@@ -545,17 +549,20 @@
 									default:
 										break;
 								}
 								sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
 
+								/*
+								 * it will be not too good result if it
+								 * truncate in middle of utf byte-sequence
+								 */
 								variable->len = varcharsize;
 							}
 						}
 						pval += size;
 					}
 					break;
-
 				case ECPGt_decimal:
 				case ECPGt_numeric:
 					if (isarray && *pval == '"')
 						nres = PGTYPESnumeric_from_asc(pval + 1, &scan_length);
 					else
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/ecpglib/descriptor.c ./src/interfaces/ecpg/ecpglib/descriptor.c
--- ../orig.HEAD/src/interfaces/ecpg/ecpglib/descriptor.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/ecpglib/descriptor.c	2013-08-20 05:00:38.000000000 -0400
@@ -198,15 +198,17 @@
 get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int varcharsize)
 {
 	switch (vartype)
 	{
 		case ECPGt_char:
+		case ECPGt_nchar:
 		case ECPGt_unsigned_char:
 		case ECPGt_string:
 			strncpy((char *) var, value, varcharsize);
 			break;
 		case ECPGt_varchar:
+		case ECPGt_nvarchar:
 			{
 				struct ECPGgeneric_varchar *variable =
 				(struct ECPGgeneric_varchar *) var;
 
 				if (varcharsize == 0)
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/ecpglib/error.c ./src/interfaces/ecpg/ecpglib/error.c
--- ../orig.HEAD/src/interfaces/ecpg/ecpglib/error.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/ecpglib/error.c	2013-08-19 20:54:00.000000000 -0400
@@ -37,10 +37,20 @@
 			 * expanded.
 			 */
 					 ecpg_gettext("out of memory on line %d"), line);
 			break;
 
+		case ECPG_ENCODING_ERROR:
+            snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
+
+            /*
+             * translator: this string will be truncated at 149 characters
+             * expanded.
+             */
+                     ecpg_gettext("encoding conversion error on line %d"), line);
+            break;
+
 		case ECPG_UNSUPPORTED:
 			snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
 
 			/*
 			 * translator: this string will be truncated at 149 characters
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/ecpglib/execute.c ./src/interfaces/ecpg/ecpglib/execute.c
--- ../orig.HEAD/src/interfaces/ecpg/ecpglib/execute.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/ecpglib/execute.c	2013-08-20 05:05:56.000000000 -0400
@@ -244,12 +244,16 @@
 			return (ECPG_ARRAY_ERROR);
 		if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), CIDROID, ECPG_ARRAY_NONE, stmt->lineno))
 			return (ECPG_ARRAY_ERROR);
 		if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), BPCHAROID, ECPG_ARRAY_NONE, stmt->lineno))
 			return (ECPG_ARRAY_ERROR);
+		if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), NBPCHAROID, ECPG_ARRAY_NONE, stmt->lineno))
+			return (ECPG_ARRAY_ERROR);
 		if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), VARCHAROID, ECPG_ARRAY_NONE, stmt->lineno))
 			return (ECPG_ARRAY_ERROR);
+		if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), NVARCHAROID, ECPG_ARRAY_NONE, stmt->lineno))
+			return (ECPG_ARRAY_ERROR);
 		if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), DATEOID, ECPG_ARRAY_NONE, stmt->lineno))
 			return (ECPG_ARRAY_ERROR);
 		if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), TIMEOID, ECPG_ARRAY_NONE, stmt->lineno))
 			return (ECPG_ARRAY_ERROR);
 		if (!ecpg_type_infocache_push(&(stmt->connection->cache_head), TIMESTAMPOID, ECPG_ARRAY_NONE, stmt->lineno))
@@ -360,10 +364,11 @@
 		if (!PQfformat(results, act_field))
 		{
 			switch (var->type)
 			{
 				case ECPGt_char:
+				case ECPGt_nchar:
 				case ECPGt_unsigned_char:
 				case ECPGt_string:
 					if (!var->varcharsize && !var->arrsize)
 					{
 						/* special mode for handling char**foo=0 */
@@ -385,10 +390,11 @@
 						}
 						var->offset *= var->varcharsize;
 						len = var->offset * ntuples;
 					}
 					break;
+				case ECPGt_nvarchar:
 				case ECPGt_varchar:
 					len = ntuples * (var->varcharsize + sizeof(int));
 					break;
 				default:
 					len = var->offset * ntuples;
@@ -421,11 +427,11 @@
 		ecpg_add_mem(var->ind_value, stmt->lineno);
 	}
 
 	/* fill the variable with the tuple(s) */
 	if (!var->varcharsize && !var->arrsize &&
-		(var->type == ECPGt_char || var->type == ECPGt_unsigned_char || var->type == ECPGt_string))
+		(var->type == ECPGt_char || var->type == ECPGt_unsigned_char || var->type == ECPGt_string || var->type == ECPGt_nchar))
 	{
 		/* special mode for handling char**foo=0 */
 
 		/* filling the array of (char*)s */
 		char	  **current_string = (char **) var->value;
@@ -791,10 +797,11 @@
 
 				*tobeinserted_p = mallocedval;
 				break;
 
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_string:
 				{
 					/* set slen to string length if type is char * */
 					int			slen = (var->varcharsize == 0) ? strlen((char *) var->value) : (unsigned int) var->varcharsize;
@@ -825,10 +832,11 @@
 
 					*tobeinserted_p = mallocedval;
 				}
 				break;
 			case ECPGt_varchar:
+			case ECPGt_nvarchar:
 				{
 					struct ECPGgeneric_varchar *variable =
 					(struct ECPGgeneric_varchar *) (var->value);
 
 					if (!(newcopy = (char *) ecpg_alloc(variable->len + 1, lineno)))
@@ -842,11 +850,10 @@
 						return false;
 
 					*tobeinserted_p = mallocedval;
 				}
 				break;
-
 			case ECPGt_decimal:
 			case ECPGt_numeric:
 				{
 					char	   *str = NULL;
 					int			slen;
@@ -1229,10 +1236,12 @@
 						desc_inlist.value = sqlda->sqlvar[i].sqldata;
 						desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata);
 						switch (desc_inlist.type)
 						{
 							case ECPGt_char:
+							case ECPGt_nchar:
+							case ECPGt_nvarchar:
 							case ECPGt_varchar:
 								desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
 								break;
 							default:
 								desc_inlist.varcharsize = 0;
@@ -1284,10 +1293,12 @@
 						desc_inlist.value = sqlda->sqlvar[i].sqldata;
 						desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata);
 						switch (desc_inlist.type)
 						{
 							case ECPGt_char:
+							case ECPGt_nchar:
+							case ECPGt_nvarchar:
 							case ECPGt_varchar:
 								desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
 								break;
 							default:
 								desc_inlist.varcharsize = 0;
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/ecpglib/extern.h ./src/interfaces/ecpg/ecpglib/extern.h
--- ../orig.HEAD/src/interfaces/ecpg/ecpglib/extern.h	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/ecpglib/extern.h	2013-08-19 20:54:00.000000000 -0400
@@ -202,7 +202,8 @@
 #define ECPG_SQLSTATE_DUPLICATE_CURSOR		"42P03"
 
 /* implementation-defined internal errors of ecpg */
 #define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR	"YE000"
 #define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY	"YE001"
+#define ECPG_SQLSTATE_ECPG_ENCODING_ERROR   "YE002"
 
 #endif   /* _ECPG_LIB_EXTERN_H */
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/ecpglib/misc.c ./src/interfaces/ecpg/ecpglib/misc.c
--- ../orig.HEAD/src/interfaces/ecpg/ecpglib/misc.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/ecpglib/misc.c	2013-08-20 05:04:28.000000000 -0400
@@ -303,10 +303,11 @@
 ECPGset_noind_null(enum ECPGttype type, void *ptr)
 {
 	switch (type)
 	{
 		case ECPGt_char:
+		case ECPGt_nchar:
 		case ECPGt_unsigned_char:
 		case ECPGt_string:
 			*((char *) ptr) = '\0';
 			break;
 		case ECPGt_short:
@@ -332,10 +333,11 @@
 			memset((char *) ptr, 0xff, sizeof(float));
 			break;
 		case ECPGt_double:
 			memset((char *) ptr, 0xff, sizeof(double));
 			break;
+		case ECPGt_nvarchar:
 		case ECPGt_varchar:
 			*(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
 			((struct ECPGgeneric_varchar *) ptr)->len = 0;
 			break;
 		case ECPGt_decimal:
@@ -405,10 +407,11 @@
 			return (_check(ptr, sizeof(float)));
 			break;
 		case ECPGt_double:
 			return (_check(ptr, sizeof(double)));
 			break;
+		case ECPGt_nvarchar:
 		case ECPGt_varchar:
 			if (*(((struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
 				return true;
 			break;
 		case ECPGt_decimal:
@@ -546,5 +549,6 @@
 	struct var_list *ptr;
 
 	for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
 	return (ptr) ? ptr->pointer : NULL;
 }
+
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/ecpglib/pg_type.h ./src/interfaces/ecpg/ecpglib/pg_type.h
--- ../orig.HEAD/src/interfaces/ecpg/ecpglib/pg_type.h	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/ecpglib/pg_type.h	2013-08-19 20:54:00.000000000 -0400
@@ -46,10 +46,12 @@
 #define CASHOID 790
 #define INETOID 869
 #define CIDROID 650
 #define BPCHAROID		1042
 #define VARCHAROID		1043
+#define NBPCHAROID              5001
+#define NVARCHAROID             6001
 #define DATEOID			1082
 #define TIMEOID			1083
 #define TIMESTAMPOID	1114
 #define TIMESTAMPTZOID	1184
 #define INTERVALOID		1186
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/ecpglib/sqlda.c ./src/interfaces/ecpg/ecpglib/sqlda.c
--- ../orig.HEAD/src/interfaces/ecpg/ecpglib/sqlda.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/ecpglib/sqlda.c	2013-08-19 20:54:00.000000000 -0400
@@ -132,10 +132,11 @@
 				break;
 			case ECPGt_interval:
 				ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
 				break;
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_string:
 			default:
 				{
 					long		datalen = strlen(PQgetvalue(res, row, i)) + 1;
@@ -371,10 +372,11 @@
 				ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
 				sqlda->sqlvar[i].sqllen = sizeof(interval);
 				break;
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_string:
 			default:
 				datalen = strlen(PQgetvalue(res, row, i)) + 1;
 				ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
@@ -560,10 +562,11 @@
 				ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
 				sqlda->sqlvar[i].sqllen = sizeof(interval);
 				break;
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_string:
 			default:
 				datalen = strlen(PQgetvalue(res, row, i)) + 1;
 				ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/ecpglib/typename.c ./src/interfaces/ecpg/ecpglib/typename.c
--- ../orig.HEAD/src/interfaces/ecpg/ecpglib/typename.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/ecpglib/typename.c	2013-08-20 05:02:32.000000000 -0400
@@ -20,10 +20,12 @@
 	switch (typ)
 	{
 		case ECPGt_char:
 		case ECPGt_string:
 			return "char";
+		case ECPGt_nchar:
+			return "national char";
 		case ECPGt_unsigned_char:
 			return "unsigned char";
 		case ECPGt_short:
 			return "short";
 		case ECPGt_unsigned_short:
@@ -46,10 +48,12 @@
 			return "double";
 		case ECPGt_bool:
 			return "bool";
 		case ECPGt_varchar:
 			return "varchar";
+		case ECPGt_nvarchar:
+			return "nvarchar";
 		case ECPGt_char_variable:
 			return "char";
 		case ECPGt_decimal:
 			return "decimal";
 		case ECPGt_numeric:
@@ -85,12 +89,16 @@
 			return SQL3_REAL;	/* float4 */
 		case FLOAT8OID:
 			return SQL3_DOUBLE_PRECISION;		/* float8 */
 		case BPCHAROID:
 			return SQL3_CHARACTER;		/* bpchar */
+		case NBPCHAROID:
+			return SQL3_CHARACTER;		/* bpchar */
 		case VARCHAROID:
 			return SQL3_CHARACTER_VARYING;		/* varchar */
+		case NVARCHAROID:
+			return SQL3_CHARACTER_VARYING;		/* nvarchar */
 		case DATEOID:
 			return SQL3_DATE_TIME_TIMESTAMP;	/* date */
 		case TIMEOID:
 			return SQL3_DATE_TIME_TIMESTAMP;	/* time */
 		case TIMESTAMPOID:
@@ -107,11 +115,13 @@
 {
 	switch (type)
 	{
 		case CHAROID:
 		case VARCHAROID:
+		case NVARCHAROID:
 		case BPCHAROID:
+		case NBPCHAROID:
 		case TEXTOID:
 			return ECPGt_char;
 		case INT2OID:
 			return ECPGt_short;
 		case INT4OID:
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/include/ecpgerrno.h ./src/interfaces/ecpg/include/ecpgerrno.h
--- ../orig.HEAD/src/interfaces/ecpg/include/ecpgerrno.h	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/include/ecpgerrno.h	2013-08-19 20:54:00.000000000 -0400
@@ -43,10 +43,13 @@
 #define ECPG_INVALID_DESCRIPTOR_INDEX	-241
 #define ECPG_UNKNOWN_DESCRIPTOR_ITEM	-242
 #define ECPG_VAR_NOT_NUMERIC		-243
 #define ECPG_VAR_NOT_CHAR		-244
 
+/*encoding conversion errors */
+#define ECPG_ENCODING_ERROR     -250
+
 /* finally the backend error messages, they start at 400 */
 #define ECPG_PGSQL			-400
 #define ECPG_TRANS			-401
 #define ECPG_CONNECT			-402
 #define ECPG_DUPLICATE_KEY		-403
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/include/ecpgtype.h ./src/interfaces/ecpg/include/ecpgtype.h
--- ../orig.HEAD/src/interfaces/ecpg/include/ecpgtype.h	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/include/ecpgtype.h	2013-08-20 05:02:01.000000000 -0400
@@ -44,10 +44,12 @@
 	ECPGt_int, ECPGt_unsigned_int, ECPGt_long, ECPGt_unsigned_long,
 	ECPGt_long_long, ECPGt_unsigned_long_long,
 	ECPGt_bool,
 	ECPGt_float, ECPGt_double,
 	ECPGt_varchar, ECPGt_varchar2,
+	ECPGt_nvarchar,				/* the same as ECPGt_varchar actually */
+	ECPGt_nchar,                            /* converted to char *arr[N] */
 	ECPGt_numeric,				/* this is a decimal that stores its digits in
 								 * a malloced array */
 	ECPGt_decimal,				/* this is a decimal that stores its digits in
 								 * a fixed array */
 	ECPGt_date,
@@ -102,5 +104,6 @@
 #ifdef __cplusplus
 }
 #endif
 
 #endif   /* _ECPGTYPE_H */
+
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/include/sqltypes.h ./src/interfaces/ecpg/include/sqltypes.h
--- ../orig.HEAD/src/interfaces/ecpg/include/sqltypes.h	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/include/sqltypes.h	2013-08-19 20:54:00.000000000 -0400
@@ -44,10 +44,11 @@
 #define	SQLTEXT		ECPGt_char
 #define	SQLVCHAR	ECPGt_char
 #define SQLINTERVAL     ECPGt_interval
 #define	SQLNCHAR	ECPGt_char
 #define	SQLNVCHAR	ECPGt_char
+#define SQLNVARCHAR     ECPGt_char
 #ifdef HAVE_LONG_LONG_INT_64
 #define	SQLINT8		ECPGt_long_long
 #define	SQLSERIAL8	ECPGt_long_long
 #else
 #define	SQLINT8		ECPGt_long
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/preproc/c_keywords.c ./src/interfaces/ecpg/preproc/c_keywords.c
--- ../orig.HEAD/src/interfaces/ecpg/preproc/c_keywords.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/preproc/c_keywords.c	2013-08-20 05:09:08.000000000 -0400
@@ -25,10 +25,12 @@
 
 	/*
 	 * category is not needed in ecpg, it is only here so we can share the
 	 * data structure with the backend
 	 */
+	{"NCHAR", NCHAR, 0},
+	{"NVARCHAR", NVARCHAR, 0},
 	{"VARCHAR", VARCHAR, 0},
 	{"auto", S_AUTO, 0},
 	{"bool", SQL_BOOL, 0},
 	{"char", CHAR_P, 0},
 	{"const", S_CONST, 0},
@@ -38,10 +40,12 @@
 	{"hour", HOUR_P, 0},
 	{"int", INT_P, 0},
 	{"long", SQL_LONG, 0},
 	{"minute", MINUTE_P, 0},
 	{"month", MONTH_P, 0},
+	{"nchar", NCHAR, 0},
+	{"nvarchar", NVARCHAR, 0},
 	{"register", S_REGISTER, 0},
 	{"second", SECOND_P, 0},
 	{"short", SQL_SHORT, 0},
 	{"signed", SQL_SIGNED, 0},
 	{"static", S_STATIC, 0},
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/preproc/ecpg.header ./src/interfaces/ecpg/preproc/ecpg.header
--- ../orig.HEAD/src/interfaces/ecpg/preproc/ecpg.header	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/preproc/ecpg.header	2013-08-20 05:08:24.000000000 -0400
@@ -267,11 +267,13 @@
 			{
 				newvar = ptr->variable;
 				skip_set_var = true;
 			}
 			else if ((ptr->variable->type->type != ECPGt_varchar
+					  && ptr->variable->type->type != ECPGt_nvarchar
 					  && ptr->variable->type->type != ECPGt_char
+					  && ptr->variable->type->type != ECPGt_nchar
 					  && ptr->variable->type->type != ECPGt_unsigned_char
 					  && ptr->variable->type->type != ECPGt_string)
 					 && atoi(ptr->variable->type->size) > 1)
 			{
 				newvar = new_variable(cat_str(4, mm_strdup("("),
@@ -283,11 +285,13 @@
 																			   ptr->variable->type->u.element->counter),
 														  ptr->variable->type->size),
 									  0);
 			}
 			else if ((ptr->variable->type->type == ECPGt_varchar
+					  || ptr->variable->type->type == ECPGt_nvarchar
 					  || ptr->variable->type->type == ECPGt_char
+					  || ptr->variable->type->type == ECPGt_nchar
 					  || ptr->variable->type->type == ECPGt_unsigned_char
 					  || ptr->variable->type->type == ECPGt_string)
 					 && atoi(ptr->variable->type->size) > 1)
 			{
 				newvar = new_variable(cat_str(4, mm_strdup("("),
@@ -296,11 +300,11 @@
 											  mm_strdup(var_text)),
 									  ECPGmake_simple_type(ptr->variable->type->type,
 														   ptr->variable->type->size,
 														   ptr->variable->type->counter),
 									  0);
-				if (ptr->variable->type->type == ECPGt_varchar)
+				if (ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_nvarchar)
 					var_ptr = true;
 			}
 			else if (ptr->variable->type->type == ECPGt_struct
 					 || ptr->variable->type->type == ECPGt_union)
 			{
@@ -543,10 +547,11 @@
 		this->type->type_sizeof = ECPGstruct_sizeof;
 		this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ?
 		ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL;
 
 		if (type_enum != ECPGt_varchar &&
+			type_enum != ECPGt_nvarchar &&
 			type_enum != ECPGt_char &&
 			type_enum != ECPGt_unsigned_char &&
 			type_enum != ECPGt_string &&
 			atoi(this->type->type_index) >= 0)
 			mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported");
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/preproc/ecpg.tokens ./src/interfaces/ecpg/preproc/ecpg.tokens
--- ../orig.HEAD/src/interfaces/ecpg/preproc/ecpg.tokens	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/preproc/ecpg.tokens	2013-08-20 05:07:52.000000000 -0400
@@ -14,14 +14,16 @@
                 SQL_RETURNED_LENGTH SQL_RETURNED_OCTET_LENGTH SQL_SCALE
                 SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL SQL_SQLERROR
                 SQL_SQLPRINT SQL_SQLWARNING SQL_START SQL_STOP
                 SQL_STRUCT SQL_UNSIGNED SQL_VAR SQL_WHENEVER
 
+
 /* C tokens */
 %token  S_ADD S_AND S_ANYTHING S_AUTO S_CONST S_DEC S_DIV
                 S_DOTPOINT S_EQUAL S_EXTERN S_INC S_LSHIFT S_MEMPOINT
                 S_MEMBER S_MOD S_MUL S_NEQUAL S_OR S_REGISTER S_RSHIFT
                 S_STATIC S_SUB S_VOLATILE
                 S_TYPEDEF
 
 %token CSTRING CVARIABLE CPP_LINE IP
 %token DOLCONST ECONST NCONST UCONST UIDENT
+
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/preproc/ecpg.trailer ./src/interfaces/ecpg/preproc/ecpg.trailer
--- ../orig.HEAD/src/interfaces/ecpg/preproc/ecpg.trailer	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/preproc/ecpg.trailer	2013-08-20 05:07:32.000000000 -0400
@@ -184,11 +184,11 @@
 			/* if array see what's inside */
 			if (type == ECPGt_array)
 				type = argsinsert->variable->type->u.element->type;
 
 			/* handle varchars */
-			if (type == ECPGt_varchar)
+			if (type == ECPGt_varchar || type == ECPGt_nvarchar)
 				$$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr"));
 			else
 				$$ = mm_strdup(argsinsert->variable->name);
 		}
 		;
@@ -209,15 +209,17 @@
 					type = p->type->u.element->type;
 
 				switch (type)
 				{
 					case ECPGt_char:
+					case ECPGt_nchar:
 					case ECPGt_unsigned_char:
 					case ECPGt_string:
 						$$ = $1;
 						break;
 					case ECPGt_varchar:
+					case ECPGt_nvarchar:
 						$$ = make2_str($1, mm_strdup(".arr"));
 						break;
 					default:
 						mmerror(PARSE_ERROR, ET_ERROR, "invalid data type");
 						$$ = $1;
@@ -548,10 +550,26 @@
 				$$.type_str = EMPTY; /*mm_strdup("varchar");*/
 				$$.type_dimension = mm_strdup("-1");
 				$$.type_index = mm_strdup("-1");
 				$$.type_sizeof = NULL;
 			}
+			else if (strcmp($1, "nvarchar") == 0)
+            {
+                $$.type_enum = ECPGt_nvarchar;
+                $$.type_str = EMPTY; /*mm_strdup("nvarchar");*/
+                $$.type_dimension = mm_strdup("-1");
+                $$.type_index = mm_strdup("-1");
+                $$.type_sizeof = NULL;
+            }
+            else if (strcmp($1, "nchar") == 0)
+            {
+                $$.type_enum = ECPGt_nchar;
+                $$.type_str = EMPTY; /*mm_strdup("nchar");*/
+                $$.type_dimension = mm_strdup("-1");
+                $$.type_index = mm_strdup("-1");
+                $$.type_sizeof = NULL;
+            }
 			else if (strcmp($1, "float") == 0)
 			{
 				$$.type_enum = ECPGt_float;
 				$$.type_str = mm_strdup("float");
 				$$.type_dimension = mm_strdup("-1");
@@ -625,11 +643,11 @@
 			else
 			{
 				/* this is for typedef'ed types */
 				struct typedefs *this = get_typedef($1);
 
-				$$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : mm_strdup(this->name);
+				$$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_nvarchar) ? EMPTY : mm_strdup(this->name);
 				$$.type_enum = this->type->type_enum;
 				$$.type_dimension = this->type->type_dimension;
 				$$.type_index = this->type->type_index;
 				if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0)
 					$$.type_sizeof = this->type->type_sizeof;
@@ -860,10 +878,11 @@
 						type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof), dimension);
 
 					$$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
 					break;
 
+				case ECPGt_nvarchar:
 				case ECPGt_varchar:
 					if (atoi(dimension) < 0)
 						type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, varchar_counter);
 					else
 						type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, varchar_counter), dimension);
@@ -884,10 +903,29 @@
 					else
 						$$ = cat_str(8, make2_str(mm_strdup(" struct varchar_"), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } "), mm_strdup($2), dim_str, $4, $5);
 					varchar_counter++;
 					break;
 
+				case ECPGt_nchar:
+                                        if (atoi(dimension) == -1)
+                                        {
+                                                int i = strlen($5);
+
+                                                if (atoi(length) == -1 && i > 0) /* char <var>[] = "string" */
+                                                {
+                                                        /* if we have an initializer but no string size set, let's use the initializer's length */
+                                                        free(length);
+                                                        length = mm_alloc(i+sizeof("sizeof()"));
+                                                        sprintf(length, "sizeof(%s)", $5+2);
+                                                }
+                                                type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0);
+                                        }
+                                        else
+                                                type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension);
+
+                                        $$ = cat_str(6, mm_strdup("char"), $1, mm_strdup($2), $3.str, $4, $5);
+                                        break;
 				case ECPGt_char:
 				case ECPGt_unsigned_char:
 				case ECPGt_string:
 					if (atoi(dimension) == -1)
 					{
@@ -1346,18 +1384,20 @@
 							type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str, $5.type_sizeof);
 						else
 							type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str, $5.type_sizeof), dimension);
 						break;
 
+					case ECPGt_nvarchar:
 					case ECPGt_varchar:
 						if (atoi(dimension) == -1)
 							type = ECPGmake_simple_type($5.type_enum, length, 0);
 						else
 							type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension);
 						break;
 
 					case ECPGt_char:
+					case ECPGt_nchar:
 					case ECPGt_unsigned_char:
 					case ECPGt_string:
 						if (atoi(dimension) == -1)
 							type = ECPGmake_simple_type($5.type_enum, length, 0);
 						else
@@ -1842,10 +1882,12 @@
 		| CHAR_P			{ $$ = mm_strdup("char"); }
 		| FLOAT_P			{ $$ = mm_strdup("float"); }
 		| TO				{ $$ = mm_strdup("to"); }
 		| UNION				{ $$ = mm_strdup("union"); }
 		| VARCHAR			{ $$ = mm_strdup("varchar"); }
+		| NVARCHAR			{ $$ = mm_strdup("nvarchar"); }
+		| NCHAR				{ $$ = mm_strdup("nchar"); }
 		| '['				{ $$ = mm_strdup("["); }
 		| ']'				{ $$ = mm_strdup("]"); }
 		| '='				{ $$ = mm_strdup("="); }
 		| ':'				{ $$ = mm_strdup(":"); }
 		;
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/preproc/type.c ./src/interfaces/ecpg/preproc/type.c
--- ../orig.HEAD/src/interfaces/ecpg/preproc/type.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/preproc/type.c	2013-08-20 05:08:51.000000000 -0400
@@ -135,10 +135,13 @@
 	switch (type)
 	{
 		case ECPGt_char:
 			return ("ECPGt_char");
 			break;
+		case ECPGt_nchar:
+			return ("ECPGt_nchar");
+			break;
 		case ECPGt_unsigned_char:
 			return ("ECPGt_unsigned_char");
 			break;
 		case ECPGt_short:
 			return ("ECPGt_short");
@@ -173,10 +176,14 @@
 		case ECPGt_bool:
 			return ("ECPGt_bool");
 			break;
 		case ECPGt_varchar:
 			return ("ECPGt_varchar");
+			break;
+		case ECPGt_nvarchar:
+			return ("ECPGt_nvarchar");
+			break;
 		case ECPGt_NO_INDICATOR:		/* no indicator */
 			return ("ECPGt_NO_INDICATOR");
 			break;
 		case ECPGt_char_variable:		/* string that should not be quoted */
 			return ("ECPGt_char_variable");
@@ -381,12 +388,12 @@
 				/*
 				 * we have to use the & operator except for arrays and
 				 * pointers
 				 */
 
+			case ECPGt_nvarchar:
 			case ECPGt_varchar:
-
 				/*
 				 * we have to use the pointer except for arrays with given
 				 * bounds
 				 */
 				if (((atoi(arrsize) > 0) ||
@@ -404,10 +411,11 @@
 					sprintf(offset, "sizeof(struct varchar_%d)", counter);
 				else
 					sprintf(offset, "sizeof(struct varchar)");
 				break;
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_char_variable:
 			case ECPGt_string:
 
 				/*
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/preproc/variable.c ./src/interfaces/ecpg/preproc/variable.c
--- ../orig.HEAD/src/interfaces/ecpg/preproc/variable.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/preproc/variable.c	2013-08-20 05:04:08.000000000 -0400
@@ -527,11 +527,11 @@
 	if (pointer_len > 2)
 		mmerror(PARSE_ERROR, ET_FATAL, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
 												"multilevel pointers (more than 2 levels) are not supported; found %d levels", pointer_len),
 				pointer_len);
 
-	if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
+	if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_nchar && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string)
 		mmerror(PARSE_ERROR, ET_FATAL, "pointer to pointer is not supported for this data type");
 
 	if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
 		mmerror(PARSE_ERROR, ET_FATAL, "multidimensional arrays are not supported");
 
@@ -552,10 +552,11 @@
 			if (atoi(*length) >= 0)
 				mmerror(PARSE_ERROR, ET_FATAL, "multidimensional arrays for structures are not supported");
 
 			break;
 		case ECPGt_varchar:
+		case ECPGt_nvarchar:
 			/* pointer has to get dimension 0 */
 			if (pointer_len)
 				*dimension = mm_strdup("0");
 
 			/* one index is the string length */
@@ -565,10 +566,11 @@
 				*dimension = mm_strdup("-1");
 			}
 
 			break;
 		case ECPGt_char:
+                case ECPGt_nchar:
 		case ECPGt_unsigned_char:
 		case ECPGt_string:
 			/* char ** */
 			if (pointer_len == 2)
 			{
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c ./src/interfaces/ecpg/test/expected/compat_informix-sqlda.c
--- ../orig.HEAD/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/test/expected/compat_informix-sqlda.c	2013-08-19 20:54:00.000000000 -0400
@@ -95,10 +95,11 @@
 #define	SQLTEXT		ECPGt_char
 #define	SQLVCHAR	ECPGt_char
 #define SQLINTERVAL     ECPGt_interval
 #define	SQLNCHAR	ECPGt_char
 #define	SQLNVCHAR	ECPGt_char
+#define SQLNVARCHAR     ECPGt_char
 #ifdef HAVE_LONG_LONG_INT_64
 #define	SQLINT8		ECPGt_long_long
 #define	SQLSERIAL8	ECPGt_long_long
 #else
 #define	SQLINT8		ECPGt_long
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/test/expected/preproc-type.c ./src/interfaces/ecpg/test/expected/preproc-type.c
--- ../orig.HEAD/src/interfaces/ecpg/test/expected/preproc-type.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/test/expected/preproc-type.c	2013-08-19 20:54:00.000000000 -0400
@@ -81,10 +81,21 @@
   
   	 
 	 
    
   
+  
+         
+         
+   
+   
+  
+         
+         
+   
+
+  
 #line 29 "type.pgc"
  struct TBempl empl ;
  
 #line 30 "type.pgc"
  string str ;
@@ -98,48 +109,72 @@
  int len ;
  
 #line 35 "type.pgc"
  char text [ 10 ] ;
  } vc ;
+ 
+#line 41 "type.pgc"
+ struct nvarchar { 
+#line 39 "type.pgc"
+ int len ;
+ 
+#line 40 "type.pgc"
+ char text [ 10 ] ;
+ } nvc ;
+ 
+#line 46 "type.pgc"
+ struct uvarchar { 
+#line 44 "type.pgc"
+ int len ;
+ 
+#line 45 "type.pgc"
+ char text [ 20 ] ;
+ } uvc ;
 /* exec sql end declare section */
-#line 37 "type.pgc"
+#line 48 "type.pgc"
 
 
   /* exec sql var vc is [ 10 ] */
-#line 39 "type.pgc"
+#line 50 "type.pgc"
+
+  /* exec sql var nvc is [ 10 ] */
+#line 51 "type.pgc"
+
+  /* exec sql var uvc is [ 20 ] */
+#line 52 "type.pgc"
 
   ECPGdebug (1, stderr);
 
   empl.idnum = 1;
   { ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0); }
-#line 43 "type.pgc"
+#line 56 "type.pgc"
 
   if (sqlca.sqlcode)
     {
       printf ("connect error = %ld\n", sqlca.sqlcode);
       exit (sqlca.sqlcode);
     }
 
-  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT);}
-#line 51 "type.pgc"
+  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) , string4 char ( 10 ) , string5 char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT);}
+#line 64 "type.pgc"
 
   if (sqlca.sqlcode)
     {
       printf ("create error = %ld\n", sqlca.sqlcode);
       exit (sqlca.sqlcode);
     }
 
-  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into empl values ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' )", ECPGt_EOIT, ECPGt_EORT);}
-#line 58 "type.pgc"
+  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into empl values ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' , 'fourth str' , 'fifth str' )", ECPGt_EOIT, ECPGt_EORT);}
+#line 71 "type.pgc"
 
   if (sqlca.sqlcode)
     {
       printf ("insert error = %ld\n", sqlca.sqlcode);
       exit (sqlca.sqlcode);
     }
 
-  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select idnum , name , accs , string1 , string2 , string3 from empl where idnum = $1 ", 
+  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select idnum , name , accs , string1 , string2 , string3 , string4 , string5 from empl where idnum = $1 ", 
 	ECPGt_long,&(empl.idnum),(long)1,(long)1,sizeof(long), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
 	ECPGt_long,&(empl.idnum),(long)1,(long)1,sizeof(long), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
 	ECPGt_char,&(empl.name),(long)21,(long)1,(21)*sizeof(char), 
@@ -149,22 +184,27 @@
 	ECPGt_char,(str),(long)11,(long)1,(11)*sizeof(char), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
 	ECPGt_char,&(ptr),(long)0,(long)1,(1)*sizeof(char), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
 	ECPGt_varchar,&(vc),(long)10,(long)1,sizeof(struct varchar), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_nvarchar,&(nvc),(long)10,(long)1,sizeof(struct varchar), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_uvarchar,&(uvc),(long)20,(long)1,sizeof(struct varchar), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
-#line 68 "type.pgc"
+#line 81 "type.pgc"
 
   if (sqlca.sqlcode)
     {
       printf ("select error = %ld\n", sqlca.sqlcode);
       exit (sqlca.sqlcode);
     }
-  printf ("id=%ld name='%s' accs=%d str='%s' ptr='%s' vc='%10.10s'\n", empl.idnum, empl.name, empl.accs, str, ptr, vc.text);
+  printf ("id=%ld name='%s' accs=%d str='%s' ptr='%s' vc='%10.10s' vc.len='%d' nvc='%10.10s' nvc.len='%d' uvc='%20.20s' uvc.len='%d'\n", empl.idnum, empl.name, empl.accs, str, ptr, vc.text, vc.len, nvc.text, nvc.len, uvc.text, uvc.len);
 
   { ECPGdisconnect(__LINE__, "CURRENT");}
-#line 76 "type.pgc"
+#line 89 "type.pgc"
 
 
   free(ptr);
   exit (0);
 }
+
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/test/expected/preproc-type.stderr ./src/interfaces/ecpg/test/expected/preproc-type.stderr
--- ../orig.HEAD/src/interfaces/ecpg/test/expected/preproc-type.stderr	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/test/expected/preproc-type.stderr	2013-08-19 20:54:00.000000000 -0400
@@ -1,40 +1,44 @@
 [NO_PID]: ECPGdebug: set to 1
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>  
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 50: query: create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) ); with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 63: query: create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) , string4 char ( 10 ) , string5 char ( 10 ) ); with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 50: using PQexec
+[NO_PID]: ecpg_execute on line 63: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 50: OK: CREATE TABLE
+[NO_PID]: ecpg_execute on line 63: OK: CREATE TABLE
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 58: query: insert into empl values ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' ); with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 71: query: insert into empl values ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' , 'fourth str' , 'fifth str' ); with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 58: using PQexec
+[NO_PID]: ecpg_execute on line 71: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 58: OK: INSERT 0 1
+[NO_PID]: ecpg_execute on line 71: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 65: query: select idnum , name , accs , string1 , string2 , string3 from empl where idnum = $1 ; with 1 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 78: query: select idnum , name , accs , string1 , string2 , string3 , string4 , string5 from empl where idnum = $1 ; with 1 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 65: using PQexecParams
+[NO_PID]: ecpg_execute on line 78: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: free_params on line 65: parameter 1 = 1
+[NO_PID]: free_params on line 78: parameter 1 = 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 65: correctly got 1 tuples with 6 fields
+[NO_PID]: ecpg_execute on line 78: correctly got 1 tuples with 8 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 65: RESULT: 1 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 78: RESULT: 1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 65: RESULT: user name            offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 78: RESULT: user name            offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 65: RESULT: 320 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 78: RESULT: 320 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 65: RESULT: first str  offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 78: RESULT: first str  offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_store_result on line 65: allocating memory for 1 tuples
+[NO_PID]: ecpg_store_result on line 78: allocating memory for 1 tuples
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 65: RESULT: second str offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 78: RESULT: second str offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 65: RESULT: third str  offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 78: RESULT: third str  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 78: RESULT: fourth str offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 78: RESULT: fifth str  offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_finish: connection regress1 closed
 [NO_PID]: sqlca: code: 0, state: 00000
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/test/expected/preproc-type.stdout ./src/interfaces/ecpg/test/expected/preproc-type.stdout
--- ../orig.HEAD/src/interfaces/ecpg/test/expected/preproc-type.stdout	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/test/expected/preproc-type.stdout	2013-08-19 20:54:00.000000000 -0400
@@ -1 +1 @@
-id=1 name='user name           ' accs=320 str='first str ' ptr='second str' vc='third str '
+id=1 name='user name           ' accs=320 str='first str ' ptr='second str' vc='third str ' vc.len='10' nvc='fourth str' nvc.len='10' uvc='                   f' uvc.len='20'
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/test/expected/sql-fetch.c ./src/interfaces/ecpg/test/expected/sql-fetch.c
--- ../orig.HEAD/src/interfaces/ecpg/test/expected/sql-fetch.c	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/test/expected/sql-fetch.c	2013-08-19 20:54:00.000000000 -0400
@@ -25,210 +25,250 @@
 int main() {
   /* exec sql begin declare section */
      
       
   
+      
+     
+     
+  
 #line 9 "fetch.pgc"
  char str [ 25 ] ;
  
 #line 10 "fetch.pgc"
  int i , count = 1 ;
-/* exec sql end declare section */
+ 
 #line 11 "fetch.pgc"
+ char nstr [ 25 ] ;
+ 
+#line 12 "fetch.pgc"
+  struct varchar_1  { int len; char arr[ 25 ]; }  _varchar ;
+ 
+#line 13 "fetch.pgc"
+  struct varchar_2  { int len; char arr[ 25 ]; }  _nvarchar ;
+ 
+#line 14 "fetch.pgc"
+  struct varchar_3  { int len; char arr[ 25 ]; }  _uvarchar ;
+/* exec sql end declare section */
+#line 15 "fetch.pgc"
 
 
   ECPGdebug(1, stderr);
   { ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0); }
-#line 14 "fetch.pgc"
+#line 18 "fetch.pgc"
 
 
   /* exec sql whenever sql_warning  sqlprint ; */
-#line 16 "fetch.pgc"
+#line 20 "fetch.pgc"
 
   /* exec sql whenever sqlerror  sqlprint ; */
-#line 17 "fetch.pgc"
+#line 21 "fetch.pgc"
 
 
-  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table My_Table ( Item1 int , Item2 text )", ECPGt_EOIT, ECPGt_EORT);
-#line 19 "fetch.pgc"
+  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table My_Table ( Item1 int , Item2 text , Item3 text , Item4 varchar , Item5 varchar , Item6 varchar )", ECPGt_EOIT, ECPGt_EORT);
+#line 23 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 19 "fetch.pgc"
+#line 23 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 19 "fetch.pgc"
+#line 23 "fetch.pgc"
 
 
-  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 1 , 'text1' )", ECPGt_EOIT, ECPGt_EORT);
-#line 21 "fetch.pgc"
+  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 1 , 'text1' , 'text1' , 'text1' , 'text1' , 'text1' )", ECPGt_EOIT, ECPGt_EORT);
+#line 25 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 21 "fetch.pgc"
+#line 25 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 21 "fetch.pgc"
+#line 25 "fetch.pgc"
 
-  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 2 , 'text2' )", ECPGt_EOIT, ECPGt_EORT);
-#line 22 "fetch.pgc"
+  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 2 , 'text2' , 'text2' , 'text2' , 'text2' , 'text2' )", ECPGt_EOIT, ECPGt_EORT);
+#line 26 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 22 "fetch.pgc"
+#line 26 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 22 "fetch.pgc"
+#line 26 "fetch.pgc"
 
-  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 3 , 'text3' )", ECPGt_EOIT, ECPGt_EORT);
-#line 23 "fetch.pgc"
+  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 3 , 'text3' , 'text3' , 'text3' , 'text3' , 'text3' )", ECPGt_EOIT, ECPGt_EORT);
+#line 27 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 23 "fetch.pgc"
+#line 27 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 23 "fetch.pgc"
+#line 27 "fetch.pgc"
 
-  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 4 , 'text4' )", ECPGt_EOIT, ECPGt_EORT);
-#line 24 "fetch.pgc"
+  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 4 , 'text4' , 'text4' , 'text4' , 'text4' , 'text4' )", ECPGt_EOIT, ECPGt_EORT);
+#line 28 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 24 "fetch.pgc"
+#line 28 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 24 "fetch.pgc"
+#line 28 "fetch.pgc"
 
 
   /* declare C cursor for select * from My_Table */
-#line 26 "fetch.pgc"
+#line 30 "fetch.pgc"
 
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare C cursor for select * from My_Table", ECPGt_EOIT, ECPGt_EORT);
-#line 28 "fetch.pgc"
+#line 32 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 28 "fetch.pgc"
+#line 32 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 28 "fetch.pgc"
+#line 32 "fetch.pgc"
 
 
   /* exec sql whenever not found  break ; */
-#line 30 "fetch.pgc"
+#line 34 "fetch.pgc"
 
   while (1) {
   	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch 1 in C", ECPGt_EOIT, 
 	ECPGt_int,&(i),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
 	ECPGt_char,(str),(long)25,(long)1,(25)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_nchar,(nstr),(long)25,(long)1,(25)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_varchar,&(_varchar),(long)25,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_nvarchar,&(_nvarchar),(long)25,(long)1,sizeof(struct varchar_2), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_uvarchar,&(_uvarchar),(long)25,(long)1,sizeof(struct varchar_3), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
-#line 32 "fetch.pgc"
+#line 36 "fetch.pgc"
 
 if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
-#line 32 "fetch.pgc"
+#line 36 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 32 "fetch.pgc"
+#line 36 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 32 "fetch.pgc"
+#line 36 "fetch.pgc"
 
-	printf("%d: %s\n", i, str);
+	printf("%d: %s, %s, %s, %s\n", i, str, nstr, _varchar.arr, _nvarchar.arr);
   }
 
   /* exec sql whenever not found  continue ; */
-#line 36 "fetch.pgc"
+#line 40 "fetch.pgc"
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "move backward 2 in C", ECPGt_EOIT, ECPGt_EORT);
-#line 37 "fetch.pgc"
+#line 41 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 37 "fetch.pgc"
+#line 41 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 37 "fetch.pgc"
+#line 41 "fetch.pgc"
 
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch $0 in C", 
 	ECPGt_int,&(count),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
 	ECPGt_int,&(i),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
 	ECPGt_char,(str),(long)25,(long)1,(25)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_nchar,(nstr),(long)25,(long)1,(25)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_varchar,&(_varchar),(long)25,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_nvarchar,&(_nvarchar),(long)25,(long)1,sizeof(struct varchar_2), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_uvarchar,&(_uvarchar),(long)25,(long)1,sizeof(struct varchar_3), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
-#line 39 "fetch.pgc"
+#line 43 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 39 "fetch.pgc"
+#line 43 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 39 "fetch.pgc"
+#line 43 "fetch.pgc"
 
-  printf("%d: %s\n", i, str);
+  printf("%d: %s, %s, %s, %s\n", i, str, nstr, _varchar.arr, _nvarchar.arr);
 
   /* declare D cursor for select * from My_Table where Item1 = $1 */
-#line 42 "fetch.pgc"
+#line 46 "fetch.pgc"
 
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare D cursor for select * from My_Table where Item1 = $1", 
 	ECPGt_const,"1",(long)1,(long)1,strlen("1"), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
-#line 44 "fetch.pgc"
+#line 48 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 44 "fetch.pgc"
+#line 48 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 44 "fetch.pgc"
+#line 48 "fetch.pgc"
 
 
   /* exec sql whenever not found  break ; */
-#line 46 "fetch.pgc"
+#line 50 "fetch.pgc"
 
   while (1) {
   	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch 1 in D", ECPGt_EOIT, 
 	ECPGt_int,&(i),(long)1,(long)1,sizeof(int), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
 	ECPGt_char,(str),(long)25,(long)1,(25)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_nchar,(nstr),(long)25,(long)1,(25)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_varchar,&(_varchar),(long)25,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_nvarchar,&(_nvarchar),(long)25,(long)1,sizeof(struct varchar_2), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_uvarchar,&(_uvarchar),(long)25,(long)1,sizeof(struct varchar_3), 
 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
-#line 48 "fetch.pgc"
+#line 52 "fetch.pgc"
 
 if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
-#line 48 "fetch.pgc"
+#line 52 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 48 "fetch.pgc"
+#line 52 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 48 "fetch.pgc"
+#line 52 "fetch.pgc"
 
-	printf("%d: %s\n", i, str);
+	printf("%d: %s, %s, %s, %s\n", i, str, nstr, _varchar.arr, _nvarchar.arr);
   }
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "close D", ECPGt_EOIT, ECPGt_EORT);
-#line 51 "fetch.pgc"
+#line 55 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 51 "fetch.pgc"
+#line 55 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 51 "fetch.pgc"
+#line 55 "fetch.pgc"
 
 
   { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table My_Table", ECPGt_EOIT, ECPGt_EORT);
-#line 53 "fetch.pgc"
+#line 57 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 53 "fetch.pgc"
+#line 57 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 53 "fetch.pgc"
+#line 57 "fetch.pgc"
 
 
   { ECPGdisconnect(__LINE__, "ALL");
-#line 55 "fetch.pgc"
+#line 59 "fetch.pgc"
 
 if (sqlca.sqlwarn[0] == 'W') sqlprint();
-#line 55 "fetch.pgc"
+#line 59 "fetch.pgc"
 
 if (sqlca.sqlcode < 0) sqlprint();}
-#line 55 "fetch.pgc"
+#line 59 "fetch.pgc"
 
 
   return 0;
 }
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/test/expected/sql-fetch.stderr ./src/interfaces/ecpg/test/expected/sql-fetch.stderr
--- ../orig.HEAD/src/interfaces/ecpg/test/expected/sql-fetch.stderr	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/test/expected/sql-fetch.stderr	2013-08-19 20:54:00.000000000 -0400
@@ -1,147 +1,195 @@
 [NO_PID]: ECPGdebug: set to 1
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>  
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 19: query: create table My_Table ( Item1 int , Item2 text ); with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 23: query: create table My_Table ( Item1 int , Item2 text , Item3 text , Item4 varchar , Item5 varchar , Item6 varchar ); with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 19: using PQexec
+[NO_PID]: ecpg_execute on line 23: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 19: OK: CREATE TABLE
+[NO_PID]: ecpg_execute on line 23: OK: CREATE TABLE
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 21: query: insert into My_Table values ( 1 , 'text1' ); with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 25: query: insert into My_Table values ( 1 , 'text1' , 'text1' , 'text1' , 'text1' , 'text1' ); with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 21: using PQexec
+[NO_PID]: ecpg_execute on line 25: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 21: OK: INSERT 0 1
+[NO_PID]: ecpg_execute on line 25: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 22: query: insert into My_Table values ( 2 , 'text2' ); with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 26: query: insert into My_Table values ( 2 , 'text2' , 'text2' , 'text2' , 'text2' , 'text2' ); with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 22: using PQexec
+[NO_PID]: ecpg_execute on line 26: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 22: OK: INSERT 0 1
+[NO_PID]: ecpg_execute on line 26: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 23: query: insert into My_Table values ( 3 , 'text3' ); with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 27: query: insert into My_Table values ( 3 , 'text3' , 'text3' , 'text3' , 'text3' , 'text3' ); with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 23: using PQexec
+[NO_PID]: ecpg_execute on line 27: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 23: OK: INSERT 0 1
+[NO_PID]: ecpg_execute on line 27: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 24: query: insert into My_Table values ( 4 , 'text4' ); with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 28: query: insert into My_Table values ( 4 , 'text4' , 'text4' , 'text4' , 'text4' , 'text4' ); with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 24: using PQexec
+[NO_PID]: ecpg_execute on line 28: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 24: OK: INSERT 0 1
+[NO_PID]: ecpg_execute on line 28: OK: INSERT 0 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 28: query: declare C cursor for select * from My_Table; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 32: query: declare C cursor for select * from My_Table; with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 28: using PQexec
+[NO_PID]: ecpg_execute on line 32: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 28: OK: DECLARE CURSOR
+[NO_PID]: ecpg_execute on line 32: OK: DECLARE CURSOR
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 36: query: fetch 1 in C; with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: using PQexec
+[NO_PID]: ecpg_execute on line 36: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: correctly got 1 tuples with 2 fields
+[NO_PID]: ecpg_execute on line 36: correctly got 1 tuples with 6 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 32: RESULT: 1 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 36: RESULT: 1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 32: RESULT: text1 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 36: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_get_data on line 36: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: using PQexec
+[NO_PID]: ecpg_get_data on line 36: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: correctly got 1 tuples with 2 fields
+[NO_PID]: ecpg_get_data on line 36: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 32: RESULT: 2 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 36: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 32: RESULT: text2 offset: -1; array: no
+[NO_PID]: ecpg_execute on line 36: query: fetch 1 in C; with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 36: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: using PQexec
+[NO_PID]: ecpg_execute on line 36: correctly got 1 tuples with 6 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: correctly got 1 tuples with 2 fields
+[NO_PID]: ecpg_get_data on line 36: RESULT: 2 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 32: RESULT: 3 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 36: RESULT: text2 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 32: RESULT: text3 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 36: RESULT: text2 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_get_data on line 36: RESULT: text2 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: using PQexec
+[NO_PID]: ecpg_get_data on line 36: RESULT: text2 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: correctly got 1 tuples with 2 fields
+[NO_PID]: ecpg_get_data on line 36: RESULT: text2 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 32: RESULT: 4 offset: -1; array: no
+[NO_PID]: ecpg_execute on line 36: query: fetch 1 in C; with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 32: RESULT: text4 offset: -1; array: no
+[NO_PID]: ecpg_execute on line 36: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 36: correctly got 1 tuples with 6 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: using PQexec
+[NO_PID]: ecpg_get_data on line 36: RESULT: 3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 36: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 36: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 32: correctly got 0 tuples with 2 fields
+[NO_PID]: ecpg_execute on line 36: correctly got 1 tuples with 6 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: raising sqlcode 100 on line 32: no data found on line 32
+[NO_PID]: ecpg_get_data on line 36: RESULT: 4 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text4 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text4 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text4 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text4 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 36: RESULT: text4 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 36: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 36: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 36: correctly got 0 tuples with 6 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode 100 on line 36: no data found on line 36
 [NO_PID]: sqlca: code: 100, state: 02000
-[NO_PID]: ecpg_execute on line 37: query: move backward 2 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 41: query: move backward 2 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: OK: MOVE 2
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 43: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 43: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 43: correctly got 1 tuples with 6 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 43: RESULT: 4 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 43: RESULT: text4 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 43: RESULT: text4 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 37: using PQexec
+[NO_PID]: ecpg_get_data on line 43: RESULT: text4 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 37: OK: MOVE 2
+[NO_PID]: ecpg_get_data on line 43: RESULT: text4 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 39: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_get_data on line 43: RESULT: text4 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 39: using PQexec
+[NO_PID]: ecpg_execute on line 48: query: declare D cursor for select * from My_Table where Item1 = $1; with 1 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 39: correctly got 1 tuples with 2 fields
+[NO_PID]: ecpg_execute on line 48: using PQexecParams
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 39: RESULT: 4 offset: -1; array: no
+[NO_PID]: free_params on line 48: parameter 1 = 1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 39: RESULT: text4 offset: -1; array: no
+[NO_PID]: ecpg_execute on line 48: OK: DECLARE CURSOR
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 44: query: declare D cursor for select * from My_Table where Item1 = $1; with 1 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 52: query: fetch 1 in D; with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 44: using PQexecParams
+[NO_PID]: ecpg_execute on line 52: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: free_params on line 44: parameter 1 = 1
+[NO_PID]: ecpg_execute on line 52: correctly got 1 tuples with 6 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 44: OK: DECLARE CURSOR
+[NO_PID]: ecpg_get_data on line 52: RESULT: 1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 48: query: fetch 1 in D; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_get_data on line 52: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 48: using PQexec
+[NO_PID]: ecpg_get_data on line 52: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 48: correctly got 1 tuples with 2 fields
+[NO_PID]: ecpg_get_data on line 52: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 48: RESULT: 1 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 52: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_get_data on line 48: RESULT: text1 offset: -1; array: no
+[NO_PID]: ecpg_get_data on line 52: RESULT: text1 offset: -1; array: no
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 48: query: fetch 1 in D; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 52: query: fetch 1 in D; with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 48: using PQexec
+[NO_PID]: ecpg_execute on line 52: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 48: correctly got 0 tuples with 2 fields
+[NO_PID]: ecpg_execute on line 52: correctly got 0 tuples with 6 fields
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: raising sqlcode 100 on line 48: no data found on line 48
+[NO_PID]: raising sqlcode 100 on line 52: no data found on line 52
 [NO_PID]: sqlca: code: 100, state: 02000
-[NO_PID]: ecpg_execute on line 51: query: close D; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 55: query: close D; with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 51: using PQexec
+[NO_PID]: ecpg_execute on line 55: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 51: OK: CLOSE CURSOR
+[NO_PID]: ecpg_execute on line 55: OK: CLOSE CURSOR
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 53: query: drop table My_Table; with 0 parameter(s) on connection regress1
+[NO_PID]: ecpg_execute on line 57: query: drop table My_Table; with 0 parameter(s) on connection regress1
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 53: using PQexec
+[NO_PID]: ecpg_execute on line 57: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_check_PQresult on line 53: bad response - ERROR:  cannot DROP TABLE "my_table" because it is being used by active queries in this session
+[NO_PID]: ecpg_check_PQresult on line 57: bad response - ERROR:  cannot DROP TABLE "my_table" because it is being used by active queries in this session
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: raising sqlstate 55006 (sqlcode -400): cannot DROP TABLE "my_table" because it is being used by active queries in this session on line 53
+[NO_PID]: raising sqlstate 55006 (sqlcode -400): cannot DROP TABLE "my_table" because it is being used by active queries in this session on line 57
 [NO_PID]: sqlca: code: -400, state: 55006
-SQL error: cannot DROP TABLE "my_table" because it is being used by active queries in this session on line 53
+SQL error: cannot DROP TABLE "my_table" because it is being used by active queries in this session on line 57
 [NO_PID]: ecpg_finish: connection regress1 closed
 [NO_PID]: sqlca: code: 0, state: 00000
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/test/expected/sql-fetch.stdout ./src/interfaces/ecpg/test/expected/sql-fetch.stdout
--- ../orig.HEAD/src/interfaces/ecpg/test/expected/sql-fetch.stdout	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/test/expected/sql-fetch.stdout	2013-08-19 20:54:00.000000000 -0400
@@ -1,6 +1,6 @@
-1: text1
-2: text2
-3: text3
-4: text4
-4: text4
-1: text1
+1: text1, text1, text1, text1
+2: text2, text2, text2, text2
+3: text3, text3, text3, text3
+4: text4, text4, text4, text4
+4: text4, text4, text4, text4
+1: text1, text1, text1, text1
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/test/preproc/type.pgc ./src/interfaces/ecpg/test/preproc/type.pgc
--- ../orig.HEAD/src/interfaces/ecpg/test/preproc/type.pgc	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/test/preproc/type.pgc	2013-08-19 20:54:00.000000000 -0400
@@ -32,13 +32,26 @@
   struct varchar
   {
   	int len;
 	char text[10];
   } vc;
+  struct nvarchar
+  {
+        int len;
+        char text[10];
+  } nvc;
+  struct uvarchar
+  {
+        int len;
+        char text[20];
+  } uvc;
+
   EXEC SQL END DECLARE SECTION;
 
   EXEC SQL var vc is varchar[10];
+  EXEC SQL var nvc is nvarchar[10];
+  EXEC SQL var uvc is uvarchar[20];
   ECPGdebug (1, stderr);
 
   empl.idnum = 1;
   EXEC SQL connect to REGRESSDB1;
   if (sqlca.sqlcode)
@@ -46,35 +59,36 @@
       printf ("connect error = %ld\n", sqlca.sqlcode);
       exit (sqlca.sqlcode);
     }
 
   EXEC SQL create table empl
-    (idnum integer, name char(20), accs smallint, string1 char(10), string2 char(10), string3 char(10));
+    (idnum integer, name char(20), accs smallint, string1 char(10), string2 char(10), string3 char(10), string4 char(10), string5 char(10));
   if (sqlca.sqlcode)
     {
       printf ("create error = %ld\n", sqlca.sqlcode);
       exit (sqlca.sqlcode);
     }
 
-  EXEC SQL insert into empl values (1, 'user name', 320, 'first str', 'second str', 'third str');
+  EXEC SQL insert into empl values (1, 'user name', 320, 'first str', 'second str', 'third str', 'fourth str', 'fifth str');
   if (sqlca.sqlcode)
     {
       printf ("insert error = %ld\n", sqlca.sqlcode);
       exit (sqlca.sqlcode);
     }
 
-  EXEC SQL select idnum, name, accs, string1, string2, string3
-	into :empl, :str, :ptr, :vc
+  EXEC SQL select idnum, name, accs, string1, string2, string3, string4, string5 
+	into :empl, :str, :ptr, :vc, :nvc, :uvc
 	from empl
 	where idnum =:empl.idnum;
   if (sqlca.sqlcode)
     {
       printf ("select error = %ld\n", sqlca.sqlcode);
       exit (sqlca.sqlcode);
     }
-  printf ("id=%ld name='%s' accs=%d str='%s' ptr='%s' vc='%10.10s'\n", empl.idnum, empl.name, empl.accs, str, ptr, vc.text);
+  printf ("id=%ld name='%s' accs=%d str='%s' ptr='%s' vc='%10.10s' vc.len='%d' nvc='%10.10s' nvc.len='%d' uvc='%20.20s' uvc.len='%d'\n", empl.idnum, empl.name, empl.accs, str, ptr, vc.text, vc.len, nvc.text, nvc.len, uvc.text, uvc.len);
 
   EXEC SQL disconnect;
 
   free(ptr);
   exit (0);
 }
+
diff -U 5 -N -r -w ../orig.HEAD/src/interfaces/ecpg/test/sql/fetch.pgc ./src/interfaces/ecpg/test/sql/fetch.pgc
--- ../orig.HEAD/src/interfaces/ecpg/test/sql/fetch.pgc	2013-08-19 20:22:13.000000000 -0400
+++ ./src/interfaces/ecpg/test/sql/fetch.pgc	2013-08-19 20:54:00.000000000 -0400
@@ -6,49 +6,53 @@
 
 int main() {
   EXEC SQL BEGIN DECLARE SECTION;
     char str[25];
     int i, count=1;
+    NCHAR nstr[25];
+    VARCHAR  _varchar[25];
+    NVARCHAR _nvarchar[25];
+    UVARCHAR _uvarchar[25];
   EXEC SQL END DECLARE SECTION;
 
   ECPGdebug(1, stderr);
   EXEC SQL CONNECT TO REGRESSDB1;
 
   EXEC SQL WHENEVER SQLWARNING SQLPRINT;
   EXEC SQL WHENEVER SQLERROR SQLPRINT;
 
-  EXEC SQL CREATE TABLE My_Table ( Item1 int, Item2 text );
+  EXEC SQL CREATE TABLE My_Table ( Item1 int, Item2 text, Item3 text, Item4 varchar, Item5 varchar, Item6 varchar );
 
-  EXEC SQL INSERT INTO My_Table VALUES ( 1, 'text1');
-  EXEC SQL INSERT INTO My_Table VALUES ( 2, 'text2');
-  EXEC SQL INSERT INTO My_Table VALUES ( 3, 'text3');
-  EXEC SQL INSERT INTO My_Table VALUES ( 4, 'text4');
+  EXEC SQL INSERT INTO My_Table VALUES ( 1, 'text1', 'text1', 'text1', 'text1', 'text1');
+  EXEC SQL INSERT INTO My_Table VALUES ( 2, 'text2', 'text2', 'text2', 'text2', 'text2');
+  EXEC SQL INSERT INTO My_Table VALUES ( 3, 'text3', 'text3', 'text3', 'text3', 'text3');
+  EXEC SQL INSERT INTO My_Table VALUES ( 4, 'text4', 'text4', 'text4', 'text4', 'text4');
 
   EXEC SQL DECLARE C CURSOR FOR SELECT * FROM My_Table;
 
   EXEC SQL OPEN C;
 
   EXEC SQL WHENEVER NOT FOUND DO BREAK;
   while (1) {
-  	EXEC SQL FETCH 1 IN C INTO :i, :str;
-	printf("%d: %s\n", i, str);
+  	EXEC SQL FETCH 1 IN C INTO :i, :str, :nstr, :_varchar, :_nvarchar, :_uvarchar;
+	printf("%d: %s, %s, %s, %s\n", i, str, nstr, _varchar.arr, _nvarchar.arr);
   }
 
   EXEC SQL WHENEVER NOT FOUND CONTINUE;
   EXEC SQL MOVE BACKWARD 2 IN C;
 
-  EXEC SQL FETCH :count IN C INTO :i, :str;
-  printf("%d: %s\n", i, str);
+  EXEC SQL FETCH :count IN C INTO :i, :str, :nstr, :_varchar, :_nvarchar, :_uvarchar;
+  printf("%d: %s, %s, %s, %s\n", i, str, nstr, _varchar.arr, _nvarchar.arr);
 
   EXEC SQL DECLARE D CURSOR FOR SELECT * FROM My_Table WHERE Item1 = $1;
 
   EXEC SQL OPEN D using 1;
 
   EXEC SQL WHENEVER NOT FOUND DO BREAK;
   while (1) {
-  	EXEC SQL FETCH 1 IN D INTO :i, :str;
-	printf("%d: %s\n", i, str);
+  	EXEC SQL FETCH 1 IN D INTO :i, :str, :nstr, :_varchar, :_nvarchar, :_uvarchar;
+	printf("%d: %s, %s, %s, %s\n", i, str, nstr, _varchar.arr, _nvarchar.arr);
   }
   EXEC SQL CLOSE D;
 
   EXEC SQL DROP TABLE My_Table;
 
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/create_function_3.out ./src/test/regress/expected/create_function_3.out
--- ../orig.HEAD/src/test/regress/expected/create_function_3.out	2013-08-19 20:22:14.000000000 -0400
+++ ./src/test/regress/expected/create_function_3.out	2013-08-19 20:54:00.000000000 -0400
@@ -306,10 +306,12 @@
  namege         | boolean    | [0:1]={name,name}
  namegt         | boolean    | [0:1]={name,name}
  namele         | boolean    | [0:1]={name,name}
  namelt         | boolean    | [0:1]={name,name}
  namene         | boolean    | [0:1]={name,name}
+ nbpchareq      | boolean    | [0:1]={"national character","national character"}
+ nbpcharne      | boolean    | [0:1]={"national character","national character"}
  network_eq     | boolean    | [0:1]={inet,inet}
  network_ge     | boolean    | [0:1]={inet,inet}
  network_gt     | boolean    | [0:1]={inet,inet}
  network_le     | boolean    | [0:1]={inet,inet}
  network_lt     | boolean    | [0:1]={inet,inet}
@@ -381,11 +383,11 @@
  varbitgt       | boolean    | [0:1]={"bit varying","bit varying"}
  varbitle       | boolean    | [0:1]={"bit varying","bit varying"}
  varbitlt       | boolean    | [0:1]={"bit varying","bit varying"}
  varbitne       | boolean    | [0:1]={"bit varying","bit varying"}
  xideq          | boolean    | [0:1]={xid,xid}
-(228 rows)
+(230 rows)
 
 --
 -- CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
 --
 CREATE FUNCTION functext_F_1(int) RETURNS bool LANGUAGE 'sql'
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/nchar.out ./src/test/regress/expected/nchar.out
--- ../orig.HEAD/src/test/regress/expected/nchar.out	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/expected/nchar.out	2013-08-19 23:31:45.000000000 -0400
@@ -0,0 +1,122 @@
+--
+-- NCHAR
+--
+-- fixed-length by value
+-- internally passed by value if <= 4 bytes in storage
+SELECT nchar 'c' = nchar 'c' AS true;
+ true 
+------
+ t
+(1 row)
+
+--
+-- Build a table for testing
+--
+CREATE TABLE NCHAR_TBL(f1 nchar);
+INSERT INTO NCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NCHAR_TBL (f1) VALUES ('A');
+-- any of the following three input formats are acceptable
+INSERT INTO NCHAR_TBL (f1) VALUES ('1');
+INSERT INTO NCHAR_TBL (f1) VALUES (2);
+INSERT INTO NCHAR_TBL (f1) VALUES ('3');
+-- zero-length nchar
+INSERT INTO NCHAR_TBL (f1) VALUES ('');
+-- try nchar's of greater than 1 length
+INSERT INTO NCHAR_TBL (f1) VALUES ('cd');
+ERROR:  value too long for type character(1)
+INSERT INTO NCHAR_TBL (f1) VALUES ('c     ');
+SELECT '' AS seven, * FROM NCHAR_TBL;
+ seven | f1 
+-------+----
+       | a
+       | A
+       | 1
+       | 2
+       | 3
+       |  
+       | c
+(7 rows)
+
+SELECT '' AS six, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 <> 'a';
+ six | f1 
+-----+----
+     | A
+     | 1
+     | 2
+     | 3
+     |  
+     | c
+(6 rows)
+
+SELECT '' AS one, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 = 'a';
+ one | f1 
+-----+----
+     | a
+(1 row)
+
+SELECT '' AS five, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 < 'a';
+ five | f1 
+------+----
+      | A
+      | 1
+      | 2
+      | 3
+      |  
+(5 rows)
+
+SELECT '' AS six, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 <= 'a';
+ six | f1 
+-----+----
+     | a
+     | A
+     | 1
+     | 2
+     | 3
+     |  
+(6 rows)
+
+SELECT '' AS one, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 > 'a';
+ one | f1 
+-----+----
+     | c
+(1 row)
+
+SELECT '' AS two, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 >= 'a';
+ two | f1 
+-----+----
+     | a
+     | c
+(2 rows)
+
+DROP TABLE NCHAR_TBL;
+--
+-- Now test longer arrays of nchar
+--
+CREATE TABLE NCHAR_TBL(f1 nchar(4));
+INSERT INTO NCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NCHAR_TBL (f1) VALUES ('ab');
+INSERT INTO NCHAR_TBL (f1) VALUES ('abcd');
+INSERT INTO NCHAR_TBL (f1) VALUES ('abcde');
+ERROR:  value too long for type character(4)
+INSERT INTO NCHAR_TBL (f1) VALUES ('abcd    ');
+SELECT '' AS four, * FROM NCHAR_TBL;
+ four |  f1  
+------+------
+      | a   
+      | ab  
+      | abcd
+      | abcd
+(4 rows)
+
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/nvarchar_1.out ./src/test/regress/expected/nvarchar_1.out
--- ../orig.HEAD/src/test/regress/expected/nvarchar_1.out	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/expected/nvarchar_1.out	2013-08-19 23:31:50.000000000 -0400
@@ -0,0 +1,111 @@
+--
+-- NVARCHAR
+--
+CREATE TABLE NVARCHAR_TBL(f1 nvarchar(1));
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('A');
+-- any of the following three input formats are acceptable
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('1');
+INSERT INTO NVARCHAR_TBL (f1) VALUES (2);
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('3');
+-- zero-length nchar
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('');
+-- try nvarchar's of greater than 1 length
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('cd');
+ERROR:  value too long for type character varying(1)
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('c     ');
+SELECT '' AS seven, * FROM NVARCHAR_TBL;
+ seven | f1 
+-------+----
+       | a
+       | A
+       | 1
+       | 2
+       | 3
+       | 
+       | c
+(7 rows)
+
+SELECT '' AS six, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 <> 'a';
+ six | f1 
+-----+----
+     | A
+     | 1
+     | 2
+     | 3
+     | 
+     | c
+(6 rows)
+
+SELECT '' AS one, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 = 'a';
+ one | f1 
+-----+----
+     | a
+(1 row)
+
+SELECT '' AS five, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 < 'a';
+ five | f1 
+------+----
+      | 1
+      | 2
+      | 3
+      | 
+(4 rows)
+
+SELECT '' AS six, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 <= 'a';
+ six | f1 
+-----+----
+     | a
+     | 1
+     | 2
+     | 3
+     | 
+(5 rows)
+
+SELECT '' AS one, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 > 'a';
+ one | f1 
+-----+----
+     | A
+     | c
+(2 rows)
+
+SELECT '' AS two, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 >= 'a';
+ two | f1 
+-----+----
+     | a
+     | A
+     | c
+(3 rows)
+
+DROP TABLE NVARCHAR_TBL;
+--
+-- Now test longer arrays of nchar
+--
+CREATE TABLE NVARCHAR_TBL(f1 nvarchar(4));
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('ab');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcd');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcde');
+ERROR:  value too long for type character varying(4)
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcd    ');
+SELECT '' AS four, * FROM NVARCHAR_TBL;
+ four |  f1  
+------+------
+      | a
+      | ab
+      | abcd
+      | abcd
+(4 rows)
+
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/nvarchar_2.out ./src/test/regress/expected/nvarchar_2.out
--- ../orig.HEAD/src/test/regress/expected/nvarchar_2.out	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/expected/nvarchar_2.out	2013-08-19 23:31:50.000000000 -0400
@@ -0,0 +1,111 @@
+--
+-- NVARCHAR
+--
+CREATE TABLE NVARCHAR_TBL(f1 nvarchar(1));
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('A');
+-- any of the following three input formats are acceptable
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('1');
+INSERT INTO NVARCHAR_TBL (f1) VALUES (2);
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('3');
+-- zero-length nchar
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('');
+-- try nvarchar's of greater than 1 length
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('cd');
+ERROR:  value too long for type character varying(1)
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('c     ');
+SELECT '' AS seven, * FROM NVARCHAR_TBL;
+ seven | f1 
+-------+----
+       | a
+       | A
+       | 1
+       | 2
+       | 3
+       | 
+       | c
+(7 rows)
+
+SELECT '' AS six, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 <> 'a';
+ six | f1 
+-----+----
+     | A
+     | 1
+     | 2
+     | 3
+     | 
+     | c
+(6 rows)
+
+SELECT '' AS one, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 = 'a';
+ one | f1 
+-----+----
+     | a
+(1 row)
+
+SELECT '' AS five, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 < 'a';
+ five | f1 
+------+----
+      | 
+(1 row)
+
+SELECT '' AS six, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 <= 'a';
+ six | f1 
+-----+----
+     | a
+     | 
+(2 rows)
+
+SELECT '' AS one, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 > 'a';
+ one | f1 
+-----+----
+     | A
+     | 1
+     | 2
+     | 3
+     | c
+(5 rows)
+
+SELECT '' AS two, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 >= 'a';
+ two | f1 
+-----+----
+     | a
+     | A
+     | 1
+     | 2
+     | 3
+     | c
+(6 rows)
+
+DROP TABLE NVARCHAR_TBL;
+--
+-- Now test longer arrays of nchar
+--
+CREATE TABLE NVARCHAR_TBL(f1 nvarchar(4));
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('ab');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcd');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcde');
+ERROR:  value too long for type character varying(4)
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcd    ');
+SELECT '' AS four, * FROM NVARCHAR_TBL;
+ four |  f1  
+------+------
+      | a
+      | ab
+      | abcd
+      | abcd
+(4 rows)
+
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/nvarchar_alter.out ./src/test/regress/expected/nvarchar_alter.out
--- ../orig.HEAD/src/test/regress/expected/nvarchar_alter.out	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/expected/nvarchar_alter.out	2013-08-19 23:31:50.000000000 -0400
@@ -0,0 +1,138 @@
+--create table
+create table nchar_test (f1 nchar(10) default N'a', f2 nvarchar(10) default N'b');
+--values
+values (N'abc各国語');
+  column1  
+-----------
+ abc各国語
+(1 row)
+
+--analyze
+analyze nchar_test(f1);
+analyze nchar_test(f2);
+--vacuum analyze
+vacuum analyze nchar_test(f1);
+vacuum analyze nchar_test(f2);
+--broken
+--set application_name to N'abc各国語';
+--select
+select f1,f2,N'abc各国語' from nchar_test;
+ f1 | f2 | nvarchar 
+----+----+----------
+(0 rows)
+
+--select into
+select f1,f2,N'abc各国語' into nchar_test1 from nchar_test;
+--revoke per column not supported
+--grant per column not supported
+--insert into/returning
+insert into nchar_test1 select f1,f2,N'abc各国語' from nchar_test returning f1,f2,nvarchar,N'abc各国語';
+ f1 | f2 | nvarchar | nvarchar 
+----+----+----------+----------
+(0 rows)
+
+--explain
+explain select f1,f2,N'abc各国語' from nchar_test;
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Seq Scan on nchar_test  (cost=0.00..17.70 rows=770 width=76)
+(1 row)
+
+--do
+do $$begin perform f1,f2,N'abc各国語' from nchar_test; end $$;
+--delete
+delete from nchar_test where f1=N'abc各国語' and f2=N'abc各国語';
+--create view
+create view v as select f1,f2,N'abc各国語' from nchar_test;
+--create index
+create index i2 on nchar_test(f2);
+create index i3 on nchar_test((f1||'abc各国語'));
+create index i1 on nchar_test(f1);
+--comment
+comment on COLUMN nchar_test.f1 is 'f1';
+comment on COLUMN nchar_test.f2 is 'f2';
+comment on type nvarchar is 'nvarchar';
+--analyze
+analyze nchar_test(f1);
+--copy
+copy nchar_test(f1, f2) to stdout;
+--alter view
+alter view v alter column f1 set default N'abc各国語';
+alter view v alter column f2 set default N'abc各国語';
+--alter table
+alter table nchar_test1 rename f1 to f3;
+alter table nchar_test1 rename f2 to f4;
+alter table nchar_test1 alter f3 type nchar(10);
+alter table nchar_test1 alter f4 type nvarchar;
+alter table nchar_test1 alter f3 set default N'abc各国語';
+alter table nchar_test1 alter f4 set default N'abc各国語';
+--declare cursor
+begin;declare qqq cursor for select f1,f2,N'abc各国語' from nchar_test;commit;
+--create trigger
+create trigger tr before update on nchar_test for each row when (OLD.f1=N'abc各国語') EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+--foreign key
+alter table nchar_test1 add CONSTRAINT nchar_test1_pk primary key(f3);
+NOTICE:  ALTER TABLE / ADD PRIMARY KEY will create implicit index "nchar_test1_pk" for table "nchar_test1"
+alter table nchar_test add CONSTRAINT qqqq FOREIGN KEY (f1) references nchar_test1(f3);
+--update
+update nchar_test set f1=N'abc各国語', f2='abc各国語';
+select * from nchar_test1;
+ f3 | f4 | nvarchar 
+----+----+----------
+(0 rows)
+
+create domain test_nchar_domain as nchar(10) default (N'a') CHECK (value <> N'b');
+create domain test_nvarchar_domain as nvarchar(10) default (N'a') CHECK (value <> N'b');
+alter domain test_nchar_domain set default (N'b');
+alter domain test_nvarchar_domain set default (N'b');
+DROP DOMAIN test_nchar_domain;
+DROP DOMAIN test_nvarchar_domain;
+CREATE AGGREGATE test_nvarchar_agg (nvarchar) ( sfunc = array_append, stype = nvarchar[], initcond = '{}');
+CREATE AGGREGATE test_nchar_agg (nchar(10)) ( sfunc = array_append, stype = nchar(10)[], initcond = '{}');
+alter aggregate test_nvarchar_agg(nvarchar) rename to test_nvarchar_aggregate;
+alter aggregate test_nchar_agg (nchar(10)) rename to test_nchar_aggregate;
+drop aggregate test_nvarchar_aggregate(nvarchar);
+drop aggregate test_nchar_aggregate(nchar(10));
+CREATE TYPE test_nchar_type AS (f1 nchar(10));
+CREATE TYPE test_nvarchar_type AS (f1 nvarchar);
+drop type test_nchar_type;
+drop type test_nvarchar_type;
+drop view v;
+drop table nchar_test;
+drop table nchar_test1;
+create table nchar_test (f1 nchar(10), f2 nvarchar(10));
+select f1, f2, N'a'  from nchar_test where f1=N'a' and f2=N'b';
+ f1 | f2 | nvarchar 
+----+----+----------
+(0 rows)
+
+insert into nchar_test values (N'a', N'b') returning (f1, f2, N'c');
+        row         
+--------------------
+ ("a         ",b,c)
+(1 row)
+
+select f1, f2, N'a' into nchar_test1 from nchar_test;
+select * from nchar_test1;
+     f1     | f2 | nvarchar 
+------------+----+----------
+ a          | b  | a
+(1 row)
+
+prepare qqq(nchar(10), nvarchar(10)) AS select f1, f2, N'a'  from nchar_test where f1=N'a' and f2=N'b';
+execute qqq(N'a', N'b');
+     f1     | f2 | nvarchar 
+------------+----+----------
+ a          | b  | a
+(1 row)
+
+explain select f1, f2, N'a'  from nchar_test where f1=N'a' and f2=N'b';
+                          QUERY PLAN                          
+--------------------------------------------------------------
+ Seq Scan on nchar_test  (cost=0.00..21.55 rows=1 width=76)
+   Filter: ((f1 = 'a'::nbpchar) AND ((f2)::text = 'b'::text))
+(2 rows)
+
+delete from nchar_test1 where f1=N'a' and f2=N'b';
+drop table nchar_test;
+drop table nchar_test1;
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/nvarchar_func.out ./src/test/regress/expected/nvarchar_func.out
--- ../orig.HEAD/src/test/regress/expected/nvarchar_func.out	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/expected/nvarchar_func.out	2013-08-19 23:31:50.000000000 -0400
@@ -0,0 +1,258 @@
+SELECT N'各国' || N'文字';
+ ?column? 
+----------
+ 各国文字
+(1 row)
+
+SELECT N'各国' || 42;
+ ?column? 
+----------
+ 各国42
+(1 row)
+
+SELECT bit_length(N'各国');
+ bit_length 
+------------
+         48
+(1 row)
+
+SELECT char_length(N'各国');
+ char_length 
+-------------
+           2
+(1 row)
+
+SELECT lower(N'各国TOM');
+  lower  
+---------
+ 各国tom
+(1 row)
+
+SELECT octet_length(N'各国');
+ octet_length 
+--------------
+            6
+(1 row)
+
+SELECT overlay(N'各XX' placing N'文字' from 2 for 3);
+ overlay 
+---------
+ 各文字
+(1 row)
+
+SELECT position(N'文' in N'各国文字');
+ position 
+----------
+        3
+(1 row)
+
+SELECT substring(N'各国文字' from 3 for 3);
+ substring 
+-----------
+ 文字
+(1 row)
+
+SELECT substring(N'各国文字列' from N'...$');
+ substring 
+-----------
+ 文字列
+(1 row)
+
+SELECT substring(N'各国文字列国' from '%#"文_列#"_' for '#');
+ substring 
+-----------
+ 文字列
+(1 row)
+
+SELECT trim(both N'X' from N'X各国文字XX');
+  btrim   
+----------
+ 各国文字
+(1 row)
+
+SELECT upper(N'各国tom');
+  upper  
+---------
+ 各国TOM
+(1 row)
+
+SELECT ascii(N'数');
+ ascii 
+-------
+ 25968
+(1 row)
+
+SELECT btrim(N'XY各国X', N'XY');
+ btrim 
+-------
+ 各国
+(1 row)
+
+SELECT chr(25968);
+ chr 
+-----
+ 数
+(1 row)
+
+SELECT concat(N'各', N'国', NULL, N'語');
+ concat 
+--------
+ 各国語
+(1 row)
+
+SELECT concat_ws(N'_', N'各国', NULL, N'文字');
+ concat_ws  
+------------
+ 各国_文字
+(1 row)
+
+-- convert_to(N'各国', 'SJIS') = '\x8a658d91'
+-- convert_to(N'各国', 'UTF8') = '\xe59084e59bbd'
+SELECT convert('\x8a658d91'::bytea, 'SJIS', 'UTF8');
+    convert     
+----------------
+ \xe59084e59bbd
+(1 row)
+
+-- N'各国'::bytea = '\xe59084e59bbd'
+SELECT convert_from('\xe59084e59bbd'::bytea, 'UTF8');
+ convert_from 
+--------------
+ 各国
+(1 row)
+
+-- '\xe59084e59bbd'::bytea = N'各国'
+SELECT convert_to(N'各国', 'UTF8');
+   convert_to   
+----------------
+ \xe59084e59bbd
+(1 row)
+
+SELECT format('各国 %s, %1$s', N'文字');
+     format      
+-----------------
+ 各国 文字, 文字
+(1 row)
+
+SELECT initcap(N'hi 各国');
+ initcap 
+---------
+ Hi 各国
+(1 row)
+
+SELECT left(N'各国文字', 2);
+ left 
+------
+ 各国
+(1 row)
+
+SELECT length(N'各国文字');
+ length 
+--------
+      4
+(1 row)
+
+-- N'各国文字'::bytea = '\xe59084e59bbde69687e5ad97'
+SELECT length('\xe59084e59bbde69687e5ad97'::bytea , 'UTF8');
+ length 
+--------
+      4
+(1 row)
+
+SELECT lpad(N'文字', 3, N'各国');
+  lpad  
+--------
+ 各文字
+(1 row)
+
+SELECT ltrim(N'◯×各国', N'◯×');
+ ltrim 
+-------
+ 各国
+(1 row)
+
+SELECT regexp_matches(N'各国文字データ', N'(文字)(データ)');
+ regexp_matches 
+----------------
+ {文字,データ}
+(1 row)
+
+SELECT regexp_replace(N'各国x文字', '.[a-z]文.', N'語');
+ regexp_replace 
+----------------
+ 各語
+(1 row)
+
+SELECT regexp_split_to_array(N'各国 文字列', E'\\s+');
+ regexp_split_to_array 
+-----------------------
+ {各国,文字列}
+(1 row)
+
+SELECT regexp_split_to_table(N'各国 文字列', E'\\s+');
+ regexp_split_to_table 
+-----------------------
+ 各国
+ 文字列
+(2 rows)
+
+SELECT repeat(N'文字', 4);
+      repeat      
+------------------
+ 文字文字文字文字
+(1 row)
+
+SELECT replace(N'各国文字国', N'国', N'語');
+  replace   
+------------
+ 各語文字語
+(1 row)
+
+SELECT reverse(N'各国語');
+ reverse 
+---------
+ 語国各
+(1 row)
+
+SELECT right(N'各国語', 2);
+ right 
+-------
+ 国語
+(1 row)
+
+SELECT rpad(N'各国', 3, N'語');
+  rpad  
+--------
+ 各国語
+(1 row)
+
+SELECT rtrim(N'◯各国◯◯', N'◯');
+ rtrim 
+-------
+ ◯各国
+(1 row)
+
+SELECT split_part(N'各国◯語◯文字', N'◯', 3);
+ split_part 
+------------
+ 文字
+(1 row)
+
+SELECT strpos(N'各国語', N'語');
+ strpos 
+--------
+      3
+(1 row)
+
+SELECT substr(N'各国語', 3, 3);
+ substr 
+--------
+ 語
+(1 row)
+
+SELECT translate(N'各国文字', N'各字', N'◯×');
+ translate 
+-----------
+ ◯国文×
+(1 row)
+
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/nvarchar_misc.out ./src/test/regress/expected/nvarchar_misc.out
--- ../orig.HEAD/src/test/regress/expected/nvarchar_misc.out	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/expected/nvarchar_misc.out	2013-08-19 23:31:50.000000000 -0400
@@ -0,0 +1,126 @@
+select N'a '=N'a';
+ ?column? 
+----------
+ f
+(1 row)
+
+select N'a '='a';
+ ?column? 
+----------
+ f
+(1 row)
+
+select N'a'='a';
+ ?column? 
+----------
+ t
+(1 row)
+
+select N'a '='a'::char(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select N'a '='a'::nchar(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select N'a '='a'::varchar(1);
+ ?column? 
+----------
+ f
+(1 row)
+
+select N'a '='a'::nvarchar(1);
+ ?column? 
+----------
+ f
+(1 row)
+
+select N'a'='a'::nvarchar(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select N'a'='a'::varchar(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select N'a'='a'::char(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select N'a'='a'::nchar(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'a'::nchar(10)='a'::char(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'a'::nchar(10)='a'::nchar(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'a'::nchar(10)='a'::varchar(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'a'::nchar(10)='a'::nvarchar(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'a'::nvarchar(10)='a'::varchar(1);
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'a'::nvarchar(10)='a'::varchar(10);
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'a'::nvarchar(10)='a '::varchar(10);
+ ?column? 
+----------
+ f
+(1 row)
+
+select 'a'::nvarchar(10)='a '::char(10);
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'a '::nchar(10)='a  '::nchar(5);
+ ?column? 
+----------
+ t
+(1 row)
+
+select 'a '::nchar(10)='a  '::char(5);
+ ?column? 
+----------
+ t
+(1 row)
+
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/nvarchar.out ./src/test/regress/expected/nvarchar.out
--- ../orig.HEAD/src/test/regress/expected/nvarchar.out	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/expected/nvarchar.out	2013-08-19 23:31:50.000000000 -0400
@@ -0,0 +1,111 @@
+--
+-- NVARCHAR
+--
+CREATE TABLE NVARCHAR_TBL(f1 nvarchar(1));
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('A');
+-- any of the following three input formats are acceptable
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('1');
+INSERT INTO NVARCHAR_TBL (f1) VALUES (2);
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('3');
+-- zero-length char
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('');
+-- try nvarchar's of greater than 1 length
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('cd');
+ERROR:  value too long for type character varying(1)
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('c     ');
+SELECT '' AS seven, * FROM NVARCHAR_TBL;
+ seven | f1 
+-------+----
+       | a
+       | A
+       | 1
+       | 2
+       | 3
+       | 
+       | c
+(7 rows)
+
+SELECT '' AS six, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 <> 'a';
+ six | f1 
+-----+----
+     | A
+     | 1
+     | 2
+     | 3
+     | 
+     | c
+(6 rows)
+
+SELECT '' AS one, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 = 'a';
+ one | f1 
+-----+----
+     | a
+(1 row)
+
+SELECT '' AS five, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 < 'a';
+ five | f1 
+------+----
+      | A
+      | 1
+      | 2
+      | 3
+      | 
+(5 rows)
+
+SELECT '' AS six, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 <= 'a';
+ six | f1 
+-----+----
+     | a
+     | A
+     | 1
+     | 2
+     | 3
+     | 
+(6 rows)
+
+SELECT '' AS one, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 > 'a';
+ one | f1 
+-----+----
+     | c
+(1 row)
+
+SELECT '' AS two, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 >= 'a';
+ two | f1 
+-----+----
+     | a
+     | c
+(2 rows)
+
+DROP TABLE NVARCHAR_TBL;
+--
+-- Now test longer arrays of char
+--
+CREATE TABLE NVARCHAR_TBL(f1 nvarchar(4));
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('ab');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcd');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcde');
+ERROR:  value too long for type character varying(4)
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcd    ');
+SELECT '' AS four, * FROM NVARCHAR_TBL;
+ four |  f1  
+------+------
+      | a
+      | ab
+      | abcd
+      | abcd
+(4 rows)
+
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/opr_sanity.out ./src/test/regress/expected/opr_sanity.out
--- ../orig.HEAD/src/test/regress/expected/opr_sanity.out	2013-08-19 20:22:14.000000000 -0400
+++ ./src/test/regress/expected/opr_sanity.out	2013-08-19 20:54:00.000000000 -0400
@@ -152,12 +152,15 @@
     (p1.prorettype < p2.prorettype)
 ORDER BY 1, 2;
  prorettype | prorettype 
 ------------+------------
          25 |       1043
+         25 |       6001
+       1042 |       5001
+       1043 |       6001
        1114 |       1184
-(2 rows)
+(5 rows)
 
 SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
 FROM pg_proc AS p1, pg_proc AS p2
 WHERE p1.oid != p2.oid AND
     p1.prosrc = p2.prosrc AND
@@ -169,14 +172,18 @@
 ORDER BY 1, 2;
  proargtypes | proargtypes 
 -------------+-------------
           25 |        1042
           25 |        1043
+          25 |        5001
+          25 |        6001
+        1042 |        5001
+        1043 |        6001
         1114 |        1184
         1560 |        1562
         2277 |        2283
-(5 rows)
+(9 rows)
 
 SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
 FROM pg_proc AS p1, pg_proc AS p2
 WHERE p1.oid != p2.oid AND
     p1.prosrc = p2.prosrc AND
@@ -187,14 +194,15 @@
     (p1.proargtypes[1] < p2.proargtypes[1])
 ORDER BY 1, 2;
  proargtypes | proargtypes 
 -------------+-------------
           23 |          28
+        1042 |        5001
         1114 |        1184
         1560 |        1562
         2277 |        2283
-(4 rows)
+(5 rows)
 
 SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]
 FROM pg_proc AS p1, pg_proc AS p2
 WHERE p1.oid != p2.oid AND
     p1.prosrc = p2.prosrc AND
@@ -433,19 +441,23 @@
     NOT EXISTS (SELECT 1 FROM pg_cast k
                 WHERE k.castmethod = 'b' AND
                     k.castsource = c.casttarget AND
                     k.casttarget = c.castsource);
     castsource     |    casttarget     | castfunc | castcontext 
--------------------+-------------------+----------+-------------
- text              | character         |        0 | i
+----------------------------+--------------------+----------+-------------
+ national character varying | character          |        0 | i
+ national character varying | national character |        0 | i
  character varying | character         |        0 | i
+ character varying          | national character |        0 | i
+ text                       | character          |        0 | i
+ text                       | national character |        0 | i
  pg_node_tree      | text              |        0 | i
  cidr              | inet              |        0 | i
  xml               | text              |        0 | a
  xml               | character varying |        0 | a
  xml               | character         |        0 | a
-(7 rows)
+(11 rows)
 
 -- **************** pg_operator ****************
 -- Look for illegal values in pg_operator fields.
 SELECT p1.oid, p1.oprname
 FROM pg_operator as p1
@@ -1211,11 +1223,13 @@
                  p3.amoplefttype = p1.amoplefttype AND
                  p3.amoprighttype = p2.amoplefttype AND
                  p3.amopstrategy = 1);
  amoplefttype | amoplefttype 
 --------------+--------------
-(0 rows)
+         1042 |         5001
+         5001 |         1042
+(2 rows)
 
 -- **************** pg_amproc ****************
 -- Look for illegal values in pg_amproc fields
 SELECT p1.amprocfamily, p1.amprocnum
 FROM pg_amproc as p1
@@ -1273,12 +1287,14 @@
 WHERE am.amname = 'btree' OR am.amname = 'gist' OR am.amname = 'gin'
 GROUP BY amname, amsupport, opcname, amprocfamily
 HAVING (count(*) != amsupport AND count(*) != amsupport - 1)
     OR amprocfamily IS NULL;
  amname | opcname | count 
---------+---------+-------
-(0 rows)
+--------+---------------+-------
+ gin    | _nbpchar_ops  |     1
+ gin    | _nvarchar_ops |     1
+(2 rows)
 
 -- Unfortunately, we can't check the amproc link very well because the
 -- signature of the function may be different for different support routines
 -- or different base data types.
 -- We can check that all the referenced instances of the same support
@@ -1316,12 +1332,14 @@
           WHEN amprocnum = 2
           THEN prorettype != 'void'::regtype OR proretset OR pronargs != 1
                OR proargtypes[0] != 'internal'::regtype
           ELSE true END);
  amprocfamily | amprocnum | oid | proname | opfname 
---------------+-----------+-----+---------+---------
-(0 rows)
+--------------+-----------+------+----------------------+--------------------
+          426 |         1 | 1078 | bpcharcmp            | bpchar_ops
+         2097 |         1 | 2180 | btbpchar_pattern_cmp | bpchar_pattern_ops
+(2 rows)
 
 -- For hash we can also do a little better: the support routines must be
 -- of the form hash(lefttype) returns int4.  There are several cases where
 -- we cheat and use a hash function that is physically compatible with the
 -- datatype even though there's no cast, so this check does find a small
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/sanity_check.out ./src/test/regress/expected/sanity_check.out
--- ../orig.HEAD/src/test/regress/expected/sanity_check.out	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/expected/sanity_check.out	2013-08-19 20:54:00.000000000 -0400
@@ -66,10 +66,11 @@
  kd_point_tbl            | t
  log_table               | f
  lseg_tbl                | f
  main_table              | f
  money_data              | f
+ nchar_tbl               | f
  num_data                | f
  num_exp_add             | t
  num_exp_div             | t
  num_exp_ln              | t
  num_exp_log10           | t
@@ -77,10 +78,11 @@
  num_exp_power_10_ln     | t
  num_exp_sqrt            | t
  num_exp_sub             | t
  num_input_test          | f
  num_result              | f
+ nvarchar_tbl            | f
  onek                    | t
  onek2                   | t
  path_tbl                | f
  person                  | f
  pg_aggregate            | t
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/strings.out ./src/test/regress/expected/strings.out
--- ../orig.HEAD/src/test/regress/expected/strings.out	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/expected/strings.out	2013-08-19 20:54:00.000000000 -0400
@@ -201,19 +201,37 @@
  ab
  abcd
  abcd
 (4 rows)
 
+SELECT CAST(f1 AS text) AS "text(nchar)" FROM NCHAR_TBL;
+ text(nchar) 
+-------------
+ a
+ ab
+ abcd
+ abcd
+(4 rows)
+
 SELECT CAST(f1 AS text) AS "text(varchar)" FROM VARCHAR_TBL;
  text(varchar) 
 ---------------
  a
  ab
  abcd
  abcd
 (4 rows)
 
+SELECT CAST(f1 AS text) AS "text(nvarchar)" FROM NVARCHAR_TBL;
+ text(nvarchar) 
+----------------
+ a
+ ab
+ abcd
+ abcd
+(4 rows)
+
 SELECT CAST(name 'namefield' AS text) AS "text(name)";
  text(name) 
 ------------
  namefield
 (1 row)
@@ -225,54 +243,106 @@
  doh!      
  hi de ho n
 (2 rows)
 
 -- note: implicit-cast case is tested in char.sql
+SELECT CAST(f1 AS nchar(10)) AS "nchar(text)" FROM TEXT_TBL;
+ nchar(text) 
+-------------
+ doh!      
+ hi de ho n
+(2 rows)
+
+-- note: implicit-cast case is tested in nchar.sql
 SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
       char(text)      
 ----------------------
  doh!                
  hi de ho neighbor   
 (2 rows)
 
+SELECT CAST(f1 AS nchar(20)) AS "nchar(text)" FROM TEXT_TBL;
+     nchar(text)      
+----------------------
+ doh!                
+ hi de ho neighbor   
+(2 rows)
+
 SELECT CAST(f1 AS char(10)) AS "char(varchar)" FROM VARCHAR_TBL;
  char(varchar) 
 ---------------
  a         
  ab        
  abcd      
  abcd      
 (4 rows)
 
+SELECT CAST(f1 AS nchar(10)) AS "nchar(nvarchar)" FROM NVARCHAR_TBL;
+ nchar(nvarchar) 
+-----------------
+ a         
+ ab        
+ abcd      
+ abcd      
+(4 rows)
+
 SELECT CAST(name 'namefield' AS char(10)) AS "char(name)";
  char(name) 
 ------------
  namefield 
 (1 row)
 
+SELECT CAST(name 'namefield' AS nchar(10)) AS "nchar(name)";
+ nchar(name) 
+-------------
+ namefield 
+(1 row)
+
 SELECT CAST(f1 AS varchar) AS "varchar(text)" FROM TEXT_TBL;
    varchar(text)   
 -------------------
  doh!
  hi de ho neighbor
 (2 rows)
 
+SELECT CAST(f1 AS nvarchar) AS "nvarchar(text)" FROM TEXT_TBL;
+  nvarchar(text)   
+-------------------
+ doh!
+ hi de ho neighbor
+(2 rows)
+
 SELECT CAST(f1 AS varchar) AS "varchar(char)" FROM CHAR_TBL;
  varchar(char) 
 ---------------
  a
  ab
  abcd
  abcd
 (4 rows)
 
+SELECT CAST(f1 AS nvarchar) AS "nvarchar(nchar)" FROM NCHAR_TBL;
+ nvarchar(nchar) 
+-----------------
+ a
+ ab
+ abcd
+ abcd
+(4 rows)
+
 SELECT CAST(name 'namefield' AS varchar) AS "varchar(name)";
  varchar(name) 
 ---------------
  namefield
 (1 row)
 
+SELECT CAST(name 'namefield' AS nvarchar) AS "nvarchar(name)";
+ nvarchar(name) 
+----------------
+ namefield
+(1 row)
+
 --
 -- test SQL string functions
 -- E### and T### are feature reference numbers from SQL99
 --
 -- E021-09 trim function
@@ -1103,22 +1173,40 @@
  Concat char to unknown type 
 -----------------------------
  characters and text
 (1 row)
 
+SELECT nchar(20) 'ncharacters' || ' and text' AS "Concat nchar to unknown type";
+ Concat nchar to unknown type 
+------------------------------
+ ncharacters and text
+(1 row)
+
 SELECT text 'text' || char(20) ' and characters' AS "Concat text to char";
  Concat text to char 
 ---------------------
  text and characters
 (1 row)
 
+SELECT text 'text' || nchar(20) ' and ncharacters' AS "Concat text to nchar";
+ Concat text to nchar 
+----------------------
+ text and ncharacters
+(1 row)
+
 SELECT text 'text' || varchar ' and varchar' AS "Concat text to varchar";
  Concat text to varchar 
 ------------------------
  text and varchar
 (1 row)
 
+SELECT text 'text' || nvarchar ' and nvarchar' AS "Concat text to nvarchar";
+ Concat text to nvarchar 
+-------------------------
+ text and nvarchar
+(1 row)
+
 --
 -- test substr with toasted text values
 --
 CREATE TABLE toasttest(f1 text);
 insert into toasttest values(repeat('1234567890',10000));
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/union.out ./src/test/regress/expected/union.out
--- ../orig.HEAD/src/test/regress/expected/union.out	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/expected/union.out	2013-08-19 20:54:00.000000000 -0400
@@ -255,10 +255,52 @@
  abcd
  doh!
  hi de ho neighbor
 (5 rows)
 
+--NVARCHAR specific
+SELECT f1 AS three FROM NVARCHAR_TBL
+UNION
+SELECT CAST(f1 AS nvarchar) FROM NCHAR_TBL
+ORDER BY 1;
+ three 
+-------
+ a
+ ab
+ abcd
+(3 rows)
+
+SELECT f1 AS eight FROM NVARCHAR_TBL
+UNION ALL
+SELECT f1 FROM NCHAR_TBL;
+ eight 
+-------
+ a
+ ab
+ abcd
+ abcd
+ a
+ ab
+ abcd
+ abcd
+(8 rows)
+
+SELECT f1 AS five FROM TEXT_TBL
+UNION
+SELECT f1 FROM NVARCHAR_TBL
+UNION
+SELECT TRIM(TRAILING FROM f1) FROM NCHAR_TBL
+ORDER BY 1;
+       five        
+-------------------
+ a
+ ab
+ abcd
+ doh!
+ hi de ho neighbor
+(5 rows)
+
 --
 -- INTERSECT and EXCEPT
 --
 SELECT q2 FROM int8_tbl INTERSECT SELECT q1 FROM int8_tbl;
         q2        
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/expected/update.out ./src/test/regress/expected/update.out
--- ../orig.HEAD/src/test/regress/expected/update.out	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/expected/update.out	2013-08-19 20:54:00.000000000 -0400
@@ -2,75 +2,101 @@
 -- UPDATE syntax tests
 --
 CREATE TABLE update_test (
     a   INT DEFAULT 10,
     b   INT,
-    c   TEXT
+    c   TEXT,
+    d   nchar(10),
+    e   nvarchar
 );
-INSERT INTO update_test VALUES (5, 10, 'foo');
+INSERT INTO update_test VALUES (5, 10, 'foo', 'a', 'a');
 INSERT INTO update_test(b, a) VALUES (15, 10);
 SELECT * FROM update_test;
- a  | b  |  c  
-----+----+-----
-  5 | 10 | foo
- 10 | 15 | 
+ a  | b  |  c  |     d      | e 
+----+----+-----+------------+---
+  5 | 10 | foo | a          | a
+ 10 | 15 |     |            | 
+(2 rows)
+
+UPDATE update_test SET d='b', e='b';
+SELECT * FROM update_test;
+ a  | b  |  c  |     d      | e 
+----+----+-----+------------+---
+  5 | 10 | foo | b          | b
+ 10 | 15 |     | b          | b
+(2 rows)
+
+UPDATE update_test SET d='c' where e='b';
+SELECT * FROM update_test;
+ a  | b  |  c  |     d      | e 
+----+----+-----+------------+---
+  5 | 10 | foo | c          | b
+ 10 | 15 |     | c          | b
+(2 rows)
+
+UPDATE update_test SET d=N'e' where e=N'b';
+SELECT * FROM update_test;
+ a  | b  |  c  |     d      | e 
+----+----+-----+------------+---
+  5 | 10 | foo | e          | b
+ 10 | 15 |     | e          | b
 (2 rows)
 
 UPDATE update_test SET a = DEFAULT, b = DEFAULT;
 SELECT * FROM update_test;
- a  | b |  c  
-----+---+-----
- 10 |   | foo
- 10 |   | 
+ a  | b |  c  |     d      | e 
+----+---+-----+------------+---
+ 10 |   | foo | e          | b
+ 10 |   |     | e          | b
 (2 rows)
 
 -- aliases for the UPDATE target table
 UPDATE update_test AS t SET b = 10 WHERE t.a = 10;
 SELECT * FROM update_test;
- a  | b  |  c  
-----+----+-----
- 10 | 10 | foo
- 10 | 10 | 
+ a  | b  |  c  |     d      | e 
+----+----+-----+------------+---
+ 10 | 10 | foo | e          | b
+ 10 | 10 |     | e          | b
 (2 rows)
 
 UPDATE update_test t SET b = t.b + 10 WHERE t.a = 10;
 SELECT * FROM update_test;
- a  | b  |  c  
-----+----+-----
- 10 | 20 | foo
- 10 | 20 | 
+ a  | b  |  c  |     d      | e 
+----+----+-----+------------+---
+ 10 | 20 | foo | e          | b
+ 10 | 20 |     | e          | b
 (2 rows)
 
 --
 -- Test VALUES in FROM
 --
 UPDATE update_test SET a=v.i FROM (VALUES(100, 20)) AS v(i, j)
   WHERE update_test.b = v.j;
 SELECT * FROM update_test;
-  a  | b  |  c  
------+----+-----
- 100 | 20 | foo
- 100 | 20 | 
+  a  | b  |  c  |     d      | e 
+-----+----+-----+------------+---
+ 100 | 20 | foo | e          | b
+ 100 | 20 |     | e          | b
 (2 rows)
 
 --
 -- Test multiple-set-clause syntax
 --
 UPDATE update_test SET (c,b,a) = ('bugle', b+11, DEFAULT) WHERE c = 'foo';
 SELECT * FROM update_test;
-  a  | b  |   c   
------+----+-------
- 100 | 20 | 
-  10 | 31 | bugle
+  a  | b  |   c   |     d      | e 
+-----+----+-------+------------+---
+ 100 | 20 |       | e          | b
+  10 | 31 | bugle | e          | b
 (2 rows)
 
 UPDATE update_test SET (c,b) = ('car', a+b), a = a + 1 WHERE a = 10;
 SELECT * FROM update_test;
-  a  | b  |  c  
------+----+-----
- 100 | 20 | 
-  11 | 41 | car
+  a  | b  |  c  |     d      | e 
+-----+----+-----+------------+---
+ 100 | 20 |     | e          | b
+  11 | 41 | car | e          | b
 (2 rows)
 
 -- fail, multi assignment to same column:
 UPDATE update_test SET (c,b) = ('car', a+b), b = a + 1 WHERE a = 10;
 ERROR:  multiple assignments to same column "b"
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/output/misc.source ./src/test/regress/output/misc.source
--- ../orig.HEAD/src/test/regress/output/misc.source	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/output/misc.source	2013-08-19 20:54:00.000000000 -0400
@@ -39,32 +39,32 @@
 --   SET age = age + 3
 --   WHERE name = 'linda';
 --
 -- copy
 --
-COPY onek TO '@abs_builddir@/results/onek.data';
+COPY onek TO '/home/mboguk/postgres/build_test/src/test/regress/results/onek.data';
 DELETE FROM onek;
-COPY onek FROM '@abs_builddir@/results/onek.data';
+COPY onek FROM '/home/mboguk/postgres/build_test/src/test/regress/results/onek.data';
 SELECT unique1 FROM onek WHERE unique1 < 2 ORDER BY unique1;
  unique1 
 ---------
        0
        1
 (2 rows)
 
 DELETE FROM onek2;
-COPY onek2 FROM '@abs_builddir@/results/onek.data';
+COPY onek2 FROM '/home/mboguk/postgres/build_test/src/test/regress/results/onek.data';
 SELECT unique1 FROM onek2 WHERE unique1 < 2 ORDER BY unique1;
  unique1 
 ---------
        0
        1
 (2 rows)
 
-COPY BINARY stud_emp TO '@abs_builddir@/results/stud_emp.data';
+COPY BINARY stud_emp TO '/home/mboguk/postgres/build_test/src/test/regress/results/stud_emp.data';
 DELETE FROM stud_emp;
-COPY BINARY stud_emp FROM '@abs_builddir@/results/stud_emp.data';
+COPY BINARY stud_emp FROM '/home/mboguk/postgres/build_test/src/test/regress/results/stud_emp.data';
 SELECT * FROM stud_emp;
  name  | age |  location  | salary | manager | gpa | percent 
 -------+-----+------------+--------+---------+-----+---------
  jeff  |  23 | (8,7.7)    |    600 | sharon  | 3.5 |        
  cim   |  30 | (10.5,4.7) |    400 |         | 3.4 |        
@@ -640,10 +640,11 @@
  kd_point_tbl
  log_table
  lseg_tbl
  main_table
  money_data
+ nchar_tbl
  num_data
  num_exp_add
  num_exp_div
  num_exp_ln
  num_exp_log10
@@ -651,10 +652,11 @@
  num_exp_power_10_ln
  num_exp_sqrt
  num_exp_sub
  num_input_test
  num_result
+ nvarchar_tbl
  onek
  onek2
  path_tbl
  person
  point_tbl
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/parallel_schedule ./src/test/regress/parallel_schedule
--- ../orig.HEAD/src/test/regress/parallel_schedule	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/parallel_schedule	2013-08-19 20:54:00.000000000 -0400
@@ -11,11 +11,11 @@
 test: tablespace
 
 # ----------
 # The first group of parallel tests
 # ----------
-test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes
+test: boolean char name varchar nchar nvarchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes nvarchar_func nvarchar_alter nvarchar_misc
 
 # Depends on things setup during char, varchar and text
 test: strings
 # Depends on int2, int4, int8, float4, float8
 test: numerology
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/serial_schedule ./src/test/regress/serial_schedule
--- ../orig.HEAD/src/test/regress/serial_schedule	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/serial_schedule	2013-08-19 20:54:00.000000000 -0400
@@ -3,10 +3,15 @@
 test: tablespace
 test: boolean
 test: char
 test: name
 test: varchar
+test: nvarchar
+test: nvarchar_alter
+test: nvarchar_func
+test: nvarchar_misc
+test: nchar
 test: text
 test: int2
 test: int4
 test: int8
 test: oid
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/sql/nchar.sql ./src/test/regress/sql/nchar.sql
--- ../orig.HEAD/src/test/regress/sql/nchar.sql	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/sql/nchar.sql	2013-08-19 23:31:21.000000000 -0400
@@ -0,0 +1,75 @@
+--
+-- NCHAR
+--
+
+-- fixed-length by value
+-- internally passed by value if <= 4 bytes in storage
+
+SELECT nchar 'c' = nchar 'c' AS true;
+
+--
+-- Build a table for testing
+--
+
+CREATE TABLE NCHAR_TBL(f1 nchar);
+
+INSERT INTO NCHAR_TBL (f1) VALUES ('a');
+
+INSERT INTO NCHAR_TBL (f1) VALUES ('A');
+
+-- any of the following three input formats are acceptable
+INSERT INTO NCHAR_TBL (f1) VALUES ('1');
+
+INSERT INTO NCHAR_TBL (f1) VALUES (2);
+
+INSERT INTO NCHAR_TBL (f1) VALUES ('3');
+
+-- zero-length nchar
+INSERT INTO NCHAR_TBL (f1) VALUES ('');
+
+-- try nchar's of greater than 1 length
+INSERT INTO NCHAR_TBL (f1) VALUES ('cd');
+INSERT INTO NCHAR_TBL (f1) VALUES ('c     ');
+
+
+SELECT '' AS seven, * FROM NCHAR_TBL;
+
+SELECT '' AS six, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 <> 'a';
+
+SELECT '' AS one, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 = 'a';
+
+SELECT '' AS five, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 < 'a';
+
+SELECT '' AS six, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 <= 'a';
+
+SELECT '' AS one, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 > 'a';
+
+SELECT '' AS two, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 >= 'a';
+
+DROP TABLE NCHAR_TBL;
+
+--
+-- Now test longer arrays of nchar
+--
+
+CREATE TABLE NCHAR_TBL(f1 nchar(4));
+
+INSERT INTO NCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NCHAR_TBL (f1) VALUES ('ab');
+INSERT INTO NCHAR_TBL (f1) VALUES ('abcd');
+INSERT INTO NCHAR_TBL (f1) VALUES ('abcde');
+INSERT INTO NCHAR_TBL (f1) VALUES ('abcd    ');
+
+SELECT '' AS four, * FROM NCHAR_TBL;
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/sql/nvarchar_alter.sql ./src/test/regress/sql/nvarchar_alter.sql
--- ../orig.HEAD/src/test/regress/sql/nvarchar_alter.sql	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/sql/nvarchar_alter.sql	2013-08-19 23:31:15.000000000 -0400
@@ -0,0 +1,126 @@
+--create table
+create table nchar_test (f1 nchar(10) default N'a', f2 nvarchar(10) default N'b');
+
+--values
+values (N'abc各国語');
+
+--analyze
+analyze nchar_test(f1);
+analyze nchar_test(f2);
+
+--vacuum analyze
+vacuum analyze nchar_test(f1);
+vacuum analyze nchar_test(f2);
+
+--broken
+--set application_name to N'abc各国語';
+
+--select
+select f1,f2,N'abc各国語' from nchar_test;
+
+--select into
+select f1,f2,N'abc各国語' into nchar_test1 from nchar_test;
+
+--revoke per column not supported
+
+--grant per column not supported
+
+--insert into/returning
+insert into nchar_test1 select f1,f2,N'abc各国語' from nchar_test returning f1,f2,nvarchar,N'abc各国語';
+
+--explain
+explain select f1,f2,N'abc各国語' from nchar_test;
+
+--do
+do $$begin perform f1,f2,N'abc各国語' from nchar_test; end $$;
+
+--delete
+delete from nchar_test where f1=N'abc各国語' and f2=N'abc各国語';
+
+--create view
+create view v as select f1,f2,N'abc各国語' from nchar_test;
+
+--create index
+create index i2 on nchar_test(f2);
+create index i3 on nchar_test((f1||'abc各国語'));
+create index i1 on nchar_test(f1);
+
+--comment
+comment on COLUMN nchar_test.f1 is 'f1';
+comment on COLUMN nchar_test.f2 is 'f2';
+comment on type nvarchar is 'nvarchar';
+
+
+--analyze
+analyze nchar_test(f1);
+
+--copy
+copy nchar_test(f1, f2) to stdout;
+
+--alter view
+alter view v alter column f1 set default N'abc各国語';
+alter view v alter column f2 set default N'abc各国語';
+
+--alter table
+alter table nchar_test1 rename f1 to f3;
+alter table nchar_test1 rename f2 to f4;
+alter table nchar_test1 alter f3 type nchar(10);
+alter table nchar_test1 alter f4 type nvarchar;
+alter table nchar_test1 alter f3 set default N'abc各国語';
+alter table nchar_test1 alter f4 set default N'abc各国語';
+
+--declare cursor
+begin;declare qqq cursor for select f1,f2,N'abc各国語' from nchar_test;commit;
+
+--create trigger
+create trigger tr before update on nchar_test for each row when (OLD.f1=N'abc各国語') EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+
+--foreign key
+alter table nchar_test1 add CONSTRAINT nchar_test1_pk primary key(f3);
+alter table nchar_test add CONSTRAINT qqqq FOREIGN KEY (f1) references nchar_test1(f3);
+
+--update
+update nchar_test set f1=N'abc各国語', f2='abc各国語';
+
+select * from nchar_test1;
+
+create domain test_nchar_domain as nchar(10) default (N'a') CHECK (value <> N'b');
+create domain test_nvarchar_domain as nvarchar(10) default (N'a') CHECK (value <> N'b');
+alter domain test_nchar_domain set default (N'b');
+alter domain test_nvarchar_domain set default (N'b');
+DROP DOMAIN test_nchar_domain;
+DROP DOMAIN test_nvarchar_domain;
+
+CREATE AGGREGATE test_nvarchar_agg (nvarchar) ( sfunc = array_append, stype = nvarchar[], initcond = '{}');
+CREATE AGGREGATE test_nchar_agg (nchar(10)) ( sfunc = array_append, stype = nchar(10)[], initcond = '{}');
+alter aggregate test_nvarchar_agg(nvarchar) rename to test_nvarchar_aggregate;
+alter aggregate test_nchar_agg (nchar(10)) rename to test_nchar_aggregate;
+drop aggregate test_nvarchar_aggregate(nvarchar);
+drop aggregate test_nchar_aggregate(nchar(10));
+
+CREATE TYPE test_nchar_type AS (f1 nchar(10));
+CREATE TYPE test_nvarchar_type AS (f1 nvarchar);
+drop type test_nchar_type;
+drop type test_nvarchar_type;
+
+
+drop view v;
+drop table nchar_test;
+drop table nchar_test1;
+
+create table nchar_test (f1 nchar(10), f2 nvarchar(10));
+select f1, f2, N'a'  from nchar_test where f1=N'a' and f2=N'b';
+insert into nchar_test values (N'a', N'b') returning (f1, f2, N'c');
+select f1, f2, N'a' into nchar_test1 from nchar_test;
+select * from nchar_test1;
+
+prepare qqq(nchar(10), nvarchar(10)) AS select f1, f2, N'a'  from nchar_test where f1=N'a' and f2=N'b';
+execute qqq(N'a', N'b');
+
+explain select f1, f2, N'a'  from nchar_test where f1=N'a' and f2=N'b';
+
+delete from nchar_test1 where f1=N'a' and f2=N'b';
+
+drop table nchar_test;
+drop table nchar_test1;
+
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/sql/nvarchar_func.sql ./src/test/regress/sql/nvarchar_func.sql
--- ../orig.HEAD/src/test/regress/sql/nvarchar_func.sql	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/sql/nvarchar_func.sql	2013-08-19 23:31:15.000000000 -0400
@@ -0,0 +1,90 @@
+
+SELECT N'各国' || N'文字';
+
+SELECT N'各国' || 42;
+
+SELECT bit_length(N'各国');
+
+SELECT char_length(N'各国');
+
+SELECT lower(N'各国TOM');
+
+SELECT octet_length(N'各国');
+
+SELECT overlay(N'各XX' placing N'文字' from 2 for 3);
+
+SELECT position(N'文' in N'各国文字');
+
+SELECT substring(N'各国文字' from 3 for 3);
+
+SELECT substring(N'各国文字列' from N'...$');
+
+SELECT substring(N'各国文字列国' from '%#"文_列#"_' for '#');
+
+SELECT trim(both N'X' from N'X各国文字XX');
+
+SELECT upper(N'各国tom');
+
+SELECT ascii(N'数');
+
+SELECT btrim(N'XY各国X', N'XY');
+
+SELECT chr(25968);
+
+SELECT concat(N'各', N'国', NULL, N'語');
+
+SELECT concat_ws(N'_', N'各国', NULL, N'文字');
+
+-- convert_to(N'各国', 'SJIS') = '\x8a658d91'
+-- convert_to(N'各国', 'UTF8') = '\xe59084e59bbd'
+SELECT convert('\x8a658d91'::bytea, 'SJIS', 'UTF8');
+
+-- N'各国'::bytea = '\xe59084e59bbd'
+SELECT convert_from('\xe59084e59bbd'::bytea, 'UTF8');
+
+-- '\xe59084e59bbd'::bytea = N'各国'
+SELECT convert_to(N'各国', 'UTF8');
+
+SELECT format('各国 %s, %1$s', N'文字');
+
+SELECT initcap(N'hi 各国');
+
+SELECT left(N'各国文字', 2);
+
+SELECT length(N'各国文字');
+
+-- N'各国文字'::bytea = '\xe59084e59bbde69687e5ad97'
+SELECT length('\xe59084e59bbde69687e5ad97'::bytea , 'UTF8');
+
+SELECT lpad(N'文字', 3, N'各国');
+
+SELECT ltrim(N'◯×各国', N'◯×');
+
+SELECT regexp_matches(N'各国文字データ', N'(文字)(データ)');
+
+SELECT regexp_replace(N'各国x文字', '.[a-z]文.', N'語');
+
+SELECT regexp_split_to_array(N'各国 文字列', E'\\s+');
+
+SELECT regexp_split_to_table(N'各国 文字列', E'\\s+');
+
+SELECT repeat(N'文字', 4);
+
+SELECT replace(N'各国文字国', N'国', N'語');
+
+SELECT reverse(N'各国語');
+
+SELECT right(N'各国語', 2);
+
+SELECT rpad(N'各国', 3, N'語');
+
+SELECT rtrim(N'◯各国◯◯', N'◯');
+
+SELECT split_part(N'各国◯語◯文字', N'◯', 3);
+
+SELECT strpos(N'各国語', N'語');
+
+SELECT substr(N'各国語', 3, 3);
+
+SELECT translate(N'各国文字', N'各字', N'◯×');
+
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/sql/nvarchar_misc.sql ./src/test/regress/sql/nvarchar_misc.sql
--- ../orig.HEAD/src/test/regress/sql/nvarchar_misc.sql	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/sql/nvarchar_misc.sql	2013-08-19 23:31:15.000000000 -0400
@@ -0,0 +1,22 @@
+select N'a '=N'a';
+select N'a '='a';
+select N'a'='a';
+select N'a '='a'::char(1);
+select N'a '='a'::nchar(1);
+select N'a '='a'::varchar(1);
+select N'a '='a'::nvarchar(1);
+select N'a'='a'::nvarchar(1);
+select N'a'='a'::varchar(1);
+select N'a'='a'::char(1);
+select N'a'='a'::nchar(1);
+select 'a'::nchar(10)='a'::char(1);
+select 'a'::nchar(10)='a'::nchar(1);
+select 'a'::nchar(10)='a'::varchar(1);
+select 'a'::nchar(10)='a'::nvarchar(1);
+select 'a'::nvarchar(10)='a'::varchar(1);
+select 'a'::nvarchar(10)='a'::varchar(10);
+select 'a'::nvarchar(10)='a '::varchar(10);
+select 'a'::nvarchar(10)='a '::char(10);
+select 'a '::nchar(10)='a  '::nchar(5);
+select 'a '::nchar(10)='a  '::char(5);
+
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/sql/nvarchar.sql ./src/test/regress/sql/nvarchar.sql
--- ../orig.HEAD/src/test/regress/sql/nvarchar.sql	1969-12-31 19:00:00.000000000 -0500
+++ ./src/test/regress/sql/nvarchar.sql	2013-08-19 23:31:15.000000000 -0400
@@ -0,0 +1,66 @@
+--
+-- NVARCHAR
+--
+
+CREATE TABLE NVARCHAR_TBL(f1 nvarchar(1));
+
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('a');
+
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('A');
+
+-- any of the following three input formats are acceptable
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('1');
+
+INSERT INTO NVARCHAR_TBL (f1) VALUES (2);
+
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('3');
+
+-- zero-length nchar
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('');
+
+-- try nvarchar's of greater than 1 length
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('cd');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('c     ');
+
+
+SELECT '' AS seven, * FROM NVARCHAR_TBL;
+
+SELECT '' AS six, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 <> 'a';
+
+SELECT '' AS one, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 = 'a';
+
+SELECT '' AS five, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 < 'a';
+
+SELECT '' AS six, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 <= 'a';
+
+SELECT '' AS one, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 > 'a';
+
+SELECT '' AS two, c.*
+   FROM NVARCHAR_TBL c
+   WHERE c.f1 >= 'a';
+
+DROP TABLE NVARCHAR_TBL;
+
+--
+-- Now test longer arrays of nchar
+--
+
+CREATE TABLE NVARCHAR_TBL(f1 nvarchar(4));
+
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('a');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('ab');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcd');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcde');
+INSERT INTO NVARCHAR_TBL (f1) VALUES ('abcd    ');
+
+SELECT '' AS four, * FROM NVARCHAR_TBL;
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/sql/strings.sql ./src/test/regress/sql/strings.sql
--- ../orig.HEAD/src/test/regress/sql/strings.sql	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/sql/strings.sql	2013-08-19 20:54:00.000000000 -0400
@@ -68,30 +68,41 @@
 -- test conversions between various string types
 -- E021-10 implicit casting among the character data types
 --
 
 SELECT CAST(f1 AS text) AS "text(char)" FROM CHAR_TBL;
+SELECT CAST(f1 AS text) AS "text(nchar)" FROM NCHAR_TBL;
 
 SELECT CAST(f1 AS text) AS "text(varchar)" FROM VARCHAR_TBL;
+SELECT CAST(f1 AS text) AS "text(nvarchar)" FROM NVARCHAR_TBL;
 
 SELECT CAST(name 'namefield' AS text) AS "text(name)";
 
 -- since this is an explicit cast, it should truncate w/o error:
 SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
 -- note: implicit-cast case is tested in char.sql
+SELECT CAST(f1 AS nchar(10)) AS "nchar(text)" FROM TEXT_TBL;
+-- note: implicit-cast case is tested in nchar.sql
 
 SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
+SELECT CAST(f1 AS nchar(20)) AS "nchar(text)" FROM TEXT_TBL;
 
 SELECT CAST(f1 AS char(10)) AS "char(varchar)" FROM VARCHAR_TBL;
+SELECT CAST(f1 AS nchar(10)) AS "nchar(nvarchar)" FROM NVARCHAR_TBL;
+
 
 SELECT CAST(name 'namefield' AS char(10)) AS "char(name)";
+SELECT CAST(name 'namefield' AS nchar(10)) AS "nchar(name)";
 
 SELECT CAST(f1 AS varchar) AS "varchar(text)" FROM TEXT_TBL;
+SELECT CAST(f1 AS nvarchar) AS "nvarchar(text)" FROM TEXT_TBL;
 
 SELECT CAST(f1 AS varchar) AS "varchar(char)" FROM CHAR_TBL;
+SELECT CAST(f1 AS nvarchar) AS "nvarchar(nchar)" FROM NCHAR_TBL;
 
 SELECT CAST(name 'namefield' AS varchar) AS "varchar(name)";
+SELECT CAST(name 'namefield' AS nvarchar) AS "nvarchar(name)";
 
 --
 -- test SQL string functions
 -- E### and T### are feature reference numbers from SQL99
 --
@@ -328,14 +339,17 @@
 SELECT 'unknown' || ' and unknown' AS "Concat unknown types";
 
 SELECT text 'text' || ' and unknown' AS "Concat text to unknown type";
 
 SELECT char(20) 'characters' || ' and text' AS "Concat char to unknown type";
+SELECT nchar(20) 'ncharacters' || ' and text' AS "Concat nchar to unknown type";
 
 SELECT text 'text' || char(20) ' and characters' AS "Concat text to char";
+SELECT text 'text' || nchar(20) ' and ncharacters' AS "Concat text to nchar";
 
 SELECT text 'text' || varchar ' and varchar' AS "Concat text to varchar";
+SELECT text 'text' || nvarchar ' and nvarchar' AS "Concat text to nvarchar";
 
 --
 -- test substr with toasted text values
 --
 CREATE TABLE toasttest(f1 text);
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/sql/union.sql ./src/test/regress/sql/union.sql
--- ../orig.HEAD/src/test/regress/sql/union.sql	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/sql/union.sql	2013-08-19 20:54:00.000000000 -0400
@@ -87,10 +87,27 @@
 SELECT f1 FROM VARCHAR_TBL
 UNION
 SELECT TRIM(TRAILING FROM f1) FROM CHAR_TBL
 ORDER BY 1;
 
+--NVARCHAR specific
+SELECT f1 AS three FROM NVARCHAR_TBL
+UNION
+SELECT CAST(f1 AS nvarchar) FROM NCHAR_TBL
+ORDER BY 1;
+
+SELECT f1 AS eight FROM NVARCHAR_TBL
+UNION ALL
+SELECT f1 FROM NCHAR_TBL;
+
+SELECT f1 AS five FROM TEXT_TBL
+UNION
+SELECT f1 FROM NVARCHAR_TBL
+UNION
+SELECT TRIM(TRAILING FROM f1) FROM NCHAR_TBL
+ORDER BY 1;
+
 --
 -- INTERSECT and EXCEPT
 --
 
 SELECT q2 FROM int8_tbl INTERSECT SELECT q1 FROM int8_tbl;
diff -U 5 -N -r -w ../orig.HEAD/src/test/regress/sql/update.sql ./src/test/regress/sql/update.sql
--- ../orig.HEAD/src/test/regress/sql/update.sql	2013-08-19 20:22:15.000000000 -0400
+++ ./src/test/regress/sql/update.sql	2013-08-19 20:54:00.000000000 -0400
@@ -3,18 +3,32 @@
 --
 
 CREATE TABLE update_test (
     a   INT DEFAULT 10,
     b   INT,
-    c   TEXT
+    c   TEXT,
+    d   nchar(10),
+    e   nvarchar
 );
 
-INSERT INTO update_test VALUES (5, 10, 'foo');
+INSERT INTO update_test VALUES (5, 10, 'foo', 'a', 'a');
 INSERT INTO update_test(b, a) VALUES (15, 10);
 
 SELECT * FROM update_test;
 
+UPDATE update_test SET d='b', e='b';
+
+SELECT * FROM update_test;
+
+UPDATE update_test SET d='c' where e='b';
+
+SELECT * FROM update_test;
+
+UPDATE update_test SET d=N'e' where e=N'b';
+
+SELECT * FROM update_test;
+
 UPDATE update_test SET a = DEFAULT, b = DEFAULT;
 
 SELECT * FROM update_test;
 
 -- aliases for the UPDATE target table


view thread (62+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected]
  Subject: Re: UTF8 national character data type support WIP patch and list of open issues.
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox