public inbox for [email protected]  
help / color / mirror / Atom feed
From: Arulappan, Arul Shaji <[email protected]>
To: MauMau <[email protected]>
To: Greg Stark <[email protected]>
Cc: Peter Eisentraut <[email protected]>
Cc: Robert Haas <[email protected]>
Cc: Tatsuo Ishii <[email protected]>
Cc: Tom Lane <[email protected]>
Cc: Boguk, Maksym <[email protected]>
Cc: Heikki Linnakangas <[email protected]>
Cc: PostgreSQL-development <[email protected]>
Subject: Re: UTF8 national character data type support WIP patch and list of open issues.
Date: Tue, 5 Nov 2013 17:04:07 +1100
Message-ID: <[email protected]> (raw)
In-Reply-To: <7C2A735AFC3E4088A8F49B677855369C@maumau>
References: <CA+TgmobWv_96dSfSHv2ZJWSXAD=QTiBEKw-LT359sGArYe+AXQ@mail.gmail.com>
	<[email protected]>
	<CA+TgmoZEy=pt2B5D+nuPAib7KvhNoBgRGYRWnkS4pyrqfcdYHQ@mail.gmail.com>
	<[email protected]>
	<D0A2FE73E8354EDCBEE56EC79268CA4E@maumau>
	<[email protected]>
	<7DCFAE8265254605840917B35EEF09F1@maumau>
	<CAM-w4HMRCTyemtmKDJPHL72dXH1Gr6q5JrkCNnE63RXLn02Tjw@mail.gmail.com>
	<7C2A735AFC3E4088A8F49B677855369C@maumau>
List-Unsubscribe: <mailto:[email protected]?body=unsub%20pgsql-hackers>

Attached is a patch that implements the first set of changes discussed
in this thread originally. They are:

(i) Implements NCHAR/NVARCHAR as distinct data types, not as synonyms so
that:
	- psql \d can display the user-specified data types.
	- pg_dump/pg_dumpall can output NCHAR/NVARCHAR columns as-is,
not as CHAR/VARCHAR.
	- Groundwork to implement additional features for NCHAR/NVARCHAR
in the future (For eg: separate encoding for nchar columns).
(ii) Support for NCHAR/NVARCHAR in ECPG
(iii) Documentation changes to reflect the new data type 


Rgds,
Arul Shaji




>-----Original Message-----
>From: [email protected] [mailto:pgsql-hackers-
>[email protected]] On Behalf Of MauMau
>
>From: "Greg Stark" <[email protected]>
>> If it's not lossy then what's the point? From the client's point of
>> view it'll be functionally equivalent to text then.
>
>Sorry, what Tatsuo san suggested meant was "same or compatible", not
lossy.
>I quote the relevant part below.  This is enough for the use case I
mentioned
>in my previous mail several hours ago (actually, that is what Oracle
manual
>describes...).
>
>http://www.postgresql.org/message-id/20130920.085853.162891705483086415
1.t-
>[email protected]
>
>[Excerpt]
>----------------------------------------
>What about limiting to use NCHAR with a database which has same
encoding or
>"compatible" encoding (on which the encoding conversion is defined)?
This way,
>NCHAR text can be automatically converted from NCHAR to the database
encoding
>in the server side thus we can treat NCHAR exactly same as CHAR
afterward.  I
>suppose what encoding is used for NCHAR should be defined in initdb
time or
>creation of the database (if we allow this, we need to add a new column
to know
>what encoding is used for NCHAR).
>
>For example, "CREATE TABLE t1(t NCHAR(10))" will succeed if NCHAR is
>UTF-8 and database encoding is UTF-8. Even succeed if NCHAR is
SHIFT-JIS and
>database encoding is UTF-8 because there is a conversion between UTF-8
and
>SHIFT-JIS. However will not succeed if NCHAR is SHIFT-JIS and database
encoding
>is ISO-8859-1 because there's no conversion between them.
>----------------------------------------
>
>
>Regards
>MauMau
>
>
>
>--
>Sent via pgsql-hackers mailing list ([email protected]) To
make
>changes to your subscription:
>http://www.postgresql.org/mailpref/pgsql-hackers



-- 
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_nchar_v1.patch (191.9K, ../[email protected]/2-PGHEAD_nchar_v1.patch)
  download | inline diff:
diff -uNr postgresql-head-20131017/doc/src/sgml/datatype.sgml postgresql-head-20131017-nchar/doc/src/sgml/datatype.sgml
--- postgresql-head-20131017/doc/src/sgml/datatype.sgml	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/doc/src/sgml/datatype.sgml	2013-10-22 16:12:19.000000000 +1100
@@ -161,6 +161,18 @@
       </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>,
@@ -1014,6 +1026,14 @@
         <entry><type>text</type></entry>
         <entry>variable unlimited length</entry>
        </row>
+       <row>
+        <entry><type>national character varying(<replaceable>n</>)</type>, <type>nvarchar(<replaceable>n</>)</type></entry>
+        <entry>variable-length national character string</entry>
+       </row>
+       <row>
+        <entry><type>national character(<replaceable>n</>)</type>, <type>nchar(<replaceable>n</>)</type></entry>
+        <entry>fixed-length national character string</entry>
+       </row>
      </tbody>
      </tgroup>
     </table>
@@ -1040,7 +1060,15 @@
     shorter
     string.
    </para>
-
+   <para>
+    The data types <type>national character(<replaceable>n</>)</type> and 
+    <type>national character varying(<replaceable>n</>)</type> can be 
+    used to store data in a specific encoding. Currently the encoding for 
+    <type>national character</type> and <type>national character varying</type> 
+    data types are limited to the database encoding. As a result, declaring a 
+    column as <type>national character</type> is equivalent to declaring 
+    the column as <type>character</type>.
+   </para>
    <para>
     If one explicitly casts a value to <type>character
     varying(<replaceable>n</>)</type> or
@@ -1060,6 +1088,15 @@
     without length specifier, the type accepts strings of any size. The
     latter is a <productname>PostgreSQL</> extension.
    </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.
+   </para>
 
    <para>
     In addition, <productname>PostgreSQL</productname> provides the
@@ -1070,50 +1107,53 @@
    </para>
 
    <para>
-    Values of type <type>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
+    Values of types <type>character</type> and <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>character</type>,
-    and they will be removed when converting a <type>character</type> value
+    disregarded when comparing two values of type <type>character</type> or
+    <type>national character</type>, and they will be removed when converting 
+    a <type>character</type> or <type>national character</type> value
     to one of the other string types.  Note that trailing spaces
     <emphasis>are</> semantically significant in
-    <type>character varying</type> and <type>text</type> values, and
-    when using pattern matching, e.g. <literal>LIKE</>,
+    <type>character varying</type>,<type>national character varying</type>
+    and <type>text</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>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
+    <type>character</type> or <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>character varying</type> without a length
+    <type>text</type> or <type>character varying</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 three types,
+     There is no performance difference among these five 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>character(<replaceable>n</>)</type> has performance
-     advantages in some other database systems, there is no such advantage in
-     <productname>PostgreSQL</productname>; in fact
-     <type>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>character varying</type> should be used
-     instead.
+     <type>character(<replaceable>n</>)</type> and <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>character(<replaceable>n</>)</type> and <type>national character
+     (<replaceable>n</>)</type> are usually the slowest of
+     the five because of its additional storage costs.  In most situations
+     <type>text</type> or <type>character varying</type> or
+     <type>national character varying</type> should be used instead.
     </para>
    </tip>
 
@@ -1153,6 +1193,31 @@
  good  |           5
  too l |           5
 </computeroutput>
+
+CREATE TABLE test3 (a national character(4));
+INSERT INTO test3 VALUES (N'ok');
+SELECT a, char_length(a) FROM test3;
+<computeroutput>
+  a   | char_length
+------+-------------
+ ok   |           2
+</computeroutput>
+
+CREATE TABLE test4 (b nvarchar(5));
+INSERT INTO test4 VALUES (N'ok');
+INSERT INTO test4 VALUES (N'good      ');
+INSERT INTO test4 VALUES (N'too long');
+<computeroutput>ERROR:  value too long for type character varying(5)</computeroutput>
+INSERT INTO test4 VALUES ('too long'::nvarchar(5)); -- explicit truncation
+SELECT b, char_length(b) FROM test4;
+<computeroutput>
+   b   | char_length
+-------+-------------
+ ok    |           2
+ good  |           5
+ too l |           5
+</computeroutput>
+
 </programlisting>
     <calloutlist>
      <callout arearefs="co.datatype-char">
@@ -4692,5 +4757,4 @@
    </para>
 
   </sect1>
-
  </chapter>
diff -uNr postgresql-head-20131017/doc/src/sgml/ecpg.sgml postgresql-head-20131017-nchar/doc/src/sgml/ecpg.sgml
--- postgresql-head-20131017/doc/src/sgml/ecpg.sgml	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/doc/src/sgml/ecpg.sgml	2013-10-22 16:03:40.000000000 +1100
@@ -890,6 +890,12 @@
        <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>
+      
      </tbody>
     </tgroup>
    </table>
@@ -968,6 +974,81 @@
     </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 similar to VARCHAR type 
+     and added mainly for SQL standard compatibility.
+    </para>
+   </sect3>
+
    <sect3 id="ecpg-special-types">
     <title>Accessing Special Data Types</title>
 
diff -uNr postgresql-head-20131017/doc/src/sgml/syntax.sgml postgresql-head-20131017-nchar/doc/src/sgml/syntax.sgml
--- postgresql-head-20131017/doc/src/sgml/syntax.sgml	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/doc/src/sgml/syntax.sgml	2013-10-22 15:53:09.000000000 +1100
@@ -553,6 +553,32 @@
     </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.
+    
+    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>
 
diff -uNr postgresql-head-20131017/src/backend/catalog/information_schema.sql postgresql-head-20131017-nchar/src/backend/catalog/information_schema.sql
--- postgresql-head-20131017/src/backend/catalog/information_schema.sql	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/backend/catalog/information_schema.sql	2013-10-17 11:56:22.000000000 +1100
@@ -79,7 +79,7 @@
 $$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
@@ -92,7 +92,7 @@
     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) *
diff -uNr postgresql-head-20131017/src/backend/optimizer/path/indxpath.c postgresql-head-20131017-nchar/src/backend/optimizer/path/indxpath.c
--- postgresql-head-20131017/src/backend/optimizer/path/indxpath.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/backend/optimizer/path/indxpath.c	2013-10-31 10:58:24.000000000 +1100
@@ -4003,6 +4003,8 @@
 		case TEXTOID:
 		case VARCHAROID:
 		case BPCHAROID:
+		case NVARCHAROID:
+		case NBPCHAROID:
 			collation = DEFAULT_COLLATION_OID;
 			constlen = -1;
 			break;
diff -uNr postgresql-head-20131017/src/backend/parser/gram.y postgresql-head-20131017-nchar/src/backend/parser/gram.y
--- postgresql-head-20131017/src/backend/parser/gram.y	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/backend/parser/gram.y	2013-11-04 10:57:47.000000000 +1100
@@ -63,6 +63,7 @@
 #include "utils/datetime.h"
 #include "utils/numeric.h"
 #include "utils/xml.h"
+#include "mb/pg_wchar.h"
 
 
 /*
@@ -442,9 +443,11 @@
 				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
@@ -564,7 +567,7 @@
 
 	NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NONE
 	NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF
-	NULLS_P NUMERIC
+	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
@@ -10302,6 +10305,14 @@
 				{
 					$$ = $1;
 				}
+			| NCharacterWithLength
+				{
+					$$ = $1;
+				}
+			| NCharacterWithoutLength
+				{
+					$$ = $1;
+				}
 		;
 
 ConstCharacter:  CharacterWithLength
@@ -10319,6 +10330,68 @@
 					$$ = $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;
+				}
+		;
+
+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
@@ -10339,8 +10412,8 @@
 
 					$$ = 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;
@@ -10353,12 +10426,10 @@
 										{ $$ = $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:
@@ -12748,6 +12819,7 @@
 			| NONE
 			| NULLIF
 			| NUMERIC
+			| NVARCHAR
 			| OUT_P
 			| OVERLAY
 			| POSITION
diff -uNr postgresql-head-20131017/src/backend/parser/scan.l postgresql-head-20131017-nchar/src/backend/parser/scan.l
--- postgresql-head-20131017/src/backend/parser/scan.l	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/backend/parser/scan.l	2013-10-17 11:56:22.000000000 +1100
@@ -482,7 +482,7 @@
 					SET_YYLLOC();
 					yyless(1);				/* eat only 'n' this time */
 
