Thread: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

[bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
"Tsunakawa, Takayuki"
Date:
Hello,

Some user hit a problem with ECPG on Windows.  The attached patch is a fix for it.  I'd appreciate it if you could
backportthis in all supported versions.
 

The problem is simple.  free() in the following example crashes:

    char *out;

    out = PGTYPESnumeric_to_asc(...);
    free(out);

The cause is the mismatch of the version of C runtime library.  The version of Visual Studio used to build the
applicationwas different from that for building PostgreSQL (libpgtypes.dll).
 

The fix is to add PGTYPES_free() in libpgtypes.dll, just like libpq has PQfreemem() described here:

https://www.postgresql.org/docs/devel/static/libpq-misc.html


Regards
Takayuki Tsunakawa


Attachment

Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Thomas Munro
Date:
On Fri, Feb 2, 2018 at 3:47 PM, Tsunakawa, Takayuki
<tsunakawa.takay@jp.fujitsu.com> wrote:
> The fix is to add PGTYPES_free() in libpgtypes.dll, just like libpq has PQfreemem() described here:

+#ifndef PGTYPES_FREE
+#define PGTYPES_FREE
+ extern void PGTYPES_free(void *ptr);
+#endif

It seems quite strange to repeat this in pgtypes_date.h,
pgtypes_interval.h and pgtypes_numeric.h.  I guess you might not want
to introduce a new common header file so that his can be back-patched
more easily?  Not sure if there is a project policy about that, but it
seems unfortunate to introduce maintenance burden by duplicating this.

+   <function>PGTYPES_free()/<function> instead of <function>free()</function>.

The "/" needs to move inside then closing tag.

-- 
Thomas Munro
http://www.enterprisedb.com


RE: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
"Tsunakawa, Takayuki"
Date:
From: Thomas Munro [mailto:thomas.munro@enterprisedb.com]
> +#ifndef PGTYPES_FREE
> +#define PGTYPES_FREE
> + extern void PGTYPES_free(void *ptr);
> +#endif
> 
> It seems quite strange to repeat this in pgtypes_date.h, pgtypes_interval.h
> and pgtypes_numeric.h.  I guess you might not want to introduce a new common
> header file so that his can be back-patched more easily?  Not sure if there
> is a project policy about that, but it seems unfortunate to introduce
> maintenance burden by duplicating this.

Your guess is correct.  I wanted to avoid the duplication, but there was no good place to put this without requiring
existingapplications to change their #include directives.  
 


> +   <function>PGTYPES_free()/<function> instead of
> <function>free()</function>.
> 
> The "/" needs to move inside then closing tag.

Thanks, fixed.

Regards
Takayuki Tsunakawa


Attachment

Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Kyotaro HORIGUCHI
Date:
Hello.

The objective of this patch looks reasonable and this doesn't
affect ecpg applications except for the problematic case that
happens only on Windows. So the points here are only the
documentation, the new function name and the how we should place
the new defintion.

At Mon, 5 Feb 2018 00:53:47 +0000, "Tsunakawa, Takayuki" <tsunakawa.takay@jp.fujitsu.com> wrote in
<0A3221C70F24FB45833433255569204D1F8AE06B@G01JPEXMBYT05>
> From: Thomas Munro [mailto:thomas.munro@enterprisedb.com]
> > +#ifndef PGTYPES_FREE
> > +#define PGTYPES_FREE
> > + extern void PGTYPES_free(void *ptr);
> > +#endif
> > 
> > It seems quite strange to repeat this in pgtypes_date.h, pgtypes_interval.h
> > and pgtypes_numeric.h.  I guess you might not want to introduce a new common
> > header file so that his can be back-patched more easily?  Not sure if there
> > is a project policy about that, but it seems unfortunate to introduce
> > maintenance burden by duplicating this.
> 
> Your guess is correct.  I wanted to avoid the duplication, but there was no good place to put this without requiring
existingapplications to change their #include directives.  
 
> 
> 
> > +   <function>PGTYPES_free()/<function> instead of
> > <function>free()</function>.
> > 
> > The "/" needs to move inside then closing tag.
> 
> Thanks, fixed.

The types PGTYPES* has corresponding PGTYPES*_free() functions. I
found it a bit strange that the function is named as
PGTYPES_free(), which looks as if it is generic for all PGTYPES*
types. Perhaps PGTYPESchar_free() or PGTYPEStext_free() would be
preferable.

The documentation for PQescapeByteaConn is saying that:

https://www.postgresql.org/docs/10/static/libpq-exec.html#LIBPQ-PQESCAPEBYTEACONN

> PQescapeByteaConn returns an escaped version of the from
> parameter binary string in memory allocated with malloc(). This
> memory should be freed using PQfreemem() when the result is no
> longer needed.

The similar description is needed for the four counterparts of
the new free function nor users doesn't have a definite
suggestion on where to use it.

I cannot (or am quite reluctant to^^;) replay the problem,
instead, I looked over the test/* files and the replacement looks
correct.

I agree to Thomas on the opinion that the definition of
PGTYPES_free shouldn't be scattered around. There's some header
files that has only one or two function defenitions. I believe
that a new header file having only this definition is preferable
than the current shape.

# By the way, I think that multiple occurance of function
# prototypes for the same function don't get error as long as
# they are identical. Or does for CL?

> Your guess is correct.  I wanted to avoid the duplication, but
> there was no good place to put this without requiring existing
> applications to change their #include directives.

I suppose that it is enough to let the pgtype headers
(pgtypes_(timestamp|numeric|interfval).h) include the new common
header. *I* think that it is better than multiple definitions for
the same function are placed here and there. Applications don't
need to be changed with this.

# Anyway existing applications need to replace free() to
# PGTYPES_free()..

I think this doesn't need more profound review so I'll mark this
Ready For Commit after confirming the amendment.

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center



Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
"MauMau"
Date:
From: Kyotaro HORIGUCHI 
The objective of this patch looks reasonable and this doesn't
affect ecpg applications except for the problematic case that
happens only on Windows. So the points here are only the
documentation, the new function name and the how we should place
the new defintion.

I think this doesn't need more profound review so I'll mark this
Ready For Commit after confirming the amendment.


I'm sorry for my late reply.  Last week I was off for a week.

And thank you for your review.  All modifications are done.


Regards
MauMau

Attachment

Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Kyotaro HORIGUCHI
Date:
At Sun, 25 Mar 2018 22:15:52 +0900, "MauMau" <maumau307@gmail.com> wrote in <B3BEB35436E3471095762969E2FCEDD6@tunaPC>
> And thank you for your review.  All modifications are done.

Thank you for the new version. I marked this as "Ready for
Committer" with one change.

- Windows requires this since different versions (MT/non-MT and
  DEBUG/RELEASE?) of CRT are not compatible on malloc/free, which
  is the same reason for PQfreemem().

- It applies on the master HEAD cleanly. Compiled with no
  error. (Except for having some warnings with MSB8018 *1 for
  some mb modules and seemingly harmless C4818 for many files and
  this patch is not to blame.)

- Documentation looks fine.

- The change on regtest looks fine and ran sucessfully on both
  Linux and Windows (vcregress ecpgcheck).  But it doesn't prove
  anything about the different versions of CRT library.  (The
  same can be said about PQfreemem())

- Style looks fine with one exception that extern "C" is
  increasing indentation, so I fixed that in the attached
  version.

*1: "The intermediate directory contains files shared from
    another project" for pg_archivecleanup, pg_stat_statements,
    pg_isolation_regress, latin2_and_win1250, utf8_and_cyrillic,
    utf8_and_iso8859 and utf8_and_sjis2004.

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml
index 98b6840520..3b8a7abaec 100644
--- a/doc/src/sgml/ecpg.sgml
+++ b/doc/src/sgml/ecpg.sgml
@@ -1951,9 +1951,14 @@ EXEC SQL SELECT started, duration INTO :ts1, :iv1 FROM datetbl WHERE d=:date1;
 PGTYPEStimestamp_add_interval(&ts1, &iv1, &tsout);
 out = PGTYPEStimestamp_to_asc(&tsout);
 printf("Started + duration: %s\n", out);
-free(out);
+PGTYPESchar_free(out);
 ]]>
 </programlisting>
+   Some functions such as <function>PGTYPESnumeric_to_asc</function> return
+   a character string. To free those strings, you need to use
+   <function>PGTYPESchar_free()</function> instead of <function>free()</function>.
+   This is necessary for Windows, because memory allocation and release must be
+   done with the functions in the same version of library.
   </para>
 
   <sect2 id="ecpg-pgtypes-numeric">
@@ -2029,6 +2034,7 @@ char *PGTYPESnumeric_to_asc(numeric *num, int dscale);
 </synopsis>
        The numeric value will be printed with <literal>dscale</literal> decimal
        digits, with rounding applied if necessary.
+       You need to free the string with <function>PGTYPESchar_free()</function>.
       </para>
      </listitem>
     </varlistentry>
@@ -2419,6 +2425,7 @@ char *PGTYPESdate_to_asc(date dDate);
         The function receives the date <literal>dDate</literal> as its only parameter.
         It will output the date in the form <literal>1999-01-18</literal>, i.e., in the
         <literal>YYYY-MM-DD</literal> format.
+        You need to free the string with <function>PGTYPESchar_free()</function>.
        </para>
       </listitem>
      </varlistentry>
@@ -2841,6 +2848,7 @@ char *PGTYPEStimestamp_to_asc(timestamp tstamp);
         The function receives the timestamp <literal>tstamp</literal> as
         its only argument and returns an allocated string that contains the
         textual representation of the timestamp.
+        You need to free the string with <function>PGTYPESchar_free()</function>.
        </para>
       </listitem>
      </varlistentry>
@@ -3349,6 +3357,7 @@ char *PGTYPESinterval_to_asc(interval *span);
         The function converts the interval variable that <literal>span</literal>
         points to into a C char*. The output looks like this example:
         <literal>@ 1 day 12 hours 59 mins 10 secs</literal>.
+        You need to free the string with <function>PGTYPESchar_free()</function>.
        </para>
       </listitem>
      </varlistentry>
diff --git a/src/interfaces/ecpg/include/Makefile b/src/interfaces/ecpg/include/Makefile
index e92e56f26f..9c68bf3c47 100644
--- a/src/interfaces/ecpg/include/Makefile
+++ b/src/interfaces/ecpg/include/Makefile
@@ -14,7 +14,7 @@ install: all installdirs install-headers
 
 .PHONY: install-headers
 ecpg_headers = ecpgerrno.h ecpglib.h ecpgtype.h sqlca.h sql3types.h ecpg_informix.h \
-    pgtypes_error.h pgtypes_numeric.h pgtypes_timestamp.h pgtypes_date.h pgtypes_interval.h \
+    pgtypes_error.h pgtypes_numeric.h pgtypes_timestamp.h pgtypes_date.h pgtypes_interval.h pgtypes.h \
     sqlda.h sqlda-compat.h sqlda-native.h
 informix_headers = datetime.h decimal.h sqltypes.h
 
diff --git a/src/interfaces/ecpg/include/pgtypes.h b/src/interfaces/ecpg/include/pgtypes.h
new file mode 100644
index 0000000000..dbf759b45f
--- /dev/null
+++ b/src/interfaces/ecpg/include/pgtypes.h
@@ -0,0 +1,17 @@
+/* src/interfaces/ecpg/include/pgtypes.h */
+
+#ifndef PGTYPES_H
+#define PGTYPES_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern void PGTYPESchar_free(char *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                            /* PGTYPES_H */
diff --git a/src/interfaces/ecpg/include/pgtypes_interval.h b/src/interfaces/ecpg/include/pgtypes_interval.h
index 5747736fe1..3b17cd1d11 100644
--- a/src/interfaces/ecpg/include/pgtypes_interval.h
+++ b/src/interfaces/ecpg/include/pgtypes_interval.h
@@ -4,6 +4,7 @@
 #define PGTYPES_INTERVAL
 
 #include <ecpg_config.h>
+#include <pgtypes.h>
 
 #ifndef C_H
 
diff --git a/src/interfaces/ecpg/include/pgtypes_numeric.h b/src/interfaces/ecpg/include/pgtypes_numeric.h
index 56c46ea272..5c763a9eb6 100644
--- a/src/interfaces/ecpg/include/pgtypes_numeric.h
+++ b/src/interfaces/ecpg/include/pgtypes_numeric.h
@@ -1,6 +1,8 @@
 #ifndef PGTYPES_NUMERIC
 #define PGTYPES_NUMERIC
 
+#include <pgtypes.h>
+
 #define NUMERIC_POS                        0x0000
 #define NUMERIC_NEG                        0x4000
 #define NUMERIC_NAN                        0xC000
diff --git a/src/interfaces/ecpg/pgtypeslib/common.c b/src/interfaces/ecpg/pgtypeslib/common.c
index ae29b6c4ab..f67b05eb94 100644
--- a/src/interfaces/ecpg/pgtypeslib/common.c
+++ b/src/interfaces/ecpg/pgtypeslib/common.c
@@ -138,3 +138,10 @@ pgtypes_fmt_replace(union un_fmt_comb replace_val, int replace_type, char **outp
     }
     return 0;
 }
