Changeset: 0f0cc8d5d1c0 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/0f0cc8d5d1c0
Modified Files:
clients/mapiclient/mclient.c
clients/mapilib/mapi.c
clients/odbc/driver/ODBCGlobal.h
clients/odbc/driver/SQLExecDirect.c
clients/odbc/driver/SQLExecute.c
sql/backends/monet5/sql.c
sql/backends/monet5/sql_result.c
sql/backends/monet5/sql_result.h
sql/test/mapi/Tests/utf8test.SQL.py
Branch: default
Log Message:
Calculate column display width on demand on client (only if C mapi lib).
The width is calculated from the first batch of rows which has been
increased to 5000 (from 1000).
For pymonetdb clients, don't calculate display width at all since it is
completely ignored.
For other clients and for older C clients, nothing changes.
diffs (truncated from 390 to 300 lines):
diff --git a/clients/mapiclient/mclient.c b/clients/mapiclient/mclient.c
--- a/clients/mapiclient/mclient.c
+++ b/clients/mapiclient/mclient.c
@@ -3893,7 +3893,11 @@ main(int argc, char **argv)
exit(2);
}
+#if SIZEOF_VOID_P == 4
mapi_cache_limit(mid, 1000);
+#else
+ mapi_cache_limit(mid, 5000);
+#endif
mapi_setAutocommit(mid, autocommit);
if (mode == SQL && !settz)
mapi_set_time_zone(mid, 0);
diff --git a/clients/mapilib/mapi.c b/clients/mapilib/mapi.c
--- a/clients/mapilib/mapi.c
+++ b/clients/mapilib/mapi.c
@@ -3127,7 +3127,10 @@ parse_header_line(MapiHdl hdl, char *lin
if (result->fieldcnt > result->maxfields) {
REALLOC(result->fields, result->fieldcnt);
- memset(result->fields + result->maxfields, 0,
(result->fieldcnt - result->maxfields) * sizeof(*result->fields));
+ for (int i = result->maxfields; i < result->fieldcnt;
i++)
+ result->fields[i] = (struct MapiColumn) {
+ .columnlength = -1,
+ };
result->maxfields = result->fieldcnt;
}
@@ -3162,7 +3165,10 @@ parse_header_line(MapiHdl hdl, char *lin
result->fieldcnt = n;
if (n > result->maxfields) {
REALLOC(result->fields, n);
- memset(result->fields + result->maxfields, 0, (n -
result->maxfields) * sizeof(*result->fields));
+ for (int i = result->maxfields; i < n; i++)
+ result->fields[i] = (struct MapiColumn) {
+ .columnlength = -1,
+ };
result->maxfields = n;
}
}
@@ -4339,25 +4345,23 @@ mapi_slice_row(struct MapiResultSet *res
free(p);
}
if (i != result->fieldcnt) {
- int j;
- for (j = 0; j < result->fieldcnt; j++) {
- if (result->fields[j].columnname)
- free(result->fields[j].columnname);
- result->fields[j].columnname = NULL;
- if (result->fields[j].columntype)
- free(result->fields[j].columntype);
- result->fields[j].columntype = NULL;
- if (result->fields[j].tablename)
- free(result->fields[j].tablename);
- result->fields[j].tablename = NULL;
- result->fields[j].columnlength = 0;
+ for (int j = 0; j < result->fieldcnt; j++) {
+ free(result->fields[j].columnname);
+ free(result->fields[j].columntype);
+ free(result->fields[j].tablename);
+ result->fields[j] = (struct MapiColumn) {
+ .columnlength = -1,
+ };
}
}
if (i > result->fieldcnt) {
result->fieldcnt = i;
if (i > result->maxfields) {
REALLOC(result->fields, i);
- memset(result->fields + result->maxfields, 0, (i -
result->maxfields) * sizeof(*result->fields));
+ for (int j = result->maxfields; j < i; j++)
+ result->fields[j] = (struct MapiColumn) {
+ .columnlength = -1,
+ };
result->maxfields = i;
}
}
@@ -4571,14 +4575,65 @@ mapi_get_table(MapiHdl hdl, int fnr)
return 0;
}
+#include "mutf8.h"
+
+static size_t
+strwidth(const char *s)
+{
+ if (s == NULL)
+ return 0;
+ size_t len = 0;
+
+ for (uint32_t state = 0, codepoint = 0; *s; s++) {
+ switch (decode(&state, &codepoint, (uint8_t) *s)) {
+ case UTF8_ACCEPT: {
+ int n = charwidth(codepoint);
+ if (n >= 0)
+ len += n;
+ else
+ len++; /* assume width 1 if
unprintable */
+ if (len >= (unsigned) INT_MAX)
+ return INT_MAX;
+ break;
+ }
+ default:
+ break;
+ case UTF8_REJECT:
+ assert(0);
+ }
+ }
+ return len;
+}
+
int
mapi_get_len(MapiHdl hdl, int fnr)
{
struct MapiResultSet *result;
mapi_hdl_check0(hdl);
- if ((result = hdl->result) != 0 && fnr >= 0 && fnr < result->fieldcnt)
+ if ((result = hdl->result) != 0 && fnr >= 0 && fnr < result->fieldcnt) {
+ if (result->fields[fnr].columnlength < 0) {
+ size_t maxlen = 0;
+ Mapi mid = hdl->mid;
+ if (mid->active && read_into_cache(mid->active, 0) !=
MOK)
+ return 0;
+ for (int i = 0; i < result->cache.writer; i++) {
+ if (result->cache.line[i].rows == NULL ||
+ result->cache.line[i].rows[0] != '[')
+ continue;
+ mapi_slice_row(result, i);
+ size_t len =
strwidth(result->cache.line[i].anchors[fnr]);
+ if (len > maxlen)
+ maxlen = len;
+ if (maxlen > (size_t) INT_MAX) {
+ maxlen = (size_t) INT_MAX;
+ break;
+ }
+ }
+ result->fields[fnr].columnlength = (int) maxlen;
+ }
return result->fields[fnr].columnlength > INT_MAX ? INT_MAX :
(int) result->fields[fnr].columnlength;
+ }
mapi_setError(hdl->mid, "Illegal field number", __func__, MERROR);
return 0;
}
@@ -4589,8 +4644,9 @@ mapi_get_digits(MapiHdl hdl, int fnr)
struct MapiResultSet *result;
mapi_hdl_check0(hdl);
- if ((result = hdl->result) != 0 && fnr >= 0 && fnr < result->fieldcnt)
+ if ((result = hdl->result) != 0 && fnr >= 0 && fnr < result->fieldcnt) {
return result->fields[fnr].digits;
+ }
mapi_setError(hdl->mid, "Illegal field number", __func__, MERROR);
return 0;
}
diff --git a/clients/odbc/driver/ODBCGlobal.h b/clients/odbc/driver/ODBCGlobal.h
--- a/clients/odbc/driver/ODBCGlobal.h
+++ b/clients/odbc/driver/ODBCGlobal.h
@@ -82,6 +82,13 @@ SQLRETURN MNDBEndTran(SQLSMALLINT nHandl
SQLRETURN MNDBFreeHandle(SQLSMALLINT handleType, SQLHANDLE handle);
SQLRETURN MNDBGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT
recNumber, SQLCHAR *sqlState, SQLINTEGER *nativeErrorPtr, SQLCHAR *messageText,
SQLSMALLINT bufferLength, SQLSMALLINT *textLengthPtr);
+#if SIZEOF_VOID_P == 4
+#define SMALL_CACHE_LIMIT 100
+#else
+#define SMALL_CACHE_LIMIT 1000
+#endif
+#define LARGE_CACHE_LIMIT 10000
+
#ifdef ODBCDEBUG
#ifdef NATIVE_WIN32
extern const wchar_t *ODBCdebug;
diff --git a/clients/odbc/driver/SQLExecDirect.c
b/clients/odbc/driver/SQLExecDirect.c
--- a/clients/odbc/driver/SQLExecDirect.c
+++ b/clients/odbc/driver/SQLExecDirect.c
@@ -77,13 +77,13 @@ ODBCExecDirect(ODBCStmt *stmt, const SQL
stmt->Dbc->FirstStmt == stmt &&
stmt->cursorType == SQL_CURSOR_FORWARD_ONLY) {
/* we're the only Stmt handle, and we're only going forward */
- if (stmt->Dbc->cachelimit != 10000)
- mapi_cache_limit(stmt->Dbc->mid, 10000);
- stmt->Dbc->cachelimit = 10000;
+ if (stmt->Dbc->cachelimit != LARGE_CACHE_LIMIT)
+ mapi_cache_limit(stmt->Dbc->mid, LARGE_CACHE_LIMIT);
+ stmt->Dbc->cachelimit = LARGE_CACHE_LIMIT;
} else {
- if (stmt->Dbc->cachelimit != 100)
- mapi_cache_limit(stmt->Dbc->mid, 100);
- stmt->Dbc->cachelimit = 100;
+ if (stmt->Dbc->cachelimit != SMALL_CACHE_LIMIT)
+ mapi_cache_limit(stmt->Dbc->mid, SMALL_CACHE_LIMIT);
+ stmt->Dbc->cachelimit = SMALL_CACHE_LIMIT;
}
ret = mapi_query_handle(hdl, query);
free(query);
diff --git a/clients/odbc/driver/SQLExecute.c b/clients/odbc/driver/SQLExecute.c
--- a/clients/odbc/driver/SQLExecute.c
+++ b/clients/odbc/driver/SQLExecute.c
@@ -521,13 +521,13 @@ MNDBExecute(ODBCStmt *stmt)
if (stmt->next == NULL && stmt->Dbc->FirstStmt == stmt &&
stmt->cursorType == SQL_CURSOR_FORWARD_ONLY) {
/* we're the only Stmt handle, and we're only going forward */
- if (stmt->Dbc->cachelimit != 10000)
- mapi_cache_limit(stmt->Dbc->mid, 10000);
- stmt->Dbc->cachelimit = 10000;
+ if (stmt->Dbc->cachelimit != LARGE_CACHE_LIMIT)
+ mapi_cache_limit(stmt->Dbc->mid, LARGE_CACHE_LIMIT);
+ stmt->Dbc->cachelimit = LARGE_CACHE_LIMIT;
} else {
- if (stmt->Dbc->cachelimit != 100)
- mapi_cache_limit(stmt->Dbc->mid, 100);
- stmt->Dbc->cachelimit = 100;
+ if (stmt->Dbc->cachelimit != SMALL_CACHE_LIMIT)
+ mapi_cache_limit(stmt->Dbc->mid, SMALL_CACHE_LIMIT);
+ stmt->Dbc->cachelimit = SMALL_CACHE_LIMIT;
}
msg = mapi_query_handle(hdl, query);
free(query);
diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c
--- a/sql/backends/monet5/sql.c
+++ b/sql/backends/monet5/sql.c
@@ -3015,7 +3015,7 @@ mvc_export_head_wrap(Client cntxt, MalBl
if ((msg = checkSQLContext(cntxt)) != NULL)
return msg;
b = cntxt->sqlcontext;
- ok = mvc_export_head(b, *s, res_id, FALSE, TRUE,
cntxt->qryctx.starttime, mb->optimize);
+ ok = mvc_export_head(b, *s, res_id, false, cntxt->qryctx.starttime,
mb->optimize);
cntxt->qryctx.starttime = 0;
cntxt->qryctx.endtime = 0;
mb->optimize = 0;
diff --git a/sql/backends/monet5/sql_result.c b/sql/backends/monet5/sql_result.c
--- a/sql/backends/monet5/sql_result.c
+++ b/sql/backends/monet5/sql_result.c
@@ -1386,14 +1386,15 @@ mvc_export(mvc *m, stream *s, res_table
b.results = t;
b.reloptimizer = 0;
t->nr_rows = nr;
- if (mvc_export_head(&b, s, t->id, TRUE, TRUE, 0/*starttime*/,
0/*maloptimizer*/) < 0)
+ if (mvc_export_head(&b, s, t->id, true, 0/*starttime*/,
0/*maloptimizer*/) < 0)
return -1;
return mvc_export_table_(m->sa, m, OFMT_CSV, s, t, 0, nr, "[ ", ",\t",
"\t]\n", "\"", "NULL");
}
static lng
-get_print_width(int mtype, sql_class eclass, int digits, int scale, int tz,
bat bid, ptr p)
+get_print_width(int mtype, sql_class eclass, int digits, int scale, int tz,
+ bat bid, ptr p, bool compute_lengths)
{
size_t count = 0, incr = 0;
@@ -1405,6 +1406,8 @@ get_print_width(int mtype, sql_class ecl
if (mtype == TYPE_str) {
if (eclass == EC_CHAR && digits) {
return digits;
+ } else if (!compute_lengths) {
+ return -1;
} else {
int l = 0;
if (bid) {
@@ -1433,6 +1436,8 @@ get_print_width(int mtype, sql_class ecl
} else if (eclass == EC_NUM || eclass == EC_POS || eclass == EC_MONTH
|| eclass == EC_SEC) {
count = 0;
if (bid) {
+ if (!compute_lengths)
+ return -1;
BAT *b = BATdescriptor(bid);
if (b) {
@@ -1545,10 +1550,10 @@ get_print_width(int mtype, sql_class ecl
}
static int
-export_length(stream *s, int mtype, sql_class eclass, int digits, int scale,
int tz, bat bid, ptr p)
+export_length(stream *s, int mtype, sql_class eclass, int digits, int scale,
int tz, bat bid, ptr p, bool compute_lengths)
{
- lng length = get_print_width(mtype, eclass, digits, scale, tz, bid, p);
- if (length < 0)
+ lng length = get_print_width(mtype, eclass, digits, scale, tz, bid, p,
compute_lengths);
+ if (length < -1)
return -2;
if (mvc_send_lng(s, length) != 1)
return -4;
@@ -1623,12 +1628,13 @@ mvc_export_affrows(backend *b, stream *s
}
int
-mvc_export_head(backend *b, stream *s, int res_id, int only_header, int
compute_lengths, lng starttime, lng maloptimizer)
+mvc_export_head(backend *b, stream *s, int res_id, bool only_header, lng
starttime, lng maloptimizer)
{
mvc *m = b->mvc;
int i, res = 0;
BUN count = 0;
res_table *t = res_tables_find(b->results, res_id);
+ bool compute_lengths = true;
if (!s || !t)
return 0;
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]