-					keyword = ScanKeywordLookup("nchar",
+					keyword = ScanKeywordLookup("nvarchar",
 												yyextra->keywords,
 												yyextra->num_keywords);
 					if (keyword != NULL)
diff -uNr postgresql-head-20131017/src/backend/utils/adt/Makefile postgresql-head-20131017-nchar/src/backend/utils/adt/Makefile
--- postgresql-head-20131017/src/backend/utils/adt/Makefile	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/backend/utils/adt/Makefile	2013-10-25 14:53:38.000000000 +1100
@@ -20,7 +20,7 @@
 	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 \
diff -uNr postgresql-head-20131017/src/backend/utils/adt/format_type.c postgresql-head-20131017-nchar/src/backend/utils/adt/format_type.c
--- postgresql-head-20131017/src/backend/utils/adt/format_type.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/backend/utils/adt/format_type.c	2013-10-31 11:01:17.000000000 +1100
@@ -218,6 +218,17 @@
 				buf = pstrdup("character");
 			break;
 
+		case NBPCHAROID:
+			if (with_typemod)
+				buf = printTypmod("national character", typemod, typeform->typmodout);
+			else if (typemod_given)
+			{
+				/* See the comment for BPCHAR above */
+			}
+			else
+				buf = pstrdup("national character");
+			break;
+
 		case FLOAT4OID:
 			buf = pstrdup("real");
 			break;
@@ -293,6 +304,13 @@
 			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)
@@ -384,6 +402,8 @@
 	{
 		case BPCHAROID:
 		case VARCHAROID:
+		case NBPCHAROID:
+		case NVARCHAROID:
 			/* typemod includes varlena header */
 
 			/* typemod is in characters not bytes */
diff -uNr postgresql-head-20131017/src/backend/utils/adt/nvarchar.c postgresql-head-20131017-nchar/src/backend/utils/adt/nvarchar.c
--- postgresql-head-20131017/src/backend/utils/adt/nvarchar.c	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/backend/utils/adt/nvarchar.c	2013-10-30 14:32:02.000000000 +1100
@@ -0,0 +1,48 @@
+/*-------------------------------------------------------------------------
+ *
+ * varchar.c
+ *	  Functions for the built-in types nchar(n) and nvarchar(n).
+ *
+ * Portions Copyright (c) 1996-2013, 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"
+
+
+/*
+ * actually just UTF8 stubs copied form char/varchar
+ */
+
+Datum
+nbpcharoctetlen(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);
+}
+
+Datum
+nvarcharoctetlen(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);
+}
+
diff -uNr postgresql-head-20131017/src/backend/utils/adt/selfuncs.c postgresql-head-20131017-nchar/src/backend/utils/adt/selfuncs.c
--- postgresql-head-20131017/src/backend/utils/adt/selfuncs.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/backend/utils/adt/selfuncs.c	2013-10-17 11:56:22.000000000 +1100
@@ -3626,7 +3626,9 @@
 			 */
 		case CHAROID:
 		case BPCHAROID:
+		case NBPCHAROID:
 		case VARCHAROID:
+		case NVARCHAROID:
 		case TEXTOID:
 		case NAMEOID:
 			{
@@ -3888,7 +3890,9 @@
 			val[1] = '\0';
 			break;
 		case BPCHAROID:
+		case NBPCHAROID:
 		case VARCHAROID:
+		case NVARCHAROID:
 		case TEXTOID:
 			val = TextDatumGetCString(value);
 			break;
@@ -5875,7 +5879,9 @@
 	{
 		case TEXTOID:
 		case VARCHAROID:
+		case NVARCHAROID:
 		case BPCHAROID:
+		case NBPCHAROID:
 			collation = DEFAULT_COLLATION_OID;
 			constlen = -1;
 			break;
diff -uNr postgresql-head-20131017/src/include/catalog/pg_amop.h postgresql-head-20131017-nchar/src/include/catalog/pg_amop.h
--- postgresql-head-20131017/src/include/catalog/pg_amop.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/include/catalog/pg_amop.h	2013-10-30 14:44:44.000000000 +1100
@@ -253,6 +253,12 @@
 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
  */
@@ -518,6 +524,10 @@
 
 /* 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 */
diff -uNr postgresql-head-20131017/src/include/catalog/pg_amproc.h postgresql-head-20131017-nchar/src/include/catalog/pg_amproc.h
--- postgresql-head-20131017/src/include/catalog/pg_amproc.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/include/catalog/pg_amproc.h	2013-10-30 14:43:25.000000000 +1100
@@ -80,6 +80,7 @@
 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 ));
@@ -129,6 +130,7 @@
 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 ));
@@ -139,6 +141,7 @@
 
 /* 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 ));
@@ -168,6 +171,7 @@
 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 -uNr postgresql-head-20131017/src/include/catalog/pg_cast.h postgresql-head-20131017-nchar/src/include/catalog/pg_cast.h
--- postgresql-head-20131017/src/include/catalog/pg_cast.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/include/catalog/pg_cast.h	2013-10-30 15:14:09.000000000 +1100
@@ -220,6 +220,20 @@
 DATA(insert ( 1042 1043  401 i f ));
 DATA(insert ( 1043	 25    0 i b ));
 DATA(insert ( 1043 1042    0 i b ));
+DATA(insert (	25 5001    0 i b ));
+DATA(insert (	25 6001    0 i b ));
+DATA(insert ( 5001	 25  401 i f ));
+DATA(insert ( 6001	 25    0 i b ));
+DATA(insert ( 1042 5001    0 a b ));
+DATA(insert ( 1042 6001  401 i f ));
+DATA(insert ( 5001 1042    0 i b ));
+DATA(insert ( 6001 1042    0 i b ));
+DATA(insert ( 1043 5001    0 i b ));
+DATA(insert ( 1043 6001    0 i b ));
+DATA(insert ( 5001 1043  401 i f ));
+DATA(insert ( 6001 1043    0 i b ));
+DATA(insert ( 5001 6001  401 i f ));
+DATA(insert ( 6001 5001    0 i b ));
 DATA(insert (	18	 25  946 i f ));
 DATA(insert (	18 1042  860 a f ));
 DATA(insert (	18 1043  946 a f ));
@@ -358,5 +372,7 @@
 DATA(insert ( 1560 1560 1685 i f ));
 DATA(insert ( 1562 1562 1687 i f ));
 DATA(insert ( 1700 1700 1703 i f ));
+DATA(insert ( 5001 5001 5668 i f ));
+DATA(insert ( 6001 6001 5669 i f ));
 
 #endif   /* PG_CAST_H */
diff -uNr postgresql-head-20131017/src/include/catalog/pg_opclass.h postgresql-head-20131017-nchar/src/include/catalog/pg_opclass.h
--- postgresql-head-20131017/src/include/catalog/pg_opclass.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/include/catalog/pg_opclass.h	2013-10-17 11:56:22.000000000 +1100
@@ -97,6 +97,8 @@
 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 ));
@@ -157,6 +159,8 @@
 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 ));
@@ -188,6 +192,7 @@
 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 ));
@@ -208,6 +213,7 @@
 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 ));
diff -uNr postgresql-head-20131017/src/include/catalog/pg_operator.h postgresql-head-20131017-nchar/src/include/catalog/pg_operator.h
--- postgresql-head-20131017/src/include/catalog/pg_operator.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/include/catalog/pg_operator.h	2013-10-31 11:11:29.000000000 +1100
@@ -1751,7 +1751,46 @@
 DATA(insert OID = 3967 (  "#>>"    PGNSP PGUID b f f 114 1009 25 0 0 json_extract_path_text_op - - ));
 DESCR("get value from json as text with path elements");
 
+DATA(insert OID = 5054 ( "="	   PGNSP PGUID b t t 5001 5001 16 5054 5057 nbpchareq eqsel eqjoinsel ));
+DESCR("equal");
+DATA(insert OID = 5055 ( "~"	   PGNSP PGUID b f f 5001 25 16    0 5056 nbpcharregexeq regexeqsel regexeqjoinsel ));
+DESCR("matches 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 = 5057 ( "<>"	   PGNSP PGUID b f f 5001 5001 16 5057 5054 nbpcharne neqsel neqjoinsel ));
+DESCR("not equal");
+DATA(insert OID = 5058 ( "<"	   PGNSP PGUID b f f 5001 5001 16 5060 5061 nbpcharlt scalarltsel scalarltjoinsel ));
+DESCR("less than");
+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 = 5060 ( ">"	   PGNSP PGUID b f f 5001 5001 16 5058 5059 nbpchargt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+DATA(insert OID = 5061 ( ">="	   PGNSP PGUID b f f 5001 5001 16 5059 5058 nbpcharge scalargtsel scalargtjoinsel ));
+DESCR("greater than or equal");
 
+DATA(insert OID = 5211 (  "~~"	   PGNSP PGUID b f f  5001 25 16 0 5212 nbpcharlike likesel likejoinsel ));
+DESCR("matches 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");
+
+DATA(insert OID = 5234 (  "~*"	   PGNSP PGUID b f f  5001 25 16 0 5235 nbpcharicregexeq icregexeqsel icregexeqjoinsel ));
+DESCR("matches 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");
+
+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 = 5327 ( "~<=~" PGNSP PGUID b f f 5001 5001 16 5329 5330 nbpchar_pattern_le scalarltsel scalarltjoinsel ));
+DESCR("less 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 = 5330 ( "~>~"  PGNSP PGUID b f f 5001 5001 16 5326 5327 nbpchar_pattern_gt scalargtsel scalargtjoinsel ));
+DESCR("greater than");
+
+DATA(insert OID = 5629 (  "~~*"	   PGNSP PGUID b f f  5001 25 16 0 5630 nbpchariclike iclikesel iclikejoinsel ));
+DESCR("matches 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");
 
 /*
  * function prototypes
diff -uNr postgresql-head-20131017/src/include/catalog/pg_proc.h postgresql-head-20131017-nchar/src/include/catalog/pg_proc.h
--- postgresql-head-20131017/src/include/catalog/pg_proc.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/include/catalog/pg_proc.h	2013-10-31 11:57:16.000000000 +1100
@@ -4741,6 +4741,82 @@
 /* event triggers */
 DATA(insert OID = 3566 (  pg_event_trigger_dropped_objects		PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,25,25,25,25}" "{o,o,o,o,o,o,o}" "{classid, objid, objsubid, object_type, schema_name, object_name, object_identity}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
 DESCR("list objects dropped by the current command");
+
+DATA(insert OID = 5044 (  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 = 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_ varcharin _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_ varcharout _null_ _null_ _null_ ));
+DESCR("I/O");
+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 = 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 = 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 = 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 = 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_ nbpcharoctetlen _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_ nvarcharoctetlen _null_ _null_ _null_ ));
+DESCR("octet length");
+
+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 = 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 = 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 = 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 = 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_ ));
+
+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 = 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 = 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 = 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");
+
 /*
  * Symbolic values for provolatile column: these indicate whether the result
  * of a function is dependent *only* on the values of its explicit arguments,
diff -uNr postgresql-head-20131017/src/include/catalog/pg_type.h postgresql-head-20131017-nchar/src/include/catalog/pg_type.h
--- postgresql-head-20131017/src/include/catalog/pg_type.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/include/catalog/pg_type.h	2013-10-30 16:07:44.000000000 +1100
@@ -669,6 +669,16 @@
 DATA(insert OID = 3831 ( anyrange		PGNSP PGUID  -1 f p P f t \054 0 0 0 anyrange_in anyrange_out - - - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
 #define ANYRANGEOID		3831
 
+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 = 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_ ));
+
+/* national character types */
+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 = 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
 
 /*
  * macros
diff -uNr postgresql-head-20131017/src/include/parser/kwlist.h postgresql-head-20131017-nchar/src/include/parser/kwlist.h
--- postgresql-head-20131017/src/include/parser/kwlist.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/include/parser/kwlist.h	2013-10-17 11:56:22.000000000 +1100
@@ -257,6 +257,7 @@
 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)
diff -uNr postgresql-head-20131017/src/include/utils/builtins.h postgresql-head-20131017-nchar/src/include/utils/builtins.h
--- postgresql-head-20131017/src/include/utils/builtins.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/include/utils/builtins.h	2013-10-17 11:56:22.000000000 +1100
@@ -326,6 +326,10 @@
 extern Datum btoidsortsupport(PG_FUNCTION_ARGS);
 extern Datum btnamesortsupport(PG_FUNCTION_ARGS);
 
+/* nvarchar.c */
+extern Datum nbpcharoctetlen(PG_FUNCTION_ARGS);
+extern Datum nvarcharoctetlen(PG_FUNCTION_ARGS);
+
 /* float.c */
 extern PGDLLIMPORT int extra_float_digits;
 
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/ecpglib/data.c postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/data.c
--- postgresql-head-20131017/src/interfaces/ecpg/ecpglib/data.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/data.c	2013-10-17 11:56:22.000000000 +1100
@@ -227,8 +227,10 @@
 		switch (type)
 		{
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_varchar:
+			case ECPGt_nvarchar:
 			case ECPGt_string:
 				break;
 
@@ -450,6 +452,7 @@
 					break;
 
 				case ECPGt_char:
+				case ECPGt_nchar:
 				case ECPGt_unsigned_char:
 				case ECPGt_string:
 					{
@@ -508,6 +511,7 @@
 					break;
 
 				case ECPGt_varchar:
+				case ECPGt_nvarchar:
 					{
 						struct ECPGgeneric_varchar *variable =
 						(struct ECPGgeneric_varchar *) (var + offset * act_tuple);
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/ecpglib/descriptor.c postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/descriptor.c
--- postgresql-head-20131017/src/interfaces/ecpg/ecpglib/descriptor.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/descriptor.c	2013-10-17 11:56:22.000000000 +1100
@@ -200,11 +200,13 @@
 	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;
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/ecpglib/execute.c postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/execute.c
--- postgresql-head-20131017/src/interfaces/ecpg/ecpglib/execute.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/execute.c	2013-10-31 10:35:42.000000000 +1100
@@ -248,6 +248,10 @@
 			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), NBPCHAROID, 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))
