diff --git a/src/backend/utils/mb/wchar.c b/src/backend/utils/mb/wchar.c index 346668711f1655cf0cb639699c1a4adbabb13731..2f0725363cc2e7ffff843aa781add0dcc5799d3f 100644 --- a/src/backend/utils/mb/wchar.c +++ b/src/backend/utils/mb/wchar.c @@ -1,7 +1,7 @@ /* * conversion functions between pg_wchar and multibyte streams. * Tatsuo Ishii - * $PostgreSQL: pgsql/src/backend/utils/mb/wchar.c,v 1.52 2005/12/26 19:30:44 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/mb/wchar.c,v 1.53 2006/02/10 00:39:04 momjian Exp $ * * WIN1250 client encoding updated by Pavel Behal * @@ -23,6 +23,13 @@ * for the particular encoding. Note that if the encoding is only * supported in the client, you don't need to define * mb2wchar_with_len() function (SJIS is the case). + * + * Note: for the display output of psql to work properly, the return values + * of these functions must conform to the Unicode standard. In particular + * the NUL character is zero width and control characters are generally + * width -1. It is recommended that non-ASCII encodings refer their ASCII + * subset to the ASCII routines to ensure consistancy. + * */ /* @@ -53,6 +60,11 @@ pg_ascii_mblen(const unsigned char *s) static int pg_ascii_dsplen(const unsigned char *s) { + if (*s == '\0') + return 0; + if (*s < 0x20 || *s == 0x7f) + return -1; + return 1; } @@ -125,7 +137,7 @@ pg_euc_dsplen(const unsigned char *s) else if (IS_HIGHBIT_SET(*s)) len = 2; else - len = 1; + len = pg_ascii_dsplen(s); return len; } @@ -156,7 +168,7 @@ pg_eucjp_dsplen(const unsigned char *s) else if (IS_HIGHBIT_SET(*s)) len = 2; else - len = 1; + len = pg_ascii_dsplen(s); return len; } @@ -244,7 +256,7 @@ pg_euccn_dsplen(const unsigned char *s) if (IS_HIGHBIT_SET(*s)) len = 2; else - len = 1; + len = pg_ascii_dsplen(s); return len; } @@ -304,7 +316,7 @@ pg_euctw_mblen(const unsigned char *s) else if (IS_HIGHBIT_SET(*s)) len = 2; else - len = 1; + len = pg_ascii_dsplen(s); return len; } @@ -320,7 +332,7 @@ pg_euctw_dsplen(const unsigned char *s) else if (IS_HIGHBIT_SET(*s)) len = 2; else - len = 1; + len = pg_ascii_dsplen(s); return len; } @@ -419,10 +431,179 @@ pg_utf_mblen(const unsigned char *s) return len; } +/* + * This is an implementation of wcwidth() and wcswidth() as defined in + * "The Single UNIX Specification, Version 2, The Open Group, 1997" + * <http://www.UNIX-systems.org/online.html> + * + * Markus Kuhn -- 2001-09-08 -- public domain + * + * customised for PostgreSQL + * + * original available at : http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + */ + +struct mbinterval +{ + unsigned short first; + unsigned short last; +}; + +/* auxiliary function for binary search in interval table */ +static int +mbbisearch(pg_wchar ucs, const struct mbinterval *table, int max) +{ + int min = 0; + int mid; + + if (ucs < table[0].first || ucs > table[max].last) + return 0; + while (max >= min) + { + mid = (min + max) / 2; + if (ucs > table[mid].last) + min = mid + 1; + else if (ucs < table[mid].first) + max = mid - 1; + else + return 1; + } + + return 0; +} + + +/* The following functions define the column width of an ISO 10646 + * character as follows: + * + * - The null character (U+0000) has a column width of 0. + * + * - Other C0/C1 control characters and DEL will lead to a return + * value of -1. + * + * - Non-spacing and enclosing combining characters (general + * category code Mn or Me in the Unicode database) have a + * column width of 0. + * + * - Other format characters (general category code Cf in the Unicode + * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. + * + * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) + * have a column width of 0. + * + * - Spacing characters in the East Asian Wide (W) or East Asian + * FullWidth (F) category as defined in Unicode Technical + * Report #11 have a column width of 2. + * + * - All remaining characters (including all printable + * ISO 8859-1 and WGL4 characters, Unicode control characters, + * etc.) have a column width of 1. + * + * This implementation assumes that wchar_t characters are encoded + * in ISO 10646. + */ + +static int +ucs_wcwidth(pg_wchar ucs) +{ + /* sorted list of non-overlapping intervals of non-spacing characters */ + static const struct mbinterval combining[] = { + {0x0300, 0x034E}, {0x0360, 0x0362}, {0x0483, 0x0486}, + {0x0488, 0x0489}, {0x0591, 0x05A1}, {0x05A3, 0x05B9}, + {0x05BB, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, + {0x05C4, 0x05C4}, {0x064B, 0x0655}, {0x0670, 0x0670}, + {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, + {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, + {0x07A6, 0x07B0}, {0x0901, 0x0902}, {0x093C, 0x093C}, + {0x0941, 0x0948}, {0x094D, 0x094D}, {0x0951, 0x0954}, + {0x0962, 0x0963}, {0x0981, 0x0981}, {0x09BC, 0x09BC}, + {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, {0x09E2, 0x09E3}, + {0x0A02, 0x0A02}, {0x0A3C, 0x0A3C}, {0x0A41, 0x0A42}, + {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A70, 0x0A71}, + {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, {0x0AC1, 0x0AC5}, + {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, {0x0B01, 0x0B01}, + {0x0B3C, 0x0B3C}, {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, + {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, + {0x0BC0, 0x0BC0}, {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, + {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, + {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, + {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, {0x0DCA, 0x0DCA}, + {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0E31, 0x0E31}, + {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1}, + {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, {0x0EC8, 0x0ECD}, + {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, + {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, {0x0F80, 0x0F84}, + {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, {0x0F99, 0x0FBC}, + {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, {0x1032, 0x1032}, + {0x1036, 0x1037}, {0x1039, 0x1039}, {0x1058, 0x1059}, + {0x1160, 0x11FF}, {0x17B7, 0x17BD}, {0x17C6, 0x17C6}, + {0x17C9, 0x17D3}, {0x180B, 0x180E}, {0x18A9, 0x18A9}, + {0x200B, 0x200F}, {0x202A, 0x202E}, {0x206A, 0x206F}, + {0x20D0, 0x20E3}, {0x302A, 0x302F}, {0x3099, 0x309A}, + {0xFB1E, 0xFB1E}, {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, + {0xFFF9, 0xFFFB} + }; + + /* test for 8-bit control characters */ + if (ucs == 0) + return 0; + + if (ucs < 0x20 || (ucs >= 0x7f && ucs < 0xa0) || ucs > 0x0010ffff) + return -1; + + /* binary search in table of non-spacing characters */ + if (mbbisearch(ucs, combining, + sizeof(combining) / sizeof(struct mbinterval) - 1)) + return 0; + + /* + * if we arrive here, ucs is not a combining or C0/C1 control character + */ + + return 1 + + (ucs >= 0x1100 && + (ucs <= 0x115f || /* Hangul Jamo init. consonants */ + (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a && + ucs != 0x303f) || /* CJK ... Yi */ + (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ + (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility + * Ideographs */ + (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ + (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */ + (ucs >= 0xffe0 && ucs <= 0xffe6) || + (ucs >= 0x20000 && ucs <= 0x2ffff))); +} + +static pg_wchar +utf2ucs(const unsigned char *c) +{ + /* + * one char version of pg_utf2wchar_with_len. no control here, c must + * point to a large enough string + */ + if ((*c & 0x80) == 0) + return (pg_wchar) c[0]; + else if ((*c & 0xe0) == 0xc0) + return (pg_wchar) (((c[0] & 0x1f) << 6) | + (c[1] & 0x3f)); + else if ((*c & 0xf0) == 0xe0) + return (pg_wchar) (((c[0] & 0x0f) << 12) | + ((c[1] & 0x3f) << 6) | + (c[2] & 0x3f)); + else if ((*c & 0xf0) == 0xf0) + return (pg_wchar) (((c[0] & 0x07) << 18) | + ((c[1] & 0x3f) << 12) | + ((c[2] & 0x3f) << 6) | + (c[3] & 0x3f)); + else + /* that is an invalid code on purpose */ + return 0xffffffff; +} + static int pg_utf_dsplen(const unsigned char *s) { - return 1; /* XXX fix me! */ + return ucs_wcwidth(utf2ucs(s)); } /* @@ -499,7 +680,7 @@ pg_mule_mblen(const unsigned char *s) static int pg_mule_dsplen(const unsigned char *s) { - return 1; /* XXX fix me! */ + return pg_ascii_dsplen(s); /* XXX fix me! */ } /* @@ -529,7 +710,7 @@ pg_latin1_mblen(const unsigned char *s) static int pg_latin1_dsplen(const unsigned char *s) { - return 1; + return pg_ascii_dsplen(s); } /* @@ -559,7 +740,7 @@ pg_sjis_dsplen(const unsigned char *s) else if (IS_HIGHBIT_SET(*s)) len = 2; /* kanji? */ else - len = 1; /* should be ASCII */ + len = pg_ascii_dsplen(s); /* should be ASCII */ return len; } @@ -586,7 +767,7 @@ pg_big5_dsplen(const unsigned char *s) if (IS_HIGHBIT_SET(*s)) len = 2; /* kanji? */ else - len = 1; /* should be ASCII */ + len = pg_ascii_dsplen(s); /* should be ASCII */ return len; } @@ -613,7 +794,7 @@ pg_gbk_dsplen(const unsigned char *s) if (IS_HIGHBIT_SET(*s)) len = 2; /* kanji? */ else - len = 1; /* should be ASCII */ + len = pg_ascii_dsplen(s); /* should be ASCII */ return len; } @@ -640,7 +821,7 @@ pg_uhc_dsplen(const unsigned char *s) if (IS_HIGHBIT_SET(*s)) len = 2; /* 2byte? */ else - len = 1; /* should be ASCII */ + len = pg_ascii_dsplen(s); /* should be ASCII */ return len; } @@ -672,10 +853,10 @@ pg_gb18030_dsplen(const unsigned char *s) { int len; - if (!IS_HIGHBIT_SET(*s)) - len = 1; /* ASCII */ - else + if (IS_HIGHBIT_SET(*s)) len = 2; + else + len = pg_ascii_dsplen(s); /* ASCII */ return len; } diff --git a/src/bin/psql/mbprint.c b/src/bin/psql/mbprint.c index 7bced92a6d4e812387f51d4d50c795b087f4d8e1..68850b196893de1df89a023ef45423cfc2365aa6 100644 --- a/src/bin/psql/mbprint.c +++ b/src/bin/psql/mbprint.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/mbprint.c,v 1.18 2005/10/15 02:49:40 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/psql/mbprint.c,v 1.19 2006/02/10 00:39:04 momjian Exp $ */ #include "postgres_fe.h" @@ -14,149 +14,6 @@ #include "mb/pg_wchar.h" -/* - * This is an implementation of wcwidth() and wcswidth() as defined in - * "The Single UNIX Specification, Version 2, The Open Group, 1997" - * <http://www.UNIX-systems.org/online.html> - * - * Markus Kuhn -- 2001-09-08 -- public domain - * - * customised for PostgreSQL - * - * original available at : http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - */ - -struct mbinterval -{ - unsigned short first; - unsigned short last; -}; - -/* auxiliary function for binary search in interval table */ -static int -mbbisearch(pg_wchar ucs, const struct mbinterval * table, int max) -{ - int min = 0; - int mid; - - if (ucs < table[0].first || ucs > table[max].last) - return 0; - while (max >= min) - { - mid = (min + max) / 2; - if (ucs > table[mid].last) - min = mid + 1; - else if (ucs < table[mid].first) - max = mid - 1; - else - return 1; - } - - return 0; -} - - -/* The following functions define the column width of an ISO 10646 - * character as follows: - * - * - The null character (U+0000) has a column width of 0. - * - * - Other C0/C1 control characters and DEL will lead to a return - * value of -1. - * - * - Non-spacing and enclosing combining characters (general - * category code Mn or Me in the Unicode database) have a - * column width of 0. - * - * - Other format characters (general category code Cf in the Unicode - * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. - * - * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) - * have a column width of 0. - * - * - Spacing characters in the East Asian Wide (W) or East Asian - * FullWidth (F) category as defined in Unicode Technical - * Report #11 have a column width of 2. - * - * - All remaining characters (including all printable - * ISO 8859-1 and WGL4 characters, Unicode control characters, - * etc.) have a column width of 1. - * - * This implementation assumes that wchar_t characters are encoded - * in ISO 10646. - */ - -static int -ucs_wcwidth(pg_wchar ucs) -{ - /* sorted list of non-overlapping intervals of non-spacing characters */ - static const struct mbinterval combining[] = { - {0x0300, 0x034E}, {0x0360, 0x0362}, {0x0483, 0x0486}, - {0x0488, 0x0489}, {0x0591, 0x05A1}, {0x05A3, 0x05B9}, - {0x05BB, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, - {0x05C4, 0x05C4}, {0x064B, 0x0655}, {0x0670, 0x0670}, - {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, - {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, - {0x07A6, 0x07B0}, {0x0901, 0x0902}, {0x093C, 0x093C}, - {0x0941, 0x0948}, {0x094D, 0x094D}, {0x0951, 0x0954}, - {0x0962, 0x0963}, {0x0981, 0x0981}, {0x09BC, 0x09BC}, - {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, {0x09E2, 0x09E3}, - {0x0A02, 0x0A02}, {0x0A3C, 0x0A3C}, {0x0A41, 0x0A42}, - {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A70, 0x0A71}, - {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, {0x0AC1, 0x0AC5}, - {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, {0x0B01, 0x0B01}, - {0x0B3C, 0x0B3C}, {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, - {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, - {0x0BC0, 0x0BC0}, {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, - {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, - {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, - {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, {0x0DCA, 0x0DCA}, - {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0E31, 0x0E31}, - {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1}, - {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, {0x0EC8, 0x0ECD}, - {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, - {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, {0x0F80, 0x0F84}, - {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, {0x0F99, 0x0FBC}, - {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, {0x1032, 0x1032}, - {0x1036, 0x1037}, {0x1039, 0x1039}, {0x1058, 0x1059}, - {0x1160, 0x11FF}, {0x17B7, 0x17BD}, {0x17C6, 0x17C6}, - {0x17C9, 0x17D3}, {0x180B, 0x180E}, {0x18A9, 0x18A9}, - {0x200B, 0x200F}, {0x202A, 0x202E}, {0x206A, 0x206F}, - {0x20D0, 0x20E3}, {0x302A, 0x302F}, {0x3099, 0x309A}, - {0xFB1E, 0xFB1E}, {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, - {0xFFF9, 0xFFFB} - }; - - /* test for 8-bit control characters */ - if (ucs == 0) - return 0; - - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0) || ucs > 0x0010ffff) - return -1; - - /* binary search in table of non-spacing characters */ - if (mbbisearch(ucs, combining, - sizeof(combining) / sizeof(struct mbinterval) - 1)) - return 0; - - /* - * if we arrive here, ucs is not a combining or C0/C1 control character - */ - - return 1 + - (ucs >= 0x1100 && - (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a && - ucs != 0x303f) || /* CJK ... Yi */ - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility - * Ideographs */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2ffff))); -} - static pg_wchar utf2ucs(const unsigned char *c) { @@ -191,35 +48,16 @@ utf2ucs(const unsigned char *c) } } -/* mb_utf_wcwidth : calculate column length for the utf8 string pwcs - */ -static int -mb_utf_wcswidth(const unsigned char *pwcs, size_t len) -{ - int w, - l = 0; - int width = 0; - - for (; *pwcs && len > 0; pwcs += l) - { - l = pg_utf_mblen(pwcs); - if ((len < (size_t) l) || ((w = ucs_wcwidth(utf2ucs(pwcs))) < 0)) - return width; - len -= l; - width += w; - } - return width; -} +/* + * Unicode 3.1 compliant validation : for each category, it checks the + * combination of each byte to make sure it maps to a valid range. It also + * returns -1 for the following UCS values: ucs > 0x10ffff ucs & 0xfffe = + * 0xfffe 0xfdd0 < ucs < 0xfdef ucs & 0xdb00 = 0xd800 (surrogates) + */ static int utf_charcheck(const unsigned char *c) { - /* - * Unicode 3.1 compliant validation : for each category, it checks the - * combination of each byte to make sur it maps to a valid range. It also - * returns -1 for the following UCS values: ucs > 0x10ffff ucs & 0xfffe = - * 0xfffe 0xfdd0 < ucs < 0xfdef ucs & 0xdb00 = 0xd800 (surrogates) - */ if ((*c & 0x80) == 0) return 1; else if ((*c & 0xe0) == 0xc0) @@ -270,6 +108,7 @@ utf_charcheck(const unsigned char *c) return -1; } + static void mb_utf_validate(unsigned char *pwcs) { @@ -277,28 +116,26 @@ mb_utf_validate(unsigned char *pwcs) while (*pwcs) { - int l; + int len; - if ((l = utf_charcheck(pwcs)) > 0) + if ((len = utf_charcheck(pwcs)) > 0) { if (p != pwcs) { int i; - for (i = 0; i < l; i++) + for (i = 0; i < len; i++) *p++ = *pwcs++; } else { - pwcs += l; - p += l; + pwcs += len; + p += len; } } else - { /* we skip the char */ pwcs++; - } } if (p != pwcs) *p = '\0'; @@ -308,23 +145,193 @@ mb_utf_validate(unsigned char *pwcs) * public functions : wcswidth and mbvalidate */ +/* + * pg_wcswidth is the dumb width function. It assumes that everything will + * only appear on one line. OTOH it is easier to use if this applies to you. + */ int -pg_wcswidth(const char *pwcs, size_t len, int encoding) +pg_wcswidth(const unsigned char *pwcs, size_t len, int encoding) { - if (encoding == PG_UTF8) - return mb_utf_wcswidth((const unsigned char *) pwcs, len); - else + int width = 0; + + while (len > 0) { - /* - * obviously, other encodings may want to fix this, but I don't know - * them myself, unfortunately. - */ - return len; + int chlen, chwidth; + + chlen = PQmblen(pwcs, encoding); + if (chlen > len) + break; /* Invalid string */ + + chwidth = PQdsplen(pwcs, encoding); + + if (chwidth > 0) + width += chwidth; + pwcs += chlen; + } + return width; +} + +/* + * pg_wcssize takes the given string in the given encoding and returns three + * values: + * result_width: Width in display character of longest line in string + * result_hieght: Number of lines in display output + * result_format_size: Number of bytes required to store formatted representation of string + */ +int +pg_wcssize(unsigned char *pwcs, size_t len, int encoding, int *result_width, + int *result_height, int *result_format_size) +{ + int w, + chlen = 0, + linewidth = 0; + int width = 0; + int height = 1; + int format_size = 0; + + for (; *pwcs && len > 0; pwcs += chlen) + { + chlen = PQmblen(pwcs, encoding); + if (len < (size_t)chlen) + break; + w = PQdsplen(pwcs, encoding); + + if (chlen == 1) /* ASCII char */ + { + if (*pwcs == '\n') /* Newline */ + { + if (linewidth > width) + width = linewidth; + linewidth = 0; + height += 1; + format_size += 1; /* For NUL char */ + } + else if (*pwcs == '\r') /* Linefeed */ + { + linewidth += 2; + format_size += 2; + } + else if (w <= 0) /* Other control char */ + { + linewidth += 4; + format_size += 4; + } + else /* Output itself */ + { + linewidth++; + format_size += 1; + } + } + else if (w <= 0) /* Non-ascii control char */ + { + linewidth += 6; /* \u0000 */ + format_size += 6; + } + else /* All other chars */ + { + linewidth += w; + format_size += chlen; + } + len -= chlen; + } + if (linewidth > width) + width = linewidth; + format_size += 1; + + /* Set results */ + if (result_width) + *result_width = width; + if (result_height) + *result_height = height; + if (result_format_size) + *result_format_size = format_size; + + return width; +} + +void +pg_wcsformat(unsigned char *pwcs, size_t len, int encoding, + struct lineptr *lines, int count) +{ + int w, + chlen = 0; + int linewidth = 0; + + char *ptr = lines->ptr; /* Pointer to data area */ + + for (; *pwcs && len > 0; pwcs += chlen) + { + chlen = PQmblen(pwcs,encoding); + if (len < (size_t)chlen) + break; + w = PQdsplen(pwcs,encoding); + + if (chlen == 1) /* single byte char char */ + { + if (*pwcs == '\n') /* Newline */ + { + *ptr++ = 0; /* NULL char */ + lines->width = linewidth; + linewidth = 0; + lines++; + count--; + if (count == 0) + exit(1); /* Screwup */ + + lines->ptr = ptr; + } + else if (*pwcs == '\r') /* Linefeed */ + { + strcpy(ptr, "\\r"); + linewidth += 2; + ptr += 2; + } + else if (w <= 0) /* Other control char */ + { + sprintf(ptr, "\\x%02X", *pwcs); + linewidth += 4; + ptr += 4; + } + else /* Output itself */ + { + linewidth++; + *ptr++ = *pwcs; + } + } + else if (w <= 0) /* Non-ascii control char */ + { + if (encoding == PG_UTF8) + sprintf(ptr, "\\u%04X", utf2ucs(pwcs)); + else + /* This case cannot happen in the current + * code because only UTF-8 signals multibyte + * control characters. But we may need to + * support it at some stage */ + sprintf(ptr, "\\u????"); + + ptr += 6; + linewidth += 6; + } + else /* All other chars */ + { + int i; + for (i=0; i < chlen; i++) + *ptr++ = pwcs[i]; + linewidth += w; + } + len -= chlen; } + *ptr++ = 0; + lines->width = linewidth; + lines++; + count--; + if (count > 0) + lines->ptr = NULL; + return; } -char * -mbvalidate(char *pwcs, int encoding) +unsigned char * +mbvalidate(unsigned char *pwcs, int encoding) { if (encoding == PG_UTF8) mb_utf_validate((unsigned char *) pwcs); diff --git a/src/bin/psql/mbprint.h b/src/bin/psql/mbprint.h index 17a8b98ea6b6c2e00372ab88beee501cae3ec82d..a1e5b0f44ebc0ae840e346fb6d9b2f8747036967 100644 --- a/src/bin/psql/mbprint.h +++ b/src/bin/psql/mbprint.h @@ -1,11 +1,18 @@ -/* $PostgreSQL: pgsql/src/bin/psql/mbprint.h,v 1.8 2005/09/24 17:53:27 tgl Exp $ */ +/* $PostgreSQL: pgsql/src/bin/psql/mbprint.h,v 1.9 2006/02/10 00:39:04 momjian Exp $ */ #ifndef MBPRINT_H #define MBPRINT_H #include "mb/pg_wchar.h" -extern char *mbvalidate(char *pwcs, int encoding); +struct lineptr { + unsigned char *ptr; + int width; +}; -extern int pg_wcswidth(const char *pwcs, size_t len, int encoding); +extern unsigned char *mbvalidate(unsigned char *pwcs, int encoding); + +extern int pg_wcswidth(const unsigned char *pwcs, size_t len, int encoding); +extern void pg_wcsformat(unsigned char *pwcs, size_t len, int encoding, struct lineptr *lines, int count); +extern int pg_wcssize(unsigned char *pwcs, size_t len, int encoding, int *width, int *height, int *format_size); #endif /* MBPRINT_H */ diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index 65d107acc4c9c84de0768205aa563f3bb8d28095..b232906426ead36a16993a5eb6d3eb04025c9941 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.79 2005/10/27 13:34:47 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.80 2006/02/10 00:39:04 momjian Exp $ */ #include "postgres_fe.h" #include "common.h" @@ -49,6 +49,20 @@ pg_local_malloc(size_t size) return tmp; } +static void * +pg_local_calloc(int count, size_t size) +{ + void *tmp; + + tmp = calloc(count, size); + if (!tmp) + { + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); + } + return tmp; +} + static int integer_digits(const char *my_str) { @@ -87,6 +101,7 @@ strlen_with_numeric_locale(const char *my_str) return strlen(my_str) + additional_numeric_locale_len(my_str); } +/* Returns the appropriately formatted string in a new allocated block, caller must free */ static char * format_numeric_locale(const char *my_str) { @@ -342,13 +357,20 @@ print_aligned_text(const char *title, const char *const * headers, { unsigned int col_count = 0; unsigned int cell_count = 0; - unsigned int *head_w, - *cell_w; unsigned int i, tmp; unsigned int *widths, total_w; - const char *const * ptr; + unsigned int *heights; + unsigned int *format_space; + unsigned char **format_buf; + + const char *const *ptr; + + struct lineptr **col_lineptrs; /* pointers to line pointer for each column */ + struct lineptr *lineptr_list; /* complete list of linepointers */ + + int *complete; /* Array remembering which columns have completed output */ /* count columns */ for (ptr = headers; *ptr; ptr++) @@ -356,64 +378,61 @@ print_aligned_text(const char *title, const char *const * headers, if (col_count > 0) { - widths = calloc(col_count, sizeof(*widths)); - if (!widths) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } - - head_w = calloc(col_count, sizeof(*head_w)); - if (!head_w) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } + widths = pg_local_calloc(col_count, sizeof(*widths)); + heights = pg_local_calloc(col_count, sizeof(*heights)); + col_lineptrs = pg_local_calloc(col_count, sizeof(*col_lineptrs)); + format_space = pg_local_calloc(col_count, sizeof(*format_space)); + format_buf = pg_local_calloc(col_count, sizeof(*format_buf)); + complete = pg_local_calloc(col_count, sizeof(*complete)); + } else { widths = NULL; - head_w = NULL; + heights = NULL; + col_lineptrs = NULL; + format_space = NULL; + format_buf = NULL; + complete = NULL; } - + /* count cells (rows * cols) */ for (ptr = cells; *ptr; ptr++) cell_count++; - if (cell_count > 0) - { - cell_w = calloc(cell_count, sizeof(*cell_w)); - if (!cell_w) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } - } - else - cell_w = NULL; - /* calc column widths */ for (i = 0; i < col_count; i++) { - tmp = pg_wcswidth(headers[i], strlen(headers[i]), encoding); + /* Get width & height */ + int height, space; + pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &tmp, &height, &space); if (tmp > widths[i]) widths[i] = tmp; - head_w[i] = tmp; + if (height > heights[i]) + heights[i] = height; + if (space > format_space[i]) + format_space[i] = space; } for (i = 0, ptr = cells; *ptr; ptr++, i++) { - int add_numeric_locale_len; + int numeric_locale_len; + int height, space; if (opt_align[i % col_count] == 'r' && opt_numeric_locale) - add_numeric_locale_len = additional_numeric_locale_len(*ptr); - else - add_numeric_locale_len = 0; - - tmp = pg_wcswidth(*ptr, strlen(*ptr), encoding) + add_numeric_locale_len; + numeric_locale_len = additional_numeric_locale_len(*ptr); + else + numeric_locale_len = 0; + + /* Get width, ignore height */ + pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp, &height, &space); + tmp += numeric_locale_len; if (tmp > widths[i % col_count]) widths[i % col_count] = tmp; - cell_w[i] = tmp; + if (height > heights[i % col_count]) + heights[i % col_count] = height; + if (space > format_space[i % col_count]) + format_space[i % col_count] = space; } if (opt_border == 0) @@ -426,10 +445,38 @@ print_aligned_text(const char *title, const char *const * headers, for (i = 0; i < col_count; i++) total_w += widths[i]; + /* At this point: + * widths contains the max width of each column + * heights contains the max height of a cell of each column + * format_space contains maximum space required to store formatted string + * so we prepare the formatting structures + */ + { + int heights_total = 0; + struct lineptr *lineptr; + + for (i = 0; i < col_count; i++) + heights_total += heights[i]; + + lineptr = lineptr_list = pg_local_calloc(heights_total, sizeof(*lineptr_list)); + + for (i = 0; i < col_count; i++) + { + col_lineptrs[i] = lineptr; + lineptr += heights[i]; + + format_buf[i] = pg_local_malloc(format_space[i]); + + col_lineptrs[i]->ptr = format_buf[i]; + } + } + /* print title */ if (title && !opt_tuples_only) { - tmp = pg_wcswidth(title, strlen(title), encoding); + /* Get width & height */ + int height; + pg_wcssize((unsigned char *)title, strlen(title), encoding, &tmp, &height, NULL); if (tmp >= total_w) fprintf(fout, "%s\n", title); else @@ -439,90 +486,138 @@ print_aligned_text(const char *title, const char *const * headers, /* print headers */ if (!opt_tuples_only) { + int cols_todo; + int line_count; + if (opt_border == 2) _print_horizontal_line(col_count, widths, opt_border, fout); - if (opt_border == 2) - fputs("| ", fout); - else if (opt_border == 1) - fputc(' ', fout); - for (i = 0; i < col_count; i++) + pg_wcsformat((unsigned char *)headers[i], strlen(headers[i]), encoding, col_lineptrs[i], heights[i]); + + cols_todo = col_count; + line_count = 0; + memset(complete, 0, col_count*sizeof(int)); + while (cols_todo) { - unsigned int nbspace; + if (opt_border == 2) + fprintf(fout, "|%c", line_count ? '+' : ' '); + else if (opt_border == 1) + fputc(line_count ? '+' : ' ', fout); - nbspace = widths[i] - head_w[i]; + for (i = 0; i < col_count; i++) + { + unsigned int nbspace; - /* centered */ - fprintf(fout, "%-*s%s%-*s", - nbspace / 2, "", headers[i], (nbspace + 1) / 2, ""); + struct lineptr *this_line = col_lineptrs[i] + line_count; + if (!complete[i]) + { + nbspace = widths[i] - this_line->width; - if (i < col_count - 1) - { - if (opt_border == 0) - fputc(' ', fout); + /* centered */ + fprintf(fout, "%-*s%s%-*s", + nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, ""); + + if (line_count == (heights[i]-1) || !(this_line+1)->ptr) + { + cols_todo--; + complete[i] = 1; + } + } else - fputs(" | ", fout); + fprintf(fout, "%*s", widths[i], ""); + if (i < col_count - 1) + { + if (opt_border == 0) + fputc(line_count ? '+' : ' ', fout); + else + fprintf(fout, " |%c", line_count ? '+' : ' '); + } } + line_count++; + + if (opt_border == 2) + fputs(" |", fout); + else if (opt_border == 1) + fputc(' ', fout);; + fputc('\n', fout); } - if (opt_border == 2) - fputs(" |", fout); - else if (opt_border == 1) - fputc(' ', fout);; - fputc('\n', fout); _print_horizontal_line(col_count, widths, opt_border, fout); } /* print cells */ - for (i = 0, ptr = cells; *ptr; i++, ptr++) + for (i = 0, ptr = cells; *ptr; i+=col_count, ptr+=col_count) { - /* beginning of line */ - if (i % col_count == 0) + int j; + int cols_todo = col_count; + int line_count; /* Number of lines output so far in row */ + + for (j = 0; j < col_count; j++) + pg_wcsformat((unsigned char*)ptr[j], strlen(ptr[j]), encoding, col_lineptrs[j], heights[j]); + + line_count = 0; + memset(complete, 0, col_count*sizeof(int)); + while (cols_todo) { + /* beginning of line */ if (opt_border == 2) fputs("| ", fout); else if (opt_border == 1) fputc(' ', fout); - } - /* content */ - if (opt_align[i % col_count] == 'r') - { - if (opt_numeric_locale) + for (j = 0; j < col_count; j++) { - char *my_cell = format_numeric_locale(*ptr); + struct lineptr *this_line = col_lineptrs[j] + line_count; + if (complete[j]) /* Just print spaces... */ + fprintf(fout, "%*s", widths[j], ""); + else + { - fprintf(fout, "%*s%s", widths[i % col_count] - cell_w[i], "", my_cell); - free(my_cell); + /* content */ + if (opt_align[j] == 'r') + { + if (opt_numeric_locale) + { + /* Assumption: This code used only on strings + * without multibyte characters, otherwise + * this_line->width < strlen(this_ptr) and we + * get an overflow */ + + char *my_cell = format_numeric_locale(this_line->ptr); + fprintf(fout, "%*s%s", widths[i % col_count] - strlen(my_cell), "", my_cell); + free(my_cell); + } + else + fprintf(fout, "%*s%s", widths[j] - this_line->width, "", this_line->ptr); + } + else + fprintf(fout, "%-s%*s", this_line->ptr, + widths[j] - this_line->width, ""); + /* If at the right height, done this col */ + if (line_count == heights[j]-1 || !this_line[1].ptr) + { + complete[j] = 1; + cols_todo--; + } + } + + /* divider */ + if ((j + 1) % col_count) + { + if (opt_border == 0) + fputc(' ', fout); + else if (line_count == 0) + fputs(" | ", fout); + else + fprintf(fout, " %c ", complete[j+1] ? ' ' : ':'); + } } - else - fprintf(fout, "%*s%s", widths[i % col_count] - cell_w[i], "", *ptr); - } - else - { - if ((i + 1) % col_count == 0 && opt_border != 2) - fputs(cells[i], fout); - else - fprintf(fout, "%-s%*s", cells[i], - widths[i % col_count] - cell_w[i], ""); - } - - /* divider */ - if ((i + 1) % col_count) - { - if (opt_border == 0) - fputc(' ', fout); - else - fputs(" | ", fout); - } - /* end of line */ - else - { if (opt_border == 2) fputs(" |", fout); fputc('\n', fout); + line_count++; } } @@ -543,9 +638,15 @@ print_aligned_text(const char *title, const char *const * headers, #endif /* clean up */ - free(cell_w); - free(head_w); free(widths); + free(heights); + free(col_lineptrs); + free(format_space); + free(complete); + free(lineptr_list); + for (i= 0; i < col_count; i++) + free(format_buf[i]); + free(format_buf); } @@ -563,12 +664,15 @@ print_aligned_vertical(const char *title, const char *const * headers, unsigned int i, tmp = 0, hwidth = 0, - dwidth = 0; + dwidth = 0, + hheight = 1, + dheight = 1, + hformatsize = 0, + dformatsize = 0; char *divider; unsigned int cell_count = 0; - unsigned int *cell_w, - *head_w; - + struct lineptr *hlineptr, *dlineptr; + if (cells[0] == NULL) { fprintf(fout, _("(No rows)\n")); @@ -578,58 +682,52 @@ print_aligned_vertical(const char *title, const char *const * headers, /* count headers and find longest one */ for (ptr = headers; *ptr; ptr++) col_count++; - if (col_count > 0) - { - head_w = calloc(col_count, sizeof(*head_w)); - if (!head_w) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } - } - else - head_w = NULL; + /* Find the maximum dimensions for the headers */ for (i = 0; i < col_count; i++) { - tmp = pg_wcswidth(headers[i], strlen(headers[i]), encoding); + int height, fs; + pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &tmp, &height, &fs); if (tmp > hwidth) hwidth = tmp; - head_w[i] = tmp; + if (height > hheight) + hheight = height; + if (fs > hformatsize) + hformatsize = fs; } /* Count cells, find their lengths */ for (ptr = cells; *ptr; ptr++) cell_count++; - if (cell_count > 0) - { - cell_w = calloc(cell_count, sizeof(*cell_w)); - if (!cell_w) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } - } - else - cell_w = NULL; - /* find longest data cell */ for (i = 0, ptr = cells; *ptr; ptr++, i++) { - int add_numeric_locale_len; + int numeric_locale_len; + int height, fs; if (opt_align[i % col_count] == 'r' && opt_numeric_locale) - add_numeric_locale_len = additional_numeric_locale_len(*ptr); - else - add_numeric_locale_len = 0; + numeric_locale_len = additional_numeric_locale_len(*ptr); + else + numeric_locale_len = 0; - tmp = pg_wcswidth(*ptr, strlen(*ptr), encoding) + add_numeric_locale_len; + pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp, &height, &fs); + tmp += numeric_locale_len; if (tmp > dwidth) dwidth = tmp; - cell_w[i] = tmp; + if (height > dheight) + dheight = height; + if (fs > dformatsize) + dformatsize = fs; } - + + /* We now have all the information we need to setup the formatting structures */ + dlineptr = pg_local_malloc(sizeof(*dlineptr) * dheight); + hlineptr = pg_local_malloc(sizeof(*hlineptr) * hheight); + + dlineptr->ptr = pg_local_malloc(dformatsize); + hlineptr->ptr = pg_local_malloc(hformatsize); + /* print title */ if (!opt_tuples_only && title) fprintf(fout, "%s\n", title); @@ -653,6 +751,8 @@ print_aligned_vertical(const char *title, const char *const * headers, /* print records */ for (i = 0, ptr = cells; *ptr; i++, ptr++) { + int line_count, dcomplete, hcomplete; + if (i % col_count == 0) { if (!opt_tuples_only) @@ -688,33 +788,66 @@ print_aligned_vertical(const char *title, const char *const * headers, fprintf(fout, "%s\n", divider); } - if (opt_border == 2) - fputs("| ", fout); - fprintf(fout, "%-s%*s", headers[i % col_count], - hwidth - head_w[i % col_count], ""); - - if (opt_border > 0) - fputs(" | ", fout); - else - fputs(" ", fout); - - if (opt_align[i % col_count] == 'r' && opt_numeric_locale) + /* Format the header */ + pg_wcsformat((unsigned char*)headers[i % col_count], + strlen(headers[i % col_count]), encoding, hlineptr, hheight); + /* Format the data */ + pg_wcsformat((unsigned char*)*ptr, strlen(*ptr), encoding, dlineptr, dheight); + + line_count = 0; + dcomplete = hcomplete = 0; + while (!dcomplete || !hcomplete) { - char *my_cell = format_numeric_locale(*ptr); - - if (opt_border < 2) - fprintf(fout, "%s\n", my_cell); + if (opt_border == 2) + fputs("| ", fout); + if (!hcomplete) + { + fprintf(fout, "%-s%*s", hlineptr[line_count].ptr, + hwidth - hlineptr[line_count].width, ""); + + if (line_count == (hheight-1) || !hlineptr[line_count+1].ptr) + hcomplete = 1; + } else - fprintf(fout, "%-s%*s |\n", my_cell, dwidth - cell_w[i], ""); - free(my_cell); - } - else - { - if (opt_border < 2) - fprintf(fout, "%s\n", *ptr); + fprintf(fout, "%*s", hwidth, ""); + + if (opt_border > 0) + fprintf(fout, " %c ", (line_count==0)?'|':':'); else - fprintf(fout, "%-s%*s |\n", *ptr, dwidth - cell_w[i], ""); - } + fputs(" ", fout); + + if (!dcomplete) + { + if (opt_align[i % col_count] == 'r' && opt_numeric_locale) + { + char *my_cell = format_numeric_locale(dlineptr[line_count].ptr); + if (opt_border < 2) + fprintf(fout, "%s\n", my_cell); + else + fprintf(fout, "%-s%*s |\n", my_cell, dwidth - strlen(my_cell), ""); + free(my_cell); + } + else + { + if (opt_border < 2) + fprintf(fout, "%s\n", dlineptr[line_count].ptr); + else + fprintf(fout, "%-s%*s |\n", dlineptr[line_count].ptr, + dwidth - dlineptr[line_count].width, ""); + } + + if (line_count == dheight - 1 || !dlineptr[line_count+1].ptr) + dcomplete = 1; + } + else + { + if (opt_border < 2) + fputc('\n', fout); + else + fprintf(fout, "%*s |\n", dwidth, ""); + } + line_count++; + } } if (opt_border == 2) @@ -732,9 +865,10 @@ print_aligned_vertical(const char *title, const char *const * headers, fputc('\n', fout); free(divider); - - free(cell_w); - free(head_w); + free(hlineptr->ptr); + free(dlineptr->ptr); + free(hlineptr); + free(dlineptr); } @@ -1613,24 +1747,14 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f /* extract headers */ nfields = PQnfields(result); - headers = calloc(nfields + 1, sizeof(*headers)); - if (!headers) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } + headers = pg_local_calloc(nfields + 1, sizeof(*headers)); for (i = 0; i < nfields; i++) headers[i] = mbvalidate(PQfname(result, i), opt->topt.encoding); /* set cells */ ncells = PQntuples(result) * nfields; - cells = calloc(ncells + 1, sizeof(*cells)); - if (!cells) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } + cells = pg_local_calloc(ncells + 1, sizeof(*cells)); for (i = 0; i < ncells; i++) { @@ -1646,12 +1770,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f footers = opt->footers; else if (!opt->topt.expanded && opt->default_footer) { - footers = calloc(2, sizeof(*footers)); - if (!footers) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } + footers = pg_local_calloc(2, sizeof(*footers)); footers[0] = pg_local_malloc(100); if (PQntuples(result) == 1) @@ -1663,12 +1782,7 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f footers = NULL; /* set alignment */ - align = calloc(nfields + 1, sizeof(*align)); - if (!align) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } + align = pg_local_calloc(nfields + 1, sizeof(*align)); for (i = 0; i < nfields; i++) { diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index b6e46393b4dc2fc0b1a925342992a6ad789120f3..02723d62ecc7153ac411cc5a5c0841309e44dc66 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -797,7 +797,6 @@ alter table atacc1 drop c; alter table atacc1 drop d; alter table atacc1 drop b; select * from atacc1; - -- (1 row) diff --git a/src/test/regress/expected/prepare.out b/src/test/regress/expected/prepare.out index 3532953f552acec5adf0923963fe027f595c6627..df5dc5dde26da580ecc0b9f3e25591b9d997867c 100644 --- a/src/test/regress/expected/prepare.out +++ b/src/test/regress/expected/prepare.out @@ -149,18 +149,18 @@ PREPARE q7(unknown) AS SELECT name, statement, parameter_types FROM pg_prepared_statements ORDER BY name; name | statement | parameter_types -------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------- - q2 | PREPARE q2(text) AS - SELECT datname, datistemplate, datallowconn - FROM pg_database WHERE datname = $1; | {text} - q3 | PREPARE q3(text, int, float, boolean, oid, smallint) AS - SELECT * FROM tenk1 WHERE string4 = $1 AND (four = $2 OR - ten = $3::bigint OR true = $4 OR oid = $5 OR odd = $6::int); | {text,integer,"double precision",boolean,oid,smallint} - q5 | PREPARE q5(int, text) AS - SELECT * FROM tenk1 WHERE unique1 = $1 OR stringu1 = $2; | {integer,text} - q6 | PREPARE q6 AS - SELECT * FROM tenk1 WHERE unique1 = $1 AND stringu1 = $2; | {integer,name} - q7 | PREPARE q7(unknown) AS - SELECT * FROM road WHERE thepath = $1; | {path} +------+------------------------------------------------------------------+-------------------------------------------------------- + q2 | PREPARE q2(text) AS | {text} + : \x09SELECT datname, datistemplate, datallowconn + : \x09FROM pg_database WHERE datname = $1; + q3 | PREPARE q3(text, int, float, boolean, oid, smallint) AS | {text,integer,"double precision",boolean,oid,smallint} + : \x09SELECT * FROM tenk1 WHERE string4 = $1 AND (four = $2 OR + : \x09ten = $3::bigint OR true = $4 OR oid = $5 OR odd = $6::int); + q5 | PREPARE q5(int, text) AS | {integer,text} + : \x09SELECT * FROM tenk1 WHERE unique1 = $1 OR stringu1 = $2; + q6 | PREPARE q6 AS | {integer,name} + : SELECT * FROM tenk1 WHERE unique1 = $1 AND stringu1 = $2; + q7 | PREPARE q7(unknown) AS | {path} + : SELECT * FROM road WHERE thepath = $1; (5 rows)