+
+/* Just frees memory (mostly needed for Windows) */
+void
+PGTYPESchar_free(char *ptr)
+{
+    free(ptr);
+}
diff --git a/src/interfaces/ecpg/pgtypeslib/exports.txt b/src/interfaces/ecpg/pgtypeslib/exports.txt
index 70ef01a8a7..2d5ec17656 100644
--- a/src/interfaces/ecpg/pgtypeslib/exports.txt
+++ b/src/interfaces/ecpg/pgtypeslib/exports.txt
@@ -45,3 +45,4 @@ PGTYPEStimestamp_from_asc       42
 PGTYPEStimestamp_sub            43
 PGTYPEStimestamp_sub_interval   44
 PGTYPEStimestamp_to_asc         45
+PGTYPESchar_free                46
diff --git a/src/interfaces/ecpg/pgtypeslib/extern.h b/src/interfaces/ecpg/pgtypeslib/extern.h
index 9df800ea1d..b84304f970 100644
--- a/src/interfaces/ecpg/pgtypeslib/extern.h
+++ b/src/interfaces/ecpg/pgtypeslib/extern.h
@@ -37,6 +37,7 @@ int            pgtypes_fmt_replace(union un_fmt_comb, int, char **, int *);
 
 char       *pgtypes_alloc(long);
 char       *pgtypes_strdup(const char *);