@@ -362,6 +366,7 @@
 			switch (var->type)
 			{
 				case ECPGt_char:
+				case ECPGt_nchar:
 				case ECPGt_unsigned_char:
 				case ECPGt_string:
 					if (!var->varcharsize && !var->arrsize)
@@ -388,6 +393,7 @@
 					}
 					break;
 				case ECPGt_varchar:
+				case ECPGt_nvarchar:
 					len = ntuples * (var->varcharsize + sizeof(int));
 					break;
 				default:
@@ -423,7 +429,7 @@
 
 	/* 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 */
 
@@ -793,6 +799,7 @@
 				break;
 
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_string:
 				{
@@ -827,6 +834,7 @@
 				}
 				break;
 			case ECPGt_varchar:
+			case ECPGt_nvarchar:
 				{
 					struct ECPGgeneric_varchar *variable =
 					(struct ECPGgeneric_varchar *) (var->value);
@@ -1232,6 +1240,8 @@
 						{
 							case ECPGt_char:
 							case ECPGt_varchar:
+							case ECPGt_nchar:
+							case ECPGt_nvarchar:
 								desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
 								break;
 							default:
@@ -1287,6 +1297,8 @@
 						{
 							case ECPGt_char:
 							case ECPGt_varchar:
+							case ECPGt_nchar:
+							case ECPGt_nvarchar:
 								desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
 								break;
 							default:
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/ecpglib/misc.c postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/misc.c
--- postgresql-head-20131017/src/interfaces/ecpg/ecpglib/misc.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/misc.c	2013-10-31 10:33:33.000000000 +1100
@@ -305,6 +305,7 @@
 	switch (type)
 	{
 		case ECPGt_char:
+		case ECPGt_nchar:
 		case ECPGt_unsigned_char:
 		case ECPGt_string:
 			*((char *) ptr) = '\0';
@@ -335,6 +336,7 @@
 			memset((char *) ptr, 0xff, sizeof(double));
 			break;
 		case ECPGt_varchar:
+		case ECPGt_nvarchar:
 			*(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
 			((struct ECPGgeneric_varchar *) ptr)->len = 0;
 			break;
@@ -408,6 +410,7 @@
 			return (_check(ptr, sizeof(double)));
 			break;
 		case ECPGt_varchar:
+		case ECPGt_nvarchar:
 			if (*(((struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
 				return true;
 			break;
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/ecpglib/pg_type.h postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/pg_type.h
--- postgresql-head-20131017/src/interfaces/ecpg/ecpglib/pg_type.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/pg_type.h	2013-10-25 15:06:05.000000000 +1100
@@ -57,5 +57,7 @@
 #define ZPBITOID	 1560
 #define VARBITOID	  1562
 #define NUMERICOID		1700
+#define NBPCHAROID		5001
+#define NVARCHAROID		6001
 
 #endif   /* PG_TYPE_H */
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/ecpglib/sqlda.c postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/sqlda.c
--- postgresql-head-20131017/src/interfaces/ecpg/ecpglib/sqlda.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/sqlda.c	2013-10-17 11:56:22.000000000 +1100
@@ -134,6 +134,7 @@
 				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:
@@ -373,6 +374,7 @@
 				sqlda->sqlvar[i].sqllen = sizeof(interval);
 				break;
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_string:
 			default:
@@ -562,6 +564,7 @@
 				sqlda->sqlvar[i].sqllen = sizeof(interval);
 				break;
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_string:
 			default:
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/ecpglib/typename.c postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/typename.c
--- postgresql-head-20131017/src/interfaces/ecpg/ecpglib/typename.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/ecpglib/typename.c	2013-10-31 10:39:30.000000000 +1100
@@ -62,6 +62,10 @@
 			return "interval";
 		case ECPGt_const:
 			return "Const";
+		case ECPGt_nchar:
+			return "national char";
+		case ECPGt_nvarchar:
+			return "nvarchar";
 		default:
 			abort();
 	}
@@ -89,6 +93,10 @@
 			return SQL3_CHARACTER;		/* bpchar */
 		case VARCHAROID:
 			return SQL3_CHARACTER_VARYING;		/* varchar */
+		case NBPCHAROID:
+			return SQL3_CHARACTER;		/* bpchar */
+		case NVARCHAROID:
+			return SQL3_CHARACTER_VARYING;		/* nvarchar */
 		case DATEOID:
 			return SQL3_DATE_TIME_TIMESTAMP;	/* date */
 		case TIMEOID:
@@ -110,6 +118,8 @@
 		case CHAROID:
 		case VARCHAROID:
 		case BPCHAROID:
+		case NVARCHAROID:
+		case NBPCHAROID:
 		case TEXTOID:
 			return ECPGt_char;
 		case INT2OID:
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/include/ecpgtype.h postgresql-head-20131017-nchar/src/interfaces/ecpg/include/ecpgtype.h
--- postgresql-head-20131017/src/interfaces/ecpg/include/ecpgtype.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/include/ecpgtype.h	2013-10-31 10:40:06.000000000 +1100
@@ -63,7 +63,9 @@
 	ECPGt_EORT,					/* End of result types. */
 	ECPGt_NO_INDICATOR,			/* no indicator */
 	ECPGt_string,				/* trimmed (char *) type */
-	ECPGt_sqlda					/* C struct descriptor */
+	ECPGt_sqlda,					/* C struct descriptor */
+	ECPGt_nvarchar,				/* the same as ECPGt_varchar actually */
+	ECPGt_nchar					/* converted to char *arr[N] */
 };
 
  /* descriptor items */
@@ -88,7 +90,7 @@
 	ECPGd_cardinality
 };
 
-#define IS_SIMPLE_TYPE(type) (((type) >= ECPGt_char && (type) <= ECPGt_interval) || ((type) == ECPGt_string))
+#define IS_SIMPLE_TYPE(type) (((type) >= ECPGt_char && (type) <= ECPGt_interval) || ((type) == ECPGt_string) || ((type) == ECPGt_nvarchar) || ((type) == ECPGt_nchar))
 
 /* we also have to handle different statement types */
 enum ECPG_statement_type
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/include/sqltypes.h postgresql-head-20131017-nchar/src/interfaces/ecpg/include/sqltypes.h
--- postgresql-head-20131017/src/interfaces/ecpg/include/sqltypes.h	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/include/sqltypes.h	2013-10-17 11:56:22.000000000 +1100
@@ -46,6 +46,7 @@
 #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
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/preproc/c_keywords.c postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/c_keywords.c
--- postgresql-head-20131017/src/interfaces/ecpg/preproc/c_keywords.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/c_keywords.c	2013-10-17 11:56:22.000000000 +1100
@@ -27,6 +27,8 @@
 	 * 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},
@@ -40,6 +42,8 @@
 	{"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},
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/preproc/ecpg.header postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/ecpg.header
--- postgresql-head-20131017/src/interfaces/ecpg/preproc/ecpg.header	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/ecpg.header	2013-10-31 10:42:27.000000000 +1100
@@ -270,9 +270,11 @@
 			}
 			else if ((ptr->variable->type->type != ECPGt_varchar
 					  && ptr->variable->type->type != ECPGt_char
+					  && ptr->variable->type->type != ECPGt_nvarchar
+					  && 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)
+					  && atoi(ptr->variable->type->size) > 1)
 			{
 				newvar = new_variable(cat_str(4, mm_strdup("("),
 											  mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)),
@@ -286,6 +288,8 @@
 			}
 			else if ((ptr->variable->type->type == ECPGt_varchar
 					  || ptr->variable->type->type == ECPGt_char
+					  || ptr->variable->type->type == ECPGt_nvarchar
+					  || 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)
@@ -298,7 +302,7 @@
 														   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
@@ -545,6 +549,7 @@
 		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 &&
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/preproc/ecpg.trailer postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/ecpg.trailer
--- postgresql-head-20131017/src/interfaces/ecpg/preproc/ecpg.trailer	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/ecpg.trailer	2013-10-31 10:47:10.000000000 +1100
@@ -186,7 +186,7 @@
 				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);
@@ -211,11 +211,13 @@
 				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:
@@ -550,6 +552,22 @@
 				$$.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;
@@ -627,7 +645,7 @@
 				/* 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;
@@ -862,6 +880,7 @@
 					$$ = 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);
@@ -886,6 +905,25 @@
 					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:
@@ -1348,6 +1386,7 @@
 							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);
@@ -1356,6 +1395,7 @@
 						break;
 
 					case ECPGt_char:
+					case ECPGt_nchar:
 					case ECPGt_unsigned_char:
 					case ECPGt_string:
 						if (atoi(dimension) == -1)
@@ -1844,6 +1884,8 @@
 		| 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("="); }
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/preproc/type.c postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/type.c
--- postgresql-head-20131017/src/interfaces/ecpg/preproc/type.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/type.c	2013-10-17 11:56:22.000000000 +1100
@@ -137,6 +137,9 @@
 		case ECPGt_char:
 			return ("ECPGt_char");
 			break;
+		case ECPGt_nchar:
+			return ("ECPGt_nchar");
+			break;
 		case ECPGt_unsigned_char:
 			return ("ECPGt_unsigned_char");
 			break;
@@ -175,6 +178,8 @@
 			break;
 		case ECPGt_varchar:
 			return ("ECPGt_varchar");
+		case ECPGt_nvarchar:
+			return ("ECPGt_nvarchar");
 		case ECPGt_NO_INDICATOR:		/* no indicator */
 			return ("ECPGt_NO_INDICATOR");
 			break;
@@ -383,6 +388,7 @@
 				 * pointers
 				 */
 
+			case ECPGt_nvarchar:
 			case ECPGt_varchar:
 
 				/*
@@ -406,6 +412,7 @@
 					sprintf(offset, "sizeof(struct varchar)");
 				break;
 			case ECPGt_char:
+			case ECPGt_nchar:
 			case ECPGt_unsigned_char:
 			case ECPGt_char_variable:
 			case ECPGt_string:
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/preproc/variable.c postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/variable.c
--- postgresql-head-20131017/src/interfaces/ecpg/preproc/variable.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/preproc/variable.c	2013-10-17 11:56:22.000000000 +1100
@@ -529,7 +529,7 @@
 												"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))
@@ -554,6 +554,7 @@
 
 			break;
 		case ECPGt_varchar:
+		case ECPGt_nvarchar:
 			/* pointer has to get dimension 0 */
 			if (pointer_len)
 				*dimension = mm_strdup("0");
@@ -567,6 +568,7 @@
 
 			break;
 		case ECPGt_char:
+		case ECPGt_nchar:
 		case ECPGt_unsigned_char:
 		case ECPGt_string:
 			/* char ** */
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/ecpg_schedule postgresql-head-20131017-nchar/src/interfaces/ecpg/test/ecpg_schedule
--- postgresql-head-20131017/src/interfaces/ecpg/test/ecpg_schedule	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/ecpg_schedule	2013-10-17 11:56:22.000000000 +1100
@@ -47,8 +47,11 @@
 test: sql/show
 test: sql/insupd
 test: sql/parser
+test: sql/nchar
+test: sql/nvarchar
 test: thread/thread
 test: thread/thread_implicit
 test: thread/prep
 test: thread/alloc
 test: thread/descriptor
+
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/ecpg_schedule_tcp postgresql-head-20131017-nchar/src/interfaces/ecpg/test/ecpg_schedule_tcp
--- postgresql-head-20131017/src/interfaces/ecpg/test/ecpg_schedule_tcp	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/ecpg_schedule_tcp	2013-10-17 11:56:22.000000000 +1100
@@ -47,6 +47,8 @@
 test: sql/show
 test: sql/insupd
 test: sql/parser
+test: sql/nchar
+test: sql/nvarchar
 test: thread/thread
 test: thread/thread_implicit
 test: thread/prep
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c	2013-10-17 11:56:22.000000000 +1100
@@ -97,6 +97,7 @@
 #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
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/preproc-type.c postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/preproc-type.c
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/preproc-type.c	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/preproc-type.c	2013-10-31 14:18:52.000000000 +1100
@@ -82,6 +82,12 @@
   	 
 	 
    
+   
+  
+	 
+	 
+   
+
   
 #line 29 "type.pgc"
  struct TBempl empl ;
@@ -100,18 +106,30 @@
 #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 ;
 /* exec sql end declare section */
-#line 37 "type.pgc"
+#line 43 "type.pgc"
 
 
   /* exec sql var vc is [ 10 ] */
-#line 39 "type.pgc"
+#line 45 "type.pgc"
+
+  /* exec sql var nvc is [ 10 ] */
+#line 46 "type.pgc"
 
   ECPGdebug (1, stderr);
 
   empl.idnum = 1;
   { ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0); }
-#line 43 "type.pgc"
+#line 50 "type.pgc"
 
   if (sqlca.sqlcode)
     {
@@ -119,8 +137,8 @@
       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 ) )", ECPGt_EOIT, ECPGt_EORT);}
+#line 58 "type.pgc"
 
   if (sqlca.sqlcode)
     {
@@ -128,8 +146,8 @@
       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' )", ECPGt_EOIT, ECPGt_EORT);}
+#line 65 "type.pgc"
 
   if (sqlca.sqlcode)
     {
@@ -137,7 +155,7 @@
       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 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), 
@@ -151,18 +169,20 @@
 	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_EORT);}
-#line 68 "type.pgc"
+#line 75 "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'\n", empl.idnum, empl.name, empl.accs, str, ptr, vc.text, vc.len, nvc.text, nvc.len);
 
   { ECPGdisconnect(__LINE__, "CURRENT");}
-#line 76 "type.pgc"
+#line 83 "type.pgc"
 
 
   free(ptr);
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/preproc-type.stderr postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/preproc-type.stderr
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/preproc-type.stderr	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/preproc-type.stderr	2013-10-17 11:56:22.000000000 +1100
@@ -2,39 +2,41 @@
 [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 57: query: create table empl ( idnum integer , name char ( 20 ) , accs smallint , string1 char ( 10 ) , string2 char ( 10 ) , string3 char ( 10 ) , string4 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 57: 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 57: 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 65: query: insert into empl values ( 1 , 'user name' , 320 , 'first str' , 'second str' , 'third str' , 'fourth 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 65: 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 65: 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 72: query: select idnum , name , accs , string1 , string2 , string3 , string4 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 72: 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 72: 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 72: correctly got 1 tuples with 7 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 72: 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 72: 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 72: 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 72: 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 72: 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 72: 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 72: RESULT: third str  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 72: RESULT: fourth 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 -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/preproc-type.stdout postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/preproc-type.stdout
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/preproc-type.stdout	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/preproc-type.stdout	2013-10-17 11:56:22.000000000 +1100
@@ -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'
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nchar.c postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nchar.c
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nchar.c	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nchar.c	2013-10-31 15:08:18.000000000 +1100
@@ -0,0 +1,417 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "nchar.pgc"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 5 "nchar.pgc"
+
+
+int main() {
+	/* exec sql begin declare section */
+			
+			
+	
+#line 9 "nchar.pgc"
+ char nchar_var [ 40 ] ;
+ 
+#line 10 "nchar.pgc"
+ char count [ 10 ] ;
+/* exec sql end declare section */
+#line 11 "nchar.pgc"
+
+
+	ECPGdebug(1, stderr);
+	{ ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0); }
+#line 14 "nchar.pgc"
+
+
+	{ ECPGsetcommit(__LINE__, "on", NULL);}
+#line 16 "nchar.pgc"
+
+	/* exec sql whenever sql_warning  sqlprint ; */
+#line 17 "nchar.pgc"
+
+	/* exec sql whenever sqlerror  sqlprint ; */
+#line 18 "nchar.pgc"
+
+
+	/*initialization of test table*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table My_Table ( Item varchar , count integer )", ECPGt_EOIT, ECPGt_EORT);
+#line 21 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 21 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 21 "nchar.pgc"
+
+
+	/*reinitalization*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "truncate My_Table", ECPGt_EOIT, ECPGt_EORT);
+#line 24 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 24 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 24 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 'foo_item' , 1 )", ECPGt_EOIT, ECPGt_EORT);
+#line 25 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 25 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 25 "nchar.pgc"
+
+	/*simple select into NCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select Item from My_Table limit 1", ECPGt_EOIT, 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 27 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 27 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 27 "nchar.pgc"
+ 
+	printf ("Item='%s'\n", nchar_var);
+	/*simple select using NCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = $1 ", 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 30 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 30 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 30 "nchar.pgc"
+
+	printf ("count=%s for Item='%s'\n", count, nchar_var);
+	/*simple update using NCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "update My_Table set count = count + 1 where Item = $1 ", 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 33 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 33 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 33 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 34 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 34 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 34 "nchar.pgc"
+
+	printf ("count=%s for Item='foo_item'\n", count);
+	/*simple delete using NCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "delete from My_Table where Item = $1 ", 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 37 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 37 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 37 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 38 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 38 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 38 "nchar.pgc"
+
+	printf ("found %s rows for Item='foo_item'\n", count);
+	/*simple insert using NCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( $1  , 3 )", 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 41 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 41 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 41 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 42 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 42 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 42 "nchar.pgc"
+
+	printf ("count='%s' for Item='foo_item'\n", count);
+
+	/*prepared tests*/
+	/*reinitalization*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "truncate My_Table", ECPGt_EOIT, ECPGt_EORT);
+#line 47 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 47 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 47 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 'foo_item' , 1 )", ECPGt_EOIT, ECPGt_EORT);
+#line 48 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 48 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 48 "nchar.pgc"
+
+	/*prepared select into NCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "SELECT Item FROM My_Table LIMIT 1");
+#line 50 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 50 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 50 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", ECPGt_EOIT, 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 51 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 51 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 51 "nchar.pgc"
+
+	printf ("Item='%s'\n", nchar_var);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 53 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 53 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 53 "nchar.pgc"
+ 
+	/*prepared select using NCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "SELECT Count FROM My_Table WHERE Item=?");
+#line 55 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 55 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 55 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 56 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 56 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 56 "nchar.pgc"
+
+	printf ("count=%s for Item='foo_item'\n", count);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 58 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 58 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 58 "nchar.pgc"
+
+	/*prepared update using NCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "UPDATE My_Table SET Count=Count+1 WHERE Item=?");
+#line 60 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 60 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 60 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 61 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 61 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 61 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 62 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 62 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 62 "nchar.pgc"
+
+	printf ("count=%s for Item='foo_item'\n", count);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 64 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 64 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 64 "nchar.pgc"
+
+	/*prepared delete using NCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "DELETE FROM My_Table WHERE Item=?");
+#line 66 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 66 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 66 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 67 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 67 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 67 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 68 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 68 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 68 "nchar.pgc"
+
+	printf ("found %s rows for Item='foo_item'\n", count);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 70 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 70 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 70 "nchar.pgc"
+
+	/*prepared insert using NCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "INSERT INTO My_Table values (?, 3)");
+#line 72 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 72 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 72 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", 
+	ECPGt_nchar,(nchar_var),(long)40,(long)1,(40)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 73 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 73 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 73 "nchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 74 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 74 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 74 "nchar.pgc"
+
+	printf ("count='%s' for Item='foo_item'\n", count);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 76 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 76 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 76 "nchar.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table My_Table", ECPGt_EOIT, ECPGt_EORT);
+#line 78 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 78 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 78 "nchar.pgc"
+
+	{ ECPGdisconnect(__LINE__, "ALL");
+#line 79 "nchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 79 "nchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 79 "nchar.pgc"
+
+
+	return 0;
+}
+
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nchar.stderr postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nchar.stderr
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nchar.stderr	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nchar.stderr	2013-10-31 15:08:18.000000000 +1100
@@ -0,0 +1,196 @@
+[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]: ECPGsetcommit on line 16: action "on"; connection "regress1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 21: query: create table My_Table ( Item varchar , count integer ); 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]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 21: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 24: query: truncate My_Table; 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]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 24: OK: TRUNCATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: query: insert into My_Table values ( 'foo_item' , 1 ); with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 27: query: select Item from My_Table limit 1; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 27: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 27: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 27: RESULT: foo_item offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: query: select count from My_Table where Item = $1 ; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 30: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 30: RESULT: 1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 33: query: update My_Table set count = count + 1 where Item = $1 ; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 33: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 33: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 33: OK: UPDATE 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 34: query: select count from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 34: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 34: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 34: RESULT: 2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 37: query: delete from My_Table where Item = $1 ; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 37: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 37: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 37: OK: DELETE 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 38: query: select count ( * ) from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 38: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 38: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 38: RESULT: 0 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: query: insert into My_Table values ( $1  , 3 ); with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 41: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 42: query: select count from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 42: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 42: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 42: RESULT: 3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 47: query: truncate My_Table; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 47: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 47: OK: TRUNCATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 48: query: insert into My_Table values ( 'foo_item' , 1 ); 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]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 48: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 50: name stmt; query: "SELECT Item FROM My_Table LIMIT 1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: query: SELECT Item FROM My_Table LIMIT 1; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: using PQexecPrepared for "SELECT Item FROM My_Table LIMIT 1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 51: RESULT: foo_item offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 53: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 55: name stmt; query: "SELECT Count FROM My_Table WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 56: query: SELECT Count FROM My_Table WHERE Item=$1; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 56: using PQexecPrepared for "SELECT Count FROM My_Table WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 56: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 56: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 56: RESULT: 1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 58: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 60: name stmt; query: "UPDATE My_Table SET Count=Count+1 WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 61: query: UPDATE My_Table SET Count=Count+1 WHERE Item=$1; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 61: using PQexecPrepared for "UPDATE My_Table SET Count=Count+1 WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 61: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 61: OK: UPDATE 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 62: query: select count from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 62: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 62: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 62: RESULT: 2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 64: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 66: name stmt; query: "DELETE FROM My_Table WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 67: query: DELETE FROM My_Table WHERE Item=$1; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 67: using PQexecPrepared for "DELETE FROM My_Table WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 67: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 67: OK: DELETE 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 68: query: select count ( * ) from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 68: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 68: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 68: RESULT: 0 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 70: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 72: name stmt; query: "INSERT INTO My_Table values ($1, 3)"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 73: query: INSERT INTO My_Table values ($1, 3); with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 73: using PQexecPrepared for "INSERT INTO My_Table values ($1, 3)"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 73: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 73: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 74: query: select count from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 74: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 74: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 74: RESULT: 3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 76: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 78: 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 78: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 78: OK: DROP TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection regress1 closed
+[NO_PID]: sqlca: code: 0, state: 00000
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nchar.stdout postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nchar.stdout
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nchar.stdout	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nchar.stdout	2013-10-17 11:56:22.000000000 +1100
@@ -0,0 +1,10 @@
+Item='foo_item'
+count=1 for Item='foo_item'
+count=2 for Item='foo_item'
+found 0 rows for Item='foo_item'
+count='3' for Item='foo_item'
+Item='foo_item'
+count=1 for Item='foo_item'
+count=2 for Item='foo_item'
+found 0 rows for Item='foo_item'
+count='3' for Item='foo_item'
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nvarchar.c postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nvarchar.c
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nvarchar.c	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nvarchar.c	2013-10-31 15:08:18.000000000 +1100
@@ -0,0 +1,418 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "nvarchar.pgc"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 5 "nvarchar.pgc"
+
+
+int main() {
+	/* exec sql begin declare section */
+		 
+			
+	
+#line 9 "nvarchar.pgc"
+  struct varchar_1  { int len; char arr[ 40 ]; }  nvarchar_var ;
+ 
+#line 10 "nvarchar.pgc"
+ char count [ 10 ] ;
+/* exec sql end declare section */
+#line 11 "nvarchar.pgc"
+
+
+	ECPGdebug(1, stderr);
+	{ ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0); }
+#line 14 "nvarchar.pgc"
+
+
+	{ ECPGsetcommit(__LINE__, "on", NULL);}
+#line 16 "nvarchar.pgc"
+
+	/* exec sql whenever sql_warning  sqlprint ; */
+#line 17 "nvarchar.pgc"
+
+	/* exec sql whenever sqlerror  sqlprint ; */
+#line 18 "nvarchar.pgc"
+
+
+	/*initialization of test table*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table My_Table ( Item varchar , count integer )", ECPGt_EOIT, ECPGt_EORT);
+#line 21 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 21 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 21 "nvarchar.pgc"
+
+
+	/*simple tests*/
+	/*reinitalization*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "truncate My_Table", ECPGt_EOIT, ECPGt_EORT);
+#line 25 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 25 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 25 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 'foo_item' , 1 )", ECPGt_EOIT, ECPGt_EORT);
+#line 26 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 26 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 26 "nvarchar.pgc"
+
+	/*simple select into NVARCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select Item from My_Table limit 1", ECPGt_EOIT, 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 28 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 28 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 28 "nvarchar.pgc"
+
+	printf ("Item='%s'\n", nvarchar_var.arr);
+	/*simple select using NVARCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = $1 ", 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 31 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 31 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 31 "nvarchar.pgc"
+
+	printf ("count=%s for Item='%s'\n", count, nvarchar_var.arr);
+	/*simple update using NVARCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "update My_Table set count = count + 1 where Item = $1 ", 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 34 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 34 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 34 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 35 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 35 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 35 "nvarchar.pgc"
+
+	printf ("count=%s for Item='foo_item'\n", count);
+	/*simple delete using NVARCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "delete from My_Table where Item = $1 ", 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 38 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 38 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 38 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 39 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 39 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 39 "nvarchar.pgc"
+
+	printf ("found %s rows for Item='foo_item'\n", count);
+	/*simple insert using NVARCHAR*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( $1  , 3 )", 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 42 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 42 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 42 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 43 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 43 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 43 "nvarchar.pgc"
+
+	printf ("count='%s' for Item='foo_item'\n", count);
+
+	/*prepared tests*/
+	/*reinitalization*/
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "truncate My_Table", ECPGt_EOIT, ECPGt_EORT);
+#line 48 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 48 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 48 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into My_Table values ( 'foo_item' , 1 )", ECPGt_EOIT, ECPGt_EORT);
+#line 49 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 49 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 49 "nvarchar.pgc"
+
+	/*prepared select into NVARCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "SELECT Item FROM My_Table LIMIT 1");
+#line 51 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 51 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 51 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", ECPGt_EOIT, 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 52 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 52 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 52 "nvarchar.pgc"
+
+	printf ("Item='%s'\n", nvarchar_var.arr);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 54 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 54 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 54 "nvarchar.pgc"
+
+	/*prepared select using NVARCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "SELECT Count FROM My_Table WHERE Item=?");
+#line 56 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 56 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 56 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 57 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 57 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 57 "nvarchar.pgc"
+
+	printf ("count=%s for Item='foo_item'\n", count);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 59 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 59 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 59 "nvarchar.pgc"
+
+	/*prepared update using NVARCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "UPDATE My_Table SET Count=Count+1 WHERE Item=?");
+#line 61 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 61 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 61 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 62 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 62 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 62 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 63 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 63 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 63 "nvarchar.pgc"
+
+	printf ("count=%s for Item='foo_item'\n", count);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 65 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 65 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 65 "nvarchar.pgc"
+
+	/*prepared delete using NVARCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "DELETE FROM My_Table WHERE Item=?");
+#line 67 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 67 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 67 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 68 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 68 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 68 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count ( * ) from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 69 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 69 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 69 "nvarchar.pgc"
+
+	printf ("found %s rows for Item='foo_item'\n", count);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 71 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 71 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 71 "nvarchar.pgc"
+
+	/*prepared insert using NVARCHAR*/
+	{ ECPGprepare(__LINE__, NULL, 0, "stmt", "INSERT INTO My_Table values (?, 3)");
+#line 73 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 73 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 73 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "stmt", 
+	ECPGt_nvarchar,&(nvarchar_var),(long)40,(long)1,sizeof(struct varchar_1), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+#line 74 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 74 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 74 "nvarchar.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select count from My_Table where Item = 'foo_item'", ECPGt_EOIT, 
+	ECPGt_char,(count),(long)10,(long)1,(10)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 75 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 75 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 75 "nvarchar.pgc"
+
+	printf ("count='%s' for Item='foo_item'\n", count);
+	{ ECPGdeallocate(__LINE__, 0, NULL, "stmt");
+#line 77 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 77 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 77 "nvarchar.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table My_Table", ECPGt_EOIT, ECPGt_EORT);
+#line 79 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 79 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 79 "nvarchar.pgc"
+
+	{ ECPGdisconnect(__LINE__, "ALL");
+#line 80 "nvarchar.pgc"
+
+if (sqlca.sqlwarn[0] == 'W') sqlprint();
+#line 80 "nvarchar.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 80 "nvarchar.pgc"
+
+
+	return 0;
+}
+
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nvarchar.stderr postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nvarchar.stderr
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nvarchar.stderr	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nvarchar.stderr	2013-10-17 11:56:22.000000000 +1100
@@ -0,0 +1,196 @@
+[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]: ECPGsetcommit on line 16: action "on"; connection "regress1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 21: query: create table My_Table ( Item varchar , count integer ); 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]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 21: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: query: truncate My_Table; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: OK: TRUNCATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 26: query: insert into My_Table values ( 'foo_item' , 1 ); with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 26: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 26: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 28: query: select Item from My_Table limit 1; 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]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 28: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 28: RESULT: foo_item offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: query: select count from My_Table where Item = $1 ; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 31: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 31: RESULT: 1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 34: query: update My_Table set count = count + 1 where Item = $1 ; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 34: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 34: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 34: OK: UPDATE 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 35: query: select count from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 35: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 35: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 35: RESULT: 2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 38: query: delete from My_Table where Item = $1 ; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 38: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 38: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 38: OK: DELETE 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 39: query: select count ( * ) from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 39: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 39: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 39: RESULT: 0 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 42: query: insert into My_Table values ( $1  , 3 ); with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 42: using PQexecParams
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 42: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 42: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 43: query: select count from My_Table where Item = 'foo_item'; 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 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 43: RESULT: 3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 48: query: truncate My_Table; 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]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 48: OK: TRUNCATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 49: query: insert into My_Table values ( 'foo_item' , 1 ); with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 49: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 49: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 51: name stmt; query: "SELECT Item FROM My_Table LIMIT 1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 52: query: SELECT Item FROM My_Table LIMIT 1; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 52: using PQexecPrepared for "SELECT Item FROM My_Table LIMIT 1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 52: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 52: RESULT: foo_item offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 54: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 56: name stmt; query: "SELECT Count FROM My_Table WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 57: query: SELECT Count FROM My_Table WHERE Item=$1; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 57: using PQexecPrepared for "SELECT Count FROM My_Table WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 57: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 57: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 57: RESULT: 1 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 59: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 61: name stmt; query: "UPDATE My_Table SET Count=Count+1 WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 62: query: UPDATE My_Table SET Count=Count+1 WHERE Item=$1; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 62: using PQexecPrepared for "UPDATE My_Table SET Count=Count+1 WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 62: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 62: OK: UPDATE 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 63: query: select count from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 63: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 63: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 63: RESULT: 2 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 65: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 67: name stmt; query: "DELETE FROM My_Table WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 68: query: DELETE FROM My_Table WHERE Item=$1; with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 68: using PQexecPrepared for "DELETE FROM My_Table WHERE Item=$1"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 68: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 68: OK: DELETE 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 69: query: select count ( * ) from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 69: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 69: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 69: RESULT: 0 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 71: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 73: name stmt; query: "INSERT INTO My_Table values ($1, 3)"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 74: query: INSERT INTO My_Table values ($1, 3); with 1 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 74: using PQexecPrepared for "INSERT INTO My_Table values ($1, 3)"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: free_params on line 74: parameter 1 = foo_item
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 74: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 75: query: select count from My_Table where Item = 'foo_item'; with 0 parameter(s) on connection regress1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 75: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 75: correctly got 1 tuples with 1 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 75: RESULT: 3 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 77: name stmt
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 79: 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 79: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 79: OK: DROP TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection regress1 closed
+[NO_PID]: sqlca: code: 0, state: 00000
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nvarchar.stdout postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nvarchar.stdout
--- postgresql-head-20131017/src/interfaces/ecpg/test/expected/sql-nvarchar.stdout	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/expected/sql-nvarchar.stdout	2013-10-17 11:56:22.000000000 +1100
@@ -0,0 +1,10 @@
+Item='foo_item'
+count=1 for Item='foo_item'
+count=2 for Item='foo_item'
+found 0 rows for Item='foo_item'
+count='3' for Item='foo_item'
+Item='foo_item'
+count=1 for Item='foo_item'
+count=2 for Item='foo_item'
+found 0 rows for Item='foo_item'
+count='3' for Item='foo_item'
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/preproc/type.pgc postgresql-head-20131017-nchar/src/interfaces/ecpg/test/preproc/type.pgc
--- postgresql-head-20131017/src/interfaces/ecpg/test/preproc/type.pgc	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/preproc/type.pgc	2013-10-31 11:24:42.000000000 +1100
@@ -34,9 +34,16 @@
   	int len;
 	char text[10];
   } vc;
+  struct nvarchar
+  {
+	int len;
+	char text[10];
+  } nvc;
+
   EXEC SQL END DECLARE SECTION;
 
   EXEC SQL var vc is varchar[10];
+  EXEC SQL var nvc is nvarchar[10];
   ECPGdebug (1, stderr);
 
   empl.idnum = 1;
@@ -48,22 +55,22 @@
     }
 
   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));
   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');
   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 
