File Fixed-CORE-3431-ISQL-pads-UTF-8-data-incorrectly.patch of Package firebird
From: asfernandes <asfernandes@de594faa-8d1b-4a0c-9a6a-a7de5f8bf859>
Date: Tue, 5 Apr 2011 21:30:27 +0000
Subject: Fixed CORE-3431 - ISQL pads UTF-8 data incorrectly.
git-svn-id: https://firebird.svn.sourceforge.net/svnroot/firebird/firebird/trunk@52676 de594faa-8d1b-4a0c-9a6a-a7de5f8bf859
Conflicts:
src/isql/isql.epp
---
src/isql/isql.epp | 159 ++++++++++++++++++++++++++++++++++++++++++++----------
src/isql/isql.h | 1 +
2 files changed, 132 insertions(+), 28 deletions(-)
diff --git a/src/isql/isql.epp b/src/isql/isql.epp
index f5e5777..31c6d6b 100644
--- a/src/isql/isql.epp
+++ b/src/isql/isql.epp
@@ -131,6 +131,8 @@ using MsgFormat::SafeArg;
#include "../isql/InputDevices.h"
#include "../isql/OptionsBase.h"
+#include "../intl/charsets.h"
+#include <unicode/utf8.h>
DATABASE DB = COMPILETIME "yachts.lnk";
@@ -245,6 +247,98 @@ const switch_info switches[] =
};
+namespace IcuUtil
+{
+ // Duplicate from ICU to not need to link ISQL with it. It's used by U8_NEXT_UNSAFE.
+ static const uint8_t utf8_countTrailBytes[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, /* illegal in Unicode */
+ 4, 4, 4, 4, /* illegal in Unicode */
+ 5, 5, /* illegal in Unicode */
+ 0, 0 /* illegal bytes 0xfe and 0xff */
+ };
+
+ // Return the number of characters of a string.
+ static unsigned charLength(SSHORT sqlsubtype, unsigned len, const char* str)
+ {
+ if (sqlsubtype != CS_UNICODE_FSS && sqlsubtype != CS_UTF8)
+ return len;
+
+ unsigned charLen = 0;
+ unsigned i = 0;
+
+ while (i < len)
+ {
+ UChar32 c;
+ U8_NEXT_UNSAFE(str, i, c);
+ ++charLen;
+ }
+
+ return charLen;
+ }
+
+ // Pads a string to a specified column width.
+ static void pad(char* buffer, SSHORT sqlsubtype, unsigned len, const char* str, unsigned width,
+ bool right)
+ {
+ if (sqlsubtype != CS_UNICODE_FSS && sqlsubtype != CS_UTF8)
+ {
+ // Truncate if necessary.
+ if (len > width)
+ len = width;
+
+ sprintf(buffer, (right ? "%*.*s" : "%-*.*s"), width, len, str);
+ return;
+ }
+
+ unsigned i = 0;
+
+ while (i < len && width > 0)
+ {
+ UChar32 c;
+ U8_NEXT_UNSAFE(str, i, c);
+ --width;
+ }
+
+ if (right)
+ {
+ while (width-- > 0)
+ *buffer++ = ' ';
+ }
+
+ memcpy(buffer, str, i);
+ buffer += i;
+
+ if (!right)
+ {
+ while (width-- > 0)
+ *buffer++ = ' ';
+ }
+
+ *buffer = '\0';
+ }
+}
+
+
static inline bool commit_trans(isc_tr_handle* x)
{
if (isc_commit_transaction (isc_status, x)) {
@@ -583,6 +677,7 @@ int ISQL_main(int argc, char* argv[])
TEXT tabname[WORDLENGTH];
tabname[0] = '\0';
isqlGlob.db_SQL_dialect = 0;
+ isqlGlob.att_charset = 0;
// Output goes to stdout by default
isqlGlob.Out = stdout;
@@ -5864,6 +5959,7 @@ void ISQL_get_version(bool call_by_create_db)
isc_info_ods_version,
isc_info_ods_minor_version,
isc_info_db_sql_dialect,
+ frb_info_att_charset,
Version_info ? isc_info_firebird_version: isc_info_end,
isc_info_end
};
@@ -6020,6 +6116,10 @@ void ISQL_get_version(bool call_by_create_db)
}
break;
+ case frb_info_att_charset:
+ isqlGlob.att_charset = gds__vax_integer(p, length);
+ break;
+
default:
isqlGlob.printf("Internal error: Unexpected isc_info_value %d%s",
item, NEWLINE);
@@ -7360,18 +7460,6 @@ static bool checkSpecial(TEXT* const p, const int length, const double value)
}
-static void align_string(char* out, unsigned clen, unsigned slen, const char* s)
-{
- if (slen > clen)
- slen = clen;
- memcpy(out, s, slen);
- if (clen > slen)
- memset(out + slen, ' ', clen - slen);
- out[clen] = ' ';
- out[clen + 1] = '\0';
-}
-
-
static SSHORT print_item(TEXT** s, XSQLVAR* var, const int length)
{
/**************************************
@@ -7659,12 +7747,12 @@ static SSHORT print_item(TEXT** s, XSQLVAR* var, const int length)
sprintf(p, "%-*s ", length, buff2);
ISQL_FREE(buff2);
}
- else if (List) {
+ else if (List)
isqlGlob.printf("%s%s", string, NEWLINE);
- }
else
{
- align_string(p, length, var->sqllen, var->sqldata);
+ IcuUtil::pad(p, var->sqlsubtype, strlen(var->sqldata), var->sqldata, length, false);
+ strcat(p, " ");
}
break;
@@ -7752,12 +7840,12 @@ static SSHORT print_item(TEXT** s, XSQLVAR* var, const int length)
}
ISQL_FREE(buff2);
}
- else if (List) {
+ else if (List)
isqlGlob.printf("%s%s", avary->vary_string, NEWLINE);
- }
else
{
- align_string(p, length, avary->vary_length, avary->vary_string);
+ IcuUtil::pad(p, var->sqlsubtype, avary->vary_length, avary->vary_string, length, false);
+ strcat(p, " ");
}
break;
}
@@ -8195,16 +8283,20 @@ static void process_header(const XSQLDA* sqlda, const int pad[], TEXT header[],
for (const XSQLVAR* const end = var + sqlda->sqld; var < end; var++, i++)
{
const SSHORT type = var->sqltype & ~1;
- if (type == SQL_TEXT || type == SQL_VARYING)
- sprintf(p, "%-*.*s ", pad[i], pad[i], var->aliasname);
- else
- sprintf(p, "%*s ", pad[i], var->aliasname);
+
+ IcuUtil::pad(p, isqlGlob.att_charset, var->aliasname_length, var->aliasname, pad[i],
+ (type != SQL_TEXT && type != SQL_VARYING));
+ strcat(p, " ");
+
+ p += strlen(p);
+
// Separators need not go on forever no more than a line
- size_t limit = strlen(p);
- for (size_t j = 1; j < limit && j < 80; j++)
+ unsigned limit = IcuUtil::charLength(isqlGlob.att_charset, var->aliasname_length, var->aliasname);
+ limit = MAX(limit, pad[i]) + 1;
+
+ for (unsigned j = 1; j < limit && j < 80; j++)
*p2++ = '=';
*p2++ = BLANK;
- p += limit;
}
*p2 = '\0';
}
@@ -8443,7 +8535,7 @@ static SLONG process_sqlda_display(XSQLDA* const sqlda, SLONG buffer[], int pad[
USHORT data_length, disp_length, alignment;
data_length = disp_length = alignment = var->sqllen;
- SSHORT namelength = var->aliasname_length;
+ SSHORT namelength = IcuUtil::charLength(isqlGlob.att_charset, var->aliasname_length, var->aliasname);
// Minimum display length should not be less than that needed
// for displaying null
@@ -8485,6 +8577,8 @@ static SLONG process_sqlda_display(XSQLDA* const sqlda, SLONG buffer[], int pad[
// OCTETS data is displayed in hex
if (var->sqlsubtype == 1)
disp_length = 2 * var->sqllen;
+ else if (var->sqlsubtype == 4)
+ disp_length /= 4;
break;
case SQL_VARYING:
data_length += sizeof(USHORT) + 1;
@@ -8492,6 +8586,8 @@ static SLONG process_sqlda_display(XSQLDA* const sqlda, SLONG buffer[], int pad[
// OCTETS data is displayed in hex
if (var->sqlsubtype == 1)
disp_length = 2 * var->sqllen;
+ else if (var->sqlsubtype == 4)
+ disp_length /= 4;
break;
case SQL_SHORT:
disp_length = SHORT_LEN;
@@ -8522,7 +8618,10 @@ static SLONG process_sqlda_display(XSQLDA* const sqlda, SLONG buffer[], int pad[
// This is the print width of each column
- pad[i] = (disp_length > namelength ? disp_length : namelength);
+ if (disp_length < namelength)
+ disp_length = namelength;
+
+ pad[i] = disp_length;
// Is there a collist entry, then use that width, but only for text
if (type == SQL_TEXT || type == SQL_VARYING)
@@ -8531,8 +8630,11 @@ static SLONG process_sqlda_display(XSQLDA* const sqlda, SLONG buffer[], int pad[
pad[i] = global_Col_default;
}
+ if ((type == SQL_TEXT || type == SQL_VARYING) && var->sqlsubtype == 4)
+ disp_length *= 4;
+
// The total line length
- linelength += pad[i] + 1;
+ linelength += disp_length + 1;
// Allocate space in buffer for data
@@ -8540,6 +8642,7 @@ static SLONG process_sqlda_display(XSQLDA* const sqlda, SLONG buffer[], int pad[
var->sqldata = (SCHAR*) buffer + offset;
offset += data_length;
}
+
return linelength;
}
diff --git a/src/isql/isql.h b/src/isql/isql.h
index e076c3c..9d350e4 100644
--- a/src/isql/isql.h
+++ b/src/isql/isql.h
@@ -362,6 +362,7 @@ public:
// from isql.epp
USHORT major_ods;
USHORT minor_ods;
+ USHORT att_charset;
void printf(const char* buffer, ...);
void prints(const char* buffer);
};
--
1.8.4.5