+void PGTYPESchar_free(char *ptr);
 
 #ifndef bool
 #define bool char
diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
index 3f90022b54..1509a56fd8 100644
--- a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
+++ b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
@@ -113,18 +113,18 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
 
     text = PGTYPESdate_to_asc(date1);
     printf ("Date: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     text = PGTYPEStimestamp_to_asc(ts1);
     printf ("timestamp: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     iv1 = PGTYPESinterval_from_asc("13556 days 12 hours 34 minutes 14 seconds ", NULL);
     PGTYPESinterval_copy(iv1, &iv2);
     text = PGTYPESinterval_to_asc(&iv2);
     printf ("interval: %s\n", text);
     PGTYPESinterval_free(iv1);
-    free(text);
+    PGTYPESchar_free(text);
 
     PGTYPESdate_mdyjul(mdy, &date2);
     printf("m: %d, d: %d, y: %d\n", mdy[0], mdy[1], mdy[2]);
@@ -144,7 +144,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_fmt_asc(date1, fmt, out);
     printf("date_day of %s is %d\n", text, PGTYPESdate_dayofweek(date1));
     printf("Above date in format \"%s\" is \"%s\"\n", fmt, out);
-    free(text);
+    PGTYPESchar_free(text);
     free(out);
 
     out = (char*) malloc(48);
@@ -164,7 +164,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc1: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mmmm. dd. yyyy";
@@ -172,7 +172,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc2: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "yy/mm/dd";
@@ -180,7 +180,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc3: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "yy/mm/dd";
@@ -188,7 +188,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc4: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "dd-mm-yy";
@@ -196,7 +196,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc5: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mmddyy";
@@ -204,7 +204,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc6: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mmm. dd. yyyy";
@@ -212,7 +212,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc7: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mmm. dd. yyyy";
@@ -220,7 +220,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc8: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mm yy   dd.";
@@ -228,7 +228,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc9: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "yyyy fierj mm   dd.";
@@ -236,7 +236,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc10: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mm/dd/yy";
@@ -244,28 +244,28 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc12: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     PGTYPEStimestamp_current(&ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     /* can't output this in regression mode */
     /* printf("timestamp_current: Now: %s\n", text); */
-    free(text);
+    PGTYPESchar_free(text);
 
     ts1 = PGTYPEStimestamp_from_asc("96-02-29", NULL);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_to_asc1: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     ts1 = PGTYPEStimestamp_from_asc("1994-02-11 3:10:35", NULL);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_to_asc2: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     ts1 = PGTYPEStimestamp_from_asc("1994-02-11 26:10:35", NULL);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_to_asc3: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
 /*    abc-03:10:35-def-02/11/94-gh  */
 /*      12345678901234567890123456789 */
@@ -280,161 +280,161 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Jul 22 17:28:44 +0200 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Feb 29 17:28:44 +0200 2000";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Feb 29 17:28:44 +0200 1900";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Feb 29 17:28:44 +0200 1996";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%b %d %H:%M:%S %z %Y";
     in =  "      Jul 31 17:28:44 +0200 1996";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%b %d %H:%M:%S %z %Y";
     in =  "      Jul 32 17:28:44 +0200 1996";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Feb 29 17:28:44 +0200 1997";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%";
     in =  "Tue Jul 22 17:28:44 +0200 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "a %";
     in =  "Tue Jul 22 17:28:44 +0200 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%b, %d %H_%M`%S %z %Y";
     in =  "    Jul, 22 17_28 `44 +0200  2003  ";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %%%d %H:%M:%S %Z %Y";
     in =  "Tue Jul %22 17:28:44 CEST 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %%%d %H:%M:%S %Z %Y";
     in =  "Tue Jul %22 17:28:44 CEST 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "abc%n %C %B %%%d %H:%M:%S %Z %Y";
     in =  "abc\n   19 October %22 17:28:44 CEST 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "abc%n %C %B %%%d %H:%M:%S %Z %y";
     in =  "abc\n   18 October %34 17:28:44 CEST 80";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "";
     in =  "abc\n   18 October %34 17:28:44 CEST 80";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = NULL;
     in =  "1980-04-12 3:49:44      ";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, NULL) = %s, error: %d\n", in, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%B %d, %Y. Time: %I:%M%p";
     in =  "July 14, 1988. Time: 9:15am";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "September 6 at 01:30 pm in the year 1983";
     fmt = "%B %d at %I:%M %p in the year %Y";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "  1976, July 14. Time: 9:15am";
     fmt = "%Y,   %B %d. Time: %I:%M %p";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "  1976, July 14. Time: 9:15 am";
     fmt = "%Y,   %B %d. Time: %I:%M%p";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "  1976, P.M. July 14. Time: 9:15";
     fmt = "%Y, %P  %B %d. Time: %I:%M";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "1234567890";
     fmt = "%s";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     { ECPGtrans(__LINE__, NULL, "rollback");
 #line 365 "dt_test.pgc"
diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
index 4024980f1e..b3e1e7519d 100644
--- a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
+++ b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
@@ -110,14 +110,14 @@ main(void)
     text = PGTYPEStimestamp_to_asc(ts1);
 
     printf("timestamp: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = PGTYPESdate_from_timestamp(ts1);
     dc = PGTYPESdate_new();
     *dc = date1;
     text = PGTYPESdate_to_asc(*dc);
     printf("Date of timestamp: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESdate_free(dc);
 
     for (i = 0; dates[i]; i++)
@@ -132,7 +132,7 @@ main(void)
                     i, err ? "-" : text,
                     endptr ? 'N' : 'Y',
                     err ? 'T' : 'F');
-        free(text);
+        PGTYPESchar_free(text);
         if (!err)
         {
             for (j = 0; times[j]; j++)
@@ -147,7 +147,7 @@ main(void)
                 text = PGTYPEStimestamp_to_asc(ts1);
                 printf("TS[%d,%d]: %s\n",
                        i, j, errno ? "-" : text);
-                free(text);
+                PGTYPESchar_free(text);
                 free(t);
             }
         }
@@ -171,13 +171,13 @@ main(void)
             continue;
         text = PGTYPESinterval_to_asc(i1);
         printf("interval[%d]: %s\n", i, text ? text : "-");
-        free(text);
+        PGTYPESchar_free(text);
 
         ic = PGTYPESinterval_new();
         PGTYPESinterval_copy(i1, ic);
         text = PGTYPESinterval_to_asc(i1);
         printf("interval_copy[%d]: %s\n", i, text ? text : "-");
-        free(text);
+        PGTYPESchar_free(text);
         PGTYPESinterval_free(ic);
         PGTYPESinterval_free(i1);
     }
diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c
b/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c
index 47c320291f..1b1239eaca 100644
--- a/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c
+++ b/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c
@@ -78,7 +78,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESnumeric_from_int(1407, value1);
     text = PGTYPESnumeric_to_asc(value1, -1);
     printf("from int = %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESnumeric_free(value1);
 
     value1 = PGTYPESnumeric_from_asc("2369.7", NULL);
@@ -87,12 +87,12 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESnumeric_add(value1, value2, res);
     text = PGTYPESnumeric_to_asc(res, -1);
     printf("add = %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     PGTYPESnumeric_sub(res, value2, res);
     text = PGTYPESnumeric_to_asc(res, -1);
     printf("sub = %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESnumeric_free(value2);
 
     des = PGTYPESnumeric_new();
@@ -122,7 +122,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     PGTYPESnumeric_mul(res, des, res);
     text = PGTYPESnumeric_to_asc(res, -1);
     printf("mul = %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESnumeric_free(des);
 
     value2 = PGTYPESnumeric_from_asc("10000", NULL);
@@ -139,7 +139,7 @@ if (sqlca.sqlcode < 0) sqlprint ( );}
     i = PGTYPESnumeric_to_long(value1, &l1) | PGTYPESnumeric_to_long(value2, &l2);
     printf("to long(%d) = %ld %ld\n", i, l1, l2);
 
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESnumeric_free(value1);
     PGTYPESnumeric_free(value2);
     PGTYPESnumeric_free(res);
diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-num_test2.c
b/src/interfaces/ecpg/test/expected/pgtypeslib-num_test2.c
index d31834e2c0..aaab4ad7d7 100644
--- a/src/interfaces/ecpg/test/expected/pgtypeslib-num_test2.c
+++ b/src/interfaces/ecpg/test/expected/pgtypeslib-num_test2.c
@@ -77,21 +77,21 @@ main(void)
 
         text = PGTYPESnumeric_to_asc(num, -1);
         if (!text) check_errno();
-        printf("num[%d,1]: %s\n", i, text); free(text);
+        printf("num[%d,1]: %s\n", i, text); PGTYPESchar_free(text);
         text = PGTYPESnumeric_to_asc(num, 0);
         if (!text) check_errno();
-        printf("num[%d,2]: %s\n", i, text); free(text);
+        printf("num[%d,2]: %s\n", i, text); PGTYPESchar_free(text);
         text = PGTYPESnumeric_to_asc(num, 1);
         if (!text) check_errno();
-        printf("num[%d,3]: %s\n", i, text); free(text);
+        printf("num[%d,3]: %s\n", i, text); PGTYPESchar_free(text);
         text = PGTYPESnumeric_to_asc(num, 2);
         if (!text) check_errno();
-        printf("num[%d,4]: %s\n", i, text); free(text);
+        printf("num[%d,4]: %s\n", i, text); PGTYPESchar_free(text);
 
         nin = PGTYPESnumeric_new();
         text = PGTYPESnumeric_to_asc(nin, 2);
         if (!text) check_errno();
-        printf("num[%d,5]: %s\n", i, text); free(text);
+        printf("num[%d,5]: %s\n", i, text); PGTYPESchar_free(text);
 
         r = PGTYPESnumeric_to_long(num, &l);
         if (r) check_errno();
@@ -103,7 +103,7 @@ main(void)
             text = PGTYPESnumeric_to_asc(nin, 2);
             q = PGTYPESnumeric_cmp(num, nin);
             printf("num[%d,7]: %s (r: %d - cmp: %d)\n", i, text, r, q);
-            free(text);
+            PGTYPESchar_free(text);
         }
 
         r = PGTYPESnumeric_to_int(num, &k);
@@ -116,7 +116,7 @@ main(void)
             text = PGTYPESnumeric_to_asc(nin, 2);
             q = PGTYPESnumeric_cmp(num, nin);
             printf("num[%d,9]: %s (r: %d - cmp: %d)\n", i, text, r, q);
-            free(text);
+            PGTYPESchar_free(text);
         }
 
         if (i != 6)
@@ -147,7 +147,7 @@ main(void)
             text = PGTYPESnumeric_to_asc(nin, 2);
             q = PGTYPESnumeric_cmp(num, nin);
             printf("num[%d,12]: %s (r: %d - cmp: %d)\n", i, text, r, q);
-            free(text);
+            PGTYPESchar_free(text);
         }
 
         PGTYPESdecimal_free(dec);
@@ -173,7 +173,7 @@ main(void)
             {
                 text = PGTYPESnumeric_to_asc(a, 10);
                 printf("num[a,%d,%d]: %s\n", i, j, text);
-                free(text);
+                PGTYPESchar_free(text);
             }
             r = PGTYPESnumeric_sub(numarr[i], numarr[j], s);
             if (r)
@@ -185,7 +185,7 @@ main(void)
             {
                 text = PGTYPESnumeric_to_asc(s, 10);
                 printf("num[s,%d,%d]: %s\n", i, j, text);
-                free(text);
+                PGTYPESchar_free(text);
             }
             r = PGTYPESnumeric_mul(numarr[i], numarr[j], m);
             if (r)
@@ -197,7 +197,7 @@ main(void)
             {
                 text = PGTYPESnumeric_to_asc(m, 10);
                 printf("num[m,%d,%d]: %s\n", i, j, text);
-                free(text);
+                PGTYPESchar_free(text);
             }
             r = PGTYPESnumeric_div(numarr[i], numarr[j], d);
             if (r)
@@ -209,7 +209,7 @@ main(void)
             {
                 text = PGTYPESnumeric_to_asc(d, 10);
                 printf("num[d,%d,%d]: %s\n", i, j, text);
-                free(text);
+                PGTYPESchar_free(text);
             }
 
             PGTYPESnumeric_free(a);
@@ -223,7 +223,7 @@ main(void)
     {
         text = PGTYPESnumeric_to_asc(numarr[i], -1);
         printf("%d: %s\n", i, text);
-        free(text);
+        PGTYPESchar_free(text);
         PGTYPESnumeric_free(numarr[i]);
     }
     free(numarr);
diff --git a/src/interfaces/ecpg/test/expected/preproc-outofscope.c
b/src/interfaces/ecpg/test/expected/preproc-outofscope.c
index f4676a083a..940cd7a31d 100644
--- a/src/interfaces/ecpg/test/expected/preproc-outofscope.c
+++ b/src/interfaces/ecpg/test/expected/preproc-outofscope.c
@@ -28,6 +28,8 @@
 #ifndef PGTYPES_NUMERIC
 #define PGTYPES_NUMERIC
 
+#include <pgtypes.h>
+
 #define NUMERIC_POS                        0x0000
 #define NUMERIC_NEG                        0x4000
 #define NUMERIC_NAN                        0xC000
diff --git a/src/interfaces/ecpg/test/expected/sql-sqlda.c b/src/interfaces/ecpg/test/expected/sql-sqlda.c
index ffaf52ca5c..8e6b600fc9 100644
--- a/src/interfaces/ecpg/test/expected/sql-sqlda.c
+++ b/src/interfaces/ecpg/test/expected/sql-sqlda.c
@@ -50,6 +50,8 @@ typedef struct sqlda_struct sqlda_t;
 #ifndef PGTYPES_NUMERIC
 #define PGTYPES_NUMERIC
 
+#include <pgtypes.h>
+
 #define NUMERIC_POS                        0x0000
 #define NUMERIC_NEG                        0x4000
 #define NUMERIC_NAN                        0xC000
diff --git a/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc b/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc
index 1cc156c3dc..95632fffee 100644
--- a/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc
+++ b/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc
@@ -39,18 +39,18 @@ main(void)
 
     text = PGTYPESdate_to_asc(date1);
     printf ("Date: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     text = PGTYPEStimestamp_to_asc(ts1);
     printf ("timestamp: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     iv1 = PGTYPESinterval_from_asc("13556 days 12 hours 34 minutes 14 seconds ", NULL);
     PGTYPESinterval_copy(iv1, &iv2);
     text = PGTYPESinterval_to_asc(&iv2);
     printf ("interval: %s\n", text);
     PGTYPESinterval_free(iv1);
-    free(text);
+    PGTYPESchar_free(text);
 
     PGTYPESdate_mdyjul(mdy, &date2);
     printf("m: %d, d: %d, y: %d\n", mdy[0], mdy[1], mdy[2]);
@@ -70,7 +70,7 @@ main(void)
     PGTYPESdate_fmt_asc(date1, fmt, out);
     printf("date_day of %s is %d\n", text, PGTYPESdate_dayofweek(date1));
     printf("Above date in format \"%s\" is \"%s\"\n", fmt, out);
-    free(text);
+    PGTYPESchar_free(text);
     free(out);
 
     out = (char*) malloc(48);
@@ -90,7 +90,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc1: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mmmm. dd. yyyy";
@@ -98,7 +98,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc2: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "yy/mm/dd";
@@ -106,7 +106,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc3: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "yy/mm/dd";
@@ -114,7 +114,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc4: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "dd-mm-yy";
@@ -122,7 +122,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc5: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mmddyy";
@@ -130,7 +130,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc6: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mmm. dd. yyyy";
@@ -138,7 +138,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc7: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mmm. dd. yyyy";
@@ -146,7 +146,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc8: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mm yy   dd.";
@@ -154,7 +154,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc9: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "yyyy fierj mm   dd.";
@@ -162,7 +162,7 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc10: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = 0;
     fmt = "mm/dd/yy";
@@ -170,28 +170,28 @@ main(void)
     PGTYPESdate_defmt_asc(&date1, fmt, in);
     text = PGTYPESdate_to_asc(date1);
     printf("date_defmt_asc12: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     PGTYPEStimestamp_current(&ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     /* can't output this in regression mode */
     /* printf("timestamp_current: Now: %s\n", text); */
-    free(text);
+    PGTYPESchar_free(text);
 
     ts1 = PGTYPEStimestamp_from_asc("96-02-29", NULL);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_to_asc1: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     ts1 = PGTYPEStimestamp_from_asc("1994-02-11 3:10:35", NULL);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_to_asc2: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     ts1 = PGTYPEStimestamp_from_asc("1994-02-11 26:10:35", NULL);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_to_asc3: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
 /*    abc-03:10:35-def-02/11/94-gh  */
 /*      12345678901234567890123456789 */
@@ -206,161 +206,161 @@ main(void)
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Jul 22 17:28:44 +0200 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Feb 29 17:28:44 +0200 2000";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Feb 29 17:28:44 +0200 1900";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Feb 29 17:28:44 +0200 1996";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%b %d %H:%M:%S %z %Y";
     in =  "      Jul 31 17:28:44 +0200 1996";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%b %d %H:%M:%S %z %Y";
     in =  "      Jul 32 17:28:44 +0200 1996";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %d %H:%M:%S %z %Y";
     in =  "Tue Feb 29 17:28:44 +0200 1997";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%";
     in =  "Tue Jul 22 17:28:44 +0200 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "a %";
     in =  "Tue Jul 22 17:28:44 +0200 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%b, %d %H_%M`%S %z %Y";
     in =  "    Jul, 22 17_28 `44 +0200  2003  ";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %%%d %H:%M:%S %Z %Y";
     in =  "Tue Jul %22 17:28:44 CEST 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%a %b %%%d %H:%M:%S %Z %Y";
     in =  "Tue Jul %22 17:28:44 CEST 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "abc%n %C %B %%%d %H:%M:%S %Z %Y";
     in =  "abc\n   19 October %22 17:28:44 CEST 2003";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "abc%n %C %B %%%d %H:%M:%S %Z %y";
     in =  "abc\n   18 October %34 17:28:44 CEST 80";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "";
     in =  "abc\n   18 October %34 17:28:44 CEST 80";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error (should be error!): %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = NULL;
     in =  "1980-04-12 3:49:44      ";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, NULL) = %s, error: %d\n", in, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     fmt = "%B %d, %Y. Time: %I:%M%p";
     in =  "July 14, 1988. Time: 9:15am";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "September 6 at 01:30 pm in the year 1983";
     fmt = "%B %d at %I:%M %p in the year %Y";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "  1976, July 14. Time: 9:15am";
     fmt = "%Y,   %B %d. Time: %I:%M %p";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "  1976, July 14. Time: 9:15 am";
     fmt = "%Y,   %B %d. Time: %I:%M%p";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "  1976, P.M. July 14. Time: 9:15";
     fmt = "%Y, %P  %B %d. Time: %I:%M";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     in = "1234567890";
     fmt = "%s";
     i = PGTYPEStimestamp_defmt_asc(in, fmt, &ts1);
     text = PGTYPEStimestamp_to_asc(ts1);
     printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
-    free(text);
+    PGTYPESchar_free(text);
 
     exec sql rollback;
         exec sql disconnect;
diff --git a/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc b/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
index 9e1f432823..62b934b07e 100644
--- a/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
+++ b/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
@@ -75,14 +75,14 @@ main(void)
     text = PGTYPEStimestamp_to_asc(ts1);
 
     printf("timestamp: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     date1 = PGTYPESdate_from_timestamp(ts1);
     dc = PGTYPESdate_new();
     *dc = date1;
     text = PGTYPESdate_to_asc(*dc);
     printf("Date of timestamp: %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESdate_free(dc);
 
     for (i = 0; dates[i]; i++)
@@ -97,7 +97,7 @@ main(void)
                     i, err ? "-" : text,
                     endptr ? 'N' : 'Y',
                     err ? 'T' : 'F');
-        free(text);
+        PGTYPESchar_free(text);
         if (!err)
         {
             for (j = 0; times[j]; j++)
@@ -112,7 +112,7 @@ main(void)
                 text = PGTYPEStimestamp_to_asc(ts1);
                 printf("TS[%d,%d]: %s\n",
                        i, j, errno ? "-" : text);
-                free(text);
+                PGTYPESchar_free(text);
                 free(t);
             }
         }
@@ -136,13 +136,13 @@ main(void)
             continue;
         text = PGTYPESinterval_to_asc(i1);
         printf("interval[%d]: %s\n", i, text ? text : "-");
-        free(text);
+        PGTYPESchar_free(text);
 
         ic = PGTYPESinterval_new();
         PGTYPESinterval_copy(i1, ic);
         text = PGTYPESinterval_to_asc(i1);
         printf("interval_copy[%d]: %s\n", i, text ? text : "-");
-        free(text);
+        PGTYPESchar_free(text);
         PGTYPESinterval_free(ic);
         PGTYPESinterval_free(i1);
     }
diff --git a/src/interfaces/ecpg/test/pgtypeslib/num_test.pgc b/src/interfaces/ecpg/test/pgtypeslib/num_test.pgc
index d276f70772..9891270494 100644
--- a/src/interfaces/ecpg/test/pgtypeslib/num_test.pgc
+++ b/src/interfaces/ecpg/test/pgtypeslib/num_test.pgc
@@ -38,7 +38,7 @@ main(void)
     PGTYPESnumeric_from_int(1407, value1);
     text = PGTYPESnumeric_to_asc(value1, -1);
     printf("from int = %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESnumeric_free(value1);
 
     value1 = PGTYPESnumeric_from_asc("2369.7", NULL);
@@ -47,12 +47,12 @@ main(void)
     PGTYPESnumeric_add(value1, value2, res);
     text = PGTYPESnumeric_to_asc(res, -1);
     printf("add = %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
 
     PGTYPESnumeric_sub(res, value2, res);
     text = PGTYPESnumeric_to_asc(res, -1);
     printf("sub = %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESnumeric_free(value2);
 
     des = PGTYPESnumeric_new();
@@ -68,7 +68,7 @@ main(void)
     PGTYPESnumeric_mul(res, des, res);
     text = PGTYPESnumeric_to_asc(res, -1);
     printf("mul = %s\n", text);
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESnumeric_free(des);
 
     value2 = PGTYPESnumeric_from_asc("10000", NULL);
@@ -85,7 +85,7 @@ main(void)
     i = PGTYPESnumeric_to_long(value1, &l1) | PGTYPESnumeric_to_long(value2, &l2);
     printf("to long(%d) = %ld %ld\n", i, l1, l2);
 
-    free(text);
+    PGTYPESchar_free(text);
     PGTYPESnumeric_free(value1);
     PGTYPESnumeric_free(value2);
     PGTYPESnumeric_free(res);
diff --git a/src/interfaces/ecpg/test/pgtypeslib/num_test2.pgc b/src/interfaces/ecpg/test/pgtypeslib/num_test2.pgc
index 16ca6a44a5..edc0c8c057 100644
--- a/src/interfaces/ecpg/test/pgtypeslib/num_test2.pgc
+++ b/src/interfaces/ecpg/test/pgtypeslib/num_test2.pgc
@@ -59,21 +59,21 @@ main(void)
 
         text = PGTYPESnumeric_to_asc(num, -1);
         if (!text) check_errno();
-        printf("num[%d,1]: %s\n", i, text); free(text);
+        printf("num[%d,1]: %s\n", i, text); PGTYPESchar_free(text);
         text = PGTYPESnumeric_to_asc(num, 0);
         if (!text) check_errno();
-        printf("num[%d,2]: %s\n", i, text); free(text);
+        printf("num[%d,2]: %s\n", i, text); PGTYPESchar_free(text);
         text = PGTYPESnumeric_to_asc(num, 1);
         if (!text) check_errno();
-        printf("num[%d,3]: %s\n", i, text); free(text);
+        printf("num[%d,3]: %s\n", i, text); PGTYPESchar_free(text);
         text = PGTYPESnumeric_to_asc(num, 2);
         if (!text) check_errno();
-        printf("num[%d,4]: %s\n", i, text); free(text);
+        printf("num[%d,4]: %s\n", i, text); PGTYPESchar_free(text);
 
         nin = PGTYPESnumeric_new();
         text = PGTYPESnumeric_to_asc(nin, 2);
         if (!text) check_errno();
-        printf("num[%d,5]: %s\n", i, text); free(text);
+        printf("num[%d,5]: %s\n", i, text); PGTYPESchar_free(text);
 
         r = PGTYPESnumeric_to_long(num, &l);
         if (r) check_errno();
@@ -85,7 +85,7 @@ main(void)
             text = PGTYPESnumeric_to_asc(nin, 2);
             q = PGTYPESnumeric_cmp(num, nin);
             printf("num[%d,7]: %s (r: %d - cmp: %d)\n", i, text, r, q);
-            free(text);
+            PGTYPESchar_free(text);
         }
 
         r = PGTYPESnumeric_to_int(num, &k);
@@ -98,7 +98,7 @@ main(void)
             text = PGTYPESnumeric_to_asc(nin, 2);
             q = PGTYPESnumeric_cmp(num, nin);
             printf("num[%d,9]: %s (r: %d - cmp: %d)\n", i, text, r, q);
-            free(text);
+            PGTYPESchar_free(text);
         }
 
         if (i != 6)
@@ -129,7 +129,7 @@ main(void)
             text = PGTYPESnumeric_to_asc(nin, 2);
             q = PGTYPESnumeric_cmp(num, nin);
             printf("num[%d,12]: %s (r: %d - cmp: %d)\n", i, text, r, q);
-            free(text);
+            PGTYPESchar_free(text);
         }
 
         PGTYPESdecimal_free(dec);
@@ -155,7 +155,7 @@ main(void)
             {
                 text = PGTYPESnumeric_to_asc(a, 10);
                 printf("num[a,%d,%d]: %s\n", i, j, text);
-                free(text);
+                PGTYPESchar_free(text);
             }
             r = PGTYPESnumeric_sub(numarr[i], numarr[j], s);
             if (r)
@@ -167,7 +167,7 @@ main(void)
             {
                 text = PGTYPESnumeric_to_asc(s, 10);
                 printf("num[s,%d,%d]: %s\n", i, j, text);
-                free(text);
+                PGTYPESchar_free(text);
             }
             r = PGTYPESnumeric_mul(numarr[i], numarr[j], m);
             if (r)
@@ -179,7 +179,7 @@ main(void)
             {
                 text = PGTYPESnumeric_to_asc(m, 10);
                 printf("num[m,%d,%d]: %s\n", i, j, text);
-                free(text);
+                PGTYPESchar_free(text);
             }
             r = PGTYPESnumeric_div(numarr[i], numarr[j], d);
             if (r)
@@ -191,7 +191,7 @@ main(void)
             {
                 text = PGTYPESnumeric_to_asc(d, 10);
                 printf("num[d,%d,%d]: %s\n", i, j, text);
-                free(text);
+                PGTYPESchar_free(text);
             }
 
             PGTYPESnumeric_free(a);
@@ -205,7 +205,7 @@ main(void)
     {
         text = PGTYPESnumeric_to_asc(numarr[i], -1);
         printf("%d: %s\n", i, text);
-        free(text);
+        PGTYPESchar_free(text);
         PGTYPESnumeric_free(numarr[i]);
     }
     free(numarr);

Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Thomas Munro
Date:
On Mon, Mar 26, 2018 at 6:07 PM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:
> At Sun, 25 Mar 2018 22:15:52 +0900, "MauMau" <maumau307@gmail.com> wrote in
<B3BEB35436E3471095762969E2FCEDD6@tunaPC>
>> And thank you for your review.  All modifications are done.
>
> Thank you for the new version. I marked this as "Ready for
> Committer" with one change.

Hi Tsunakawa-san and Horiguchi-san,

I would like to get this committed soon, but I'm not sure about
backpatching -- see below.  Here's a new version with a couple of
minor changes:

1.  Small changes to the documentation.

2.  I see that you added #include <pgtypes.h> to pgtypes_numeric.h and
pgtypes_interval.h.  They have functions returning char *.  I
experimented with removing those and including <pgtypes.h> directly in
the .pgc test files, but then I saw why you did that: it changes all
the line numbers in the expected output files making the patch much
larger.  No strong objection there.  But I figured we should at least
be consistent, so I added #include <pgtypes.h> to pgtypes_timestamp.h
and pgtypes_date.h (they also declare functions that return new
strings).

3.  It seemed unnecessary to declare the new function in extern.h
*and* in pgtypes.h.  I added #include "pgtypes.h" to common.c instead,
and a comment to introduce the section of that file that defines
functions from pgtypes.h.

4.  I found a place in src/interfaces/ecpg/test/sql/sqlda.pgc where
you missed a free() call.

Are these changes OK?

Why is it OK that we do "free(outp_sqlda)" having got that pointer
from a statement like "exec sql fetch 1 from mycur1 into descriptor
outp_sqlda"?  Isn't that memory allocated by libecpg.dll?

The files in this area all seem to lack our standard boilerplate,
copyright message, blaming everything on UC Berkeley etc.  Your new
header fits the existing pattern, so I can't really complain about
that.

The examples in the documentation call a bunch of _to_asc() functions
and then don't free the result, which is a leak, but that isn't your
patch's fault.  (Example: printf("numeric = %s\n",
PGTYPESnumeric_to_asc(num, 0))).

One question I have is whether it is against project policy to
backport a new file and a new user-facing function.  It doesn't seem
like a great idea, because it means that client code would need to
depend on a specific patch release.  Even if we found an existing
header to declare this function in, you'd still need to do conditional
magic before using it.  So... how inconvenient do you think it would
be if we did this for 11+ only?  Does anyone see a better way to do an
API evolution here?  It's not beautiful but I suppose one work-around
that end-user applications could use while they are stuck on older
releases might be something like this, in their own tree, conditional
on major version:

#define PGTYPESchar_free(x) PGTYPESdate_free((date *)(x))

-- 
Thomas Munro
http://www.enterprisedb.com

Attachment

Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Tom Lane
Date:
Thomas Munro <thomas.munro@enterprisedb.com> writes:
> One question I have is whether it is against project policy to
> backport a new file and a new user-facing function.

Given that this has been broken since forever, and there've been
no complaints before now, I do not think the case for back-patching
is strong enough to justify the problems it would cause.  Just
put it in v11 and be done.

Also, this bit in the proposed documentation seems quite inappropriate:

    (This is a change from earlier releases of
    <productname>PostgreSQL</productname> ...

We don't normally put in such comments at all, and if we do, we
specify which version we're talking about.  Two years from now
this'd be totally confusing.  I'd just make it read

    (This is important only on Windows, where ...

            regards, tom lane


RE: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
"Tsunakawa, Takayuki"
Date:
> From: Thomas Munro [mailto:thomas.munro@enterprisedb.com]
> I would like to get this committed soon, but I'm not sure about backpatching
> -- see below.  Here's a new version with a couple of minor changes:

Thank you for taking care of this patch.


> 1.  Small changes to the documentation.

I agree with Tom on this.


> 2.  I see that you added #include <pgtypes.h> to pgtypes_numeric.h and
> pgtypes_interval.h.  They have functions returning char *.  I
> experimented with removing those and including <pgtypes.h> directly in
> the .pgc test files, but then I saw why you did that: it changes all the
> line numbers in the expected output files making the patch much larger.
> No strong objection there.  But I figured we should at least be consistent,
> so I added #include <pgtypes.h> to pgtypes_timestamp.h and pgtypes_date.h
> (they also declare functions that return new strings).

The reason I added pgtypes.h only in pgtypes_numeric.h and pgtypes_interval.h is that the opgtypes_date.h includes
pgtypes_timestamp.hand pgtypes_timestamp.h in turn includes pgtypes_interval.h.  So additional inclusion of pgtypes.h
wasnot necessary.  But I'm OK with your patch for consistency.
 



> 3.  It seemed unnecessary to declare the new function in extern.h
> *and* in pgtypes.h.  I added #include "pgtypes.h" to common.c instead, and
> a comment to introduce the section of that file that defines functions from
> pgtypes.h.

Agreed, thanks.



> 4.  I found a place in src/interfaces/ecpg/test/sql/sqlda.pgc where you
> missed a free() call.
> 
> Are these changes OK?
> 
> Why is it OK that we do "free(outp_sqlda)" having got that pointer from
> a statement like "exec sql fetch 1 from mycur1 into descriptor outp_sqlda"?
> Isn't that memory allocated by libecpg.dll?

My colleague is now preparing a patch for that, which adds a function ECPGFreeSQLDA() in libecpg.so.  That thread is
here:

https://www.postgresql.org/message-id/25C1C6B2E7BE044889E4FE8643A58BA963A42097@G01JPEXMBKW03




> One question I have is whether it is against project policy to backport
> a new file and a new user-facing function.  It doesn't seem like a great
> idea, because it means that client code would need to depend on a specific
> patch release.  Even if we found an existing header to declare this function
> in, you'd still need to do conditional magic before using it.  So... how
> inconvenient do you think it would be if we did this for 11+ only?  Does
> anyone see a better way to do an API evolution here?  It's not beautiful
> but I suppose one work-around that end-user applications could use while
> they are stuck on older releases might be something like this, in their
> own tree, conditional on major version:
> 
> #define PGTYPESchar_free(x) PGTYPESdate_free((date *)(x))

I want some remedy for older releases.  Our customer worked around this problem by getting a libpq connection in their
ECPGapplication and calling PQfreemem().  That's an ugly kludge, and I don't want other users to follow it.
 

I don't see a problem with back-patching as-is, because existing users who just call free() or don't call free() won't
beaffected.  I think that most serious applications somehow state their supported minor releases like "this application
supports(or is certified against) PostgreSQL 10.5 or later", just like other applications support "RHEL 6.2 or later"
or"Windows XP Sp2 or later."
 


Regards
Takayuki Tsunakawa



Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Thomas Munro
Date:
On Tue, Jun 12, 2018 at 2:04 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Thomas Munro <thomas.munro@enterprisedb.com> writes:
>> One question I have is whether it is against project policy to
>> backport a new file and a new user-facing function.
>
> Given that this has been broken since forever, and there've been
> no complaints before now, I do not think the case for back-patching
> is strong enough to justify the problems it would cause.  Just
> put it in v11 and be done.

Done.

> Also, this bit in the proposed documentation seems quite inappropriate:
>
>         (This is a change from earlier releases of
>         <productname>PostgreSQL</productname> ...
>
> We don't normally put in such comments at all, and if we do, we
> specify which version we're talking about.  Two years from now
> this'd be totally confusing.  I'd just make it read
>
>         (This is important only on Windows, where ...

Done.

On Tue, Jun 12, 2018 at 1:09 PM, Tsunakawa, Takayuki
<tsunakawa.takay@jp.fujitsu.com> wrote:
>> From: Thomas Munro [mailto:thomas.munro@enterprisedb.com]
>> Why is it OK that we do "free(outp_sqlda)" having got that pointer from
>> a statement like "exec sql fetch 1 from mycur1 into descriptor outp_sqlda"?
>> Isn't that memory allocated by libecpg.dll?
>
> My colleague is now preparing a patch for that, which adds a function ECPGFreeSQLDA() in libecpg.so.  That thread is
here:
>
> https://www.postgresql.org/message-id/25C1C6B2E7BE044889E4FE8643A58BA963A42097@G01JPEXMBKW03

Thanks.  I will follow up on that thread.

> I want some remedy for older releases.  Our customer worked around this problem by getting a libpq connection in
theirECPG application and calling PQfreemem().  That's an ugly kludge, and I don't want other users to follow it. 
>
> I don't see a problem with back-patching as-is, because existing users who just call free() or don't call free()
won'tbe affected.  I think that most serious applications somehow state their supported minor releases like "this
applicationsupports (or is certified against) PostgreSQL 10.5 or later", just like other applications support "RHEL 6.2
orlater" or "Windows XP Sp2 or later." 

If there is a consensus that we should do that then I'll back-patch,
but so far no one else has spoken up in support.

--
Thomas Munro
http://www.enterprisedb.com


RE: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
"Tsunakawa, Takayuki"
Date:
> On Tue, Jun 12, 2018 at 1:09 PM, Tsunakawa, Takayuki
> <tsunakawa.takay@jp.fujitsu.com> wrote:
> > My colleague is now preparing a patch for that, which adds a function
> ECPGFreeSQLDA() in libecpg.so.  That thread is here:
> >
> https://www.postgresql.org/message-id/25C1C6B2E7BE044889E4FE8643A58BA9
> 63A42097@G01JPEXMBKW03
> 
> Thanks.  I will follow up on that thread.

He's created a separate thread for a new CF entry here:

https://commitfest.postgresql.org/18/1669/



> > I want some remedy for older releases.  Our customer worked around this
> problem by getting a libpq connection in their ECPG application and calling
> PQfreemem().  That's an ugly kludge, and I don't want other users to follow
> it.
> >
> > I don't see a problem with back-patching as-is, because existing users
> who just call free() or don't call free() won't be affected.  I think that
> most serious applications somehow state their supported minor releases like
> "this application supports (or is certified against) PostgreSQL 10.5 or
> later", just like other applications support "RHEL 6.2 or later" or "Windows
> XP Sp2 or later."
> 
> If there is a consensus that we should do that then I'll back-patch,
> but so far no one else has spoken up in support.

I'll follow the community decision.  But I'm afraid that not enough people will comment on this to call it a consensus,
becausethis topic will not be interesting...  FWIW, I thought back-patching would make committers' future burdon
smallerthanks to the smaller difference in the code of multiple major versions.
 


Regards
Takayuki Tsunakawa



Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Robert Haas
Date:
On Mon, Jun 11, 2018 at 10:04 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Given that this has been broken since forever, and there've been
> no complaints before now, I do not think the case for back-patching
> is strong enough to justify the problems it would cause.  Just
> put it in v11 and be done.

I'm not sure I understand what problem would be created by
back-patching.  It is true that anyone writing code that must work
with any version of PostgreSQL wouldn't able to count on this being
there, but the chances that anyone is writing such software using ECPG
is remote.  In other words, nobody's going to add a version number
test to their ECPG code.  They're just going to apply the update and
then use the new function.

I don't think this is a very important issue so I'm not prepared to
fight about it, but this looks pretty low-risk to me.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Kyotaro HORIGUCHI
Date:
Hello. Thank you for commiting this, Thomas.

At Mon, 18 Jun 2018 07:25:13 +0000, "Tsunakawa, Takayuki" <tsunakawa.takay@jp.fujitsu.com> wrote in
<0A3221C70F24FB45833433255569204D1FA1BCD9@G01JPEXMBYT05>
> > > I want some remedy for older releases.  Our customer worked around this
> > problem by getting a libpq connection in their ECPG application and calling
> > PQfreemem().  That's an ugly kludge, and I don't want other users to follow
> > it.
> > >
> > > I don't see a problem with back-patching as-is, because existing users
> > who just call free() or don't call free() won't be affected.  I think that
> > most serious applications somehow state their supported minor releases like
> > "this application supports (or is certified against) PostgreSQL 10.5 or
> > later", just like other applications support "RHEL 6.2 or later" or "Windows
> > XP Sp2 or later."
> > 
> > If there is a consensus that we should do that then I'll back-patch,
> > but so far no one else has spoken up in support.
> 
> I'll follow the community decision.  But I'm afraid that not
> enough people will comment on this to call it a consensus,
> because this topic will not be interesting...

ECPG x Windows makes very small cardinarity even if it is not
zero. Anyway the vast majority of deverloper here are only
working on Unix like OSes. So only two or three persons can make
consensus on this issue:p

> FWIW, I thought back-patching would make committers' future
> burdon smaller thanks to the smaller difference in the code of
> multiple major versions.

However I also don't see a problem to back-patch it, I don't see
a problem on such difference between versions.

I vote for back-patching this up to 9.5 (quite arbitrary..) but
it is fine for me if the documentation of 9.6 and earlier mention
a restriction like "For Windows environment, the application may
crash when it is using free() to the return values from
PGTYPES*_to_ascii functions. Make sure to use the same version of
CRT libray with the ECPG compiler in the case."

.. Is there any means to find the library version on the
installed environment?

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center



RE: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
"Tsunakawa, Takayuki"
Date:
From: Kyotaro HORIGUCHI [mailto:horiguchi.kyotaro@lab.ntt.co.jp]
> However I also don't see a problem to back-patch it, I don't see
> a problem on such difference between versions.

Thank you, Horiguchi-san and Robert.


> .. Is there any means to find the library version on the
> installed environment?

You can manually see the library version on the [Details] tab in the properties dialog with Windows Explorer.  I don't
knowhow to get the version in a program.
 


Regards
Takayuki Tsunakawa





Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Kyotaro HORIGUCHI
Date:
At Mon, 25 Jun 2018 08:16:10 +0000, "Tsunakawa, Takayuki" <tsunakawa.takay@jp.fujitsu.com> wrote in
<0A3221C70F24FB45833433255569204D1FA241F9@G01JPEXMBYT05>
> From: Kyotaro HORIGUCHI [mailto:horiguchi.kyotaro@lab.ntt.co.jp]
> > However I also don't see a problem to back-patch it, I don't see
> > a problem on such difference between versions.
> 
> Thank you, Horiguchi-san and Robert.
> 
> 
> > .. Is there any means to find the library version on the
> > installed environment?
> 
> You can manually see the library version on the [Details] tab in the properties dialog with Windows Explorer.  I
don'tknow how to get the version in a program.
 

I meant by the "version" not the version-number but the
identification of /MT /MD of CRT libraries. Such description
(mentioned in my previous mail) makes sense if the reader has any
means to see what "version" of the CRT library the target ECPG
library (and/or compiler) uses.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center



Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
Thomas Munro
Date:
On Mon, Jun 25, 2018 at 8:16 PM, Tsunakawa, Takayuki
<tsunakawa.takay@jp.fujitsu.com> wrote:
> From: Kyotaro HORIGUCHI [mailto:horiguchi.kyotaro@lab.ntt.co.jp]
>> However I also don't see a problem to back-patch it, I don't see
>> a problem on such difference between versions.
>
> Thank you, Horiguchi-san and Robert.

Ok, back-patched.

It seems like the other patch[1] might need the same treatment, right?

[1] https://commitfest.postgresql.org/18/1669/

-- 
Thomas Munro
http://www.enterprisedb.com


Re: [bug fix] ECPG: freeing memory for pgtypes crashes on Windows

From
"MauMau"
Date:
From: Thomas Munro
> Ok, back-patched.

Thank you very much!

> It seems like the other patch[1] might need the same treatment,
right?

I believe so, because that patch is based on the same cause.


Regards
MauMau