+	into :empl, :str, :ptr, :vc, :nvc
 	from empl
 	where idnum =:empl.idnum;
   if (sqlca.sqlcode)
@@ -71,7 +78,7 @@
       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'\n", empl.idnum, empl.name, empl.accs, str, ptr, vc.text, vc.len, nvc.text, nvc.len);
 
   EXEC SQL disconnect;
 
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/sql/Makefile postgresql-head-20131017-nchar/src/interfaces/ecpg/test/sql/Makefile
--- postgresql-head-20131017/src/interfaces/ecpg/test/sql/Makefile	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/sql/Makefile	2013-10-17 11:56:22.000000000 +1100
@@ -22,7 +22,9 @@
         parser parser.c \
         quote quote.c \
         show show.c \
-        insupd insupd.c
+        insupd insupd.c \
+	nchar nchar.c \
+	nvarchar nvarchar.c
 
 all: $(TESTS)
 
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/sql/nchar.pgc postgresql-head-20131017-nchar/src/interfaces/ecpg/test/sql/nchar.pgc
--- postgresql-head-20131017/src/interfaces/ecpg/test/sql/nchar.pgc	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/sql/nchar.pgc	2013-10-31 14:49:22.000000000 +1100
@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+EXEC SQL INCLUDE ../regression;
+
+int main() {
+	EXEC SQL BEGIN DECLARE SECTION;
+		NCHAR	nchar_var[40];
+		char	count[10];
+	EXEC SQL END DECLARE SECTION;
+
+	ECPGdebug(1, stderr);
+	EXEC SQL CONNECT TO REGRESSDB1;
+
+	EXEC SQL SET AUTOCOMMIT TO ON;
+	EXEC SQL WHENEVER SQLWARNING SQLPRINT;
+	EXEC SQL WHENEVER SQLERROR SQLPRINT;
+
+	/*initialization of test table*/
+	EXEC SQL CREATE TABLE My_Table (Item varchar, Count integer);
+
+	/*reinitalization*/
+	EXEC SQL TRUNCATE My_Table;
+	EXEC SQL INSERT INTO My_Table VALUES ('foo_item', 1);
+	/*simple select into NCHAR*/
+	EXEC SQL SELECT Item INTO :nchar_var FROM My_Table LIMIT 1; 
+	printf ("Item='%s'\n", nchar_var);
+	/*simple select using NCHAR*/
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item=:nchar_var;
+	printf ("count=%s for Item='%s'\n", count, nchar_var);
+	/*simple update using NCHAR*/
+	EXEC SQL UPDATE My_Table SET Count=Count+1 WHERE Item=:nchar_var;
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("count=%s for Item='foo_item'\n", count);
+	/*simple delete using NCHAR*/
+	EXEC SQL DELETE FROM My_Table WHERE Item=:nchar_var;
+	EXEC SQL SELECT count(*) INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("found %s rows for Item='foo_item'\n", count);
+	/*simple insert using NCHAR*/
+	EXEC SQL INSERT INTO My_Table values (:nchar_var, 3);
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("count='%s' for Item='foo_item'\n", count);
+
+	/*prepared tests*/
+	/*reinitalization*/
+	EXEC SQL TRUNCATE My_Table;
+	EXEC SQL INSERT INTO My_Table VALUES ('foo_item', 1);
+	/*prepared select into NCHAR*/
+	EXEC SQL PREPARE stmt FROM "SELECT Item FROM My_Table LIMIT 1";
+	EXEC SQL EXECUTE stmt INTO :nchar_var;
+	printf ("Item='%s'\n", nchar_var);
+	EXEC SQL DEALLOCATE PREPARE stmt; 
+	/*prepared select using NCHAR*/
+	EXEC SQL PREPARE stmt FROM "SELECT Count FROM My_Table WHERE Item=?";
+	EXEC SQL EXECUTE stmt INTO :count USING :nchar_var;
+	printf ("count=%s for Item='foo_item'\n", count);
+	EXEC SQL DEALLOCATE PREPARE stmt;
+	/*prepared update using NCHAR*/
+	EXEC SQL PREPARE stmt FROM "UPDATE My_Table SET Count=Count+1 WHERE Item=?";
+	EXEC SQL EXECUTE stmt USING :nchar_var;
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("count=%s for Item='foo_item'\n", count);
+	EXEC SQL DEALLOCATE PREPARE stmt;
+	/*prepared delete using NCHAR*/
+	EXEC SQL PREPARE stmt FROM "DELETE FROM My_Table WHERE Item=?";
+	EXEC SQL EXECUTE stmt USING :nchar_var;
+	EXEC SQL SELECT count(*) INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("found %s rows for Item='foo_item'\n", count);
+	EXEC SQL DEALLOCATE PREPARE stmt;
+	/*prepared insert using NCHAR*/
+	EXEC SQL PREPARE stmt FROM "INSERT INTO My_Table values (?, 3)";
+	EXEC SQL EXECUTE stmt USING :nchar_var;
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("count='%s' for Item='foo_item'\n", count);
+	EXEC SQL DEALLOCATE PREPARE stmt;
+
+	EXEC SQL DROP TABLE My_Table;
+	EXEC SQL DISCONNECT ALL;
+
+	return 0;
+}
+
diff -uNr postgresql-head-20131017/src/interfaces/ecpg/test/sql/nvarchar.pgc postgresql-head-20131017-nchar/src/interfaces/ecpg/test/sql/nvarchar.pgc
--- postgresql-head-20131017/src/interfaces/ecpg/test/sql/nvarchar.pgc	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/interfaces/ecpg/test/sql/nvarchar.pgc	2013-10-31 14:50:53.000000000 +1100
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+EXEC SQL INCLUDE ../regression;
+
+int main() {
+	EXEC SQL BEGIN DECLARE SECTION;
+		NVARCHAR nvarchar_var[40];
+		char	count[10];
+	EXEC SQL END DECLARE SECTION;
+
+	ECPGdebug(1, stderr);
+	EXEC SQL CONNECT TO REGRESSDB1;
+
+	EXEC SQL SET AUTOCOMMIT TO ON;
+	EXEC SQL WHENEVER SQLWARNING SQLPRINT;
+	EXEC SQL WHENEVER SQLERROR SQLPRINT;
+
+	/*initialization of test table*/
+	EXEC SQL CREATE TABLE My_Table (Item varchar, Count integer);
+
+	/*simple tests*/
+	/*reinitalization*/
+	EXEC SQL TRUNCATE My_Table;
+	EXEC SQL INSERT INTO My_Table VALUES ('foo_item', 1);
+	/*simple select into NVARCHAR*/
+	EXEC SQL SELECT Item INTO :nvarchar_var FROM My_Table LIMIT 1;
+	printf ("Item='%s'\n", nvarchar_var.arr);
+	/*simple select using NVARCHAR*/
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item=:nvarchar_var;
+	printf ("count=%s for Item='%s'\n", count, nvarchar_var.arr);
+	/*simple update using NVARCHAR*/
+	EXEC SQL UPDATE My_Table SET Count=Count+1 WHERE Item=:nvarchar_var;
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("count=%s for Item='foo_item'\n", count);
+	/*simple delete using NVARCHAR*/
+	EXEC SQL DELETE FROM My_Table WHERE Item=:nvarchar_var;
+	EXEC SQL SELECT count(*) INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("found %s rows for Item='foo_item'\n", count);
+	/*simple insert using NVARCHAR*/
+	EXEC SQL INSERT INTO My_Table values (:nvarchar_var, 3);
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("count='%s' for Item='foo_item'\n", count);
+
+	/*prepared tests*/
+	/*reinitalization*/
+	EXEC SQL TRUNCATE My_Table;
+	EXEC SQL INSERT INTO My_Table VALUES ('foo_item', 1);
+	/*prepared select into NVARCHAR*/
+	EXEC SQL PREPARE stmt FROM "SELECT Item FROM My_Table LIMIT 1";
+	EXEC SQL EXECUTE stmt INTO :nvarchar_var;
+	printf ("Item='%s'\n", nvarchar_var.arr);
+	EXEC SQL DEALLOCATE PREPARE stmt;
+	/*prepared select using NVARCHAR*/
+	EXEC SQL PREPARE stmt FROM "SELECT Count FROM My_Table WHERE Item=?";
+	EXEC SQL EXECUTE stmt INTO :count USING :nvarchar_var;
+	printf ("count=%s for Item='foo_item'\n", count);
+	EXEC SQL DEALLOCATE PREPARE stmt;
+	/*prepared update using NVARCHAR*/
+	EXEC SQL PREPARE stmt FROM "UPDATE My_Table SET Count=Count+1 WHERE Item=?";
+	EXEC SQL EXECUTE stmt USING :nvarchar_var;
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("count=%s for Item='foo_item'\n", count);
+	EXEC SQL DEALLOCATE PREPARE stmt;
+	/*prepared delete using NVARCHAR*/
+	EXEC SQL PREPARE stmt FROM "DELETE FROM My_Table WHERE Item=?";
+	EXEC SQL EXECUTE stmt USING :nvarchar_var;
+	EXEC SQL SELECT count(*) INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("found %s rows for Item='foo_item'\n", count);
+	EXEC SQL DEALLOCATE PREPARE stmt;
+	/*prepared insert using NVARCHAR*/
+	EXEC SQL PREPARE stmt FROM "INSERT INTO My_Table values (?, 3)";
+	EXEC SQL EXECUTE stmt USING :nvarchar_var;
+	EXEC SQL SELECT Count INTO :count FROM My_Table WHERE Item='foo_item';
+	printf ("count='%s' for Item='foo_item'\n", count);
+	EXEC SQL DEALLOCATE PREPARE stmt;
+
+	EXEC SQL DROP TABLE My_Table;
+	EXEC SQL DISCONNECT ALL;
+
+	return 0;
+}
+
diff -uNr postgresql-head-20131017/src/test/regress/expected/create_function_3.out postgresql-head-20131017-nchar/src/test/regress/expected/create_function_3.out
--- postgresql-head-20131017/src/test/regress/expected/create_function_3.out	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/expected/create_function_3.out	2013-10-17 11:56:22.000000000 +1100
@@ -308,6 +308,8 @@
  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}
