Update of /cvsroot/monetdb/clients/src/mapiclient
In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv12461
Modified Files:
MapiClient.mx dump.c msqldump.c msqldump.h
Log Message:
Use the new iconv stream to convert tty I/O between the tty charset
and utf-8. Also try to guess the tty's charset, but provide an
override with the --encoding option.
XML output is always in UTF-8, but the non-ASCII characters are now
converted to character entities (&#XXX;) so that it won't do any harm
on non-UTF-8 ttys.
msqldump doesn't (yet?) use the tty's encoding: it always dumps UTF-8.
Index: MapiClient.mx
===================================================================
RCS file: /cvsroot/monetdb/clients/src/mapiclient/MapiClient.mx,v
retrieving revision 1.90
retrieving revision 1.91
diff -u -d -r1.90 -r1.91
--- MapiClient.mx 22 Oct 2007 10:35:41 -0000 1.90
+++ MapiClient.mx 5 Dec 2007 13:48:49 -0000 1.91
@@ -106,9 +106,26 @@
#include <readline/history.h>
#include "ReadlineTools.h"
#endif
+#include "stream.h"
#include "msqldump.h"
#include "mprompt.h"
-#include "stream.h"
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#ifdef HAVE_ICONV
+#ifdef HAVE_ICONV_H
+#include <iconv.h>
+#endif
+#ifdef HAVE_NL_LANGINFO
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+#else
+#ifdef NATIVE_WIN32
+#include <Windows.h>
+#endif
+#endif
+#endif
#ifndef S_ISCHR
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
@@ -131,13 +148,20 @@
};
static enum modes mode = NOLANGUAGE;
-static FILE *toConsole;
+static stream *toConsole;
+static stream *toConsole_raw; /* toConsole without iconv conversion */
+static stream *stdout_stream;
+static stream *stderr_stream;
static FILE *fromConsole = NULL;
static char *language = NULL;
static char *logfile = NULL;
static int start_with_help = 0;
static char promptbuf[16];
static int echoquery = 0;
+#ifdef HAVE_ICONV
+static char *encoding;
+static iconv_t cd_in;
+#endif
#define setPrompt() sprintf(promptbuf, "%.*s>", (int) sizeof(promptbuf) - 2,
language)
#define debugMode() (strncmp(promptbuf, "mdb", 3) == 0)
@@ -242,9 +266,42 @@
{
t1 = gettime();
if (mark && specials == NOmodifier) {
- fprintf(toConsole, "%s % 7ld.%03ld msec %s\n", mark, (t1 - t0)
/ 1000, (t1 - t0) % 1000, mark2 ? mark2 : "");
- fflush(toConsole);
+ stream_printf(toConsole, "%s % 7ld.%03ld msec %s\n", mark, (t1
- t0) / 1000, (t1 - t0) % 1000, mark2 ? mark2 : "");
+ stream_flush(toConsole);
+ }
+}
+
[EMAIL PROTECTED]
+The Mapi library eats away the comment lines, which
+we need to detect end of debugging. We overload
+the routine to our liking.
[EMAIL PROTECTED]
+static char *
+fetch_line(MapiHdl hdl)
+{
+ char *reply;
+
+ if ((reply = mapi_fetch_line(hdl)) == NULL)
+ return NULL;
+ if (strncmp(reply, "mdb>#", 5) == 0) {
+ if (strncmp(reply, "mdb>#EOD", 8) == 0)
+ setPrompt();
+ else
+ sprintf(promptbuf, "mdb>");
}
+ return reply;
+}
+
+static int
+fetch_row(MapiHdl hdl)
+{
+ char *reply;
+
+ do {
+ if ((reply = fetch_line(hdl)) == NULL)
+ return 0;
+ } while (*reply != '[' && *reply != '=');
+ return mapi_split_line(hdl);
}
static void
@@ -284,11 +341,11 @@
}
do {
- fprintf(toConsole,"%c ", first? '|':':');
+ stream_printf(toConsole,"%c ", first? '|':':');
more = 0;
for (i = 0; i < fields; i++) {
if (rest[i] == NULL || *rest[i] == 0)
- fprintf(toConsole, "%*s |", len[i], " ");
+ stream_printf(toConsole, "%*s |", len[i], " ");
else {
/* break the string into pieces and left-adjust
them in the column */
if (strlen(rest[i]) > (size_t) len[i]) {
@@ -297,20 +354,20 @@
t--;
if (t == rest[i] && !isspace((int) *t))
t = rest[i] + len[i];
- fprintf(toConsole, "%*.*s |", first &&
numeric[i] ? len[i] : -len[i], (int) (t - rest[i]), rest[i]);
+ stream_printf(toConsole, "%*.*s |",
first && numeric[i] ? len[i] : -len[i], (int) (t - rest[i]), rest[i]);
while (isspace((int) *t))
t++;
rest[i] = *t ? t : 0;
if (rest[i])
more = 1;
} else {
- fprintf(toConsole, "%*s |", first &&
numeric[i] ? len[i] : -len[i], rest[i]);
+ stream_printf(toConsole, "%*s |", first
&& numeric[i] ? len[i] : -len[i], rest[i]);
rest[i] = 0;
}
}
}
first = 0;
- fprintf(toConsole, "\n");
+ stream_printf(toConsole, "\n");
rows++;
} while (more);
return rows;
@@ -323,19 +380,28 @@
return;
while (*val) {
if (*val == '&')
- fprintf(toConsole, "&");
+ stream_printf(toConsole_raw, "&");
else if (*val == '<')
- fprintf(toConsole, "<");
+ stream_printf(toConsole_raw, "<");
else if (*val == '>')
- fprintf(toConsole, ">");
+ stream_printf(toConsole_raw, ">");
else if (*val == '"')
- fprintf(toConsole, """);
+ stream_printf(toConsole_raw, """);
else if (*val == '\'')
- fprintf(toConsole, "'");
- else if ((*val & 0xFF) < 0x20)
- fprintf(toConsole, "&#%d;", *val & 0xFF);
- else
- fputc(*val, toConsole);
+ stream_printf(toConsole_raw, "'");
+ else if ((*val & 0xFF) < 0x20) /* control character */
+ stream_printf(toConsole_raw, "&#%d;", *val & 0xFF);
+ else if ((*val & 0x80) != 0 /* && encoding != NULL */) {
+ int n, m;
+ int c = *val & 0x7F;
+
+ for (n = 0, m = 0x40; c & m; n++, m >>= 1)
+ c &= ~m;
+ while (--n >= 0)
+ c = (c << 6) | (*++val & 0x3F);
+ stream_printf(toConsole_raw, "&#x%x;", c);
+ } else
+ stream_write(toConsole_raw, val, 1, 1);
val++;
}
}
@@ -343,42 +409,9 @@
static void
XMLprattr(const char *name, const char *val)
{
- fprintf(toConsole, " %s=\"", name);
+ stream_printf(toConsole_raw, " %s=\"", name);
XMLprdata(val);
- fputc('"', toConsole);
-}
-
[EMAIL PROTECTED]
-The Mapi library eats away the comment lines, which
-we need to detect end of debugging. We overload
-the routine to our liking.
[EMAIL PROTECTED]
-static char *
-fetch_line(MapiHdl hdl)
-{
- char *reply;
-
- if ((reply = mapi_fetch_line(hdl)) == NULL)
- return NULL;
- if (strncmp(reply, "mdb>#", 5) == 0) {
- if (strncmp(reply, "mdb>#EOD", 8) == 0)
- setPrompt();
- else
- sprintf(promptbuf, "mdb>");
- }
- return reply;
-}
-
-static int
-fetch_row(MapiHdl hdl)
-{
- char *reply;
-
- do {
- if ((reply = fetch_line(hdl)) == NULL)
- return 0;
- } while (*reply != '[' && *reply != '=');
- return mapi_split_line(hdl);
+ stream_write(toConsole_raw, "\"", 1, 1);
}
static void
@@ -387,35 +420,38 @@
int i, fields;
char *name;
- fprintf(toConsole, "<?xml version='1.0' encoding='UT-8'?>\n");
- fprintf(toConsole, "<!DOCTYPE table [\n"
+ /* we must use toConsole_raw since the XML file is encoded in UTF-8 */
+ stream_flush(toConsole);
+ stream_printf(toConsole_raw, "<?xml version='1.0'
encoding='UTF-8'?>\n");
+ stream_printf(toConsole_raw, "<!DOCTYPE table [\n"
" <!ELEMENT table (row)*>\n" /* a table
consists of zero or more rows */
" <!ELEMENT row (column)+>\n" /* a row
consists of one or more columns */
" <!ELEMENT column (#PCDATA)>\n"
" <!ATTLIST table name CDATA #IMPLIED>\n" /* a table may
have a name */
" <!ATTLIST column name CDATA #IMPLIED>]>\n"); /* a column may
have a name */
- fprintf(toConsole, "<table");
+ stream_printf(toConsole_raw, "<table");
name = mapi_get_table(hdl, 0);
if (name != NULL && *name != 0)
XMLprattr("name", name);
- fprintf(toConsole, ">\n");
+ stream_printf(toConsole_raw, ">\n");
while ((fields = fetch_row(hdl)) != 0) {
- fprintf(toConsole, "<row>");
+ stream_printf(toConsole_raw, "<row>");
for (i = 0; i < fields; i++) {
char *data = mapi_fetch_field(hdl, i);
- fprintf(toConsole, "<column");
+ stream_printf(toConsole_raw, "<column");
name = mapi_get_name(hdl, i);
if (name != NULL && *name != 0)
XMLprattr("name", name);
- fputc('>', toConsole);
+ stream_write(toConsole_raw, ">", 1, 1);
if (data)
XMLprdata(data);
- fprintf(toConsole, "</column>");
+ stream_printf(toConsole_raw, "</column>");
}
- fprintf(toConsole, "</row>\n");
+ stream_printf(toConsole_raw, "</row>\n");
}
- fprintf(toConsole, "</table>\n");
+ stream_printf(toConsole_raw, "</table>\n");
+ stream_flush(toConsole_raw);
}
static void
@@ -426,7 +462,7 @@
while ((line = fetch_line(hdl)) != 0) {
if (*line == '=')
line++;
- fprintf(toConsole, "%s\n", line);
+ stream_printf(toConsole, "%s\n", line);
}
}
@@ -444,42 +480,37 @@
if (s == NULL)
s = "";
if (strchr(s, *sep) != NULL || strchr(s, '\n') != NULL
|| strchr(s, '"') != NULL) {
- fprintf(toConsole, "%s\"", i == 0 ? "" : sep);
+ stream_printf(toConsole, "%s\"", i == 0 ? "" :
sep);
while (*s) {
switch (*s) {
case '\n':
- putc('\\', toConsole);
- putc('n', toConsole);
+ stream_write(toConsole, "\\n",
1, 2);
break;
case '\t':
- putc('\\', toConsole);
- putc('t', toConsole);
+ stream_write(toConsole, "\\t",
1, 2);
break;
case '\r':
- putc('\\', toConsole);
- putc('r', toConsole);
+ stream_write(toConsole, "\\r",
1, 2);
break;
case '\\':
- putc('\\', toConsole);
- putc('\\', toConsole);
+ stream_write(toConsole, "\\\\",
1, 2);
break;
case '"':
- putc('\\', toConsole);
- putc('"', toConsole);
+ stream_write(toConsole, "\\\"",
1, 2);
break;
default:
if (*s == *sep)
- putc('\\', toConsole);
- putc(*s, toConsole);
+ stream_write(toConsole,
"\\", 1, 1);
+ stream_write(toConsole, s, 1,
1);
break;
}
s++;
}
- putc('"', toConsole);
+ stream_write(toConsole, "\"", 1, 1);
} else
- fprintf(toConsole, "%s%s", i == 0 ? "" : sep, s
? s : "");
+ stream_printf(toConsole, "%s%s", i == 0 ? "" :
sep, s ? s : "");
}
- fprintf(toConsole, "\n");
+ stream_printf(toConsole, "\n");
}
}
@@ -488,13 +519,13 @@
{
int i, j;
- fprintf(toConsole, "+%c", sep);
+ stream_printf(toConsole, "+%c", sep);
for (i = 0; i < fields; i++) {
for (j = 0; j < (len[i] < 0 ? -len[i] : len[i]); j++)
- fprintf(toConsole, "%c", sep);
- fprintf(toConsole, "%c+", sep);
+ stream_printf(toConsole, "%c", sep);
+ stream_printf(toConsole, "%c+", sep);
}
- fprintf(toConsole, "\n");
+ stream_printf(toConsole, "\n");
}
static void
@@ -505,9 +536,9 @@
qry = mapi_get_query(hdl);
if (!interactive_stdin)
- fputc('#', toConsole);
+ stream_write(toConsole, "#", 1, 1);
if (qry) {
- fprintf(toConsole, "%s", qry);
+ stream_printf(toConsole, "%s", qry);
free(qry);
}
}
@@ -540,7 +571,7 @@
sprintf(promptbuf, "mdb>");
while ((reply = fetch_line(hdl))) {
cnt++;
- fprintf(toConsole, "%s\n", reply);
+ stream_printf(toConsole, "%s\n", reply);
if (strncmp(reply, "mdb>#EOD", 8) == 0) {
cnt = 0;
break;
@@ -558,7 +589,7 @@
int c;
SQLseparator(len, fields, '-');
- fprintf(toConsole, "next page? (continue,quit,next)");
+ stream_printf(toConsole, "next page? (continue,quit,next)");
c = getc(fromConsole);
if (c == 'c')
*ps = 0;
@@ -807,7 +838,7 @@
else if (strcmp(s, "xml") == 0)
formatter = XMLformatter;
else
- fprintf(toConsole, "unsupported formatter\n");
+ stream_printf(toConsole, "unsupported formatter\n");
}
static void
@@ -827,17 +858,27 @@
format_result(MapiHdl hdl)
{
#ifdef HAVE_POPEN
- FILE *saveFD = NULL; /* for external paging */
+ stream *saveFD = NULL, *saveFD_raw; /* for external paging */
#endif
MapiMsg rc;
#ifdef HAVE_POPEN
if (pager) {
- saveFD = toConsole;
- toConsole = popen(pager, "w");
- if (toConsole == NULL) {
- toConsole = saveFD;
+ FILE *p;
+
+ p = popen(pager, "w");
+ if (p == NULL)
fprintf(stderr, "Starting '%s' failed\n", pager);
+ else {
+ saveFD = toConsole;
+ saveFD_raw = toConsole_raw;
+ /* put | in name to indicate that file should be closed
with pclose */
+ toConsole = file_wastream(p, "|pager");
+ toConsole_raw = toConsole;
+#ifdef HAVE_ICONV
+ if (encoding != NULL)
+ toConsole = iconv_wstream(toConsole, encoding,
"pager");
+#endif
}
}
#endif
@@ -849,9 +890,9 @@
oldpagewidth = pagewidth;
if (mapi_get_querytype(hdl) == Q_UPDATE) {
if (formatter == RAWformatter)
- fprintf(toConsole, "[ %d\t]\n",
mapi_rows_affected(hdl));
+ stream_printf(toConsole, "[ %d\t]\n",
mapi_rows_affected(hdl));
else
- fprintf(toConsole, "Rows affected %d\n",
mapi_rows_affected(hdl));
+ stream_printf(toConsole, "Rows affected %d\n",
mapi_rows_affected(hdl));
continue;
}
if (pagewidth <= 0) {
@@ -873,7 +914,7 @@
if (formatter == RAWformatter)
mapi_explain_result(hdl, stderr);
else
- fprintf(toConsole, "%s", reply);
+ stream_printf(toConsole, "%s", reply);
}
if (debugMode())
RAWrenderer(hdl);
@@ -912,8 +953,9 @@
#ifdef HAVE_POPEN
if (saveFD) {
- pclose(toConsole);
+ stream_close(toConsole);
toConsole = saveFD;
+ toConsole_raw = saveFD_raw;
}
#endif
@@ -1073,7 +1115,7 @@
free(buf);
if (file != NULL)
fclose(fp);
- fflush(stdout);
+ stream_flush(toConsole);
return 0;
}
@@ -1086,15 +1128,15 @@
{
/* XQuery prelude */
if (mode == XQUERY) {
- fprintf(toConsole, "mclient interactive MonetDB/XQuery session:
type an XQuery or XQUF update.\n");
- fprintf(toConsole, "\nSupported document-management XQuery
extensions:\n");
- fprintf(toConsole, " pf:collections() as node()\n");
- fprintf(toConsole, " pf:documents($collectionName as xs:string)
as node()\n");
- fprintf(toConsole, " pf:del-doc($documentName as xs:string)\n");
- fprintf(toConsole, " pf:add-doc($uri as xs:string,
$documentName as xs:string\n");
- fprintf(toConsole, " [,$collectionName as xs:string
[,$freePercentage as xs:integer]])\n");
- fprintf(toConsole, "\nSession commands:\n");
- fprintf(toConsole, "<> - send query to server (or %s)\n",
+ stream_printf(toConsole, "mclient interactive MonetDB/XQuery
session: type an XQuery or XQUF update.\n");
+ stream_printf(toConsole, "\nSupported document-management
XQuery extensions:\n");
+ stream_printf(toConsole, " pf:collections() as node()\n");
+ stream_printf(toConsole, " pf:documents($collectionName as
xs:string) as node()\n");
+ stream_printf(toConsole, " pf:del-doc($documentName as
xs:string)\n");
+ stream_printf(toConsole, " pf:add-doc($uri as xs:string,
$documentName as xs:string\n");
+ stream_printf(toConsole, " [,$collectionName as xs:string
[,$freePercentage as xs:integer]])\n");
+ stream_printf(toConsole, "\nSession commands:\n");
+ stream_printf(toConsole, "<> - send query to server (or
%s)\n",
#ifdef WIN32
"CTRL-Z"
#else
@@ -1104,29 +1146,29 @@
}
/* shared control options */
- fprintf(toConsole, "\\? - show this message\n");
+ stream_printf(toConsole, "\\? - show this message\n");
if (mode == MAL)
- fprintf(toConsole, "?pat - MAL function help.
pat=[modnme[.fcnnme][(][)]] wildcard *\n");
- fprintf(toConsole, "\\<file - read input from file\n");
- fprintf(toConsole, "\\>file - save response in file, or stdout if no
file is given\n");
- fprintf(toConsole, "\\|cmd - pipe result to process, or stop when no
command is given\n");
+ stream_printf(toConsole, "?pat - MAL function help.
pat=[modnme[.fcnnme][(][)]] wildcard *\n");
+ stream_printf(toConsole, "\\<file - read input from file\n");
+ stream_printf(toConsole, "\\>file - save response in file, or stdout
if no file is given\n");
+ stream_printf(toConsole, "\\|cmd - pipe result to process, or stop
when no command is given\n");
#ifdef HAVE_LIBREADLINE
- fprintf(toConsole, "\\h - show the readline history\n");
+ stream_printf(toConsole, "\\h - show the readline history\n");
#endif
- fprintf(toConsole, "\\t - toggle timer\n");
- fprintf(toConsole, "\\e - echo the query in sql formatting
mode\n");
+ stream_printf(toConsole, "\\t - toggle timer\n");
+ stream_printf(toConsole, "\\e - echo the query in sql formatting
mode\n");
if (mode == SQL) {
- fprintf(toConsole, "\\D table- dumps the table, or the complete
database if none given.\n");
- fprintf(toConsole, "\\d table- describe the table, or the
complete database if none given.\n");
- fprintf(toConsole, "\\A - enable auto commit\n");
- fprintf(toConsole, "\\a - disable auto commit\n");
+ stream_printf(toConsole, "\\D table- dumps the table, or the
complete database if none given.\n");
+ stream_printf(toConsole, "\\d table- describe the table, or the
complete database if none given.\n");
+ stream_printf(toConsole, "\\A - enable auto commit\n");
+ stream_printf(toConsole, "\\a - disable auto commit\n");
}
- fprintf(toConsole, "\\f - format using a built-in renderer
{csv,tab,raw,sql,xml} \n");
- fprintf(toConsole, "\\w# - set maximal page width (-1=raw,0=no
limit, >0 max char)\n");
- fprintf(toConsole, "\\r# - set maximum rows per page (-1=raw)\n");
- fprintf(toConsole, "\\L file - save client/server interaction\n");
- fprintf(toConsole, "\\X - trace mclient code\n");
- fprintf(toConsole, "\\q - terminate session\n");
+ stream_printf(toConsole, "\\f - format using a built-in renderer
{csv,tab,raw,sql,xml} \n");
+ stream_printf(toConsole, "\\w# - set maximal page width
(-1=raw,0=no limit, >0 max char)\n");
+ stream_printf(toConsole, "\\r# - set maximum rows per page
(-1=raw)\n");
+ stream_printf(toConsole, "\\L file - save client/server interaction\n");
+ stream_printf(toConsole, "\\X - trace mclient code\n");
+ stream_printf(toConsole, "\\q - terminate session\n");
}
static int
@@ -1179,6 +1221,20 @@
#endif
line = fgets(buf, BUFSIZ, fp);
}
+#ifdef HAVE_ICONV
+ if (line != NULL && encoding != NULL && cd_in != (iconv_t) -1) {
+ ICONV_CONST char *from = line;
+ size_t fromlen = strlen(from);
+ size_t tolen = 4 * fromlen + 1;
+ char *to = malloc(tolen);
+
+ line = to;
+ iconv(cd_in, &from, &fromlen, &to, &tolen);
+ *to = 0;
+ free(buf);
+ buf = line;
+ }
+#endif
if (line == NULL || (mode == XQUERY && line[0] == '<' &&
line[1] == '>')) {
/* end of file */
if (hdl == NULL)
@@ -1267,9 +1323,9 @@
for (line += 2; *line && isspace((int)
*line); line++)
;
if (*line) {
- fprintf(toConsole, "START
TRANSACTION;\n");
+ stream_printf(toConsole, "START
TRANSACTION;\n");
dump_table(mid, line,
toConsole, 0);
- fprintf(toConsole, "COMMIT;\n");
+ stream_printf(toConsole,
"COMMIT;\n");
} else
dump_tables(mid, toConsole);
continue;
@@ -1287,14 +1343,17 @@
line[--length] = 0;
for (line += 2; *line && isspace((int)
*line); line++)
;
- if (toConsole != stdout && toConsole !=
stderr)
- fclose(toConsole);
+ if (toConsole != stdout_stream &&
toConsole != stderr_stream)
+ stream_close(toConsole);
if (*line == 0 || strcmp(line,
"stdout") == 0)
- toConsole = stdout;
+ toConsole = stdout_stream;
else if (strcmp(line, "stderr") == 0)
- toConsole = stderr;
- else if ((toConsole = fopen(line, "w"))
== NULL) {
- toConsole = stdout;
+ toConsole = stderr_stream;
+ else if ((toConsole =
open_wastream(line)) == NULL ||
+ stream_errnr(toConsole)) {
+ if (toConsole != NULL)
+ stream_close(toConsole);
+ toConsole = stdout_stream;
fprintf(stderr, "Cannot open
%s\n", line);
}
continue;
@@ -1341,7 +1400,7 @@
for (h = 0; h < history_length; h++) {
nl = history_get(h) ?
history_get(h)->line : 0;
if (nl)
- fprintf(toConsole, "%d
%s\n", h, nl);
+
stream_printf(toConsole, "%d %s\n", h, nl);
}
continue;
}
@@ -1354,9 +1413,9 @@
if (nl)
*nl = 0;
if (history_expand(line + 2, &nl)) {
- fprintf(toConsole, "%s\n", nl);
+ stream_printf(toConsole,
"%s\n", nl);
}
- fprintf(toConsole, "Expansion needs
work\n");
+ stream_printf(toConsole, "Expansion
needs work\n");
continue;
}
*/
@@ -1370,25 +1429,25 @@
for (line += 2; *line && isspace((int)
*line); line++)
;
if (*line == 0) {
- fprintf(toConsole, "Current
formatter: ");
+ stream_printf(toConsole,
"Current formatter: ");
switch (formatter) {
case RAWformatter:
- fprintf(toConsole,
"raw\n");
+
stream_printf(toConsole, "raw\n");
break;
case TABLEformatter:
- fprintf(toConsole,
"sql\n");
+
stream_printf(toConsole, "sql\n");
break;
case CSVformatter:
- fprintf(toConsole,
"csv\n");
+
stream_printf(toConsole, "csv\n");
break;
case TABformatter:
- fprintf(toConsole,
"tab\n");
+
stream_printf(toConsole, "tab\n");
break;
case XMLformatter:
- fprintf(toConsole,
"xml\n");
+
stream_printf(toConsole, "xml\n");
break;
default:
- fprintf(toConsole,
"none\n");
+
stream_printf(toConsole, "none\n");
break;
}
} else
@@ -1466,6 +1525,9 @@
fprintf(stderr, " -d database | --database=database database to
connect to\n");
fprintf(stderr, " -e | --echo echo the query\n");
+#ifdef HAVE_ICONV
+ fprintf(stderr, " -E charset | --encoding=charset specify encoding
(character set) of the terminal\n");
+#endif
fprintf(stderr, " -f kind | --format=kind specify output
format {dm,xml} for Xquery, or {csv,tab,raw,sql,xml}\n");
fprintf(stderr, " -H | --history load/save cmdline
history (default off)\n");
fprintf(stderr, " -h hostname | --host=hostname host to connect
to\n");
@@ -1520,32 +1582,40 @@
struct stat statb;
static struct option long_options[] = {
{"collection", 1, 0, 'C'},
- {"dump", 0, 0, 'D'},
{"database", 1, 0, 'd'},
+ {"dump", 0, 0, 'D'},
{"echo", 0, 0, 'e'},
+#ifdef HAVE_ICONV
+ {"encoding", 1, 0, 'E'},
+#endif
{"format", 1, 0, 'f'},
+ {"help", 0, 0, '?'},
+ {"history", 0, 0, 'H'},
+ {"host", 1, 0, 'h'},
{"input", 1, 0, 'I'},
{"interactive", 0, 0, 'i'},
- {"host", 1, 0, 'h'},
- {"log", 1, 0, 'L'},
{"language", 1, 0, 'l'},
+ {"log", 1, 0, 'L'},
#ifdef HAVE_POPEN
{"pager", 1, 0, '|'},
#endif
- {"width", 1, 0, 'w'},
- {"rows", 1, 0, 'r'},
{"passwd", 2, 0, 'P'},
{"port", 1, 0, 'p'},
+ {"rows", 1, 0, 'r'},
{"statement", 1, 0, 's'},
{"time", 0, 0, 't'},
- {"Xdebug", 0, 0, 'X'},
{"user", 2, 0, 'u'},
- {"history", 0, 0, 'H'},
- {"help", 0, 0, '?'},
+ {"width", 1, 0, 'w'},
+ {"Xdebug", 0, 0, 'X'},
{0, 0, 0, 0}
};
- toConsole = stdout;
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_ALL, "");
+#endif
+ toConsole = stdout_stream = file_wastream(stdout, "stdout");
+ toConsole_raw = toConsole;
+ stderr_stream = file_wastream(stderr, "stderr");
/* execute from stdin? */
if (fstat(fileno(stdin), &statb) == 0 && S_ISCHR(statb.st_mode))
@@ -1554,7 +1624,11 @@
mark = NULL;
mark2 = NULL;
- while ((c = getopt_long(argc, argv, "C:Dd:ef:I:ih:L:l:"
+ while ((c = getopt_long(argc, argv, "C:Dd:e"
+#ifdef HAVE_ICONV
+ "E:"
+#endif
+ "f:I:ih:L:l:"
#ifdef HAVE_POPEN
"|:"
#endif
@@ -1574,6 +1648,11 @@
case 'e':
echoquery = 1;
break;
+#ifdef HAVE_ICONV
+ case 'E':
+ encoding = optarg;
+ break;
+#endif
case 'L':
logfile = strdup(optarg);
break;
@@ -1678,6 +1757,38 @@
usage(argv[0]);
}
+#ifdef HAVE_ICONV
+ if (encoding == NULL) {
+#ifdef HAVE_NL_LANGINFO
+ encoding = nl_langinfo(CODESET);
+#else
+#ifdef NATIVE_WIN32
+ UINT cp = GetOEMCP();
+
+ if (cp != 0) {
+ encoding = malloc(10);
+ snprintf(encoding, 10, "cp%d", cp);
+
+ }
+#endif
+#endif
+ }
+ if (strcasecmp(encoding, "utf-8") == 0)
+ encoding = NULL;
+ if (encoding != NULL) {
+ toConsole = iconv_wstream(toConsole, encoding, "stdout");
+ if (toConsole == NULL || stream_errnr(toConsole)) {
+ fprintf(stderr, "%s: warning: cannot convert local
character set %s to UTF-8\n", argv[0], encoding);
+ if (toConsole != NULL)
+ stream_close(toConsole);
+ toConsole = toConsole_raw;
+ }
+ stdout_stream = toConsole;
+ if ((cd_in = iconv_open("utf-8", encoding)) == (iconv_t) -1)
+ fprintf(stderr, "%s: warning: cannot convert UTF-8 to
local character set %s\n", argv[0], encoding);
+ }
+#endif
+
/* default to administrator account (eeks) when being called without
* any arguments, default to the current user if -u flag is given */
if (guest) {
Index: msqldump.h
===================================================================
RCS file: /cvsroot/monetdb/clients/src/mapiclient/msqldump.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- msqldump.h 13 Aug 2007 12:26:49 -0000 1.4
+++ msqldump.h 5 Dec 2007 13:48:49 -0000 1.5
@@ -16,5 +16,5 @@
* All Rights Reserved.
*/
-extern int dump_table(Mapi mid, char *tname, FILE *toConsole, int describe);
-extern int dump_tables(Mapi mid, FILE *toConsole);
+extern int dump_table(Mapi mid, char *tname, stream *toConsole, int describe);
+extern int dump_tables(Mapi mid, stream *toConsole);
Index: msqldump.c
===================================================================
RCS file: /cvsroot/monetdb/clients/src/mapiclient/msqldump.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- msqldump.c 3 Oct 2007 13:56:17 -0000 1.6
+++ msqldump.c 5 Dec 2007 13:48:49 -0000 1.7
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include "stream.h"
#include "msqldump.h"
#include "mprompt.h"
@@ -68,6 +69,7 @@
int c;
Mapi mid;
int quiet = 0;
+ stream *out;
static struct option long_options[] = {
{"host", 1, 0, 'h'},
{"passwd", 2, 0, 'P'},
@@ -141,7 +143,9 @@
}
mapi_trace(mid, trace);
- c = dump_tables(mid, stdout);
+ out = file_wastream(stdout, "stdout");
+ c = dump_tables(mid, out);
+ stream_flush(out);
mapi_disconnect(mid);
return c;
Index: dump.c
===================================================================
RCS file: /cvsroot/monetdb/clients/src/mapiclient/dump.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- dump.c 30 Nov 2007 12:33:53 -0000 1.15
+++ dump.c 5 Dec 2007 13:48:49 -0000 1.16
@@ -19,6 +19,7 @@
#include "clients_config.h"
#include <monet_options.h>
#include "mapilib/Mapi.h"
+#include "stream.h"
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
@@ -31,34 +32,32 @@
#endif
static void
-quoted_print(FILE *f, const char *s)
+quoted_print(stream *f, const char *s)
{
- putc('"', f);
+ stream_write(f, "\"", 1, 1);
while (*s) {
switch (*s) {
case '\\':
case '"':
- putc('\\', f);
- putc(*s, f);
+ stream_write(f, "\\", 1, 1);
+ stream_write(f, s, 1, 1);
break;
case '\n':
- putc('\\', f);
- putc('n', f);
+ stream_write(f, "\\n", 1, 2);
break;
case '\t':
- putc('\\', f);
- putc('t', f);
+ stream_write(f, "\\t", 1, 2);
break;
default:
if ((0 < *s && *s < 32) || *s == '\377')
- fprintf(f, "\\%03o", *s & 0377);
+ stream_printf(f, "\\%03o", *s & 0377);
else
- putc(*s, f);
+ stream_write(f, s, 1, 1);
break;
}
s++;
}
- putc('"', f);
+ stream_write(f, "\"", 1, 1);
}
static char *actions[] = {
@@ -103,7 +102,7 @@
}
int
-dump_table(Mapi mid, char *tname, FILE *toConsole, int describe)
+dump_table(Mapi mid, char *tname, stream *toConsole, int describe)
{
int cnt, i;
MapiHdl hdl;
@@ -165,14 +164,14 @@
return 1;
}
- fprintf(toConsole, "CREATE TABLE ");
+ stream_printf(toConsole, "CREATE TABLE ");
quoted_print(toConsole, sname);
free(sname);
- fprintf(toConsole, ".");
+ stream_printf(toConsole, ".");
quoted_print(toConsole, tname);
- fprintf(toConsole, " (\n");
+ stream_printf(toConsole, " (\n");
snprintf(query, maxquerylen,
"SELECT \"c\".\"name\"," /* 0 */
@@ -216,11 +215,11 @@
return 1;
}
if (cnt)
- fprintf(toConsole, ",\n");
+ stream_printf(toConsole, ",\n");
- putc('\t', toConsole);
+ stream_write(toConsole, "\t", 1, 1);
quoted_print(toConsole, c_name);
- putc(' ', toConsole);
+ stream_write(toConsole, " ", 1, 1);
if (strcmp(c_type, "boolean") == 0 ||
strcmp(c_type, "int") == 0 ||
strcmp(c_type, "smallint") == 0 ||
@@ -228,82 +227,82 @@
strcmp(c_type, "double") == 0 ||
strcmp(c_type, "real") == 0 ||
strcmp(c_type, "date") == 0) {
- fprintf(toConsole, "%s", c_type);
+ stream_printf(toConsole, "%s", c_type);
} else if (strcmp(c_type, "month_interval") == 0) {
if (*c_type_scale == '1') {
if (*c_type_digits == 1)
- fprintf(toConsole, "INTERVAL YEAR");
+ stream_printf(toConsole, "INTERVAL
YEAR");
else
- fprintf(toConsole, "INTERVAL YEAR TO
MONTH");
+ stream_printf(toConsole, "INTERVAL YEAR
TO MONTH");
} else
- fprintf(toConsole, "INTERVAL MONTH");
+ stream_printf(toConsole, "INTERVAL MONTH");
} else if (strcmp(c_type, "sec_interval") == 0) {
switch (*c_type_scale) {
case '3':
switch (*c_type_digits) {
case '3':
- fprintf(toConsole, "INTERVAL DAY");
+ stream_printf(toConsole, "INTERVAL
DAY");
break;
case '4':
- fprintf(toConsole, "INTERVAL DAY TO
HOUR");
+ stream_printf(toConsole, "INTERVAL DAY
TO HOUR");
break;
case '5':
- fprintf(toConsole, "INTERVAL DAY TO
MINUTE");
+ stream_printf(toConsole, "INTERVAL DAY
TO MINUTE");
break;
case '6':
- fprintf(toConsole, "INTERVAL DAY TO
SECOND");
+ stream_printf(toConsole, "INTERVAL DAY
TO SECOND");
break;
}
break;
case '4':
switch (*c_type_digits) {
case '4':
- fprintf(toConsole, "INTERVAL HOUR");
+ stream_printf(toConsole, "INTERVAL
HOUR");
break;
case '5':
- fprintf(toConsole, "INTERVAL HOUR TO
MINUTE");
+ stream_printf(toConsole, "INTERVAL HOUR
TO MINUTE");
break;
case '6':
- fprintf(toConsole, "INTERVAL HOUR TO
SECOND");
+ stream_printf(toConsole, "INTERVAL HOUR
TO SECOND");
break;
}
break;
case '5':
switch (*c_type_digits) {
case '5':
- fprintf(toConsole, "INTERVAL MINUTE");
+ stream_printf(toConsole, "INTERVAL
MINUTE");
break;
case '6':
- fprintf(toConsole, "INTERVAL MINUTE TO
SECOND");
+ stream_printf(toConsole, "INTERVAL
MINUTE TO SECOND");
break;
}
break;
case '6':
- fprintf(toConsole, "INTERVAL SECOND");
+ stream_printf(toConsole, "INTERVAL SECOND");
break;
}
} else if (strcmp(c_type, "clob") == 0) {
- fprintf(toConsole, "CHARACTER LARGE OBJECT");
+ stream_printf(toConsole, "CHARACTER LARGE OBJECT");
if (strcmp(c_type_digits, "0") != 0)
- fprintf(toConsole, "(%s)", c_type_digits);
+ stream_printf(toConsole, "(%s)", c_type_digits);
} else if (strcmp(c_type, "timestamp") == 0 ||
strcmp(c_type, "time") == 0) {
- fprintf(toConsole, "%s", c_type);
+ stream_printf(toConsole, "%s", c_type);
if (strcmp(c_type_digits, "0") != 0)
- fprintf(toConsole, "(%s)", c_type_digits);
+ stream_printf(toConsole, "(%s)", c_type_digits);
if (strcmp(c_type_scale, "1") == 0)
- fprintf(toConsole, " WITH TIME ZONE");
+ stream_printf(toConsole, " WITH TIME ZONE");
} else if (strcmp(c_type_digits, "0") == 0) {
- fprintf(toConsole, "%s", c_type);
+ stream_printf(toConsole, "%s", c_type);
} else if (strcmp(c_type_scale, "0") == 0) {
- fprintf(toConsole, "%s(%s)", c_type, c_type_digits);
+ stream_printf(toConsole, "%s(%s)", c_type,
c_type_digits);
} else {
- fprintf(toConsole, "%s(%s,%s)", c_type, c_type_digits,
c_type_scale);
+ stream_printf(toConsole, "%s(%s,%s)", c_type,
c_type_digits, c_type_scale);
}
if (strcmp(c_null, "false") == 0)
- fprintf(toConsole, " NOT NULL");
+ stream_printf(toConsole, " NOT NULL");
if (c_default != NULL)
- fprintf(toConsole, " DEFAULT %s", c_default);
+ stream_printf(toConsole, " DEFAULT %s", c_default);
cnt++;
}
if (mapi_error(mid)) {
@@ -346,20 +345,20 @@
return 1;
}
if (cnt == 0) {
- fprintf(toConsole, ",\n\t");
+ stream_printf(toConsole, ",\n\t");
if (k_name) {
- fprintf(toConsole, "CONSTRAINT ");
+ stream_printf(toConsole, "CONSTRAINT ");
quoted_print(toConsole, k_name);
- putc(' ', toConsole);
+ stream_write(toConsole, " ", 1, 1);
}
- fprintf(toConsole, "PRIMARY KEY (");
+ stream_printf(toConsole, "PRIMARY KEY (");
} else
- fprintf(toConsole, ", ");
+ stream_printf(toConsole, ", ");
quoted_print(toConsole, c_column);
cnt++;
}
if (cnt)
- fprintf(toConsole, ")");
+ stream_printf(toConsole, ")");
if (mapi_error(mid)) {
mapi_explain_query(hdl, stderr);
mapi_close_handle(hdl);
@@ -403,21 +402,21 @@
}
if (strcmp(kc_nr, "0") == 0) {
if (cnt)
- putc(')', toConsole);
- fprintf(toConsole, ",\n\t");
+ stream_write(toConsole, ")", 1, 1);
+ stream_printf(toConsole, ",\n\t");
if (k_name) {
- fprintf(toConsole, "CONSTRAINT ");
+ stream_printf(toConsole, "CONSTRAINT ");
quoted_print(toConsole, k_name);
- putc(' ', toConsole);
+ stream_write(toConsole, " ", 1, 1);
}
- fprintf(toConsole, "UNIQUE (");
+ stream_printf(toConsole, "UNIQUE (");
cnt = 1;
} else
- fprintf(toConsole, ", ");
+ stream_printf(toConsole, ", ");
quoted_print(toConsole, c_column);
}
if (cnt)
- putc(')', toConsole);
+ stream_write(toConsole, ")", 1, 1);
if (mapi_error(mid)) {
mapi_explain_query(hdl, stderr);
mapi_close_handle(hdl);
@@ -487,27 +486,27 @@
pkeys[nkeys - 1] = mapi_fetch_field(hdl, 1);
fkeys[nkeys - 1] = mapi_fetch_field(hdl, 2);
}
- fprintf(toConsole, ",\n\t");
+ stream_printf(toConsole, ",\n\t");
if (c_fkname) {
- fprintf(toConsole, "CONSTRAINT ");
+ stream_printf(toConsole, "CONSTRAINT ");
quoted_print(toConsole, c_fkname);
- putc(' ', toConsole);
+ stream_write(toConsole, " ", 1, 1);
}
- fprintf(toConsole, "FOREIGN KEY (");
+ stream_printf(toConsole, "FOREIGN KEY (");
for (i = 0; i < nkeys; i++) {
if (i > 0)
- fprintf(toConsole, ", ");
+ stream_printf(toConsole, ", ");
quoted_print(toConsole, fkeys[i]);
}
- fprintf(toConsole, ") REFERENCES ");
+ stream_printf(toConsole, ") REFERENCES ");
quoted_print(toConsole, c_name);
- fprintf(toConsole, " (");
+ stream_printf(toConsole, " (");
for (i = 0; i < nkeys; i++) {
if (i > 0)
- fprintf(toConsole, ", ");
+ stream_printf(toConsole, ", ");
quoted_print(toConsole, pkeys[i]);
}
- fprintf(toConsole, ")");
+ stream_printf(toConsole, ")");
free(fkeys);
free(pkeys);
if (c_faction) {
@@ -516,9 +515,9 @@
int on_delete = action & 255;
if (0 < on_delete && on_delete < NR_ACTIONS &&
on_delete != 2 /* RESTRICT -- default */)
- fprintf(toConsole, " ON DELETE %s",
actions[on_delete]);
+ stream_printf(toConsole, " ON DELETE %s",
actions[on_delete]);
if (0 < on_update && on_update < NR_ACTIONS &&
on_delete != 2 /* RESTRICT -- default */)
- fprintf(toConsole, " ON UPDATE %s",
actions[on_update]);
+ stream_printf(toConsole, " ON UPDATE %s",
actions[on_update]);
}
}
if (mapi_error(mid)) {
@@ -529,9 +528,9 @@
}
mapi_close_handle(hdl);
- fprintf(toConsole, "\n");
+ stream_printf(toConsole, "\n");
- fprintf(toConsole, ");\n");
+ stream_printf(toConsole, ");\n");
snprintf(query, maxquerylen,
"SELECT \"i\".\"name\", " /* 0 */
@@ -579,19 +578,19 @@
if (strcmp(kc_nr, "0") == 0) {
if (cnt)
- fprintf(toConsole, ");\n");
- fprintf(toConsole, "CREATE INDEX ");
+ stream_printf(toConsole, ");\n");
+ stream_printf(toConsole, "CREATE INDEX ");
quoted_print(toConsole, i_name);
- fprintf(toConsole, " ON ");
+ stream_printf(toConsole, " ON ");
quoted_print(toConsole, tname);
- fprintf(toConsole, " (");
+ stream_printf(toConsole, " (");
cnt = 1;
} else
- fprintf(toConsole, ", ");
+ stream_printf(toConsole, ", ");
quoted_print(toConsole, c_name);
}
if (cnt)
- fprintf(toConsole, ");\n");
+ stream_printf(toConsole, ");\n");
if (mapi_error(mid)) {
mapi_explain_query(hdl, stderr);
mapi_close_handle(hdl);
@@ -617,9 +616,9 @@
if (mapi_fetch_row(hdl)) {
char *cntfld = mapi_fetch_field(hdl, 0);
- fprintf(toConsole, "COPY %s RECORDS INTO ", cntfld);
+ stream_printf(toConsole, "COPY %s RECORDS INTO ", cntfld);
quoted_print(toConsole, tname);
- fprintf(toConsole, " FROM stdin USING DELIMITERS '\\t';\n");
+ stream_printf(toConsole, " FROM stdin USING DELIMITERS
'\\t';\n");
}
mapi_close_handle(hdl);
@@ -648,17 +647,17 @@
for (i = 0; i < cnt; i++) {
s = mapi_fetch_field(hdl, i);
if (s == NULL)
- fputs("NULL", toConsole);
+ stream_printf(toConsole, "NULL");
else if (string[i]) {
/* write double-quoted string with
certain characters escaped */
quoted_print(toConsole, s);
} else
- fputs(s, toConsole);
+ stream_printf(toConsole, "%s", s);
if (i < cnt - 1)
- putc('\t', toConsole);
+ stream_write(toConsole, "\t", 1, 1);
else
- putc('\n', toConsole);
+ stream_write(toConsole, "\n", 1, 1);
}
}
free(string);
@@ -674,7 +673,7 @@
}
int
-dump_tables(Mapi mid, FILE *toConsole)
+dump_tables(Mapi mid, stream *toConsole)
{
const char *start = "START TRANSACTION";
const char *end = "COMMIT";
@@ -691,7 +690,7 @@
int rc = 0;
/* start a transaction for the dump */
- fprintf(toConsole, "START TRANSACTION;\n");
+ stream_printf(toConsole, "START TRANSACTION;\n");
if ((hdl = mapi_query(mid, start)) == NULL || mapi_error(mid)) {
if (hdl) {
@@ -707,8 +706,8 @@
if (sname == NULL)
return 1;
if (strcmp(sname, "sys") != 0 && strcmp(sname, "tmp") != 0) {
- fprintf(toConsole, "CREATE SCHEMA %s;\n", sname);
- fprintf(toConsole, "SET SCHEMA %s;\n", sname);
+ stream_printf(toConsole, "CREATE SCHEMA %s;\n", sname);
+ stream_printf(toConsole, "SET SCHEMA %s;\n", sname);
}
free(sname);
@@ -725,7 +724,7 @@
while (mapi_fetch_row(hdl) != 0) {
char *name = mapi_fetch_field(hdl, 0);
- fprintf(toConsole, "CREATE SEQUENCE \"%s\" AS INTEGER;\n",
name);
+ stream_printf(toConsole, "CREATE SEQUENCE \"%s\" AS
INTEGER;\n", name);
}
if (mapi_error(mid)) {
mapi_explain_query(hdl, stderr);
@@ -774,14 +773,14 @@
char *increment = mapi_fetch_field(hdl, 4);
char *cycle = mapi_fetch_field(hdl, 5);
- fprintf(toConsole, "ALTER SEQUENCE \"%s\" RESTART WITH %s",
name, restart);
+ stream_printf(toConsole, "ALTER SEQUENCE \"%s\" RESTART WITH
%s", name, restart);
if (strcmp(increment, "1") != 0)
- fprintf(toConsole, " INCREMENT BY %s", increment);
+ stream_printf(toConsole, " INCREMENT BY %s", increment);
if (strcmp(minvalue, "0") != 0)
- fprintf(toConsole, " MINVALUE %s", minvalue);
+ stream_printf(toConsole, " MINVALUE %s", minvalue);
if (strcmp(maxvalue, "0") != 0)
- fprintf(toConsole, " MAXVALUE %s", maxvalue);
- fprintf(toConsole, " %sCYCLE;\n", strcmp(cycle, "true") == 0 ?
"" : "NO ");
+ stream_printf(toConsole, " MAXVALUE %s", maxvalue);
+ stream_printf(toConsole, " %sCYCLE;\n", strcmp(cycle, "true")
== 0 ? "" : "NO ");
}
if (mapi_error(mid)) {
mapi_explain_query(hdl, stderr);
@@ -803,9 +802,9 @@
char *vname = mapi_fetch_field(hdl, 0);
char *query = mapi_fetch_field(hdl, 1);
- fprintf(toConsole, "CREATE VIEW ");
+ stream_printf(toConsole, "CREATE VIEW ");
quoted_print(toConsole, vname);
- fprintf(toConsole, " AS %s\n", query);
+ stream_printf(toConsole, " AS %s\n", query);
}
if (mapi_error(mid)) {
mapi_explain_query(hdl, stderr);
@@ -826,7 +825,7 @@
while (mapi_fetch_row(hdl) != 0) {
char *query = mapi_fetch_field(hdl, 0);
- fprintf(toConsole, "%s\n", query);
+ stream_printf(toConsole, "%s\n", query);
}
if (mapi_error(mid)) {
mapi_explain_query(hdl, stderr);
@@ -846,7 +845,7 @@
mapi_close_handle(hdl);
/* finally commit the whole transaction */
- fprintf(toConsole, "COMMIT;\n");
+ stream_printf(toConsole, "COMMIT;\n");
return rc;
}
-------------------------------------------------------------------------
SF.Net email is sponsored by: The Future of Linux Business White Paper
from Novell. From the desktop to the data center, Linux is going
mainstream. Let it simplify your IT future.
http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4
_______________________________________________
Monetdb-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/monetdb-checkins