@@ -383,7 +385,7 @@
  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
diff -uNr postgresql-head-20131017/src/test/regress/expected/n_test.out postgresql-head-20131017-nchar/src/test/regress/expected/n_test.out
--- postgresql-head-20131017/src/test/regress/expected/n_test.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/n_test.out	2013-10-17 11:56:22.000000000 +1100
@@ -0,0 +1,81 @@
+create domain test1_n_domain as varchar default (N'a');
+create domain test2_n_domain as varchar CHECK (value <> N'b');
+alter domain test1_n_domain set default (N'b');
+values (N'a');
+ column1 
+---------
+ a
+(1 row)
+
+create table n_test (f varchar default N'a', val varchar);
+insert into n_test values (N'a', 'test_val') returning f;
+ f 
+---
+ a
+(1 row)
+
+SELECT f from n_test;
+ f 
+---
+ a
+(1 row)
+
+select N'a' as f into n_test1 from n_test;
+select * from n_test1;
+ f 
+---
+ a
+(1 row)
+
+select N'a' as f from n_test;
+ f 
+---
+ a
+(1 row)
+
+select val from n_test where f=N'a';
+   val    
+----------
+ test_val
+(1 row)
+
+copy (select N'a' from n_test) to stdout;
+a
+alter table n_test alter f set default N'a';
+prepare stmt AS select N'a' as f from n_test;
+deallocate stmt;
+create index i on n_test((f||N'a'));
+create trigger tr before update on n_test for each row when (OLD.f=N'a') EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+do $$begin perform N'a' from n_test; end $$;
+create view v as select N'a' as f from n_test;
+select * from v;
+ f 
+---
+ a
+(1 row)
+
+alter view v alter column f set default N'a';
+begin;declare c cursor for select N'a' as f from n_test;commit;
+prepare stmt(varchar) AS select val from n_test where f=$1;
+execute stmt(N'a');
+   val    
+----------
+ test_val
+(1 row)
+
+deallocate stmt;
+UPDATE n_test SET f=N'b';
+SELECT * from n_test;
+ f |   val    
+---+----------
+ b | test_val
+(1 row)
+
+delete from n_test where f=N'b';
+CREATE FUNCTION foo(f varchar default N'a') returns setof varchar as $$SELECT N'a' from n_test;$$ LANGUAGE SQL;
+drop view v;
+drop table n_test;
+drop table n_test1;
+drop function foo(varchar);
+drop domain test1_n_domain;
+drop domain test2_n_domain;
diff -uNr postgresql-head-20131017/src/test/regress/expected/nchar.out postgresql-head-20131017-nchar/src/test/regress/expected/nchar.out
--- postgresql-head-20131017/src/test/regress/expected/nchar.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/nchar.out	2013-10-17 11:56:22.000000000 +1100
@@ -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 -uNr postgresql-head-20131017/src/test/regress/expected/nchar_1.out postgresql-head-20131017-nchar/src/test/regress/expected/nchar_1.out
--- postgresql-head-20131017/src/test/regress/expected/nchar_1.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/nchar_1.out	2013-10-17 11:56:22.000000000 +1100
@@ -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 
+------+----
+      | 1
+      | 2
+      | 3
+      |  
+(4 rows)
+
+SELECT '' AS six, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 <= 'a';
+ six | f1 
+-----+----
+     | a
+     | 1
+     | 2
+     | 3
+     |  
+(5 rows)
+
+SELECT '' AS one, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 > 'a';
+ one | f1 
+-----+----
+     | A
+     | c
+(2 rows)
+
+SELECT '' AS two, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 >= 'a';
+ two | f1 
+-----+----
+     | a
+     | A
+     | c
+(3 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 -uNr postgresql-head-20131017/src/test/regress/expected/nchar_2.out postgresql-head-20131017-nchar/src/test/regress/expected/nchar_2.out
--- postgresql-head-20131017/src/test/regress/expected/nchar_2.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/nchar_2.out	2013-10-17 11:56:22.000000000 +1100
@@ -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 
+------+----
+      |  
+(1 row)
+
+SELECT '' AS six, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 <= 'a';
+ six | f1 
+-----+----
+     | a
+     |  
+(2 rows)
+
+SELECT '' AS one, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 > 'a';
+ one | f1 
+-----+----
+     | A
+     | 1
+     | 2
+     | 3
+     | c
+(5 rows)
+
+SELECT '' AS two, c.*
+   FROM NCHAR_TBL c
+   WHERE c.f1 >= 'a';
+ two | f1 
+-----+----
+     | a
+     | A
+     | 1
+     | 2
+     | 3
+     | c
+(6 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 -uNr postgresql-head-20131017/src/test/regress/expected/nchar_test.out postgresql-head-20131017-nchar/src/test/regress/expected/nchar_test.out
--- postgresql-head-20131017/src/test/regress/expected/nchar_test.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/nchar_test.out	2013-10-17 11:56:22.000000000 +1100
@@ -0,0 +1,101 @@
+CREATE AGGREGATE test_nchar_agg (nchar(10)) ( sfunc = array_append, stype = nchar(10)[], initcond = '{}');
+alter aggregate test_nchar_agg (nchar(10)) rename to test_nchar_aggregate;
+drop aggregate test_nchar_aggregate(nchar(10));
+create domain test_nchar_domain as nchar(10);
+drop domain test_nchar_domain;
+create table nchar_test (f nchar(10), val varchar);
+create index i on nchar_test(f);
+vacuum analyze nchar_test(f);
+insert into nchar_test values ('a', 'test_val') returning (f);
+     f      
+------------
+ a         
+(1 row)
+
+SELECT f from nchar_test;
+     f      
+------------
+ a         
+(1 row)
+
+select f into nchar_test1 from nchar_test;
+select * from nchar_test1;
+     f      
+------------
+ a         
+(1 row)
+
+drop table nchar_test1;
+select f from nchar_test;
+     f      
+------------
+ a         
+(1 row)
+
+select val from nchar_test where f='a';
+   val    
+----------
+ test_val
+(1 row)
+
+prepare stmt AS select f from nchar_test;
+prepare stmt1(nchar(10)) AS select val from nchar_test where f=$1;
+deallocate stmt;
+deallocate stmt1;
+prepare stmt(varchar) AS select val from nchar_test where f=$1;
+execute stmt('a');
+   val    
+----------
+ test_val
+(1 row)
+
+deallocate stmt;
+begin;declare c cursor for select f from nchar_test;commit;
+create view v as select f from nchar_test;
+select * from v;
+     f      
+------------
+ a         
+(1 row)
+
+alter view v alter column f set default 'a';
+drop view v;
+do $$begin perform f from nchar_test; end $$;
+CREATE TYPE test_nchar_type AS (f nchar(10));
+comment on type test_nchar_type is 'comment';
+drop type test_nchar_type;
+create trigger tr before update on nchar_test for each row when (OLD.f='a') EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+copy nchar_test(f) to stdout;
+a         
+comment on COLUMN nchar_test.f is 'comment';
+analyze nchar_test(f);
+alter table nchar_test rename f to f_renamed;
+alter table nchar_test rename f_renamed to f;
+alter table nchar_test alter val type nchar(10);
+UPDATE nchar_test SET f='b';
+SELECT * from nchar_test;
+     f      |    val     
+------------+------------
+ b          | test_val  
+(1 row)
+
+delete from nchar_test where f='b';
+CREATE FUNCTION foo(f nchar(10)) returns setof nchar(10) as $$SELECT f from nchar_test;$$ LANGUAGE SQL;
+alter function foo(nchar(10)) reset all;
+drop function foo(nchar(10));
+drop table nchar_test;
+create function dummy_eq (nchar, nchar) returns boolean as 'SELECT $1=$2;' LANGUAGE SQL;
+CREATE OPERATOR === (LEFTARG = nchar, RIGHTARG = nchar, PROCEDURE = dummy_eq);
+alter operator === (nchar,nchar) set schema pg_catalog;
+DROP OPERATOR  === (nchar,nchar);
+drop function dummy_eq (nchar, nchar);
+create cast (nchar as bytea) with FUNCTION nbpcharsend(nchar);
+drop cast (nchar as bytea);
+create foreign data wrapper dummy;
+CREATE SERVER foo FOREIGN DATA WRAPPER "dummy";
+create foreign table ft_nchar (f nchar(10), var varchar) server foo;
+alter foreign table ft_nchar alter var type nchar(10);
+alter foreign table ft_nchar rename column f to f_new;
+drop foreign table ft_nchar;
+drop SERVER foo;
+drop foreign data wrapper dummy;
diff -uNr postgresql-head-20131017/src/test/regress/expected/nvarchar.out postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar.out
--- postgresql-head-20131017/src/test/regress/expected/nvarchar.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar.out	2013-10-17 11:56:22.000000000 +1100
@@ -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 nvarchar
+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 nvarchar
+--
+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 -uNr postgresql-head-20131017/src/test/regress/expected/nvarchar_1.out postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar_1.out
--- postgresql-head-20131017/src/test/regress/expected/nvarchar_1.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar_1.out	2013-10-17 11:56:22.000000000 +1100
@@ -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 nvarchar
+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 nvarchar
+--
+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 -uNr postgresql-head-20131017/src/test/regress/expected/nvarchar_2.out postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar_2.out
--- postgresql-head-20131017/src/test/regress/expected/nvarchar_2.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar_2.out	2013-10-17 11:56:22.000000000 +1100
@@ -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 nvarchar
+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 nvarchar
+--
+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 -uNr postgresql-head-20131017/src/test/regress/expected/nvarchar_misc.out postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar_misc.out
--- postgresql-head-20131017/src/test/regress/expected/nvarchar_misc.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar_misc.out	2013-10-17 11:56:22.000000000 +1100
@@ -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 -uNr postgresql-head-20131017/src/test/regress/expected/nvarchar_test.out postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar_test.out
--- postgresql-head-20131017/src/test/regress/expected/nvarchar_test.out	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/expected/nvarchar_test.out	2013-10-17 11:56:22.000000000 +1100
@@ -0,0 +1,101 @@
+CREATE AGGREGATE test_nvarchar_agg (nvarchar) ( sfunc = array_append, stype = nvarchar[], initcond = '{}');
+alter aggregate test_nvarchar_agg (nvarchar) rename to test_nvarchar_aggregate;
+drop aggregate test_nvarchar_aggregate(nvarchar);
+create domain test_nvarchar_domain as nvarchar;
+drop domain test_nvarchar_domain;
+create table nvarchar_test (f nvarchar, val varchar);
+create index i on nvarchar_test(f);
+vacuum analyze nvarchar_test(f);
+insert into nvarchar_test values ('a', 'test_val') returning (f);
+ f 
+---
+ a
+(1 row)
+
+SELECT f from nvarchar_test;
+ f 
+---
+ a
+(1 row)
+
+select f into nvarchar_test1 from nvarchar_test;
+select * from nvarchar_test1;
+ f 
+---
+ a
+(1 row)
+
+drop table nvarchar_test1;
+select f from nvarchar_test;
+ f 
+---
+ a
+(1 row)
+
+select val from nvarchar_test where f='a';
+   val    
+----------
+ test_val
+(1 row)
+
+prepare stmt AS select f from nvarchar_test;
+prepare stmt1(nvarchar) AS select val from nvarchar_test where f=$1;
+deallocate stmt;
+deallocate stmt1;
+prepare stmt(varchar) AS select val from nvarchar_test where f=$1;
+execute stmt('a');
+   val    
+----------
+ test_val
+(1 row)
+
+deallocate stmt;
+begin;declare c cursor for select f from nvarchar_test;commit;
+create view v as select f from nvarchar_test;
+select * from v;
+ f 
+---
+ a
+(1 row)
+
+alter view v alter column f set default 'a';
+drop view v;
+do $$begin perform f from nvarchar_test; end $$;
+CREATE TYPE test_nvarchar_type AS (f nvarchar);
+comment on type test_nvarchar_type is 'comment';
+drop type test_nvarchar_type;
+create trigger tr before update on nvarchar_test for each row when (OLD.f='a') EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+copy nvarchar_test(f) to stdout;
+a
+comment on COLUMN nvarchar_test.f is 'comment';
+analyze nvarchar_test(f);
+alter table nvarchar_test rename f to f_renamed;
+alter table nvarchar_test rename f_renamed to f;
+alter table nvarchar_test alter val type nvarchar;
+UPDATE nvarchar_test SET f='b';
+SELECT * from nvarchar_test;
+ f |   val    
+---+----------
+ b | test_val
+(1 row)
+
+delete from nvarchar_test where f='b';
+CREATE FUNCTION foo(f nvarchar) returns setof nvarchar as $$SELECT f from nvarchar_test;$$ LANGUAGE SQL;
+alter function foo(nvarchar) reset all;
+drop function foo(nvarchar);
+drop table nvarchar_test;
+create function dummy_eq (nvarchar, nvarchar) returns boolean as 'SELECT $1=$2;' LANGUAGE SQL;
+CREATE OPERATOR === (LEFTARG = nvarchar, RIGHTARG = nvarchar, PROCEDURE = dummy_eq);
+alter operator === (nvarchar,nvarchar) set schema pg_catalog;
+DROP OPERATOR  === (nvarchar,nvarchar);
+drop function dummy_eq (nvarchar, nvarchar);
+create cast (name as nvarchar) with FUNCTION  "nvarchar"(name);
+drop cast (name as nvarchar);
+create foreign data wrapper dummy;
+CREATE SERVER foo FOREIGN DATA WRAPPER "dummy";
+create foreign table ft_nvarchar (f nvarchar, var varchar) server foo;
+alter foreign table ft_nvarchar alter var type nvarchar;
+alter foreign table ft_nvarchar rename column f to f_new;
+drop foreign table ft_nvarchar;
+drop SERVER foo;
+drop foreign data wrapper dummy;
diff -uNr postgresql-head-20131017/src/test/regress/expected/opr_sanity.out postgresql-head-20131017-nchar/src/test/regress/expected/opr_sanity.out
--- postgresql-head-20131017/src/test/regress/expected/opr_sanity.out	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/expected/opr_sanity.out	2013-10-31 13:47:56.000000000 +1100
@@ -154,8 +154,11 @@
  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
@@ -171,10 +174,14 @@
 -------------+-------------
           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
@@ -189,10 +196,11 @@
  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
@@ -434,16 +442,20 @@
                 WHERE k.castmethod = 'b' AND
                     k.castsource = c.casttarget AND
                     k.casttarget = c.castsource);
-    castsource     |    casttarget     | castfunc | castcontext 
--------------------+-------------------+----------+-------------
- text              | character         |        0 | i
- character varying | 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)
+         castsource         |     casttarget     | castfunc | castcontext 
+----------------------------+--------------------+----------+-------------
+ text                       | character          |        0 | i
+ character varying          | character          |        0 | i
+ text                       | national character |        0 | i
+ national character varying | character          |        0 | i
+ character varying          | national character |        0 | i
+ national character varying | 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
+(11 rows)
 
 -- **************** pg_operator ****************
 -- Look for illegal values in pg_operator fields.
@@ -1228,7 +1240,9 @@
                  p3.amopstrategy = 1);
  amoplefttype | amoplefttype 
 --------------+--------------
-(0 rows)
+         1042 |         5001
+         5001 |         1042
+(2 rows)
 
 -- **************** pg_amproc ****************
 -- Look for illegal values in pg_amproc fields
@@ -1289,9 +1303,11 @@
 GROUP BY amname, amsupport, opcname, amprocfamily
 HAVING (count(*) != amsupport AND count(*) != amsupport - 1)
     OR amprocfamily IS NULL;
- amname | opcname | count 
---------+---------+-------
-(0 rows)
+ amname |    opcname    | count 
+--------+---------------+-------
+ 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
@@ -1332,9 +1348,11 @@
           THEN prorettype != 'void'::regtype OR proretset OR pronargs != 1
                OR proargtypes[0] != 'internal'::regtype
           ELSE true END);
- amprocfamily | amprocnum | oid | proname | opfname 
---------------+-----------+-----+---------+---------
-(0 rows)
+ amprocfamily | amprocnum | oid  |       proname        |      opfname       
+--------------+-----------+------+----------------------+--------------------
+          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
diff -uNr postgresql-head-20131017/src/test/regress/expected/sanity_check.out postgresql-head-20131017-nchar/src/test/regress/expected/sanity_check.out
--- postgresql-head-20131017/src/test/regress/expected/sanity_check.out	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/expected/sanity_check.out	2013-10-17 14:05:30.000000000 +1100
@@ -69,6 +69,7 @@
  lseg_tbl                | f
  main_table              | f
  money_data              | f
+ nchar_tbl               | f
  num_data                | f
  num_exp_add             | t
  num_exp_div             | t
@@ -80,6 +81,7 @@
  num_exp_sub             | t
  num_input_test          | f
  num_result              | f
+ nvarchar_tbl            | f
  onek                    | t
  onek2                   | t
  path_tbl                | f
@@ -167,7 +169,7 @@
  timetz_tbl              | f
  tinterval_tbl           | f
  varchar_tbl             | f
-(156 rows)
+(158 rows)
 
 --
 -- another sanity check: every system catalog that has OIDs should have
diff -uNr postgresql-head-20131017/src/test/regress/expected/strings.out postgresql-head-20131017-nchar/src/test/regress/expected/strings.out
--- postgresql-head-20131017/src/test/regress/expected/strings.out	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/expected/strings.out	2013-10-17 11:56:22.000000000 +1100
@@ -203,6 +203,15 @@
  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) 
 ---------------
@@ -212,6 +221,15 @@
  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) 
 ------------
@@ -227,6 +245,14 @@
 (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)      
 ----------------------
@@ -234,6 +260,13 @@
  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) 
 ---------------
@@ -243,12 +276,27 @@
  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)   
 -------------------
@@ -256,6 +304,13 @@
  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) 
 ---------------
@@ -265,12 +320,27 @@
  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
@@ -1105,18 +1175,36 @@
  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
 --
diff -uNr postgresql-head-20131017/src/test/regress/expected/union.out postgresql-head-20131017-nchar/src/test/regress/expected/union.out
--- postgresql-head-20131017/src/test/regress/expected/union.out	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/expected/union.out	2013-10-17 11:56:22.000000000 +1100
@@ -257,6 +257,48 @@
  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
 --
diff -uNr postgresql-head-20131017/src/test/regress/expected/update.out postgresql-head-20131017-nchar/src/test/regress/expected/update.out
--- postgresql-head-20131017/src/test/regress/expected/update.out	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/expected/update.out	2013-10-17 11:56:22.000000000 +1100
@@ -4,40 +4,66 @@
 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)
 
 --
@@ -46,10 +72,10 @@
 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)
 
 --
@@ -57,18 +83,18 @@
 --
 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:
diff -uNr postgresql-head-20131017/src/test/regress/output/misc.source postgresql-head-20131017-nchar/src/test/regress/output/misc.source
--- postgresql-head-20131017/src/test/regress/output/misc.source	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/output/misc.source	2013-10-17 14:06:41.000000000 +1100
@@ -643,6 +643,7 @@
  lseg_tbl
  main_table
  money_data
+ nchar_tbl
  num_data
  num_exp_add
  num_exp_div
@@ -654,6 +655,7 @@
  num_exp_sub
  num_input_test
  num_result
+ nvarchar_tbl
  onek
  onek2
  path_tbl
@@ -697,7 +699,7 @@
  tvvmv
  varchar_tbl
  xacttest
-(119 rows)
+(121 rows)
 
 SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer')));
  name 
diff -uNr postgresql-head-20131017/src/test/regress/parallel_schedule postgresql-head-20131017-nchar/src/test/regress/parallel_schedule
--- postgresql-head-20131017/src/test/regress/parallel_schedule	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/parallel_schedule	2013-10-22 15:16:06.000000000 +1100
@@ -13,7 +13,7 @@
 # ----------
 # 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_misc
 
 # Depends on things setup during char, varchar and text
 test: strings
@@ -109,3 +109,8 @@
 
 # run stats by itself because its delay may be insufficient under heavy load
 test: stats
+
+test: n_test
+test: nchar_test
+test: nvarchar_test
+
diff -uNr postgresql-head-20131017/src/test/regress/serial_schedule postgresql-head-20131017-nchar/src/test/regress/serial_schedule
--- postgresql-head-20131017/src/test/regress/serial_schedule	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/serial_schedule	2013-10-22 14:38:27.000000000 +1100
@@ -5,6 +5,9 @@
 test: char
 test: name
 test: varchar
+test: nvarchar
+test: nvarchar_misc
+test: nchar
 test: text
 test: int2
 test: int4
@@ -141,3 +144,7 @@
 test: with
 test: xml
 test: stats
+test: n_test
+test: nchar_test
+test: nvarchar_test
+
diff -uNr postgresql-head-20131017/src/test/regress/sql/n_test.sql postgresql-head-20131017-nchar/src/test/regress/sql/n_test.sql
--- postgresql-head-20131017/src/test/regress/sql/n_test.sql	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/sql/n_test.sql	2013-10-17 11:56:22.000000000 +1100
@@ -0,0 +1,57 @@
+
+create domain test1_n_domain as varchar default (N'a');
+create domain test2_n_domain as varchar CHECK (value <> N'b');
+
+alter domain test1_n_domain set default (N'b');
+
+values (N'a');
+
+create table n_test (f varchar default N'a', val varchar);
+
+insert into n_test values (N'a', 'test_val') returning f;
+SELECT f from n_test;
+
+select N'a' as f into n_test1 from n_test;
+select * from n_test1;
+
+select N'a' as f from n_test;
+select val from n_test where f=N'a';
+
+copy (select N'a' from n_test) to stdout;
+
+alter table n_test alter f set default N'a';
+
+prepare stmt AS select N'a' as f from n_test;
+deallocate stmt;
+
+create index i on n_test((f||N'a'));
+
+create trigger tr before update on n_test for each row when (OLD.f=N'a') EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+
+do $$begin perform N'a' from n_test; end $$;
+
+create view v as select N'a' as f from n_test;
+select * from v;
+
+alter view v alter column f set default N'a';
+
+begin;declare c cursor for select N'a' as f from n_test;commit;
+
+prepare stmt(varchar) AS select val from n_test where f=$1;
+execute stmt(N'a');
+deallocate stmt;
+
+UPDATE n_test SET f=N'b';
+SELECT * from n_test;
+
+delete from n_test where f=N'b';
+
+CREATE FUNCTION foo(f varchar default N'a') returns setof varchar as $$SELECT N'a' from n_test;$$ LANGUAGE SQL;
+
+drop view v;
+drop table n_test;
+drop table n_test1;
+drop function foo(varchar);
+drop domain test1_n_domain;
+drop domain test2_n_domain;
+
diff -uNr postgresql-head-20131017/src/test/regress/sql/nchar.sql postgresql-head-20131017-nchar/src/test/regress/sql/nchar.sql
--- postgresql-head-20131017/src/test/regress/sql/nchar.sql	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/sql/nchar.sql	2013-10-17 11:56:22.000000000 +1100
@@ -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 -uNr postgresql-head-20131017/src/test/regress/sql/nchar_test.sql postgresql-head-20131017-nchar/src/test/regress/sql/nchar_test.sql
--- postgresql-head-20131017/src/test/regress/sql/nchar_test.sql	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/sql/nchar_test.sql	2013-10-17 11:56:22.000000000 +1100
@@ -0,0 +1,101 @@
+
+CREATE AGGREGATE test_nchar_agg (nchar(10)) ( sfunc = array_append, stype = nchar(10)[], initcond = '{}');
+
+alter aggregate test_nchar_agg (nchar(10)) rename to test_nchar_aggregate;
+
+drop aggregate test_nchar_aggregate(nchar(10));
+
+create domain test_nchar_domain as nchar(10);
+
+drop domain test_nchar_domain;
+
+create table nchar_test (f nchar(10), val varchar);
+
+create index i on nchar_test(f);
+
+vacuum analyze nchar_test(f);
+
+insert into nchar_test values ('a', 'test_val') returning (f);
+SELECT f from nchar_test;
+
+select f into nchar_test1 from nchar_test;
+select * from nchar_test1;
+
+drop table nchar_test1;
+
+select f from nchar_test;
+select val from nchar_test where f='a';
+
+prepare stmt AS select f from nchar_test;
+prepare stmt1(nchar(10)) AS select val from nchar_test where f=$1;
+
+deallocate stmt;
+deallocate stmt1;
+
+prepare stmt(varchar) AS select val from nchar_test where f=$1;
+execute stmt('a');
+
+deallocate stmt;
+
+begin;declare c cursor for select f from nchar_test;commit;
+
+create view v as select f from nchar_test;
+select * from v;
+
+alter view v alter column f set default 'a';
+
+drop view v;
+
+do $$begin perform f from nchar_test; end $$;
+
+CREATE TYPE test_nchar_type AS (f nchar(10));
+
+comment on type test_nchar_type is 'comment';
+
+drop type test_nchar_type;
+
+create trigger tr before update on nchar_test for each row when (OLD.f='a') EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+
+copy nchar_test(f) to stdout;
+
+comment on COLUMN nchar_test.f is 'comment';
+
+analyze nchar_test(f);
+
+alter table nchar_test rename f to f_renamed;
+alter table nchar_test rename f_renamed to f;
+
+alter table nchar_test alter val type nchar(10);
+
+UPDATE nchar_test SET f='b';
+SELECT * from nchar_test;
+
+delete from nchar_test where f='b';
+
+CREATE FUNCTION foo(f nchar(10)) returns setof nchar(10) as $$SELECT f from nchar_test;$$ LANGUAGE SQL;
+
+alter function foo(nchar(10)) reset all;
+
+drop function foo(nchar(10));
+
+drop table nchar_test;
+
+create function dummy_eq (nchar, nchar) returns boolean as 'SELECT $1=$2;' LANGUAGE SQL;
+CREATE OPERATOR === (LEFTARG = nchar, RIGHTARG = nchar, PROCEDURE = dummy_eq);
+alter operator === (nchar,nchar) set schema pg_catalog;
+DROP OPERATOR  === (nchar,nchar);
+drop function dummy_eq (nchar, nchar);
+
+create cast (nchar as bytea) with FUNCTION nbpcharsend(nchar);
+drop cast (nchar as bytea);
+
+create foreign data wrapper dummy;
+CREATE SERVER foo FOREIGN DATA WRAPPER "dummy";
+create foreign table ft_nchar (f nchar(10), var varchar) server foo;
+alter foreign table ft_nchar alter var type nchar(10);
+alter foreign table ft_nchar rename column f to f_new;
+drop foreign table ft_nchar;
+drop SERVER foo;
+drop foreign data wrapper dummy;
+
+
diff -uNr postgresql-head-20131017/src/test/regress/sql/nvarchar.sql postgresql-head-20131017-nchar/src/test/regress/sql/nvarchar.sql
--- postgresql-head-20131017/src/test/regress/sql/nvarchar.sql	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/sql/nvarchar.sql	2013-10-17 11:56:22.000000000 +1100
@@ -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 nvarchar
+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 nvarchar
+--
+
+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 -uNr postgresql-head-20131017/src/test/regress/sql/nvarchar_misc.sql postgresql-head-20131017-nchar/src/test/regress/sql/nvarchar_misc.sql
--- postgresql-head-20131017/src/test/regress/sql/nvarchar_misc.sql	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/sql/nvarchar_misc.sql	2013-10-17 11:56:22.000000000 +1100
@@ -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 -uNr postgresql-head-20131017/src/test/regress/sql/nvarchar_test.sql postgresql-head-20131017-nchar/src/test/regress/sql/nvarchar_test.sql
--- postgresql-head-20131017/src/test/regress/sql/nvarchar_test.sql	1970-01-01 10:00:00.000000000 +1000
+++ postgresql-head-20131017-nchar/src/test/regress/sql/nvarchar_test.sql	2013-10-17 11:56:22.000000000 +1100
@@ -0,0 +1,101 @@
+
+CREATE AGGREGATE test_nvarchar_agg (nvarchar) ( sfunc = array_append, stype = nvarchar[], initcond = '{}');
+
+alter aggregate test_nvarchar_agg (nvarchar) rename to test_nvarchar_aggregate;
+
+drop aggregate test_nvarchar_aggregate(nvarchar);
+
+create domain test_nvarchar_domain as nvarchar;
+
+drop domain test_nvarchar_domain;
+
+create table nvarchar_test (f nvarchar, val varchar);
+
+create index i on nvarchar_test(f);
+
+vacuum analyze nvarchar_test(f);
+
+insert into nvarchar_test values ('a', 'test_val') returning (f);
+SELECT f from nvarchar_test;
+
+select f into nvarchar_test1 from nvarchar_test;
+select * from nvarchar_test1;
+
+drop table nvarchar_test1;
+
+select f from nvarchar_test;
+select val from nvarchar_test where f='a';
+
+prepare stmt AS select f from nvarchar_test;
+prepare stmt1(nvarchar) AS select val from nvarchar_test where f=$1;
+
+deallocate stmt;
+deallocate stmt1;
+
+prepare stmt(varchar) AS select val from nvarchar_test where f=$1;
+execute stmt('a');
+
+deallocate stmt;
+
+begin;declare c cursor for select f from nvarchar_test;commit;
+
+create view v as select f from nvarchar_test;
+select * from v;
+
+alter view v alter column f set default 'a';
+
+drop view v;
+
+do $$begin perform f from nvarchar_test; end $$;
+
+CREATE TYPE test_nvarchar_type AS (f nvarchar);
+
+comment on type test_nvarchar_type is 'comment';
+
+drop type test_nvarchar_type;
+
+create trigger tr before update on nvarchar_test for each row when (OLD.f='a') EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+
+copy nvarchar_test(f) to stdout;
+
+comment on COLUMN nvarchar_test.f is 'comment';
+
+analyze nvarchar_test(f);
+
+alter table nvarchar_test rename f to f_renamed;
+alter table nvarchar_test rename f_renamed to f;
+
+alter table nvarchar_test alter val type nvarchar;
+
+UPDATE nvarchar_test SET f='b';
+SELECT * from nvarchar_test;
+
+delete from nvarchar_test where f='b';
+
+CREATE FUNCTION foo(f nvarchar) returns setof nvarchar as $$SELECT f from nvarchar_test;$$ LANGUAGE SQL;
+
+alter function foo(nvarchar) reset all;
+
+drop function foo(nvarchar);
+
+drop table nvarchar_test;
+
+create function dummy_eq (nvarchar, nvarchar) returns boolean as 'SELECT $1=$2;' LANGUAGE SQL;
+CREATE OPERATOR === (LEFTARG = nvarchar, RIGHTARG = nvarchar, PROCEDURE = dummy_eq);
+alter operator === (nvarchar,nvarchar) set schema pg_catalog;
+DROP OPERATOR  === (nvarchar,nvarchar);
+drop function dummy_eq (nvarchar, nvarchar);
+
+create cast (name as nvarchar) with FUNCTION  "nvarchar"(name);
+drop cast (name as nvarchar);
+
+create foreign data wrapper dummy;
+CREATE SERVER foo FOREIGN DATA WRAPPER "dummy";
+create foreign table ft_nvarchar (f nvarchar, var varchar) server foo;
+alter foreign table ft_nvarchar alter var type nvarchar;
+alter foreign table ft_nvarchar rename column f to f_new;
+drop foreign table ft_nvarchar;
+drop SERVER foo;
+drop foreign data wrapper dummy;
+
+
diff -uNr postgresql-head-20131017/src/test/regress/sql/strings.sql postgresql-head-20131017-nchar/src/test/regress/sql/strings.sql
--- postgresql-head-20131017/src/test/regress/sql/strings.sql	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/sql/strings.sql	2013-10-31 11:26:49.000000000 +1100
@@ -70,26 +70,36 @@
 --
 
 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
@@ -330,10 +340,13 @@
 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
diff -uNr postgresql-head-20131017/src/test/regress/sql/union.sql postgresql-head-20131017-nchar/src/test/regress/sql/union.sql
--- postgresql-head-20131017/src/test/regress/sql/union.sql	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/sql/union.sql	2013-10-17 11:56:22.000000000 +1100
@@ -89,6 +89,23 @@
 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
 --
diff -uNr postgresql-head-20131017/src/test/regress/sql/update.sql postgresql-head-20131017-nchar/src/test/regress/sql/update.sql
--- postgresql-head-20131017/src/test/regress/sql/update.sql	2013-10-17 04:22:55.000000000 +1100
+++ postgresql-head-20131017-nchar/src/test/regress/sql/update.sql	2013-10-17 11:56:22.000000000 +1100
@@ -5,14 +5,28 @@
 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;


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], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [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