MonetDB: Aug2024 - Tweak socket parameters to simulate network a...
Changeset: 7a82419603d3 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/7a82419603d3 Modified Files: documentation/source/manual_pages/monetdbd.rst.in tools/merovingian/ChangeLog.Aug2024 tools/merovingian/daemon/client.c tools/merovingian/daemon/merovingian.c tools/merovingian/daemon/monetdbd.1.in Branch: Aug2024 Log Message: Tweak socket parameters to simulate network activity on client connections diffs (146 lines): diff --git a/documentation/source/manual_pages/monetdbd.rst.in b/documentation/source/manual_pages/monetdbd.rst.in --- a/documentation/source/manual_pages/monetdbd.rst.in +++ b/documentation/source/manual_pages/monetdbd.rst.in @@ -251,6 +251,17 @@ using the **set** command. The following use redirects instead of proxies. Changing this property takes effect immediately at runtime. +**keepalive** + Specifies the keepalive interval for incoming connections. If this is + set to a positive number, *monetdbd* configures the system to send + automatic periodic keepalive probes on all client connections. This + can help keep firewalls from killing connections that seem idle but + are in fact waiting for a long running query to finish. The default + is 60 seconds. When 127 consecutive probes have failed, the + connection is closed. With the default setting of 60 seconds this + means the connection is closed when the client has been unreachable + for more than two hours. + REMOTE DATABASES diff --git a/tools/merovingian/ChangeLog.Aug2024 b/tools/merovingian/ChangeLog.Aug2024 --- a/tools/merovingian/ChangeLog.Aug2024 +++ b/tools/merovingian/ChangeLog.Aug2024 @@ -1,3 +1,8 @@ # ChangeLog file for sql/src/backends/monet5/merovingian # This file is updated with mchangelog +* Mon Oct 7 2024 Joeri van Ruth +- Tweak socket parameters to simulate network activity on client connections. + This prevents firewalls from killing connections that seem idle but are + actually waiting for a long-running query. Can be controlled with a new + 'keepalive' option to monetdbd. diff --git a/tools/merovingian/daemon/client.c b/tools/merovingian/daemon/client.c --- a/tools/merovingian/daemon/client.c +++ b/tools/merovingian/daemon/client.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef HAVE_POLL_H #include #endif @@ -57,6 +58,8 @@ struct clientdata { char challenge[32]; }; +static void configureKeepAlive(int sock, int keepalive); + static void * handleClient(void *data) { @@ -80,6 +83,7 @@ handleClient(void *data) int sock; bool isusock; struct threads *self; + int keepalive; #ifdef HAVE_PTHREAD_SETNAME_NP pthread_setname_np( @@ -94,6 +98,11 @@ handleClient(void *data) self = ((struct clientdata *) data)->self; memcpy(chal, ((struct clientdata *) data)->challenge, sizeof(chal)); free(data); + + keepalive = getConfNum(_mero_props, "keepalive"); + if (keepalive > 0 && !isusock) + configureKeepAlive(sock, keepalive); + fdin = socket_rstream(sock, "merovingian<-client (read)"); if (fdin == NULL) { self->dead = true; @@ -661,3 +670,37 @@ error: } return(newErr("accept connection: %s", msg)); } + +static void +configureKeepAlive(int sock, const int keepalive) +{ + // It seems that on MacOS, TCP_KEEPIDLE is called TCP_KEEPALIVE. + // (Not to be confused with SO_KEEPALIVE). + int flag; + #if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE) + flag = TCP_KEEPALIVE; + #else + flag = TCP_KEEPIDLE; + #endif + if (setsockopt(sock, IPPROTO_TCP, flag, &keepalive, sizeof(keepalive)) < 0) { + Mlevelfprintf(WARNING, _mero_ctlerr, "could not set TCP_KEEPIDLE on socket: %s\n", strerror(errno)); + return; + } + + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepalive, sizeof(keepalive)) < 0) { + Mlevelfprintf(WARNING, _mero_ctlerr, "could not set TCP_KEEPINTVL on socket: %s\n", strerror(errno)); + return; + } + + const int keepcnt = 127; // fixed value, maximum allowed + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt)) < 0) { + Mlevelfprintf(WARNING, _mero_ctlerr, "could not set TCP_KEEPCNT on socket: %s\n", strerror(errno)); + return; + } + + const int enabled = 1; + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &enabled, sizeof(enabled)) < 0) { + Mlevelfprintf(WARNING, _mero_ctlerr, "could not set SO_KEEPALIVE on socket: %s\n", strerror(errno)); + return; + } +} diff --git a/tools/merovingian/daemon/merovingian.c b/tools/merovingian/daemon/merovingian.c --- a/
MonetDB: Aug2024 - Revert "Tweak socket parameters to simulate n...
Changeset: 6e8087cb5902 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/6e8087cb5902 Modified Files: documentation/source/manual_pages/monetdbd.rst.in tools/merovingian/ChangeLog.Aug2024 tools/merovingian/daemon/client.c tools/merovingian/daemon/merovingian.c tools/merovingian/daemon/monetdbd.1.in Branch: Aug2024 Log Message: Revert "Tweak socket parameters to simulate network activity on client connections" diffs (138 lines): diff --git a/documentation/source/manual_pages/monetdbd.rst.in b/documentation/source/manual_pages/monetdbd.rst.in --- a/documentation/source/manual_pages/monetdbd.rst.in +++ b/documentation/source/manual_pages/monetdbd.rst.in @@ -251,17 +251,6 @@ using the **set** command. The following use redirects instead of proxies. Changing this property takes effect immediately at runtime. -**keepalive** - Specifies the keepalive interval for incoming connections. If this is - set to a positive number, *monetdbd* configures the system to send - automatic periodic keepalive probes on all client connections. This - can help keep firewalls from killing connections that seem idle but - are in fact waiting for a long running query to finish. The default - is 60 seconds. When 127 consecutive probes have failed, the - connection is closed. With the default setting of 60 seconds this - means the connection is closed when the client has been unreachable - for more than two hours. - REMOTE DATABASES diff --git a/tools/merovingian/ChangeLog.Aug2024 b/tools/merovingian/ChangeLog.Aug2024 --- a/tools/merovingian/ChangeLog.Aug2024 +++ b/tools/merovingian/ChangeLog.Aug2024 @@ -1,8 +1,3 @@ # ChangeLog file for sql/src/backends/monet5/merovingian # This file is updated with mchangelog -* Mon Oct 7 2024 Joeri van Ruth -- Tweak socket parameters to simulate network activity on client connections. - This prevents firewalls from killing connections that seem idle but are - actually waiting for a long-running query. Can be controlled with a new - 'keepalive' option to monetdbd. diff --git a/tools/merovingian/daemon/client.c b/tools/merovingian/daemon/client.c --- a/tools/merovingian/daemon/client.c +++ b/tools/merovingian/daemon/client.c @@ -18,7 +18,6 @@ #include #include #include -#include #ifdef HAVE_POLL_H #include #endif @@ -58,8 +57,6 @@ struct clientdata { char challenge[32]; }; -static void configureKeepAlive(int sock, int keepalive); - static void * handleClient(void *data) { @@ -83,7 +80,6 @@ handleClient(void *data) int sock; bool isusock; struct threads *self; - int keepalive; #ifdef HAVE_PTHREAD_SETNAME_NP pthread_setname_np( @@ -98,11 +94,6 @@ handleClient(void *data) self = ((struct clientdata *) data)->self; memcpy(chal, ((struct clientdata *) data)->challenge, sizeof(chal)); free(data); - - keepalive = getConfNum(_mero_props, "keepalive"); - if (keepalive > 0) - configureKeepAlive(sock, keepalive); - fdin = socket_rstream(sock, "merovingian<-client (read)"); if (fdin == NULL) { self->dead = true; @@ -670,29 +661,3 @@ error: } return(newErr("accept connection: %s", msg)); } - -static void -configureKeepAlive(int sock, const int keepalive) -{ - if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalive, sizeof(keepalive)) < 0) { - Mlevelfprintf(WARNING, _mero_ctlerr, "could not set TCP_KEEPIDLE on socket: %s", strerror(errno)); - return; - } - - if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepalive, sizeof(keepalive)) < 0) { - Mlevelfprintf(WARNING, _mero_ctlerr, "could not set TCP_KEEPINTVL on socket: %s", strerror(errno)); - return; - } - - const int keepcnt = 127; // fixed value, maximum allowed - if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt)) < 0) { - Mlevelfprintf(WARNING, _mero_ctlerr, "could not set TCP_KEEPCNT on socket: %s", strerror(errno)); - return; - } - - const int enabled = 1; - if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &enabled, sizeof(enabled)) < 0) { - Mlevelfprintf(WARNING, _mero_ctlerr, "could not set SO_KEEPALIVE on socket: %s", strerror(errno)); - return; - } -} diff --git a/tools/merovingian/daemon/merovingian.c b/tools/merovingian/daemon/merovingian.c --- a/tools/merovingian/daemon/merovingian.c +++ b/tools/merovingian/daemon/merovingian.c @@ -461,7 +461,6 @@ main(int argc, char *argv[]) #else {"snapshotcompression", strdup(".tar"), 0, STR}, #endif - {"keepalive", str
MonetDB: Aug2024 - Tweak socket parameters to simulate network a...
Changeset: 7398ed995a3e for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/7398ed995a3e Modified Files: documentation/source/manual_pages/monetdbd.rst.in tools/merovingian/ChangeLog.Aug2024 tools/merovingian/daemon/client.c tools/merovingian/daemon/merovingian.c tools/merovingian/daemon/monetdbd.1.in Branch: Aug2024 Log Message: Tweak socket parameters to simulate network activity on client connections diffs (138 lines): diff --git a/documentation/source/manual_pages/monetdbd.rst.in b/documentation/source/manual_pages/monetdbd.rst.in --- a/documentation/source/manual_pages/monetdbd.rst.in +++ b/documentation/source/manual_pages/monetdbd.rst.in @@ -251,6 +251,17 @@ using the **set** command. The following use redirects instead of proxies. Changing this property takes effect immediately at runtime. +**keepalive** + Specifies the keepalive interval for incoming connections. If this is + set to a positive number, *monetdbd* configures the system to send + automatic periodic keepalive probes on all client connections. This + can help keep firewalls from killing connections that seem idle but + are in fact waiting for a long running query to finish. The default + is 60 seconds. When 127 consecutive probes have failed, the + connection is closed. With the default setting of 60 seconds this + means the connection is closed when the client has been unreachable + for more than two hours. + REMOTE DATABASES diff --git a/tools/merovingian/ChangeLog.Aug2024 b/tools/merovingian/ChangeLog.Aug2024 --- a/tools/merovingian/ChangeLog.Aug2024 +++ b/tools/merovingian/ChangeLog.Aug2024 @@ -1,3 +1,8 @@ # ChangeLog file for sql/src/backends/monet5/merovingian # This file is updated with mchangelog +* Mon Oct 7 2024 Joeri van Ruth +- Tweak socket parameters to simulate network activity on client connections. + This prevents firewalls from killing connections that seem idle but are + actually waiting for a long-running query. Can be controlled with a new + 'keepalive' option to monetdbd. diff --git a/tools/merovingian/daemon/client.c b/tools/merovingian/daemon/client.c --- a/tools/merovingian/daemon/client.c +++ b/tools/merovingian/daemon/client.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef HAVE_POLL_H #include #endif @@ -57,6 +58,8 @@ struct clientdata { char challenge[32]; }; +static void configureKeepAlive(int sock, int keepalive); + static void * handleClient(void *data) { @@ -80,6 +83,7 @@ handleClient(void *data) int sock; bool isusock; struct threads *self; + int keepalive; #ifdef HAVE_PTHREAD_SETNAME_NP pthread_setname_np( @@ -94,6 +98,11 @@ handleClient(void *data) self = ((struct clientdata *) data)->self; memcpy(chal, ((struct clientdata *) data)->challenge, sizeof(chal)); free(data); + + keepalive = getConfNum(_mero_props, "keepalive"); + if (keepalive > 0) + configureKeepAlive(sock, keepalive); + fdin = socket_rstream(sock, "merovingian<-client (read)"); if (fdin == NULL) { self->dead = true; @@ -661,3 +670,29 @@ error: } return(newErr("accept connection: %s", msg)); } + +static void +configureKeepAlive(int sock, const int keepalive) +{ + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalive, sizeof(keepalive)) < 0) { + Mlevelfprintf(WARNING, _mero_ctlerr, "could not set TCP_KEEPIDLE on socket: %s", strerror(errno)); + return; + } + + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepalive, sizeof(keepalive)) < 0) { + Mlevelfprintf(WARNING, _mero_ctlerr, "could not set TCP_KEEPINTVL on socket: %s", strerror(errno)); + return; + } + + const int keepcnt = 127; // fixed value, maximum allowed + if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt)) < 0) { + Mlevelfprintf(WARNING, _mero_ctlerr, "could not set TCP_KEEPCNT on socket: %s", strerror(errno)); + return; + } + + const int enabled = 1; + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &enabled, sizeof(enabled)) < 0) { + Mlevelfprintf(WARNING, _mero_ctlerr, "could not set SO_KEEPALIVE on socket: %s", strerror(errno)); + return; + } +} diff --git a/tools/merovingian/daemon/merovingian.c b/tools/merovingian/daemon/merovingian.c --- a/tools/merovingian/daemon/merovingian.c +++ b/tools/merovingian/daemon/merovingian.c @@ -461,6 +461,7 @@ main(int argc, char *argv[]) #else {"snapshotcompression", strdup(".tar"), 0, STR}, #endif + {"keepalive", strdup("60&quo
MonetDB: default - Add system function sys.unclosed_result_sets()
Changeset: 3812616d921c for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/3812616d921c Modified Files: sql/backends/monet5/sql.c sql/backends/monet5/sql_upgrades.c sql/scripts/22_clients.sql Branch: default Log Message: Add system function sys.unclosed_result_sets() Returns a tuple (query_id, res_id) for every unclosed result set. This is useful for checking for resource leaks in client libraries. diffs (94 lines): 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 @@ -3542,6 +3542,47 @@ dump_trace(Client cntxt, MalBlkPtr mb, M } static str +sql_unclosed_result_sets(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) +{ + (void)mb; + bat *ret_query_id = getArgReference_bat(stk, pci, 0); + bat *ret_res_id = getArgReference_bat(stk, pci, 1); + backend *be = cntxt->sqlcontext; + + BUN count = 0; + for (res_table *p = be->results; p != NULL; p = p->next) + count++; + + BAT *query_ids = COLnew(0, TYPE_oid, count, TRANSIENT); + BAT *res_ids = COLnew(0, TYPE_int, count, TRANSIENT); + + if (query_ids == NULL || res_ids == NULL) { + BBPreclaim(query_ids); + BBPreclaim(res_ids); + throw(SQL, "sql.sql_unclosed_result_sets", SQLSTATE(HY013) MAL_MALLOC_FAIL); + } + + for (res_table *p = be->results; p != NULL; p = p->next) { + if (BUNappend(query_ids, &p->query_id, false) != GDK_SUCCEED) + goto bailout; + if (BUNappend(res_ids, &p->id, false) != GDK_SUCCEED) + goto bailout; + } + + *ret_query_id = query_ids->batCacheid; + BBPkeepref(query_ids); + *ret_res_id = res_ids->batCacheid; + BBPkeepref(res_ids); + + return MAL_SUCCEED; + +bailout: + BBPunfix(query_ids->batCacheid); + BBPunfix(res_ids->batCacheid); + throw(SQL, "sql.sql_unclosed_result_sets", SQLSTATE(42000)"failed to retrieve result tables"); +} + +static str sql_sessions_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { BAT *id = NULL, *user = NULL, *login = NULL, *sessiontimeout = NULL, @@ -5629,6 +5670,7 @@ static mel_func sql_init_funcs[] = { pattern("sql", "argRecord", SQLargRecord, false, "Glue together the calling sequence", args(1,2, arg("",str),varargany("a",0))), pattern("sql", "sql_variables", sql_variables, false, "return the table with session variables", args(4,4, batarg("sname",str),batarg("name",str),batarg("type",str),batarg("value",str))), pattern("sql", "sessions", sql_sessions_wrap, false, "SQL export table of active sessions, their timeouts and idle status",args(16,16,batarg("id",int),batarg("user",str),batarg("start",timestamp),batarg("idle",timestamp),batarg("optimizer",str),batarg("stimeout",int),batarg("qtimeout",int),batarg("wlimit",int),batarg("mlimit",int),batarg("language", str),batarg("peer", str),batarg("hostname", str),batarg("application", str),batarg("client", str),batarg("clientpid", lng),batarg("remark", str),)), + pattern("sql", "unclosed_result_sets", sql_unclosed_result_sets, false, "return query_id/res_id of unclosed result sets", args(2,2, batarg("query_id",oid),batarg("res_id", int))), pattern("sql", "password", SQLuser_password, false, "Return password hash of user", args(1,2, arg("",str),arg("user",str))), pattern("sql", "decypher", SQLdecypher, false, "Return decyphered password", args(1,2, arg("",str),arg("hash",str))), pattern("sql", "dump_cache", dump_cache, false, "dump the content of the query cache", args(2,2, batarg("query",str),batarg("count",int))), diff --git a/sql/backends/monet5/sql_upgrades.c b/sql/backends/monet5/sql_upgrades.c --- a/sql/backends/monet5/sql_upgrades.c +++ b/sql/backends/monet5/sql_upgrades.c @@ -4384,6 +4384,13 @@ sql_update_default(Client c, mvc *sql, s "external name sql.vacuum;\n" "create procedure sys.stop_vacuum(sname string, tname string)\n" "external name sql.stop_vacuum;\n" + "create function sys.unclosed_result_sets()\n" + "returns table(\n" + " \"query_id\" oid,\n" + " \"res_id\" int\n" + ")\n" + "external name sql.unclosed_result_sets;\n" + "grant execute on function sys.unclosed_result_sets() to public;\n" "update sys.functions set system = true where system <> true and schema_id = 2000 and name in ('vacuum', 'stop_vacuum');\n"; printf("Running database upgrade commands:\n%s\n", query); fflush(stdout); diff --git a/sql/scripts/22_clients.sql b/sql/scripts/22_clients.sql --- a/sql/scripts/22_clients.sql +++ b/sql/scripts/22_clients.sql @@ -41,6 +41,14
MonetDB: default - tlstester: listen on both AF_INET and AF_INET6
Changeset: ed17ccf72c48 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/ed17ccf72c48 Modified Files: testing/tlstester.py Branch: default Log Message: tlstester: listen on both AF_INET and AF_INET6 This should speed up the tlssecurity test on Windows. diffs (91 lines): diff --git a/testing/tlstester.py b/testing/tlstester.py --- a/testing/tlstester.py +++ b/testing/tlstester.py @@ -416,6 +416,32 @@ class TLSTester: for t in threads: t.join() +def spawn_server(self, name, server_class, addr, port, handler): +fam = server_class.address_family.name +try: +server = server_class((addr, port), handler) +except Exception as e: +log.debug(f"Could not bind {name} to {fam} = {addr} port {port}: {e}") +raise +bound_addr, bound_port = server.server_address[:2] +log.debug(f"Bound {name}: {fam} = {bound_addr} port {bound_port}") +self.portmap[name] = bound_port +self.workers.append(server.serve_forever) +return bound_port + +def spawn_servers(self, name, server_classes, addr, port, handler): +exceptions = [] +for server_class in server_classes: +try: +# update 'port' so all servers use the same port number +port = self.spawn_server(name, server_class, addr, port, handler) +except OSError as e: +exceptions.append(e) +if len(exceptions) == len(server_classes): +e = exceptions[0] +log.error(f"Could not spawn any listener for {name} on {addr}: {e}") +raise e + def spawn_http(self, name: str, only_preassigned: bool): if only_preassigned and name not in self.preassigned: return @@ -425,11 +451,7 @@ class TLSTester: handler = lambda req, addr, server: WebHandler( req, addr, server, self.certs, self.portmap ) -server = http.server.HTTPServer((self.listen_addr, port), handler) -port = server.server_address[1] -log.debug(f"Bound port {name} to {port}") -self.portmap[name] = port -self.workers.append(server.serve_forever) +self.spawn_servers(name, [MyHTTPServer, MyHTTP6Server], self.listen_addr, port, handler) def spawn_mapi(self, name: str, only_preassigned, ctx: SSLContext, check_alpn=None, redirect_to=None): if only_preassigned and name not in self.preassigned: @@ -438,11 +460,7 @@ class TLSTester: return port = self.allocate_port(name) handler = lambda req, addr, server: MapiHandler(req, addr, server, self, name, ctx, check_alpn, redirect_to) -server = MyTCPServer((self.listen_addr, port), handler) -port = server.server_address[1] -log.debug(f"Bound port {name} to {port}") -self.portmap[name] = port -self.workers.append(server.serve_forever) +self.spawn_servers(name, [MyTCPServer, MyTCP6Server], self.listen_addr, port, handler) def spawn_forward(self, name, ctx: SSLContext): if name in self.portmap: @@ -451,11 +469,8 @@ class TLSTester: handler = lambda req, addr, server: ForwardHandler( req, addr, server, name, ctx, self.forward_to ) -server = MyTCPServer((self.listen_addr, local_port), handler) -port = server.server_address[1] -log.debug(f"Bound port {name} to {port}") -self.portmap[name] = port -self.workers.append(server.serve_forever) +self.spawn_servers(name, [MyTCPServer, MyTCP6Server], self.listen_addr, local_port, handler) + def allocate_port(self, name): if name in self.preassigned: @@ -551,6 +566,14 @@ class MyTCPServer(socketserver.Threading allow_reuse_address = True pass +class MyTCP6Server(MyTCPServer): +address_family = socket.AF_INET6 + +class MyHTTPServer(http.server.HTTPServer): +pass + +class MyHTTP6Server(MyHTTPServer): +address_family = socket.AF_INET6 class MapiHandler(socketserver.BaseRequestHandler): tlstester: TLSTester ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - Support hot snapshotting huge bats and log files
Changeset: 25d775cb23fc for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/25d775cb23fc Added Files: sql/test/Tests/hot_snapshot_huge_file.py sql/test/Tests/hot_snapshot_huge_file.timeout Modified Files: ChangeLog sql/storage/store.c sql/test/Tests/All tools/merovingian/daemon/snapshot.c Branch: default Log Message: Support hot snapshotting huge bats and log files The regular tar format does not allow member files >8GiB because the size field in the per-member header is 11 octal digits plus a NUL byte. However, because we and most tar implementations don't need the NUL byte, it actually worked up to 64GiB. This patch adds support for binary size headers as originally introduced by GNU tar. The new limit is 8 exabyte which is sufficient for the foreseeable future. diffs (truncated from 347 to 300 lines): diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ # ChangeLog file for devel # This file is updated with Maddlog +* Mon Sep 16 2024 Joeri van Ruth +- Hot snapshot: allow member files larger than 64 GiB. By member files we mean + the files inside the resulting .tar file, not the tar file itself. Huge member + files are written using a GNU tar extension to the original tar format, which + doesn't support more than 8 GiB. + diff --git a/sql/storage/store.c b/sql/storage/store.c --- a/sql/storage/store.c +++ b/sql/storage/store.c @@ -2561,13 +2561,8 @@ tar_write_header(stream *tarfile, const { char buf[TAR_BLOCK_SIZE] = {0}; char *cursor = buf; - char *chksum; - - if (size > 0777) { // 0_777__ - // doesn't fit header field - GDKerror("error writing tar file: member %s too large", path); - return GDK_FAIL; - } + char *size_field; + char *chksum_field; // We set the uid/gid fields to 0 and the uname/gname fields to "". // When unpacking as a normal user, they are ignored and the files are @@ -2580,9 +2575,10 @@ tar_write_header(stream *tarfile, const tar_write_header_field(&cursor, 8, "644"); // mode[8] tar_write_header_field(&cursor, 8, "%07o", 0U); // uid[8] tar_write_header_field(&cursor, 8, "%07o", 0U); // gid[8] - tar_write_header_field(&cursor, 12, "%011"PRIo64, size); // size[12] + size_field = cursor; + cursor += 12; // size[12] tar_write_header_field(&cursor, 12, "%011lo", (unsigned long)mtime); // mtime[12] - chksum = cursor; // use this later to set the computed checksum + chksum_field = cursor; // use this later to set the computed checksum tar_write_header_field(&cursor, 8, "%8s", ""); // chksum[8] *cursor++ = '0'; // typeflag REGTYPE tar_write_header_field(&cursor, 100, "%s", ""); // linkname[100] @@ -2593,14 +2589,27 @@ tar_write_header(stream *tarfile, const tar_write_header_field(&cursor, 8, "%07o", 0U); // devmajor[8] tar_write_header_field(&cursor, 8, "%07o", 0U); // devminor[8] tar_write_header_field(&cursor, 155, "%s", ""); // prefix[155] - assert(cursor - buf == 500); + int64_t max_oct_size = 0777;// 0_777__, 11 octal digits + // max_oct_size = 077; // for testing + if (size <= max_oct_size) { + tar_write_header_field(&size_field, 12, "%011"PRIo64, size); // size[12] + } else { + uint8_t *field = (uint8_t *)size_field; + field[0] = 0x80; + for (int i = 11; i >= 4; i--) { + field[i] = size & 0xFF; + size >>= 8; + } + } + + // checksum unsigned sum = 0; for (int i = 0; i < TAR_BLOCK_SIZE; i++) sum += (unsigned char) buf[i]; - tar_write_header_field(&chksum, 8, "%06o", sum); + tar_write_header_field(&chksum_field, 8, "%06o", sum); if (mnstr_write(tarfile, buf, TAR_BLOCK_SIZE, 1) != 1) { GDKerror("error writing tar header %s: %s", path, mnstr_peek_error(tarfile)); @@ -2688,7 +2697,7 @@ tar_copy_stream(stream *tarfile, const c } static gdk_return __attribute__((__warn_unused_result__)) -hot_snapshot_write_tar(stream *out, const char *prefix, char *plan) +hot_snapshot_write_tar(stream *out, const char *prefix, const char *plan) { if (plan == NULL) return GDK_FAIL; @@ -2729,6 +2738,11 @@ hot_snapshot_write_tar(stream *out, cons src_name = abs_src_path + len - 1; // - 1 because len includes the trailing newline *sr
MonetDB: default - Test tlssecurity: leave logging permanently e...
Changeset: bb5de91bf7dc for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/bb5de91bf7dc Modified Files: clients/mapilib/Tests/tlssecurity.py Branch: default Log Message: Test tlssecurity: leave logging permanently enabled Prefix levels DEBUG and INFO with a # so Mtest does not consider them a failure. diffs (46 lines): diff --git a/clients/mapilib/Tests/tlssecurity.py b/clients/mapilib/Tests/tlssecurity.py --- a/clients/mapilib/Tests/tlssecurity.py +++ b/clients/mapilib/Tests/tlssecurity.py @@ -20,11 +20,10 @@ from MonetDBtesting.tlstester import TLS log_level = logging.WARNING log_format = '%(levelname)s:t=%(relativeCreated)d:%(name)s:%(message)s'# if sys.platform == 'win32': -if sys.platform == 'win32': -log_level=logging.DEBUG -if '-v' in sys.argv: -log_level = logging.DEBUG -# log_level = logging.DEBUG +# Be verbose but make Mtest ignore it +log_level = logging.DEBUG +logging.addLevelName(logging.DEBUG, '#DEBUG') +logging.addLevelName(logging.INFO, '#INFO') logging.basicConfig(level=log_level,format=log_format) @@ -47,13 +46,13 @@ def attempt(experiment: str, portname: s if params: # should be percent-escaped url += '?' + '&'.join(f"{k}={v}" for k, v in params.items()) -logging.debug(f" START TEST {experiment}") -logging.debug(f"Connecting to {url}, expected_error={expected_error_regex}") +logging.info(f" START TEST {experiment}") +logging.info(f"Connecting to {url}, expected_error={expected_error_regex}") test_log_file = os.path.join(scratchdir, portname + '.log') cmd = ['mclient', '-d', url, '-L', test_log_file] -logging.debug(f"cmd={cmd}") +logging.info(f"cmd={cmd}") proc = subprocess.run(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE) -logging.debug(f"mclient exited with code {proc.returncode}, err={proc.stderr}") +logging.info(f"mclient exited with code {proc.returncode}, err={proc.stderr}") with open(test_log_file, 'r') as f: for line in f: logging.debug(f'mclient log: {line.rstrip()}') @@ -70,7 +69,7 @@ def attempt(experiment: str, portname: s elif expected_error_regex is not None and actual_error is not None and re.search(expected_error_regex, actual_error): ok = True if ok: -logging.debug(f" END SUCCESSFUL TEST {experiment} ") +logging.info(f" END SUCCESSFUL TEST {experiment} ") return logging.error(f"Unexpected result for test {experiment}") logging.error(f"When connecting to port '{portname}' using URL {url}") ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - Do not use non-ascii characters in mapi log file
Changeset: ab6f5e3f15f3 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/ab6f5e3f15f3 Modified Files: clients/mapilib/mapi.c Branch: default Log Message: Do not use non-ascii characters in mapi log file \u25B6 right pointing triangle looked pretty but caused problems on Windows diffs (12 lines): diff --git a/clients/mapilib/mapi.c b/clients/mapilib/mapi.c --- a/clients/mapilib/mapi.c +++ b/clients/mapilib/mapi.c @@ -1217,7 +1217,7 @@ mapi_log_header(Mapi mid, const char *fu if (firstcall == 0) firstcall = now; double seconds = (double)(now - firstcall) / 1e6; - mnstr_printf(mid->tracelog, "\342\226\266 [%u] t=%.3fs %s%s %s(), line %ld\n", mid->index, seconds, mark1, mark2, funcname, line); /* U+25B6: right-pointing triangle */ + mnstr_printf(mid->tracelog, "\n** [%u] t=%.3fs %s%s %s(), line %ld\n", mid->index, seconds, mark1, mark2, funcname, line); } void ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - Remove spurious else-clause
Changeset: ace959bab520 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/ace959bab520 Modified Files: clients/mapilib/msettings.c Branch: default Log Message: Remove spurious else-clause Not sure what was intended to be there. diffs (11 lines): diff --git a/clients/mapilib/msettings.c b/clients/mapilib/msettings.c --- a/clients/mapilib/msettings.c +++ b/clients/mapilib/msettings.c @@ -477,7 +477,6 @@ msetting_set_string(msettings *mp, mparm mp->lang_is_mal = true; else if (strstr(value, "sql") == value) mp->lang_is_sql = true; - else if (strcmp(value, "`")) break; default: break; ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - In test tlssecurity: temporarily enable mclie...
Changeset: 36618f6168bd for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/36618f6168bd Modified Files: clients/mapilib/Tests/tlssecurity.py testing/Mtest.py.in Branch: default Log Message: In test tlssecurity: temporarily enable mclient verbosity Still debugging Windows slowness diffs (56 lines): diff --git a/clients/mapilib/Tests/tlssecurity.py b/clients/mapilib/Tests/tlssecurity.py --- a/clients/mapilib/Tests/tlssecurity.py +++ b/clients/mapilib/Tests/tlssecurity.py @@ -24,7 +24,7 @@ if sys.platform == 'win32': log_level=logging.DEBUG if '-v' in sys.argv: log_level = logging.DEBUG -#level = logging.DEBUG +# log_level = logging.DEBUG logging.basicConfig(level=log_level,format=log_format) @@ -34,13 +34,13 @@ assert os.path.isdir(tgtdir) scratchdir = os.path.join(tgtdir, "scratch") logging.debug(f"scratchdir={scratchdir}") -tlstester = TLSTesterClient(scratchdir, host='127.0.0.1') +tlstester = TLSTesterClient(scratchdir) def certpath(name): return tlstester.download(name) -def attempt(experiment: str, portname: str, expected_error_regex: str, tls=True, host='127.0.0.1', **params): +def attempt(experiment: str, portname: str, expected_error_regex: str, tls=True, host='localhost', **params): port = tlstester.get_port(portname) scheme = 'monetdbs' if tls else 'monetdb' url = f"{scheme}://{host}:{port}/demo" @@ -49,10 +49,14 @@ def attempt(experiment: str, portname: s url += '?' + '&'.join(f"{k}={v}" for k, v in params.items()) logging.debug(f" START TEST {experiment}") logging.debug(f"Connecting to {url}, expected_error={expected_error_regex}") -cmd = ['mclient', '-d', url] +test_log_file = os.path.join(scratchdir, portname + '.log') +cmd = ['mclient', '-d', url, '-L', test_log_file] logging.debug(f"cmd={cmd}") proc = subprocess.run(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE) logging.debug(f"mclient exited with code {proc.returncode}, err={proc.stderr}") +with open(test_log_file, 'r') as f: +for line in f: +logging.debug(f'mclient log: {line.rstrip()}') if proc.returncode != 2: msg = str(proc.stderr, 'utf-8') print(f"mclient is supposed to exit with status 2, not {proc.returncode}.\n--- stderr ---\n{msg}\n---end stderr ---", file=sys.stderr) diff --git a/testing/Mtest.py.in b/testing/Mtest.py.in --- a/testing/Mtest.py.in +++ b/testing/Mtest.py.in @@ -3299,7 +3299,7 @@ def StartTlsTester(): # Start a dummy server that only returns errors. return DummyTlsTester() from MonetDBtesting import tlstester -hostnames = ['localhost', '127.0.0.1'] # make certificates also valid for 127.0.0.1 +hostnames = ['localhost'] certs = tlstester.Certs(hostnames) server = tlstester.TLSTester( certs = certs, ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - In test tlssecurity: access tlstester on 127....
Changeset: f3c6d48acaca for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f3c6d48acaca Modified Files: clients/mapilib/Tests/tlssecurity.py testing/Mtest.py.in Branch: default Log Message: In test tlssecurity: access tlstester on 127.0.0.1 instead of localhost Still debugging Windows slowness. If the delay is in host resolution, it should disappear now. If it's because the Python TCPServer code is trying to do a reverse lookup, the delay will remain. If it's something else, all bets are still off. diffs (31 lines): diff --git a/clients/mapilib/Tests/tlssecurity.py b/clients/mapilib/Tests/tlssecurity.py --- a/clients/mapilib/Tests/tlssecurity.py +++ b/clients/mapilib/Tests/tlssecurity.py @@ -34,13 +34,13 @@ assert os.path.isdir(tgtdir) scratchdir = os.path.join(tgtdir, "scratch") logging.debug(f"scratchdir={scratchdir}") -tlstester = TLSTesterClient(scratchdir) +tlstester = TLSTesterClient(scratchdir, host='127.0.0.1') def certpath(name): return tlstester.download(name) -def attempt(experiment: str, portname: str, expected_error_regex: str, tls=True, host='localhost', **params): +def attempt(experiment: str, portname: str, expected_error_regex: str, tls=True, host='127.0.0.1', **params): port = tlstester.get_port(portname) scheme = 'monetdbs' if tls else 'monetdb' url = f"{scheme}://{host}:{port}/demo" diff --git a/testing/Mtest.py.in b/testing/Mtest.py.in --- a/testing/Mtest.py.in +++ b/testing/Mtest.py.in @@ -3299,7 +3299,7 @@ def StartTlsTester(): # Start a dummy server that only returns errors. return DummyTlsTester() from MonetDBtesting import tlstester -hostnames = ['localhost'] +hostnames = ['localhost', '127.0.0.1'] # make certificates also valid for 127.0.0.1 certs = tlstester.Certs(hostnames) server = tlstester.TLSTester( certs = certs, ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - Try to figure out why test 'tlssecurity' take...
Changeset: 0458139ac3f7 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/0458139ac3f7 Modified Files: clients/mapilib/Tests/tlssecurity.py Branch: default Log Message: Try to figure out why test 'tlssecurity' takes so long on Windows Enable DEBUG on Windows only, with timestamps. The stderr output will make the test fail but that's not a big deal on the default branch. diffs (25 lines): diff --git a/clients/mapilib/Tests/tlssecurity.py b/clients/mapilib/Tests/tlssecurity.py --- a/clients/mapilib/Tests/tlssecurity.py +++ b/clients/mapilib/Tests/tlssecurity.py @@ -17,13 +17,16 @@ import sys from MonetDBtesting.tlstester import TLSTesterClient -level = logging.WARNING -# if sys.platform == 'win32': -# level=logging.DEBUG +log_level = logging.WARNING +log_format = '%(levelname)s:t=%(relativeCreated)d:%(name)s:%(message)s'# if sys.platform == 'win32': + +if sys.platform == 'win32': +level=logging.DEBUG if '-v' in sys.argv: -level = logging.DEBUG +log_level = logging.DEBUG #level = logging.DEBUG -logging.basicConfig(level=level) + +logging.basicConfig(level=log_level,format=log_format) # A tmpdir to write certificates to tgtdir = os.environ['TSTTRGDIR'] ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - In snapshot code, use int64_t to represent fi...
Changeset: cde28737021c for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/cde28737021c Modified Files: sql/storage/store.c Branch: default Log Message: In snapshot code, use int64_t to represent file sizes diffs (164 lines): diff --git a/sql/storage/store.c b/sql/storage/store.c --- a/sql/storage/store.c +++ b/sql/storage/store.c @@ -2557,12 +2557,18 @@ tar_write_header_field(char **cursor_ptr // Write a tar header to the given stream. static gdk_return __attribute__((__warn_unused_result__)) -tar_write_header(stream *tarfile, const char *path, time_t mtime, size_t size) +tar_write_header(stream *tarfile, const char *path, time_t mtime, int64_t size) { char buf[TAR_BLOCK_SIZE] = {0}; char *cursor = buf; char *chksum; + if (size > 0777) { // 0_777__ + // doesn't fit header field + GDKerror("error writing tar file: member %s too large", path); + return GDK_FAIL; + } + // We set the uid/gid fields to 0 and the uname/gname fields to "". // When unpacking as a normal user, they are ignored and the files are // owned by that user. When unpacking as root it is reasonable that @@ -2574,7 +2580,7 @@ tar_write_header(stream *tarfile, const tar_write_header_field(&cursor, 8, "644"); // mode[8] tar_write_header_field(&cursor, 8, "%07o", 0U); // uid[8] tar_write_header_field(&cursor, 8, "%07o", 0U); // gid[8] - tar_write_header_field(&cursor, 12, "%011zo", size); // size[12] + tar_write_header_field(&cursor, 12, "%011"PRIo64, size); // size[12] tar_write_header_field(&cursor, 12, "%011lo", (unsigned long)mtime); // mtime[12] chksum = cursor; // use this later to set the computed checksum tar_write_header_field(&cursor, 8, "%8s", ""); // chksum[8] @@ -2609,7 +2615,7 @@ tar_write_header(stream *tarfile, const * of TAR_BLOCK_SIZE. */ static gdk_return __attribute__((__warn_unused_result__)) -tar_write(stream *outfile, const char *data, size_t size) +tar_write(stream *outfile, const char *path, const char *data, size_t size) { const size_t tail = size % TAR_BLOCK_SIZE; const size_t bulk = size - tail; @@ -2617,7 +2623,7 @@ tar_write(stream *outfile, const char *d if (bulk) { size_t written = mnstr_write(outfile, data, 1, bulk); if (written != bulk) { - GDKerror("Wrote only %zu bytes instead of first %zu", written, bulk); + GDKerror("Wrote only %zu bytes of %s instead of first %zu", written, path, bulk); return GDK_FAIL; } } @@ -2627,7 +2633,7 @@ tar_write(stream *outfile, const char *d memcpy(buf, data + bulk, tail); size_t written = mnstr_write(outfile, buf, 1, TAR_BLOCK_SIZE); if (written != TAR_BLOCK_SIZE) { - GDKerror("Wrote only %zu tail bytes instead of %d", written, TAR_BLOCK_SIZE); + GDKerror("Wrote only %zu tail bytes of %s instead of %d", written, path, TAR_BLOCK_SIZE); return GDK_FAIL; } } @@ -2644,40 +2650,38 @@ tar_write_data(stream *tarfile, const ch if (res != GDK_SUCCEED) return res; - return tar_write(tarfile, data, size); + return tar_write(tarfile, path, data, size); } static gdk_return __attribute__((__warn_unused_result__)) -tar_copy_stream(stream *tarfile, const char *path, time_t mtime, stream *contents, size_t size, char *buf, size_t bufsize) -{ - size_t file_size; - size_t to_read; - - file_size = getFileSize(contents); - if (file_size < size) { - GDKerror("Have to copy %zd bytes but only %zd exist in %s", size, file_size, path); - return GDK_FAIL; - } - +tar_copy_stream(stream *tarfile, const char *path, time_t mtime, stream *contents, int64_t size, char *buf, size_t bufsize) +{ assert( (bufsize % TAR_BLOCK_SIZE) == 0); assert(bufsize >= TAR_BLOCK_SIZE); - if (tar_write_header(tarfile, path, mtime, size) != GDK_SUCCEED) return GDK_FAIL; - to_read = size; - - while (to_read > 0) { - size_t chunk = (to_read <= bufsize) ? to_read : bufsize; + int64_t to_do = size; + while (to_do > 0) { + size_t chunk = (to_do <= (int64_t)bufsize) ? (size_t)to_do : bufsize; ssize_t nbytes = mnstr_read(contents, buf, 1, chunk); - if (nbytes != (ssize_t)chunk) { - GDKerror("Read only %zd/%zd bytes of component %s: %s", nbytes, chunk, path, mnstr_peek_error(contents)); + if (nbytes > 0) { + if (tar_write(tarfile, path, buf, nbytes) != GDK_SUCCEED) + return GDK_FAIL; +
MonetDB: default - Merge branch 'branches/Aug2024' into branches...
Changeset: f4087ca49840 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f4087ca49840 Branch: default Log Message: Merge branch 'branches/Aug2024' into branches/default diffs (11 lines): diff --git a/sql/ChangeLog.Aug2024 b/sql/ChangeLog.Aug2024 --- a/sql/ChangeLog.Aug2024 +++ b/sql/ChangeLog.Aug2024 @@ -1,3 +1,7 @@ # ChangeLog file for sql # This file is updated with Maddlog +* Fri Aug 23 2024 Joeri van Ruth +- Increase the buffer size used by hot snapshot from 64kiB to 1MiB, + and make it configurable through setting 'hot_snapshot_buffer_size'. + It must be a multiple of 512. ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Merge with Dec2023
Changeset: 9175965842f6 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/9175965842f6 Modified Files: sql/ChangeLog.Aug2024 sql/storage/store.c Branch: Aug2024 Log Message: Merge with Dec2023 diffs (118 lines): diff --git a/sql/ChangeLog.Aug2024 b/sql/ChangeLog.Aug2024 --- a/sql/ChangeLog.Aug2024 +++ b/sql/ChangeLog.Aug2024 @@ -1,3 +1,7 @@ # ChangeLog file for sql # This file is updated with Maddlog +* Fri Aug 23 2024 Joeri van Ruth +- Increase the buffer size used by hot snapshot from 64kiB to 1MiB, + and make it configurable through setting 'hot_snapshot_buffer_size'. + It must be a multiple of 512. diff --git a/sql/storage/store.c b/sql/storage/store.c --- a/sql/storage/store.c +++ b/sql/storage/store.c @@ -2648,52 +2648,39 @@ tar_write_data(stream *tarfile, const ch } static gdk_return __attribute__((__warn_unused_result__)) -tar_copy_stream(stream *tarfile, const char *path, time_t mtime, stream *contents, ssize_t size) -{ - const ssize_t bufsize = 64 * 1024; - gdk_return ret = GDK_FAIL; - ssize_t file_size; - char *buf = NULL; - ssize_t to_read; +tar_copy_stream(stream *tarfile, const char *path, time_t mtime, stream *contents, size_t size, char *buf, size_t bufsize) +{ + size_t file_size; + size_t to_read; file_size = getFileSize(contents); if (file_size < size) { GDKerror("Have to copy %zd bytes but only %zd exist in %s", size, file_size, path); - goto end; + return GDK_FAIL; } assert( (bufsize % TAR_BLOCK_SIZE) == 0); assert(bufsize >= TAR_BLOCK_SIZE); - buf = GDKmalloc(bufsize); - if (!buf) { - GDKerror("could not allocate buffer"); - goto end; - } if (tar_write_header(tarfile, path, mtime, size) != GDK_SUCCEED) - goto end; + return GDK_FAIL; to_read = size; while (to_read > 0) { - ssize_t chunk = (to_read <= bufsize) ? to_read : bufsize; + size_t chunk = (to_read <= bufsize) ? to_read : bufsize; ssize_t nbytes = mnstr_read(contents, buf, 1, chunk); - if (nbytes != chunk) { + if (nbytes != (ssize_t)chunk) { GDKerror("Read only %zd/%zd bytes of component %s: %s", nbytes, chunk, path, mnstr_peek_error(contents)); - goto end; - } - ret = tar_write(tarfile, buf, chunk); - if (ret != GDK_SUCCEED) - goto end; + return GDK_FAIL; + } + if (tar_write(tarfile, buf, chunk) != GDK_SUCCEED) + return GDK_FAIL; to_read -= chunk; } - ret = GDK_SUCCEED; -end: - if (buf) - GDKfree(buf); - return ret; + return GDK_SUCCEED; } static gdk_return __attribute__((__warn_unused_result__)) @@ -2712,6 +2699,20 @@ hot_snapshot_write_tar(stream *out, cons char dest_path[100]; // size imposed by tar format. char *dest_name = dest_path + snprintf(dest_path, sizeof(dest_path), "%s/", prefix); stream *infile = NULL; + const char *bufsize_env_var = "hot_snapshot_buffer_size"; + int bufsize = GDKgetenv_int(bufsize_env_var, 1024 * 1024); + char *buffer = NULL; + + if (bufsize < TAR_BLOCK_SIZE || (bufsize % TAR_BLOCK_SIZE) != 0) { + GDKerror("invalid value for setting %s=%d: must be a multiple of %d", + bufsize_env_var, bufsize, TAR_BLOCK_SIZE); + goto end; + } + buffer = GDKmalloc(bufsize); + if (!buffer) { + GDKerror("could not allocate buffer"); + goto end; + } QryCtx *qry_ctx = MT_thread_get_qry_ctx(); @@ -2741,7 +2742,7 @@ hot_snapshot_write_tar(stream *out, cons GDKerror("%s", mnstr_peek_error(NULL)); goto end; } - if (tar_copy_stream(out, dest_path, timestamp, infile, size) != GDK_SUCCEED) + if (tar_copy_stream(out, dest_path, timestamp, infile, size, buffer, (size_t)bufsize) != GDK_SUCCEED) goto end; close_stream(infile); infile = NULL; @@ -2767,6 +2768,7 @@ hot_snapshot_write_tar(stream *out, cons end: free(plan); + GDKfree(buffer); if (infile) close_stream(infile); return ret; ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Dec2023 - ChangeLog for hot snapshot change
Changeset: 5483eaecec98 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/5483eaecec98 Modified Files: sql/ChangeLog.Dec2023 Branch: Dec2023 Log Message: ChangeLog for hot snapshot change diffs (11 lines): diff --git a/sql/ChangeLog.Dec2023 b/sql/ChangeLog.Dec2023 --- a/sql/ChangeLog.Dec2023 +++ b/sql/ChangeLog.Dec2023 @@ -1,3 +1,7 @@ # ChangeLog file for sql # This file is updated with Maddlog +* Fri Aug 23 2024 Joeri van Ruth +- Increase the buffer size used by hot snapshot from 64kiB to 1MiB, + and make it configurable through setting 'hot_snapshot_buffer_size'. + It must be a multiple of 512. ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Dec2023 - Make hot snapshot buffer size configurable, i...
Changeset: 0c0746a5f0b9 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/0c0746a5f0b9 Modified Files: sql/storage/store.c Branch: Dec2023 Log Message: Make hot snapshot buffer size configurable, increase the default The buffer size is configurable with setting 'hot_snapshot_buffer_size'. The value is in bytes. It must be a multiple of 512. The default has been increased from 65536 to 1048576. For example, mserver5 --set hot_snapshot_buffer_size=2097152 diffs (107 lines): diff --git a/sql/storage/store.c b/sql/storage/store.c --- a/sql/storage/store.c +++ b/sql/storage/store.c @@ -2615,52 +2615,39 @@ tar_write_data(stream *tarfile, const ch } static gdk_return __attribute__((__warn_unused_result__)) -tar_copy_stream(stream *tarfile, const char *path, time_t mtime, stream *contents, ssize_t size) -{ - const ssize_t bufsize = 64 * 1024; - gdk_return ret = GDK_FAIL; - ssize_t file_size; - char *buf = NULL; - ssize_t to_read; +tar_copy_stream(stream *tarfile, const char *path, time_t mtime, stream *contents, size_t size, char *buf, size_t bufsize) +{ + size_t file_size; + size_t to_read; file_size = getFileSize(contents); if (file_size < size) { GDKerror("Have to copy %zd bytes but only %zd exist in %s", size, file_size, path); - goto end; + return GDK_FAIL; } assert( (bufsize % TAR_BLOCK_SIZE) == 0); assert(bufsize >= TAR_BLOCK_SIZE); - buf = GDKmalloc(bufsize); - if (!buf) { - GDKerror("could not allocate buffer"); - goto end; - } if (tar_write_header(tarfile, path, mtime, size) != GDK_SUCCEED) - goto end; + return GDK_FAIL; to_read = size; while (to_read > 0) { - ssize_t chunk = (to_read <= bufsize) ? to_read : bufsize; + size_t chunk = (to_read <= bufsize) ? to_read : bufsize; ssize_t nbytes = mnstr_read(contents, buf, 1, chunk); - if (nbytes != chunk) { + if (nbytes != (ssize_t)chunk) { GDKerror("Read only %zd/%zd bytes of component %s: %s", nbytes, chunk, path, mnstr_peek_error(contents)); - goto end; - } - ret = tar_write(tarfile, buf, chunk); - if (ret != GDK_SUCCEED) - goto end; + return GDK_FAIL; + } + if (tar_write(tarfile, buf, chunk) != GDK_SUCCEED) + return GDK_FAIL; to_read -= chunk; } - ret = GDK_SUCCEED; -end: - if (buf) - GDKfree(buf); - return ret; + return GDK_SUCCEED; } static gdk_return __attribute__((__warn_unused_result__)) @@ -2679,6 +2666,20 @@ hot_snapshot_write_tar(stream *out, cons char dest_path[100]; // size imposed by tar format. char *dest_name = dest_path + snprintf(dest_path, sizeof(dest_path), "%s/", prefix); stream *infile = NULL; + const char *bufsize_env_var = "hot_snapshot_buffer_size"; + int bufsize = GDKgetenv_int(bufsize_env_var, 1024 * 1024); + char *buffer = NULL; + + if (bufsize < TAR_BLOCK_SIZE || (bufsize % TAR_BLOCK_SIZE) != 0) { + GDKerror("invalid value for setting %s=%d: must be a multiple of %d", + bufsize_env_var, bufsize, TAR_BLOCK_SIZE); + goto end; + } + buffer = GDKmalloc(bufsize); + if (!buffer) { + GDKerror("could not allocate buffer"); + goto end; + } lng timeoffset = 0; QryCtx *qry_ctx = MT_thread_get_qry_ctx(); @@ -2712,7 +2713,7 @@ hot_snapshot_write_tar(stream *out, cons GDKerror("%s", mnstr_peek_error(NULL)); goto end; } - if (tar_copy_stream(out, dest_path, timestamp, infile, size) != GDK_SUCCEED) + if (tar_copy_stream(out, dest_path, timestamp, infile, size, buffer, (size_t)bufsize) != GDK_SUCCEED) goto end; close_stream(infile); infile = NULL; @@ -2738,6 +2739,7 @@ hot_snapshot_write_tar(stream *out, cons end: free(plan); + GDKfree(buffer); if (infile) close_stream(infile); return ret; ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - Make hot snapshot buffer size configurable, i...
Changeset: dab11424c673 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/dab11424c673 Modified Files: sql/storage/store.c Branch: default Log Message: Make hot snapshot buffer size configurable, increase the default The buffer size is configurable with setting 'hot_snapshot_buffer_size'. The value is in bytes. It must be a multiple of 512. The default has been increased from 65536 to 1048576. For example, mserver5 --set hot_snapshot_buffer_size=2097152 diffs (107 lines): diff --git a/sql/storage/store.c b/sql/storage/store.c --- a/sql/storage/store.c +++ b/sql/storage/store.c @@ -2648,52 +2648,39 @@ tar_write_data(stream *tarfile, const ch } static gdk_return __attribute__((__warn_unused_result__)) -tar_copy_stream(stream *tarfile, const char *path, time_t mtime, stream *contents, ssize_t size) -{ - const ssize_t bufsize = 64 * 1024; - gdk_return ret = GDK_FAIL; - ssize_t file_size; - char *buf = NULL; - ssize_t to_read; +tar_copy_stream(stream *tarfile, const char *path, time_t mtime, stream *contents, size_t size, char *buf, size_t bufsize) +{ + size_t file_size; + size_t to_read; file_size = getFileSize(contents); if (file_size < size) { GDKerror("Have to copy %zd bytes but only %zd exist in %s", size, file_size, path); - goto end; + return GDK_FAIL; } assert( (bufsize % TAR_BLOCK_SIZE) == 0); assert(bufsize >= TAR_BLOCK_SIZE); - buf = GDKmalloc(bufsize); - if (!buf) { - GDKerror("could not allocate buffer"); - goto end; - } if (tar_write_header(tarfile, path, mtime, size) != GDK_SUCCEED) - goto end; + return GDK_FAIL; to_read = size; while (to_read > 0) { - ssize_t chunk = (to_read <= bufsize) ? to_read : bufsize; + size_t chunk = (to_read <= bufsize) ? to_read : bufsize; ssize_t nbytes = mnstr_read(contents, buf, 1, chunk); - if (nbytes != chunk) { + if (nbytes != (ssize_t)chunk) { GDKerror("Read only %zd/%zd bytes of component %s: %s", nbytes, chunk, path, mnstr_peek_error(contents)); - goto end; - } - ret = tar_write(tarfile, buf, chunk); - if (ret != GDK_SUCCEED) - goto end; + return GDK_FAIL; + } + if (tar_write(tarfile, buf, chunk) != GDK_SUCCEED) + return GDK_FAIL; to_read -= chunk; } - ret = GDK_SUCCEED; -end: - if (buf) - GDKfree(buf); - return ret; + return GDK_SUCCEED; } static gdk_return __attribute__((__warn_unused_result__)) @@ -2712,6 +2699,20 @@ hot_snapshot_write_tar(stream *out, cons char dest_path[100]; // size imposed by tar format. char *dest_name = dest_path + snprintf(dest_path, sizeof(dest_path), "%s/", prefix); stream *infile = NULL; + const char *bufsize_env_var = "hot_snapshot_buffer_size"; + int bufsize = GDKgetenv_int(bufsize_env_var, 1024 * 1024); + char *buffer = NULL; + + if (bufsize < TAR_BLOCK_SIZE || (bufsize % TAR_BLOCK_SIZE) != 0) { + GDKerror("invalid value for setting %s=%d: must be a multiple of %d", + bufsize_env_var, bufsize, TAR_BLOCK_SIZE); + goto end; + } + buffer = GDKmalloc(bufsize); + if (!buffer) { + GDKerror("could not allocate buffer"); + goto end; + } QryCtx *qry_ctx = MT_thread_get_qry_ctx(); @@ -2741,7 +2742,7 @@ hot_snapshot_write_tar(stream *out, cons GDKerror("%s", mnstr_peek_error(NULL)); goto end; } - if (tar_copy_stream(out, dest_path, timestamp, infile, size) != GDK_SUCCEED) + if (tar_copy_stream(out, dest_path, timestamp, infile, size, buffer, (size_t)bufsize) != GDK_SUCCEED) goto end; close_stream(infile); infile = NULL; @@ -2767,6 +2768,7 @@ hot_snapshot_write_tar(stream *out, cons end: free(plan); + GDKfree(buffer); if (infile) close_stream(infile); return ret; ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
monetdb-java: default - ChangeLog
Changeset: 0ce63f3686fe for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/0ce63f3686fe Modified Files: ChangeLog Branch: default Log Message: ChangeLog diffs (15 lines): diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ # ChangeLog file for monetdb-java # This file is updated with Maddlog +* Wed Jun 19 2024 Joeri van Ruth +- Implemented Connection#set/getClientInfo, and send sensible default info + at connect time. This can be controlled with the properties 'client_info=on/off', + 'client_application=ApplicationName' and 'client_remark=Other Useful Info'. + * Thu Apr 4 2024 Martin van Dinther - Corrected ResultSetMetaData methods getColumnTypeName(), getPrecision(), getColumnDisplaySize() and ParameterMetaData methods getParameterTypeName() ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Test sys.sessions row permissions interaction...
Changeset: a4c6641aaeac for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/a4c6641aaeac Modified Files: sql/test/mapi/Tests/clientinfo-nonadmin.test Branch: Aug2024 Log Message: Test sys.sessions row permissions interaction with SET ROLE diffs (33 lines): diff --git a/sql/test/mapi/Tests/clientinfo-nonadmin.test b/sql/test/mapi/Tests/clientinfo-nonadmin.test --- a/sql/test/mapi/Tests/clientinfo-nonadmin.test +++ b/sql/test/mapi/Tests/clientinfo-nonadmin.test @@ -60,3 +60,29 @@ 3 user 2b +# Having the same role does not mean you can see each others details + +statement ok +CREATE ROLE common + +statement ok +GRANT common TO user1 + +statement ok +GRANT common TO user2 + +@connection(id=user1) +statement ok +SET ROLE common + +@connection(id=user2a) +statement ok +SET ROLE common + +# no user2! +@connection(id=user1) +query IT rowsort +SELECT sessionid, remark FROM sys.sessions + +1 +user 1 ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Use proper sqlid to decide which sessions row...
Changeset: f6c052f76604 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f6c052f76604 Modified Files: sql/backends/monet5/sql.c Branch: Aug2024 Log Message: Use proper sqlid to decide which sessions rows to show diffs (45 lines): 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 @@ -37,6 +37,7 @@ #include "mal_resolve.h" #include "mal_client.h" #include "mal_interpreter.h" +#include "mal_scenario.h" #include "mal_profiler.h" #include "bat5.h" #include "opt_pipes.h" @@ -3563,6 +3564,9 @@ sql_sessions_wrap(Client cntxt, MalBlkPt bat *clientpidId = getArgReference_bat(stk, pci, 14); bat *remarkId = getArgReference_bat(stk, pci, 15); Client c; + backend *be; + sqlid user_id; + sqlid role_id; bool admin; timestamp ts; lng pid; @@ -3615,14 +3619,21 @@ sql_sessions_wrap(Client cntxt, MalBlkPt throw(SQL, "sql.sessions", SQLSTATE(HY013) MAL_MALLOC_FAIL); } - admin = strcmp(cntxt->username, "monetdb") == 0; + be = cntxt->sqlcontext; + user_id = be->mvc->user_id; + role_id = be->mvc->role_id; + admin = user_id == USER_MONETDB || role_id == ROLE_SYSADMIN; MT_lock_set(&mal_contextLock); for (c = mal_clients; c < mal_clients + MAL_MAXCLIENTS; c++) { if (c->mode != RUNCLIENT) continue; - bool allowed_to_see = admin || c == cntxt || strcmp(c->username, cntxt->username) == 0; + backend *their_be = c->sqlcontext; + bool allowed_to_see = admin || c == cntxt || their_be->mvc->user_id == user_id; + // Note that their role_id is not checked. Just because we have + // both been granted a ROLE does not mean you are allowed to see + // my private details. if (!allowed_to_see) continue; ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Inline CLTsessions into sql_sessions_wrap
Changeset: 6e71ccb990b3 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/6e71ccb990b3 Modified Files: clients/Tests/exports.stable.out monetdb5/modules/mal/clients.c monetdb5/modules/mal/clients.h sql/backends/monet5/sql.c Branch: Aug2024 Log Message: Inline CLTsessions into sql_sessions_wrap Because in the clients module we don't have access to the be->mvc diffs (truncated from 454 to 300 lines): diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out --- a/clients/Tests/exports.stable.out +++ b/clients/Tests/exports.stable.out @@ -790,7 +790,6 @@ str AUTHunlockVault(const char *password str AUTHverifyPassword(const char *passwd); str BKCmirror(bat *ret, const bat *bid); str BKCnewBAT(bat *res, const int *tt, const BUN *cap, role_t role); -str CLTsessions(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); str CLTshutdown(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); str COPYrejects(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); str COPYrejects_clear(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci); diff --git a/monetdb5/modules/mal/clients.c b/monetdb5/modules/mal/clients.c --- a/monetdb5/modules/mal/clients.c +++ b/monetdb5/modules/mal/clients.c @@ -773,214 +773,6 @@ CLTshutdown(Client cntxt, MalBlkPtr mb, return MAL_SUCCEED; } -str -CLTsessions(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) -{ - BAT *id = NULL, *user = NULL, *login = NULL, *sessiontimeout = NULL, - *querytimeout = NULL, *idle = NULL; - BAT *opt = NULL, *wlimit = NULL, *mlimit = NULL; - BAT *language = NULL, *peer = NULL, *hostname = NULL, *application = NULL, *client = NULL, *clientpid = NULL, *remark = NULL; - bat *idId = getArgReference_bat(stk, pci, 0); - bat *userId = getArgReference_bat(stk, pci, 1); - bat *loginId = getArgReference_bat(stk, pci, 2); - bat *idleId = getArgReference_bat(stk, pci, 3); - bat *optId = getArgReference_bat(stk, pci, 4); - bat *sessiontimeoutId = getArgReference_bat(stk, pci, 5); - bat *querytimeoutId = getArgReference_bat(stk, pci, 6); - bat *wlimitId = getArgReference_bat(stk, pci, 7); - bat *mlimitId = getArgReference_bat(stk, pci, 8); - bat *languageId = getArgReference_bat(stk, pci, 9); - bat *peerId = getArgReference_bat(stk, pci, 10); - bat *hostnameId = getArgReference_bat(stk, pci, 11); - bat *applicationId = getArgReference_bat(stk, pci, 12); - bat *clientId = getArgReference_bat(stk, pci, 13); - bat *clientpidId = getArgReference_bat(stk, pci, 14); - bat *remarkId = getArgReference_bat(stk, pci, 15); - Client c; - bool admin; - timestamp ts; - lng pid; - const char *s; - int timeout; - str msg = NULL; - - (void) cntxt; - (void) mb; - - id = COLnew(0, TYPE_int, 0, TRANSIENT); - user = COLnew(0, TYPE_str, 0, TRANSIENT); - login = COLnew(0, TYPE_timestamp, 0, TRANSIENT); - opt = COLnew(0, TYPE_str, 0, TRANSIENT); - sessiontimeout = COLnew(0, TYPE_int, 0, TRANSIENT); - querytimeout = COLnew(0, TYPE_int, 0, TRANSIENT); - wlimit = COLnew(0, TYPE_int, 0, TRANSIENT); - mlimit = COLnew(0, TYPE_int, 0, TRANSIENT); - idle = COLnew(0, TYPE_timestamp, 0, TRANSIENT); - language = COLnew(0, TYPE_str, 0, TRANSIENT); - peer = COLnew(0, TYPE_str, 0, TRANSIENT); - hostname = COLnew(0, TYPE_str, 0, TRANSIENT); - application = COLnew(0, TYPE_str, 0, TRANSIENT); - client = COLnew(0, TYPE_str, 0, TRANSIENT); - clientpid = COLnew(0, TYPE_lng, 0, TRANSIENT); - remark = COLnew(0, TYPE_str, 0, TRANSIENT); - - if (id == NULL || user == NULL || login == NULL || sessiontimeout == NULL - || idle == NULL || querytimeout == NULL || opt == NULL || wlimit == NULL - || mlimit == NULL || language == NULL || peer == NULL || hostname == NULL - || application == NULL || client == NULL || clientpid == NULL - || remark == NULL) { - BBPreclaim(id); - BBPreclaim(user); - BBPreclaim(login); - BBPreclaim(sessiontimeout); - BBPreclaim(querytimeout); - BBPreclaim(idle); - BBPreclaim(opt); - BBPreclaim(wlimit); - BBPreclaim(mlimit); - BBPreclaim(language); - BBPreclaim(peer); - BBPreclaim(hostname); - BBPreclaim(application); - BBPreclaim(client); - BBPreclaim(clientpid); - BBPreclaim(remark); - - throw(SQL, "sql.sessions", SQLSTATE(HY013) MAL_MALLOC_FAIL); - } - - admin = strcmp(cntxt->username, "monetdb") == 0; - - MT_lock_set(&mal_contextLock); - for (c = mal_clients; c < mal_clients + MAL_MAXCLIENTS; c++) { -
MonetDB: Aug2024 - Export getScenarioLanguage
Changeset: ec523f3b884f for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/ec523f3b884f Modified Files: clients/Tests/exports.stable.out monetdb5/mal/mal_scenario.h Branch: Aug2024 Log Message: Export getScenarioLanguage so the sql backend can use it diffs (27 lines): diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out --- a/clients/Tests/exports.stable.out +++ b/clients/Tests/exports.stable.out @@ -1022,6 +1022,7 @@ int getOidConstant(MalBlkPtr mb, oid val int getPC(MalBlkPtr mb, InstrPtr p); str getPipeCatalog(bat *nme, bat *def, bat *stat); const char *getRef; +str getScenarioLanguage(Client c); int getShtConstant(MalBlkPtr mb, sht val); int getStrConstant(MalBlkPtr mb, str val); const char *getTraceRef; diff --git a/monetdb5/mal/mal_scenario.h b/monetdb5/mal/mal_scenario.h --- a/monetdb5/mal/mal_scenario.h +++ b/monetdb5/mal/mal_scenario.h @@ -37,11 +37,11 @@ typedef struct SCENARIO { mal_export Scenario getFreeScenario(void); mal_export Scenario findScenario(const char *nme); +mal_export str getScenarioLanguage(Client c); #ifdef LIBMONETDB5 extern str setScenario(Client c, const char *nme); extern str runScenario(Client c); -extern str getScenarioLanguage(Client c); extern void showCurrentScenario(void); extern void showScenarioByName(stream *f, const char *s); ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Convert sql/test/clientinfo-nonadmin into a s...
Changeset: c9475f5c9773 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/c9475f5c9773 Added Files: sql/test/mapi/Tests/clientinfo-nonadmin.test Removed Files: sql/test/mapi/Tests/clientinfo-nonadmin.SQL.py Branch: Aug2024 Log Message: Convert sql/test/clientinfo-nonadmin into a sqllogictest (I wasn't aware of @connection before) diffs (133 lines): diff --git a/sql/test/mapi/Tests/clientinfo-nonadmin.SQL.py b/sql/test/mapi/Tests/clientinfo-nonadmin.SQL.py deleted file mode 100644 --- a/sql/test/mapi/Tests/clientinfo-nonadmin.SQL.py +++ /dev/null @@ -1,61 +0,0 @@ - -import os -import sys -from typing import List, Tuple -import pymonetdb - - -def connect(remark: str, **args) -> pymonetdb.Connection: -dbname = os.environ['TSTDB'] -mapiport = os.environ['MAPIPORT'] -conn = pymonetdb.connect(dbname, port=mapiport, autocommit=True, **args) -with conn.cursor() as c: -c.execute("CALL sys.setclientinfo('ClientRemark', %s)", [remark]) -return conn - -def get_remarks(conn: pymonetdb.Connection) -> List[Tuple[int,str]]: -with conn.cursor() as c: -c.execute("SELECT sessionid, remark FROM sys.sessions ORDER BY sessionid") -return c.fetchall() - -def assert_equal(left, right): -if left != right: -print(f'LEFT: {left!r}\nRIGHT: {right!r}\n', file=sys.stderr) -assert left == right - - -### -# Connect as admin - -conn0 = connect('admin 0') -assert_equal(get_remarks(conn0), [(0, 'admin 0')]) - - -### -# Create a user - -c0 = conn0.cursor() -# try: -# c0.execute('DROP USER nonadmin')# convenientduring interactive testing -# except pymonetdb.Error: -# pass -c0.execute("CREATE USER nonadmin WITH PASSWORD 'na' NAME 'Not Admin' SCHEMA sys") - - -### -# Connect as that user, twice - -conn1 = connect('user 1', user='nonadmin', password='na') -conn2 = connect('user 2', user='nonadmin', password='na') - - -### -# Check who can see what - -# admin can see both -assert_equal(get_remarks(conn0), [(0, 'admin 0'), (1, 'user 1'), (2, 'user 2')]) - -# users can only see themselves -assert_equal(get_remarks(conn1), [(1, 'user 1'), (2, 'user 2')]) -assert_equal(get_remarks(conn2), [(1, 'user 1'), (2, 'user 2')]) - diff --git a/sql/test/mapi/Tests/clientinfo-nonadmin.test b/sql/test/mapi/Tests/clientinfo-nonadmin.test new file mode 100644 --- /dev/null +++ b/sql/test/mapi/Tests/clientinfo-nonadmin.test @@ -0,0 +1,62 @@ + +# admin logs in with ClientRemark and creates users + +statement ok +CALL sys.setclientinfo('ClientRemark', 'admin') + +statement ok +CREATE USER user1 WITH PASSWORD 'bla' NAME 'User 1' SCHEMA sys; + +statement ok +CREATE USER user2 WITH PASSWORD 'bla' NAME 'User 2' SCHEMA sys; + + +# user1 logs in with ClientRemark + +@connection(id=user1, username=user1, password=bla) +statement ok +CALL sys.setclientinfo('ClientRemark', 'user 1') + + +# user2 logs in twice, with different ClientRemarks + +@connection(id=user2a, username=user2, password=bla) +statement ok +CALL sys.setclientinfo('ClientRemark', 'user 2a') + +@connection(id=user2b, username=user2, password=bla) +statement ok +CALL sys.setclientinfo('ClientRemark', 'user 2b') + + +# Now verify what everybody sees + +query IT rowsort +SELECT sessionid, remark FROM sys.sessions + +0 +admin +1 +user 1 +2 +user 2a +3 +user 2b + +@connection(id=user1) +query IT rowsort +SELECT sessionid, remark FROM sys.sessions + +1 +user 1 + +@connection(id=user2a) +query IT rowsort +SELECT sessionid, remark FROM sys.sessions + +2 +user 2a +3 +user 2b + + ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Mention public select privilege on sys.sessio...
Changeset: 08cc537c4877 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/08cc537c4877 Modified Files: sql/ChangeLog.Aug2024 Branch: Aug2024 Log Message: Mention public select privilege on sys.sessions in client info ChangeLog entry See #7549 diffs (12 lines): diff --git a/sql/ChangeLog.Aug2024 b/sql/ChangeLog.Aug2024 --- a/sql/ChangeLog.Aug2024 +++ b/sql/ChangeLog.Aug2024 @@ -8,6 +8,8 @@ * Wed May 29 2024 Joeri van Ruth - Extended view sys.sessions and function sys.sessions() with new columns: language, peer, hostname, application, client, clientpid and remark. +- All users now have SELECT privilege on view sys.sessions, but non-admin + users only see their own sessions. - Added procedure sys.setclientinfo(property string, value string) to allow the client application to set a specific client info property. - Added system table sys.clientinfo_properties that lists the supported ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Allow every user to see their own rows in sys...
Changeset: 79294808aa31 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/79294808aa31 Added Files: sql/test/mapi/Tests/clientinfo-nonadmin.SQL.py Modified Files: monetdb5/modules/mal/clients.c sql/backends/monet5/sql_upgrades.c sql/scripts/22_clients.sql sql/test/mapi/Tests/All Branch: Aug2024 Log Message: Allow every user to see their own rows in sys.sessions This fixes #7549 diffs (246 lines): diff --git a/monetdb5/modules/mal/clients.c b/monetdb5/modules/mal/clients.c --- a/monetdb5/modules/mal/clients.c +++ b/monetdb5/modules/mal/clients.c @@ -797,6 +797,7 @@ CLTsessions(Client cntxt, MalBlkPtr mb, bat *clientpidId = getArgReference_bat(stk, pci, 14); bat *remarkId = getArgReference_bat(stk, pci, 15); Client c; + bool admin; timestamp ts; lng pid; const char *s; @@ -848,73 +849,80 @@ CLTsessions(Client cntxt, MalBlkPtr mb, throw(SQL, "sql.sessions", SQLSTATE(HY013) MAL_MALLOC_FAIL); } + admin = strcmp(cntxt->username, "monetdb") == 0; + MT_lock_set(&mal_contextLock); - for (c = mal_clients; c < mal_clients + MAL_MAXCLIENTS; c++) { - if (c->mode == RUNCLIENT) { - const char *username = c->username; - if (!username) - username = str_nil; - if (BUNappend(user, username, false) != GDK_SUCCEED) + if (c->mode != RUNCLIENT) + continue; + + bool allowed_to_see = admin || c == cntxt || strcmp(c->username, cntxt->username) == 0; + if (!allowed_to_see) + continue; + + const char *username = c->username; + if (!username) + username = str_nil; + if (BUNappend(user, username, false) != GDK_SUCCEED) + goto bailout; + ts = timestamp_fromtime(c->login); + if (is_timestamp_nil(ts)) { + msg = createException(SQL, "sql.sessions", + SQLSTATE(22003) + "Failed to convert user logged time"); + goto bailout; + } + if (BUNappend(id, &c->idx, false) != GDK_SUCCEED) goto bailout; - ts = timestamp_fromtime(c->login); + if (BUNappend(login, &ts, false) != GDK_SUCCEED) + goto bailout; + timeout = (int) (c->logical_sessiontimeout); + if (BUNappend(sessiontimeout, &timeout, false) != GDK_SUCCEED) + goto bailout; + timeout = (int) (c->querytimeout / 100); + if (BUNappend(querytimeout, &timeout, false) != GDK_SUCCEED) + goto bailout; + if (c->idle) { + ts = timestamp_fromtime(c->idle); if (is_timestamp_nil(ts)) { msg = createException(SQL, "sql.sessions", - SQLSTATE(22003) - "Failed to convert user logged time"); + SQLSTATE(22003) + "Failed to convert user logged time"); goto bailout; } - if (BUNappend(id, &c->idx, false) != GDK_SUCCEED) -goto bailout; - if (BUNappend(login, &ts, false) != GDK_SUCCEED) - goto bailout; - timeout = (int) (c->logical_sessiontimeout); - if (BUNappend(sessiontimeout, &timeout, false) != GDK_SUCCEED) - goto bailout; - timeout = (int) (c->querytimeout / 100); - if (BUNappend(querytimeout, &timeout, false) != GDK_SUCCEED) - goto bailout; - if (c->idle) { - ts = timestamp_fromtime(c->idle); - if (is_timestamp_nil(ts)) { - msg = createException(SQL, "sql.sessions", - SQLSTATE(22003) - "Failed to convert user logged time"); - goto bailout; - } - } else - ts = tim
MonetDB: Aug2024 - streamline unicode usage in ODBCconnect.py
Changeset: d743f73c34cf for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/d743f73c34cf Modified Files: sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: streamline unicode usage in ODBCconnect.py diffs (81 lines): diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -25,10 +25,17 @@ user = 'monetdb' password = 'monetdb' port = os.environ.get('MAPIPORT', 5) -# \u{E1} is LATIN SMALL LETTER A WITH ACUTE -unicode_text = 'R\u00E1inbow' + +# UnixODBC turns out to be broken when it comes to Unicode in connection +# strings. In SQLBrowseConnectW it basically converts the 16-bit connection +# string to an 8-bit connection string by dropping the upper bytes and keeping +# only the lower bytes. The character sequence below has been chosen with this +# in mind. + +# \u{E1} is LATIN SMALL LETTER A WITH ACUTE. +basic_unicode_text = 'R\u00E1inbow' # \u{1F308} is RAINBOW EMOJI -#unicode_text += '\U0001F308' +full_unicode_text = basic_unicode_text + '\U0001F308' class Execution: def __init__(self, *odbcconnect_args): @@ -279,9 +286,11 @@ ex.expect('08001') # something wrong wi ex.end() # test wide characters -ex = Execution('-w', '-d', f'DSN={dsn};Client Remark={unicode_text}') +# we can use the full character set because UnixODBC's SQLDriverConnect +# passes the connection string on without looking at it +ex = Execution('-w', '-d', f'DSN={dsn};Client Remark={full_unicode_text}') # expect OK followed by connection string containing the rainbow -ex.expect('OK', f'CLIENTREMARK={unicode_text}') +ex.expect('OK', f'CLIENTREMARK={full_unicode_text}') ex.end() # test maptolongvarchar @@ -340,12 +349,14 @@ ex.expect('OK', ';') ex.end() # test wide characters +# we use the limited character set because UnixODBC's SQLBrowserConnect +# messes up code points > 255 ex = Execution('-w', '-b', f'DSN={dsn}') ex.expect('OK', ';') ex.end() -ex = Execution('-w', '-b', f'DSN={dsn};Client Remark={unicode_text}') -ex.expect('OK', f';CLIENTREMARK={unicode_text}') +ex = Execution('-w', '-b', f'DSN={dsn};Client Remark={basic_unicode_text}') +ex.expect('OK', f';CLIENTREMARK={basic_unicode_text}') ex.expect ex.end() @@ -354,20 +365,20 @@ ex = Execution('-0', '-w', '-b', f'DSN={ ex.expect('OK', ';') ex.end() -ex = Execution('-0', '-w', '-b', f'DSN={dsn};Client Remark={unicode_text}') -ex.expect('OK', f';CLIENTREMARK={unicode_text}') +ex = Execution('-0', '-w', '-b', f'DSN={dsn};Client Remark={basic_unicode_text}') +ex.expect('OK', f';CLIENTREMARK={basic_unicode_text}') ex.expect ex.end() # Also test that queries return unicode ok ex = Execution( '-w', -'-b', f'DSN={dsn};Client Remark={unicode_text}', +'-b', f'DSN={dsn};Client Remark={basic_unicode_text}', '-q', 'select remark from sys.sessions where sessionid = current_sessionid()', ) -ex.expect('OK', f';CLIENTREMARK={unicode_text}') +ex.expect('OK', f';CLIENTREMARK={basic_unicode_text}') ex.expect('RESULT') -ex.expect(unicode_text) +ex.expect(basic_unicode_text) ex.end() ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Let odbcconnect -l print some Driver Manager ...
Changeset: 870ac42eacb2 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/870ac42eacb2 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Let odbcconnect -l print some Driver Manager info diffs (34 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -368,10 +368,30 @@ do_sqlbrowseconnect(const char *target) static int do_listdrivers(void) { + SQLRETURN ret; SQLSMALLINT dir = SQL_FETCH_FIRST; SQLSMALLINT len1, len2; int count = 0; + // unixodbc defines these in sqlext.h: + // #define SQL_ATTR_UNIXODBC_SYSPATH 65001 + // #define SQL_ATTR_UNIXODBC_VERSION 65002 + ret = SQLGetEnvAttr(env, 65002, outabuf, OUTBUF_SIZE, NULL); + if (SQL_SUCCEEDED(ret)) + printf("SQL_ATTR_UNIXODBC_VERSION=%s\n", outabuf); + ret = SQLGetEnvAttr(env, 65001, outabuf, OUTBUF_SIZE, NULL); + if (SQL_SUCCEEDED(ret)) + printf("SQL_ATTR_UNIXODBC_SYSPATH=%s\n", outabuf); + + // SQLGetInfo needs a DBC handle. It does not need to be connected to anything + ensure_ok( + SQL_HANDLE_ENV, env, "allocate conn handle", + SQLAllocHandle(SQL_HANDLE_DBC, env, &conn)); + + ret = SQLGetInfoA(conn, SQL_DM_VER, outabuf, OUTBUF_SIZE, NULL); + if (SQL_SUCCEEDED(ret)) + printf("SQL_DM_VER=%s\n", outabuf); + while (1) { outabuf[0] = attrbuf[0] = '\0'; SQLRETURN ret = SQLDriversA( ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Restore mapToLongVarchar setting
Changeset: 90b3c951a5ec for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/90b3c951a5ec Modified Files: clients/odbc/driver/ODBCAttrs.c clients/odbc/driver/SQLBrowseConnect.c clients/odbc/tests/odbcconnect.c sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Restore mapToLongVarchar setting It was available on the URL but not in ODBC diffs (109 lines): diff --git a/clients/odbc/driver/ODBCAttrs.c b/clients/odbc/driver/ODBCAttrs.c --- a/clients/odbc/driver/ODBCAttrs.c +++ b/clients/odbc/driver/ODBCAttrs.c @@ -50,6 +50,7 @@ const struct attr_setting attr_settings[ { "CLIENTINFO", "Send Client Info", MP_CLIENT_INFO }, { "APPNAME", "Application Name", MP_CLIENT_APPLICATION }, { "CLIENTREMARK", "Client Remark", MP_CLIENT_REMARK }, + { "MAPTOLONGVARCHAR", NULL, MP_MAPTOLONGVARCHAR }, }; const int attr_setting_count = sizeof(attr_settings) / sizeof(attr_settings[0]); diff --git a/clients/odbc/driver/SQLBrowseConnect.c b/clients/odbc/driver/SQLBrowseConnect.c --- a/clients/odbc/driver/SQLBrowseConnect.c +++ b/clients/odbc/driver/SQLBrowseConnect.c @@ -53,7 +53,12 @@ suggest_settings(ODBCDbc *dbc, char **bu mparm parm = entry->parm; if (dbc->setting_touched[(int)parm] == touched_as) { const char *sep = *pos > 0 ? ";" : ""; - reallocprintf(buf, pos, cap, "%s%s%s:%s=?", sep, prefix, entry->name, entry->alt_name); + reallocprintf( + buf, pos, cap, + "%s%s%s%s%s=?", + sep, prefix, entry->name, + entry->alt_name ? ":" : "", + entry->alt_name ? entry->alt_name : ""); if (entry->is_enum) { assert(entry->values != NULL); *pos -= 1; // eat the '?' diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -455,7 +455,45 @@ do_execute_stmt(void) SQL_HANDLE_STMT, stmt, "SQLNumResultCols", SQLNumResultCols(stmt, &colcount)); - printf("RESULT rows=%ld cols=%d \n", rowcount, colcount); + printf("RESULT rows=%ld: ", rowcount); + char *sep = ""; + for (int i = 1; i <= colcount; i++) { + printf("%s", sep); + sep = "; "; + SQLSMALLINT n; + ensure_ok( + SQL_HANDLE_STMT, stmt, "SQLColAttributeW SQL_DESC_NAME", + SQLColAttributeW(stmt, i, SQL_DESC_NAME, outwbuf, sizeof(outwbuf) /* in bytes! */, &n, NULL)); + convert_outw_outa(n); + printf("%s", outabuf); + SQLLEN typenr; + ensure_ok( + SQL_HANDLE_STMT, stmt, "SQLColAttributeW SQL_DESC_TYPE", + SQLColAttributeW(stmt, i, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &typenr)); + ensure_ok( + SQL_HANDLE_STMT, stmt, "SQLColAttributeW SQL_DESC_TYPE_NAME", + SQLColAttributeW(stmt, i, SQL_DESC_TYPE_NAME, outwbuf, sizeof(outwbuf) /* in bytes! */, &n, NULL)); + convert_outw_outa(n); + char *marker = typenr == SQL_LONGVARCHAR || typenr == SQL_WLONGVARCHAR ? "*" : ""; + printf(":%s%s", marker, outabuf); + SQLLEN fixed, len, scale; + ensure_ok( + SQL_HANDLE_STMT, stmt, "SQLColAttributeW SQL_DESC_LENGTH", + SQLColAttributeW(stmt, i, SQL_DESC_FIXED_PREC_SCALE, NULL, 0, NULL, &fixed)); + ensure_ok( + SQL_HANDLE_STMT, stmt, "SQLColAttributeW SQL_DESC_LENGTH", + SQLColAttributeW(stmt, i, SQL_DESC_LENGTH, NULL, 0, NULL, &len)); + ensure_ok( + SQL_HANDLE_STMT, stmt, "SQLColAttributeW SQL_DESC_SCALE", + SQLColAttributeW(stmt, i, SQL_DESC_SCALE, NULL, 0, NULL, &scale)); + if (!fixed || scale) { + if (scale > 0) + printf("(%ld,%ld)", len, scale); + else + printf("(%ld)", len); + } + } + printf("\n"); while (colcount > 0 && SQL_SUCCEEDED(SQLFetch(stmt))) { printf("- "); diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/od
MonetDB: Aug2024 - Print more info when ODBCconnect.py fails
Changeset: b87fb6cce3e5 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/b87fb6cce3e5 Modified Files: sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Print more info when ODBCconnect.py fails diffs (19 lines): diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -118,6 +118,15 @@ def show_context(): print(ex.report(), file=sys.stderr) if list_output: print(f'\n--- output of odbcconnect -l ---\n{list_output}--- end ---', file=sys.stderr) +odbcini = os.getenv('ODBCINI', 'odbc.ini') +sysini = os.getenv('ODBCSYSINI', os.getenv('TSTTRGDIR')) +fullpath = os.path.join(sysini, odbcini) +try: +with open(fullpath) as f: +content = f.read() +print(f'\n--- content of {fullpath} ---\n{content}\n--- end ---', file=sys.stderr) +except FileNotFoundError: +pass ### ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Fix uninitialized use
Changeset: 3b49dad3d4f7 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/3b49dad3d4f7 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Fix uninitialized use Hadn't realized mutf8 decode() reads the *codepoint without writing it first diffs (14 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -559,9 +559,9 @@ gen_utf16(SQLWCHAR *dest, const char *sr { SQLWCHAR *p = dest; uint32_t state = UTF8_ACCEPT; + uint32_t codepoint = UTF8_ACCEPT; for (size_t i = 0; i < len; i++) { unsigned char byte = (unsigned char)src[i]; - uint32_t codepoint; switch (decode(&state, &codepoint, byte)) { case UTF8_ACCEPT: if (codepoint <= 0x) { ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Fix SQLErrorW: odbc errors start at 1, not 0
Changeset: 1962142fc6d2 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/1962142fc6d2 Modified Files: clients/odbc/driver/SQLError.c sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Fix SQLErrorW: odbc errors start at 1, not 0 diffs (51 lines): diff --git a/clients/odbc/driver/SQLError.c b/clients/odbc/driver/SQLError.c --- a/clients/odbc/driver/SQLError.c +++ b/clients/odbc/driver/SQLError.c @@ -125,19 +125,19 @@ SQLErrorW(SQLHENV EnvironmentHandle, if (StatementHandle) rc = MNDBGetDiagRec(SQL_HANDLE_STMT, StatementHandle, - ((ODBCStmt *) StatementHandle)->RetrievedErrors, + ++((ODBCStmt *) StatementHandle)->RetrievedErrors, state, NativeErrorPtr, errmsg, (SQLSMALLINT) sizeof(errmsg), &n); else if (ConnectionHandle) rc = MNDBGetDiagRec(SQL_HANDLE_DBC, ConnectionHandle, - ((ODBCDbc *) ConnectionHandle)->RetrievedErrors, + ++((ODBCDbc *) ConnectionHandle)->RetrievedErrors, state, NativeErrorPtr, errmsg, (SQLSMALLINT) sizeof(errmsg), &n); else if (EnvironmentHandle) rc = MNDBGetDiagRec(SQL_HANDLE_ENV, EnvironmentHandle, - ((ODBCEnv *) EnvironmentHandle)->RetrievedErrors, + ++((ODBCEnv *) EnvironmentHandle)->RetrievedErrors, state, NativeErrorPtr, errmsg, (SQLSMALLINT) sizeof(errmsg), &n); else diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -254,6 +254,21 @@ ex.expect('RESULT') ex.expect('- ;') # the second connection does not have a Client Remark ex.end() +# test error handling when -w is given + +# first without the -w to demonstrate the expected behavior +ex = Execution('-d', f'Driver={{MonetDB}};User={user};Password={password};Database={dbname + "-Wrong"}') +ex.expect_fail() +ex.expect('Error') +ex.expect('08001') # something wrong with the database +ex.end() +# then with the -w +ex = Execution('-w', '-d', f'Driver={{MonetDB}};User={user};Password={password};Database={dbname + "-Wrong"}') +ex.expect_fail() +ex.expect('Error') +ex.expect('08001') # something wrong with the database +ex.end() + # test wide characters ex = Execution('-w', '-d', f'DSN={dsn};Client Remark={unicode_text}') # expect OK followed by connection string containing the rainbow ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Show output of odbcconnect -l when test fails
Changeset: 1f00aade5a18 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/1f00aade5a18 Modified Files: sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Show output of odbcconnect -l when test fails diffs (23 lines): diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -101,6 +101,10 @@ class Execution: raise Exception( f'Process exited with code {code!r}, expected {expected!r}') +# Grab the output of 'odbcconnect -l' so we can show it if a test fails +list_output = None +ex = Execution('-l') +list_output = ex.proc.stdout ex = None @@ -112,6 +116,8 @@ def show_context(): # ex.end() print(file=sys.stderr) print(ex.report(), file=sys.stderr) +if list_output: +print(f'\n--- output of odbcconnect -l ---\n{list_output}--- end ---', file=sys.stderr) ### ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Include wide character tests in sql/odbc/test...
Changeset: c85461b96b69 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/c85461b96b69 Modified Files: sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Include wide character tests in sql/odbc/tests/ODBCconnect diffs (109 lines): diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -25,6 +25,10 @@ user = 'monetdb' password = 'monetdb' port = os.environ.get('MAPIPORT', 5) +# \u{E1} is LATIN SMALL LETTER A WITH ACUTE +unicode_text = 'R\u00E1inbow' +# \u{1F308} is RAINBOW EMOJI +#unicode_text += '\U0001F308' class Execution: def __init__(self, *odbcconnect_args): @@ -110,6 +114,10 @@ def show_context(): print(ex.report(), file=sys.stderr) +### +# Test SQLConnect +### + ex = Execution(dsn) ex.expect('OK') ex.end() @@ -164,7 +172,21 @@ ex = Execution(dsn, '-0', '-u', user, '- ex.expect('OK') ex.end() -# test connection strings +# test wide characters +ex = Execution('-w', dsn + '-Wrong', '-u', user, '-p', password) +ex.expect('OK') +ex.end() + +# test wide characters in combination with non-NUL +ex = Execution('-0', '-w', dsn + '-Wrong', '-u', user, '-p', password) +ex.expect('OK') +ex.end() + + + +### +# Test SQLDriverConnect +### ex = Execution('-d', f'DSN={dsn}') ex.expect('OK') @@ -226,8 +248,15 @@ ex.expect('RESULT') ex.expect('- ;') # the second connection does not have a Client Remark ex.end() +# test wide characters +ex = Execution('-w', '-d', f'DSN={dsn};Client Remark={unicode_text}') +# expect OK followed by connection string containing the rainbow +ex.expect('OK', f'CLIENTREMARK={unicode_text}') +ex.end() -# Test browsing +### +# Test SQLBrowseConnect +### ex = Execution('-b', 'Driver={MonetDB}') ex.expect('Info') @@ -259,6 +288,41 @@ ex = Execution('-b', f'DSN={dsn}') ex.expect('OK', ';') ex.end() -# clear 'ex', otherwise the atexit handler will write things -# to stderr +# test wide characters +ex = Execution('-w', '-b', f'DSN={dsn}') +ex.expect('OK', ';') +ex.end() + +ex = Execution('-w', '-b', f'DSN={dsn};Client Remark={unicode_text}') +ex.expect('OK', f';CLIENTREMARK={unicode_text}') +ex.expect +ex.end() + +# also with non-NUL terminated strings +ex = Execution('-0', '-w', '-b', f'DSN={dsn}') +ex.expect('OK', ';') +ex.end() + +ex = Execution('-0', '-w', '-b', f'DSN={dsn};Client Remark={unicode_text}') +ex.expect('OK', f';CLIENTREMARK={unicode_text}') +ex.expect +ex.end() + +# Also test that queries return unicode ok +ex = Execution( +'-w', +'-b', f'DSN={dsn};Client Remark={unicode_text}', +'-q', 'select remark from sys.sessions where sessionid = current_sessionid()', +) +ex.expect('OK', f';CLIENTREMARK={unicode_text}') +ex.expect('RESULT') +ex.expect(unicode_text) +ex.end() + + +### +# +# clear 'ex', otherwise the atexit handler will write things to stderr +# +### ex = None ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Make odbcconnect handle full utf-16, not just...
Changeset: d0a155c796b6 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/d0a155c796b6 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Make odbcconnect handle full utf-16, not just ascii-16 diffs (90 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -338,7 +338,7 @@ do_sqlbrowseconnect(const char *target) { void *target_buf; SQLSMALLINT target_len = SQL_NTS; - make_arg(false, target, &target_buf, &target_len); + make_arg(use_wide, target, &target_buf, &target_len); SQLSMALLINT n; @@ -462,9 +462,13 @@ do_execute_stmt(void) for (int i = 1; i <= colcount; i++) { SQLLEN n; outabuf[0] = '\0'; - SQLRETURN ret = SQLGetData(stmt, i, SQL_C_CHAR, outabuf, OUTBUF_SIZE, &n); + SQLRETURN ret = use_wide + ? SQLGetData(stmt, i, SQL_C_WCHAR, outwbuf, OUTBUF_SIZE * sizeof(SQLWCHAR), &n) + : SQLGetData(stmt, i, SQL_C_CHAR, outabuf, OUTBUF_SIZE, &n); if (!SQL_SUCCEEDED(ret)) ensure_ok(SQL_HANDLE_STMT, stmt, "SQLGetData", ret); + if (use_wide) + convert_outw_outa(n); printf("%s;", outabuf); } printf("\n"); @@ -584,17 +588,54 @@ gen_utf16(SQLWCHAR *dest, const char *sr return p; } +static inline SQLCHAR +continuation_byte(uint32_t val, int n) +{ + val >>= 6 * n; // chop off right hand bits + val &= 0x3F; // chop off left hand bits + val |= 0x80; // add continuation marker bit + return val; +} + static void convert_outw_outa(size_t n) { - // outw mostly holds connection strings and those are mostly ascii - for (size_t i = 0; i < n; i++) { - SQLWCHAR w = outwbuf[i]; - if (w > 127) { - fprintf(stderr, "Sorry, this test is lazy and should be extended to non-ascii utf-16\n"); - exit(1); + SQLWCHAR *end = &outwbuf[n]; + SQLWCHAR *in = &outwbuf[0]; + SQLCHAR *out = &outabuf[0]; + + while (in < end) { + SQLWCHAR w = *in++; + uint32_t codepoint; + if (w < 0xD800 || w >= 0xE000) { + codepoint = w; + } else if (w < 0xDC00 && in < end && *in >= 0xDC00 && *in < 0xE000) { + uint32_t hi = w - 0xD800; + uint32_t lo = *in++ - 0xDC00; + codepoint = 0x1 + (hi << 10) + lo; + } else { + strcpy((char*)out, "!!INVALID UTF-16 OR A BUG IN THE TEST ITSELF!!"); + break; } - outabuf[i] = (SQLCHAR)w; + if (codepoint == 0xFEFF && out == &outabuf[0]) { + // skip the BOM + } else if (codepoint < 0x80) { + *out++ = codepoint; + } else if (codepoint < 0x800) { + *out++ = 0xC0 | (codepoint >> 6); + *out++ = continuation_byte(codepoint, 0); + } else if (codepoint < 0x1) { + *out++ = 0xE0 | (codepoint >> 12); + *out++ = continuation_byte(codepoint, 1); + *out++ = continuation_byte(codepoint, 0); + } else { + assert(codepoint < 0x11); + *out++ = 0xF0 | (codepoint >> 18); + *out++ = continuation_byte(codepoint, 2); + *out++ = continuation_byte(codepoint, 1); + *out++ = continuation_byte(codepoint, 0); + } } - outabuf[n] = '\0'; + + *out = '\0'; } ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - SQLDriverConnect: build connection string eve...
Changeset: 89396b04faf9 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/89396b04faf9 Modified Files: clients/odbc/driver/SQLDriverConnect.c Branch: Aug2024 Log Message: SQLDriverConnect: build connection string even with tryOnly It's the only reason tryOnly exists! diffs (56 lines): diff --git a/clients/odbc/driver/SQLDriverConnect.c b/clients/odbc/driver/SQLDriverConnect.c --- a/clients/odbc/driver/SQLDriverConnect.c +++ b/clients/odbc/driver/SQLDriverConnect.c @@ -189,6 +189,18 @@ MNDBDriverConnect(ODBCDbc *dbc, goto end; } + // Build a connect string for the current connection and put it in the out buffer. + scratch_alloc = buildConnectionString(dsn ? dsn : "DEFAULT", settings); + if (!scratch_alloc) + goto failure; + out_len = strcpy_len((char*)OutConnectionString, scratch_alloc, BufferLength); + if (StringLength2Ptr) + *StringLength2Ptr = (SQLSMALLINT)out_len; + if (out_len + 1 > (size_t)BufferLength) { + addDbcError(dbc, "01004", NULL, 0); + rc = SQL_SUCCESS_WITH_INFO; + } + if (tryOnly) { assert(sqlstate == NULL); goto end; @@ -200,23 +212,8 @@ MNDBDriverConnect(ODBCDbc *dbc, rc = MNDBConnectSettings(dbc, dsn, settings); settings = NULL; // do not free now - if (!SQL_SUCCEEDED(rc)) - goto end; // not to 'failure', all errors have already been logged - - // Build a connect string for the current connection - // and put it in the buffer. - scratch_alloc = buildConnectionString(dsn ? dsn : "DEFAULT", dbc->settings); - if (!scratch_alloc) - goto failure; - out_len = strcpy_len((char*)OutConnectionString, scratch_alloc, BufferLength); - if (StringLength2Ptr) - *StringLength2Ptr = (SQLSMALLINT)out_len; - if (out_len + 1 > (size_t)BufferLength) { - addDbcError(dbc, "01004", NULL, 0); - rc = SQL_SUCCESS_WITH_INFO; - } - + // always go to end, MNDBConnectSettings has already logged any failures goto end; failure: @@ -313,7 +310,7 @@ SQLDriverConnectW(SQLHDBC ConnectionHand addDbcError, dbc, return SQL_ERROR); rc = MNDBDriverConnect(dbc, WindowHandle, in, SQL_NTS, NULL, 0, &n, - DriverCompletion, 1); // Try Only + DriverCompletion, 1); // 1 = Try Only if (!SQL_SUCCEEDED(rc)) return rc; clearDbcErrors(dbc); ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Extend odbcconnect with -w to test the Wide API
Changeset: e37e83b564b7 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/e37e83b564b7 Modified Files: clients/odbc/tests/CMakeLists.txt clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Extend odbcconnect with -w to test the Wide API diffs (truncated from 400 to 300 lines): diff --git a/clients/odbc/tests/CMakeLists.txt b/clients/odbc/tests/CMakeLists.txt --- a/clients/odbc/tests/CMakeLists.txt +++ b/clients/odbc/tests/CMakeLists.txt @@ -44,6 +44,7 @@ add_executable(odbcconnect target_link_libraries(odbcconnect PRIVATE + mutf8 ODBC::ODBC) install(TARGETS diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -26,6 +26,8 @@ #include #include +#include "mutf8.h" + static const char *USAGE = "Usage:\n" "odbcconnect [-d | -c | -b ] [-v] [-u USER] [-p PASSWORD] TARGET..\n" @@ -37,6 +39,7 @@ static const char *USAGE = "-p PASSWORD\n" "-q SQL Execute SQL statement when connection succeeds\n" "-0 use counted strings rather than nul-terminated arguments\n" + "-w use the wide-char (unicode) interface\n" "-v Be verbose\n" "TARGET DSN or with -d and -b, Connection String\n"; @@ -57,7 +60,13 @@ static void ensure_ok_impl(SQLSMALLINT t #define ensure_ok(type, handle, message, ret)ensure_ok_impl(type, handle, message, ret, __LINE__) -static void make_arg(const char *arg, SQLCHAR**bufp, SQLSMALLINT *buflen); +static void make_arg(bool wide, const char *arg, void **bufp, SQLSMALLINT *buflen); +static void make_arga(const char *arg, void **bufp, SQLSMALLINT *buflen); +static void make_argw(const char *arg, void **bufp, SQLSMALLINT *buflen, bool bytes_not_chars); + + +static SQLWCHAR *gen_utf16(SQLWCHAR *dest, const char *src, size_t len); +static void convert_outw_outa(size_t n); int verbose = 0; @@ -65,13 +74,17 @@ char *user = NULL; char *password = NULL; char *query = NULL; bool use_counted_strings = false; +bool use_wide = false; SQLHANDLE env = NULL; SQLHANDLE conn = NULL; SQLHANDLE stmt = NULL; -SQLCHAR outbuf[4096]; +#define OUTBUF_SIZE 4096 SQLCHAR attrbuf[4096]; +SQLCHAR outabuf[OUTBUF_SIZE]; +SQLWCHAR outwbuf[OUTBUF_SIZE]; + // This free-list will be processed by cleanup(). // It is added to by alloc() @@ -131,6 +144,8 @@ main(int argc, char **argv) query = argv[++i]; else if (strcmp(arg, "-0") == 0) use_counted_strings = true; + else if (strcmp(arg, "-w") == 0) + use_wide = true; else if (strcmp(arg, "-v") == 0) verbose += 1; else if (arg[0] != '-') @@ -247,7 +262,8 @@ do_actions(action_t action, int ntargets char *t = targets[i]; if (verbose) printf("\nTarget: %s\n", t); - outbuf[0] = '\0'; + outabuf[0] = '\0'; + outwbuf[0] = 0; int ret = action(t); if (ret) return ret; @@ -259,21 +275,24 @@ do_actions(action_t action, int ntargets static int do_sqlconnect(const char *target) { - SQLCHAR *target_buf; + void *target_buf; SQLSMALLINT target_len = SQL_NTS; - make_arg(target, &target_buf, &target_len); + make_arg(use_wide, target, &target_buf, &target_len); - SQLCHAR *user_buf; + void *user_buf; SQLSMALLINT user_len = SQL_NTS; - make_arg(user, &user_buf, &user_len); + make_arg(use_wide, user, &user_buf, &user_len); - SQLCHAR *password_buf; + void *password_buf; SQLSMALLINT password_len = SQL_NTS; - make_arg(password, &password_buf, &password_len); + make_arg(use_wide, password, &password_buf, &password_len); ensure_ok( SQL_HANDLE_DBC, conn, "SQLConnect", - SQLConnectA(conn, target_buf, target_len, user_buf, user_len, password_buf, password_len)); + use_wide + ? SQLConnectW(conn, target_buf, target_len, user_buf, user_len, password_buf, password_len) + : SQLConnectA(conn, target_buf, target_len, user_buf, user_len, password_buf, password_len) + ); printf("OK\n"); int exitcode = do_execute_stmt(); @@ -288,22 +307,22 @@ do_sqlconnect(const char *target) static int do_sqldriverconnect(const char *target) { - SQLCHAR *target_buf; + void *target_buf; SQLSMALLINT target_len = SQL_NTS; - make_arg(target, &target_buf, &target_len); + make_arg(use_wide, target, &target_buf, &target_len); SQLSMALLINT n; ensure_ok( SQL_HANDLE_DBC, conn, "SQLDriverConnect", -
MonetDB: Aug2024 - Simplify memory management in odbcconnect.c
Changeset: dd08c6628fb2 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/dd08c6628fb2 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Simplify memory management in odbcconnect.c diffs (truncated from 316 to 300 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -40,13 +40,13 @@ static const char *USAGE = "-v Be verbose\n" "TARGET DSN or with -d and -b, Connection String\n"; -typedef int (action_t)(SQLCHAR *); +typedef int (action_t)(const char *); static action_t do_sqlconnect; static action_t do_sqldriverconnect; static action_t do_sqlbrowseconnect; -static int do_actions(action_t action, int ntargets, SQLCHAR **targets); +static int do_actions(action_t action, int ntargets, char **targets); static int do_listdrivers(void); static int do_listdsns(const char *prefix, SQLSMALLINT dir); @@ -57,17 +57,13 @@ static void ensure_ok_impl(SQLSMALLINT t #define ensure_ok(type, handle, message, ret)ensure_ok_impl(type, handle, message, ret, __LINE__) -#define MARGIN 100 -static SQLCHAR* sqldup_with_margin(const char *str); -static void fuzz_sql_nts(SQLCHAR **str, SQLSMALLINT *len); +static void make_arg(const char *arg, SQLCHAR**bufp, SQLSMALLINT *buflen); + int verbose = 0; -SQLCHAR *user = NULL; -SQLSMALLINT user_len = SQL_NTS; -SQLCHAR *password = NULL; -SQLSMALLINT password_len = SQL_NTS; -SQLCHAR *query = NULL; -SQLSMALLINT query_len = SQL_NTS; +char *user = NULL; +char *password = NULL; +char *query = NULL; bool use_counted_strings = false; SQLHANDLE env = NULL; @@ -77,12 +73,25 @@ SQLHANDLE stmt = NULL; SQLCHAR outbuf[4096]; SQLCHAR attrbuf[4096]; +// This free-list will be processed by cleanup(). +// It is added to by alloc() +unsigned int ngarbage = 0; +void *garbage[100] = { NULL }; + + +static void* +alloc(size_t size) +{ + void *p = calloc(size, 1); + assert(p); + if (ngarbage < sizeof(garbage) / sizeof(garbage[0])) + garbage[ngarbage++] = p; + return p; +} + static void cleanup(void) { - free(user); - free(password); - free(query); if (stmt) SQLFreeHandle(SQL_HANDLE_STMT, stmt); if (conn) { @@ -91,14 +100,18 @@ cleanup(void) } if (env) SQLFreeHandle(SQL_HANDLE_DBC, env); + + while (ngarbage > 0) { + free(garbage[--ngarbage]); + } } int main(int argc, char **argv) { - int (*action)(SQLCHAR *); + int (*action)(const char*); action = do_sqlconnect; - SQLCHAR **targets = calloc(argc, sizeof(argv[0])); + char **targets = alloc(argc * sizeof(argv[0])); int ntargets = 0; int ret; @@ -111,17 +124,17 @@ main(int argc, char **argv) else if (strcmp(arg, "-l") == 0) action = NULL; else if (strcmp(arg, "-u") == 0 && i + 1 < argc) - user = sqldup_with_margin(argv[++i]); + user = argv[++i]; else if (strcmp(arg, "-p") == 0 && i + 1 < argc) - password = sqldup_with_margin(argv[++i]); + password = argv[++i]; else if (strcmp(arg, "-q") == 0 && i + 1 < argc) - query = sqldup_with_margin(argv[++i]); + query = argv[++i]; else if (strcmp(arg, "-0") == 0) use_counted_strings = true; else if (strcmp(arg, "-v") == 0) verbose += 1; else if (arg[0] != '-') - targets[ntargets++] = sqldup_with_margin(arg); + targets[ntargets++] = arg; else { fprintf(stderr, "\nERROR: invalid argument: %s\n%s", arg, USAGE); ret = 1; @@ -137,11 +150,6 @@ main(int argc, char **argv) SQL_HANDLE_ENV, env, "set odbc version", SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0)); - if (use_counted_strings) { - fuzz_sql_nts(&user, &user_len); - fuzz_sql_nts(&password, &password_len); - } - if (action) { if (ntargets == 0) { fprintf(stderr, "\nERROR: pass at least one target\n%s", USAGE); @@ -161,9 +169,6 @@ main(int argc, char **argv) } end: - for (int i = 0; i < ntargets; i++) - free(targets[i]); - free(targets); cleanup(); return ret; @@ -232,14 +237,14 @@ ensure_ok_impl(SQLSMALLINT type, SQLHAND static int -do_actions(action_t action, int ntargets, SQLCHAR **targets) +do_actions(action_t action, int ntargets, char **targets) { ensure_ok( SQL_HANDLE_ENV, env, "al
MonetDB: Aug2024 - Mark user DNS's as such
Changeset: 327a94079349 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/327a94079349 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Mark user DNS's as such diffs (12 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -157,7 +157,7 @@ main(int argc, char **argv) } ret = do_listdrivers(); ret |= do_listdsns("SYSTEM", SQL_FETCH_FIRST_SYSTEM); - ret |= do_listdsns("SYSTEM", SQL_FETCH_FIRST_USER); + ret |= do_listdsns("USER", SQL_FETCH_FIRST_USER); } end: ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Write SQLConnectA, etc in odbcconnect.c
Changeset: 0fe29b9b9760 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/0fe29b9b9760 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Write SQLConnectA, etc in odbcconnect.c diffs (74 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -24,6 +24,7 @@ #include #include #include +#include static const char *USAGE = "Usage:\n" @@ -206,7 +207,7 @@ ensure_ok_impl(SQLSMALLINT type, SQLHAND bool printed_something = false; for (int i = 1; ; i++) { - SQLRETURN diag_ret = SQLGetDiagRec( + SQLRETURN diag_ret = SQLGetDiagRecA( type, handle, i, state, &error, explanation, sizeof(explanation), &len); if (!SQL_SUCCEEDED(diag_ret)) @@ -259,7 +260,7 @@ do_sqlconnect(SQLCHAR *target) ensure_ok( SQL_HANDLE_DBC, conn, "SQLConnect", - SQLConnect(conn, target, target_len, user, user_len, password, password_len)); + SQLConnectA(conn, target, target_len, user, user_len, password, password_len)); printf("OK\n"); int exitcode = do_execute_stmt(); @@ -281,7 +282,7 @@ do_sqldriverconnect(SQLCHAR *target) ensure_ok( SQL_HANDLE_DBC, conn, "SQLDriverConnect", - SQLDriverConnect( + SQLDriverConnectA( conn, NULL, target, target_len, outbuf, sizeof(outbuf), &n, @@ -307,7 +308,7 @@ do_sqlbrowseconnect(SQLCHAR *target) if (use_counted_strings) fuzz_sql_nts(&target, &target_len); - SQLRETURN ret = SQLBrowseConnect( + SQLRETURN ret = SQLBrowseConnectA( conn, target, target_len, outbuf, sizeof(outbuf), &n @@ -338,7 +339,7 @@ do_listdrivers(void) while (1) { outbuf[0] = attrbuf[0] = '\0'; - SQLRETURN ret = SQLDrivers( + SQLRETURN ret = SQLDriversA( env, dir, outbuf, sizeof(outbuf), &len1, attrbuf, sizeof(attrbuf), &len2 @@ -367,7 +368,7 @@ do_listdsns(const char *prefix, SQLSMALL while (1) { outbuf[0] = attrbuf[0] = '\0'; - SQLRETURN ret = SQLDataSources( + SQLRETURN ret = SQLDataSourcesA( env, dir, outbuf, sizeof(outbuf), &len1, attrbuf, sizeof(attrbuf), &len2 @@ -401,7 +402,7 @@ do_execute_stmt(void) ensure_ok( SQL_HANDLE_STMT, stmt, "SQLExecDirect", - SQLExecDirect(stmt, query, query_len)); + SQLExecDirectA(stmt, query, query_len)); do { SQLLEN rowcount = -1; ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Last four parameters of MNDBConnect are now u...
Changeset: 28ad5b5a for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/28ad5b5a Modified Files: clients/odbc/driver/ODBCDbc.h clients/odbc/driver/SQLConnect.c Branch: Aug2024 Log Message: Last four parameters of MNDBConnect are now unused diffs (88 lines): diff --git a/clients/odbc/driver/ODBCDbc.h b/clients/odbc/driver/ODBCDbc.h --- a/clients/odbc/driver/ODBCDbc.h +++ b/clients/odbc/driver/ODBCDbc.h @@ -144,8 +144,7 @@ int ODBCGetKeyAttr(const SQLCHAR **conn, SQLRETURN MNDBAllocStmt(ODBCDbc *dbc, SQLHANDLE *pnOutputHandle); SQLRETURN MNDBConnect(ODBCDbc *dbc, const SQLCHAR *szDataSource, SQLSMALLINT nDataSourceLength, const SQLCHAR *szUID, SQLSMALLINT nUIDLength, - const SQLCHAR *szPWD, SQLSMALLINT nPWDLength, - const char *host, int port, const char *dbname, int mapToLongVarchar); + const SQLCHAR *szPWD, SQLSMALLINT nPWDLength); SQLRETURN MNDBGetConnectAttr(ODBCDbc *dbc, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER BufferLength, SQLINTEGER *StringLength); SQLRETURN MNDBSetConnectAttr(ODBCDbc *dbc, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength); diff --git a/clients/odbc/driver/SQLConnect.c b/clients/odbc/driver/SQLConnect.c --- a/clients/odbc/driver/SQLConnect.c +++ b/clients/odbc/driver/SQLConnect.c @@ -311,17 +311,14 @@ end: SQLRETURN + MNDBConnect(ODBCDbc *dbc, const SQLCHAR *ServerName, SQLSMALLINT NameLength1, const SQLCHAR *UserName, SQLSMALLINT NameLength2, const SQLCHAR *Authentication, - SQLSMALLINT NameLength3, - const char *host, - int port, - const char *dbname, - int mapToLongVarchar) + SQLSMALLINT NameLength3) { // These will be passed to addDbcError if you 'goto failure'. // If unset, 'goto failure' will assume an allocation error. @@ -402,30 +399,12 @@ MNDBConnect(ODBCDbc *dbc, goto failure; } - if (host != NULL) { - error_explanation = msetting_set_string(settings, MP_HOST, host); - if (error_explanation != NULL) - goto failure; - } - mapiport_env = getenv("MAPIPORT"); - if (port > 0) - error_explanation = msetting_set_long(settings, MP_PORT, port); - else if (mapiport_env != NULL) + if (mapiport_env != NULL) error_explanation = msetting_parse(settings, MP_PORT, mapiport_env); if (error_explanation != NULL) goto failure; - if (dbname != NULL) { - error_explanation = msetting_set_string(settings, MP_DATABASE, dbname); - if (error_explanation != NULL) - goto failure; - } - - error_explanation = msetting_set_long(settings, MP_MAPTOLONGVARCHAR, mapToLongVarchar); - if (error_explanation) - goto failure; - #ifdef ODBCDEBUG { free(scratch); @@ -545,8 +524,7 @@ SQLConnect(SQLHDBC ConnectionHandle, return MNDBConnect((ODBCDbc *) ConnectionHandle, ServerName, NameLength1, UserName, NameLength2, - Authentication, NameLength3, - NULL, 0, NULL, 0); + Authentication, NameLength3); } SQLRETURN SQL_API @@ -596,8 +574,7 @@ SQLConnectW(SQLHDBC ConnectionHandle, rc = MNDBConnect(dbc, ds, SQL_NTS, uid, SQL_NTS, -pwd, SQL_NTS, -NULL, 0, NULL, 0); +pwd, SQL_NTS); bailout: if (ds) ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - ODBCConnectionString is no longer used
Changeset: 4b59dd0861ce for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/4b59dd0861ce Modified Files: clients/odbc/driver/ODBCDbc.h clients/odbc/driver/SQLDriverConnect.c Branch: Aug2024 Log Message: ODBCConnectionString is no longer used instead we have buildConnectionString which takes all msettings into account diffs (199 lines): diff --git a/clients/odbc/driver/ODBCDbc.h b/clients/odbc/driver/ODBCDbc.h --- a/clients/odbc/driver/ODBCDbc.h +++ b/clients/odbc/driver/ODBCDbc.h @@ -141,14 +141,6 @@ ODBCError *getDbcError(ODBCDbc *dbc); void destroyODBCDbc(ODBCDbc *dbc); int ODBCGetKeyAttr(const SQLCHAR **conn, SQLSMALLINT *nconn, char **key, char **attr); -SQLRETURN ODBCConnectionString(SQLRETURN rc, ODBCDbc *dbc, - SQLCHAR *OutConnectionString, - SQLSMALLINT BufferLength, - SQLSMALLINT *StringLength2Ptr, - const char *dsn, const char *uid, - const char *pwd, const char *host, - int port, const char *database, - int mapToLongVarchar); SQLRETURN MNDBAllocStmt(ODBCDbc *dbc, SQLHANDLE *pnOutputHandle); SQLRETURN MNDBConnect(ODBCDbc *dbc, const SQLCHAR *szDataSource, SQLSMALLINT nDataSourceLength, const SQLCHAR *szUID, SQLSMALLINT nUIDLength, diff --git a/clients/odbc/driver/SQLDriverConnect.c b/clients/odbc/driver/SQLDriverConnect.c --- a/clients/odbc/driver/SQLDriverConnect.c +++ b/clients/odbc/driver/SQLDriverConnect.c @@ -105,177 +105,6 @@ ODBCGetKeyAttr(const SQLCHAR **conn, SQL return 1; } -SQLRETURN -ODBCConnectionString(SQLRETURN rc, -ODBCDbc *dbc, -SQLCHAR *OutConnectionString, -SQLSMALLINT BufferLength, -SQLSMALLINT *StringLength2Ptr, -const char *dsn, -const char *uid, -const char *pwd, -const char *host, -int port, -const char *database, -int mapToLongVarchar) -{ - int n; -#ifdef ODBCDEBUG - SQLCHAR *buf = OutConnectionString; - int buflen = BufferLength; -#endif - - if (OutConnectionString == NULL) - BufferLength = -1; - if (BufferLength > 0) { - n = snprintf((char *) OutConnectionString, BufferLength, -"DSN=%s;", dsn ? dsn : "DEFAULT"); - /* some snprintf's return -1 if buffer too small */ - if (n < 0) - n = BufferLength + 1; /* make sure it becomes < 0 */ - BufferLength -= n; - OutConnectionString += n; - } else { - BufferLength = -1; - } - if (uid) { - if (BufferLength > 0) { - n = snprintf((char *) OutConnectionString, -BufferLength, "UID=%s;", uid); - if (n < 0) - n = BufferLength + 1; - BufferLength -= n; - OutConnectionString += n; - } else { - BufferLength = -1; - } - } - if (pwd) { - if (BufferLength > 0) { - n = snprintf((char *) OutConnectionString, -BufferLength, "PWD=%s;", pwd); - if (n < 0) - n = BufferLength + 1; - BufferLength -= n; - OutConnectionString += n; - } else { - BufferLength = -1; - } - } - if (host) { - if (BufferLength > 0) { - n = snprintf((char *) OutConnectionString, -BufferLength, "HOST=%s;", host); - if (n < 0) - n = BufferLength + 1; - BufferLength -= n; - OutConnectionString += n; - } else { - BufferLength = -1; - } - } - if (port) { - char portbuf[10]; - - if (BufferLength > 0) { - n = snprintf((char *) OutConnectionString, -BufferLength, "PORT=%d;", port); - if (n < 0) - n = BufferLength + 1; - BufferLength -= n; - OutConnectionString += n; - } else { - BufferLength = -1; - } - port = snprintf(portbuf, sizeof(portbuf), "%d", port); - } - if (database) { - if (BufferLength > 0) { - n = snprintf((char *) OutConnectionS
MonetDB: Aug2024 - Test SQLConnect user/pass parameters take pre...
Changeset: 3f6bfb98715f for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/3f6bfb98715f Modified Files: sql/odbc/tests/Tests/ODBCconnect.py testing/Mtest.py.in Branch: Aug2024 Log Message: Test SQLConnect user/pass parameters take precedence Modify MonetDB-Test-Wrong dsn in Mtest.py to not set DATABASE wrong as there is no way we can override it in with SQLConnect. diffs (41 lines): diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -144,6 +144,16 @@ ex.expect('Error') ex.expect('28000:') # 28000 bad credentials ex.end() +# parameters passed directly to SQLConnect override those from the dsn +ex = Execution(dsn + '-Wrong') +ex.expect_fail() +ex.expect('Error') +ex.expect('28000:')# this dsn uses the wrong user name and password +ex.end() +ex = Execution(dsn + '-Wrong', '-u', user, '-p', password) +ex.expect('OK')# but those passes as arguments take precedence +ex.end() + # test non-NUL terminated strings ex = Execution(dsn, '-0') @@ -213,7 +223,7 @@ ex.expect('RESULT') ex.expect('- banana;') # as set by Client Remark property ex.expect('OK') ex.expect('RESULT') -ex.expect('- ;') # this connection did not have a Client Remark +ex.expect('- ;') # the second connection does not have a Client Remark ex.end() diff --git a/testing/Mtest.py.in b/testing/Mtest.py.in --- a/testing/Mtest.py.in +++ b/testing/Mtest.py.in @@ -2239,7 +2239,7 @@ Description = Wrong values for Database, Driver = MonetDB Host = localhost Port = {env["MAPIPORT"]} -Database = {TSTDB}-Wrong +Database = {TSTDB} User = {user or "monetdb"}-Wrong Password = {passwd or "monetdb"}-Wrong ''') ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Comment
Changeset: 0b8f54cd8c3f for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/0b8f54cd8c3f Modified Files: clients/odbc/driver/SQLBrowseConnect.c Branch: Aug2024 Log Message: Comment diffs (11 lines): diff --git a/clients/odbc/driver/SQLBrowseConnect.c b/clients/odbc/driver/SQLBrowseConnect.c --- a/clients/odbc/driver/SQLBrowseConnect.c +++ b/clients/odbc/driver/SQLBrowseConnect.c @@ -116,6 +116,7 @@ MNDBBrowseConnect(ODBCDbc *dbc, size_t cap = 0; suggest_settings(dbc, &buf, &pos, &cap, 2, "");// mandatory first suggest_settings(dbc, &buf, &pos, &cap, 0, "*"); // then optional + // note that we leave out level 1, they have already been provided if (buf && pos) { size_t n = strcpy_len((char*)OutConnectionString, buf, BufferLength); ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Test that settings do not leak into next conn...
Changeset: f8838596f8c9 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f8838596f8c9 Modified Files: sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Test that settings do not leak into next connection when a handle is reused diffs (41 lines): diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -15,6 +15,7 @@ import atexit import os +import shlex import subprocess import sys @@ -37,7 +38,7 @@ class Execution: self.checks = [] def report(self): -parts = [f'COMMAND: {self.cmd}', +parts = [f'COMMAND: {shlex.join(self.cmd)}', f'EXIT CODE: {self.proc.returncode}', ''] if self.proc.stdout: parts += [ @@ -201,6 +202,20 @@ ex.expect('OK') # connect succee ex.expect('RESULT') # rollback succeeds ex.end() +# test that configuration does not leak to next connection when handle is reused +ex = Execution('-d', +'-q', 'select remark from sys.sessions where sessionid = current_sessionid()', +f'DSN={dsn};Client Remark=banana', +f'DSN={dsn}' +) +ex.expect('OK') +ex.expect('RESULT') +ex.expect('- banana;') # as set by Client Remark property +ex.expect('OK') +ex.expect('RESULT') +ex.expect('- ;') # this connection did not have a Client Remark +ex.end() + # Test browsing ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Get rid of sql_attr_autocommit
Changeset: e48d017e9a10 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/e48d017e9a10 Modified Files: clients/odbc/driver/ODBCDbc.c clients/odbc/driver/ODBCDbc.h clients/odbc/driver/SQLConnect.c clients/odbc/driver/SQLEndTran.c clients/odbc/driver/SQLGetConnectAttr.c clients/odbc/driver/SQLSetConnectAttr.c sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Get rid of sql_attr_autocommit It's part of the msettings now and shouldn't blindly override those. diffs (111 lines): diff --git a/clients/odbc/driver/ODBCDbc.c b/clients/odbc/driver/ODBCDbc.c --- a/clients/odbc/driver/ODBCDbc.c +++ b/clients/odbc/driver/ODBCDbc.c @@ -80,7 +80,6 @@ newODBCDbc(ODBCEnv *env) *dbc = (ODBCDbc) { .Env = env, .settings = settings, - .sql_attr_autocommit = SQL_AUTOCOMMIT_ON, /* default is autocommit */ .sql_attr_metadata_id = SQL_FALSE, /* add this dbc to start of the administrative linked dbc list */ .next = env->FirstDbc, diff --git a/clients/odbc/driver/ODBCDbc.h b/clients/odbc/driver/ODBCDbc.h --- a/clients/odbc/driver/ODBCDbc.h +++ b/clients/odbc/driver/ODBCDbc.h @@ -59,7 +59,6 @@ typedef struct tODBCDRIVERDBC { bool allow_hugeint; /* whether the application deals with HUGEINT */ bool raw_strings; /* server uses raw strings */ int mapToLongVarchar; /* when > 0 we map WVARCHAR to WLONGVARCHAR, default 0 */ - SQLUINTEGER sql_attr_autocommit; SQLUINTEGER sql_attr_metadata_id; /* MonetDB connection handle & status information */ diff --git a/clients/odbc/driver/SQLConnect.c b/clients/odbc/driver/SQLConnect.c --- a/clients/odbc/driver/SQLConnect.c +++ b/clients/odbc/driver/SQLConnect.c @@ -482,7 +482,6 @@ MNDBConnectSettings(ODBCDbc *dbc, const if (mid) { settings = NULL; // will be free'd as part of 'mid' now mapi_setclientprefix(mid, "ODBC " MONETDB_VERSION); - mapi_setAutocommit(mid, dbc->sql_attr_autocommit == SQL_AUTOCOMMIT_ON); mapi_set_size_header(mid, true); mapi_reconnect(mid); } diff --git a/clients/odbc/driver/SQLEndTran.c b/clients/odbc/driver/SQLEndTran.c --- a/clients/odbc/driver/SQLEndTran.c +++ b/clients/odbc/driver/SQLEndTran.c @@ -119,7 +119,7 @@ MNDBEndTran(SQLSMALLINT HandleType, assert(HandleType == SQL_HANDLE_DBC); - if (dbc->sql_attr_autocommit == SQL_AUTOCOMMIT_ON) { + if (msetting_bool(dbc->settings, MP_AUTOCOMMIT)) { /* nothing to do if in autocommit mode */ return SQL_SUCCESS; } diff --git a/clients/odbc/driver/SQLGetConnectAttr.c b/clients/odbc/driver/SQLGetConnectAttr.c --- a/clients/odbc/driver/SQLGetConnectAttr.c +++ b/clients/odbc/driver/SQLGetConnectAttr.c @@ -64,7 +64,8 @@ MNDBGetConnectAttr(ODBCDbc *dbc, break; case SQL_ATTR_AUTOCOMMIT: /* SQLUINTEGER */ /* SQL_AUTOCOMMIT */ - WriteData(ValuePtr, dbc->sql_attr_autocommit, SQLUINTEGER); + bool autocommit = msetting_bool(dbc->settings, MP_AUTOCOMMIT); + WriteData(ValuePtr, autocommit, SQLUINTEGER); break; case SQL_ATTR_CONNECTION_DEAD: /* SQLUINTEGER */ WriteData(ValuePtr, dbc->mid && mapi_is_connected(dbc->mid) ? SQL_CD_FALSE : SQL_CD_TRUE, SQLUINTEGER); diff --git a/clients/odbc/driver/SQLSetConnectAttr.c b/clients/odbc/driver/SQLSetConnectAttr.c --- a/clients/odbc/driver/SQLSetConnectAttr.c +++ b/clients/odbc/driver/SQLSetConnectAttr.c @@ -47,13 +47,12 @@ MNDBSetConnectAttr(ODBCDbc *dbc, switch ((SQLUINTEGER) (uintptr_t) ValuePtr) { case SQL_AUTOCOMMIT_ON: case SQL_AUTOCOMMIT_OFF: - dbc->sql_attr_autocommit = (SQLUINTEGER) (uintptr_t) ValuePtr; + bool autocommit = (bool) (SQLUINTEGER) (uintptr_t) ValuePtr; #ifdef ODBCDEBUG - ODBCLOG("SQLSetConnectAttr set autocommit %s\n", - dbc->sql_attr_autocommit == SQL_AUTOCOMMIT_ON ? "on" : "off"); + ODBCLOG("SQLSetConnectAttr set autocommit %s\n", autocommit ? "on" : "off"); #endif if (dbc->mid) - mapi_setAutocommit(dbc->mid, dbc->sql_attr_autocommit == SQL_AUTOCOMMIT_ON); + mapi_setAutocommit(dbc->mid, autocommit); break; default: /* Invalid attribute value */ diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -179,6 +179,29 @@ ex = Execution('-0', '-d', f'DSN={dsn}-W ex.expect('OK') ex.end() +# test autocommit
MonetDB: Aug2024 - Include line numbers in -v output
Changeset: 2cc634740180 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/2cc634740180 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Include line numbers in -v output diffs (59 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -51,7 +51,10 @@ static int do_listdrivers(void); static int do_listdsns(const char *prefix, SQLSMALLINT dir); static int do_execute_stmt(void); -static void ensure_ok(SQLSMALLINT type, SQLHANDLE handle, const char *message, SQLRETURN ret); + +static void ensure_ok_impl(SQLSMALLINT type, SQLHANDLE handle, const char *message, SQLRETURN ret, int lineno); + +#define ensure_ok(type, handle, message, ret)ensure_ok_impl(type, handle, message, ret, __LINE__) #define MARGIN 100 static SQLCHAR* sqldup_with_margin(const char *str); @@ -167,14 +170,23 @@ end: static void -ensure_ok(SQLSMALLINT type, SQLHANDLE handle, const char *message, SQLRETURN ret) +ensure_ok_impl(SQLSMALLINT type, SQLHANDLE handle, const char *message, SQLRETURN ret, int lineno) { + static const char *filename = NULL; + if (!filename) { + filename = __FILE__; + for (const char *p = filename; *p; p++) { + if (*p == '/' || *p == '\\') + filename = p + 1; + } + } + char *class = "Info"; switch (ret) { case SQL_SUCCESS: case SQL_NEED_DATA: if (verbose) - printf("Succeeded: %s\n", message); + printf(" Succeeded: %s (%s:%d)\n", message, filename, lineno); break; case SQL_SUCCESS_WITH_INFO: class = "Warning"; @@ -183,7 +195,7 @@ ensure_ok(SQLSMALLINT type, SQLHANDLE ha class = "Error"; break; default: - printf("Internal error: %s: unknown SQLRETURN %d", message, ret); + printf("Internal error: %s (%s:%d): unknown SQLRETURN %d", message, filename, lineno, ret); break; } @@ -200,7 +212,7 @@ ensure_ok(SQLSMALLINT type, SQLHANDLE ha if (!SQL_SUCCEEDED(diag_ret)) break; if (class) { - printf("%s: %s\n", class, message); + printf("%s: %s (%s:%d)\n", class, message, filename, lineno); class = NULL; } printf("- %s: %s\n", state, explanation); ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Add option to execute a sql statement after c...
Changeset: f552db6c983d for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f552db6c983d Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Add option to execute a sql statement after connecting diffs (193 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -34,21 +34,23 @@ static const char *USAGE = "-l List registered drivers and data sources\n" "-u USER\n" "-p PASSWORD\n" + "-q SQL Execute SQL statement when connection succeeds\n" "-0 use counted strings rather than nul-terminated arguments\n" "-v Be verbose\n" "TARGET DSN or with -d and -b, Connection String\n"; typedef int (action_t)(SQLCHAR *); -static int do_actions(action_t action, int ntargets, SQLCHAR **targets); - static action_t do_sqlconnect; static action_t do_sqldriverconnect; static action_t do_sqlbrowseconnect; +static int do_actions(action_t action, int ntargets, SQLCHAR **targets); + static int do_listdrivers(void); static int do_listdsns(const char *prefix, SQLSMALLINT dir); +static int do_execute_stmt(void); static void ensure_ok(SQLSMALLINT type, SQLHANDLE handle, const char *message, SQLRETURN ret); #define MARGIN 100 @@ -60,10 +62,13 @@ SQLCHAR *user = NULL; SQLSMALLINT user_len = SQL_NTS; SQLCHAR *password = NULL; SQLSMALLINT password_len = SQL_NTS; +SQLCHAR *query = NULL; +SQLSMALLINT query_len = SQL_NTS; bool use_counted_strings = false; SQLHANDLE env = NULL; SQLHANDLE conn = NULL; +SQLHANDLE stmt = NULL; SQLCHAR outbuf[4096]; SQLCHAR attrbuf[4096]; @@ -73,6 +78,9 @@ cleanup(void) { free(user); free(password); + free(query); + if (stmt) + SQLFreeHandle(SQL_HANDLE_STMT, stmt); if (conn) { SQLDisconnect(conn); SQLFreeHandle(SQL_HANDLE_DBC, conn); @@ -102,6 +110,8 @@ main(int argc, char **argv) user = sqldup_with_margin(argv[++i]); else if (strcmp(arg, "-p") == 0 && i + 1 < argc) password = sqldup_with_margin(argv[++i]); + else if (strcmp(arg, "-q") == 0 && i + 1 < argc) + query = sqldup_with_margin(argv[++i]); else if (strcmp(arg, "-0") == 0) use_counted_strings = true; else if (strcmp(arg, "-v") == 0) @@ -159,7 +169,6 @@ end: static void ensure_ok(SQLSMALLINT type, SQLHANDLE handle, const char *message, SQLRETURN ret) { - char *class = "Info"; switch (ret) { case SQL_SUCCESS: @@ -241,11 +250,13 @@ do_sqlconnect(SQLCHAR *target) SQLConnect(conn, target, target_len, user, user_len, password, password_len)); printf("OK\n"); + int exitcode = do_execute_stmt(); + ensure_ok( - SQL_HANDLE_DBC, conn, "Banana", + SQL_HANDLE_DBC, conn, "SQLDisconnect", SQLDisconnect(conn)); - return 0; + return exitcode; } static int @@ -267,11 +278,13 @@ do_sqldriverconnect(SQLCHAR *target) printf("OK %s\n", outbuf); + int exitcode = do_execute_stmt(); + ensure_ok( - SQL_HANDLE_DBC, conn, "Banana", + SQL_HANDLE_DBC, conn, "SQLDisconnect", SQLDisconnect(conn)); - return 0; + return exitcode; } static int @@ -293,10 +306,15 @@ do_sqlbrowseconnect(SQLCHAR *target) outbuf ); + int exitcode = 0; + if (ret != SQL_NEED_DATA) + exitcode = do_execute_stmt(); + + // Do not call SQLDisconnect, SQLBrowseConnect is intended to // be invoked multiple times without disconnecting inbetween - return 0; + return exitcode; } static int @@ -353,6 +371,64 @@ do_listdsns(const char *prefix, SQLSMALL } +static int +do_execute_stmt(void) +{ + if (query == NULL) + return 0; + + if (verbose) + printf("Statement: %s\n", query); + + if (use_counted_strings) + fuzz_sql_nts(&query, &query_len); + + ensure_ok( + SQL_HANDLE_ENV, conn, "allocate stmt handle", + SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt)); + + ensure_ok( + SQL_HANDLE_STMT, stmt, "SQLExecDirect", + SQLExecDirect(stmt, query, query_len)); + + do { + SQLLEN rowcount = -1; + SQLSMALLINT colcount = -1; + + ensure_ok( + SQL_HANDLE_STMT, stmt, "SQLRowCount", + SQLRowCount(stmt, &rowcount)); + + ensure_ok( + SQL_HANDLE_STMT, stmt, "SQLNumResultCols", + SQL
MonetDB: Aug2024 - Show errors that do not set any diagnostics
Changeset: 3da6dc78a5f8 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/3da6dc78a5f8 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Show errors that do not set any diagnostics diffs (26 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -183,6 +183,7 @@ ensure_ok(SQLSMALLINT type, SQLHANDLE ha SQLCHAR explanation[256]; SQLSMALLINT len; + bool printed_something = false; for (int i = 1; ; i++) { SQLRETURN diag_ret = SQLGetDiagRec( type, handle, i, @@ -194,9 +195,14 @@ ensure_ok(SQLSMALLINT type, SQLHANDLE ha class = NULL; } printf("- %s: %s\n", state, explanation); + printed_something = true; } if (!SQL_SUCCEEDED(ret) && ret != SQL_NEED_DATA) { + if (!printed_something) { + printf("%s: %s\n", class, message); + printf("- failed without explanation\n"); + } cleanup(); exit(1); } ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Close connection handles after use
Changeset: 62dcc4c2 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/62dcc4c2 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Close connection handles after use diffs (55 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -71,6 +71,8 @@ SQLCHAR attrbuf[4096]; static void cleanup(void) { + free(user); + free(password); if (conn) { SQLDisconnect(conn); SQLFreeHandle(SQL_HANDLE_DBC, conn); @@ -145,8 +147,6 @@ main(int argc, char **argv) } end: - free(user); - free(password); for (int i = 0; i < ntargets; i++) free(targets[i]); free(targets); @@ -235,6 +235,10 @@ do_sqlconnect(SQLCHAR *target) SQLConnect(conn, target, target_len, user, user_len, password, password_len)); printf("OK\n"); + ensure_ok( + SQL_HANDLE_DBC, conn, "Banana", + SQLDisconnect(conn)); + return 0; } @@ -256,6 +260,11 @@ do_sqldriverconnect(SQLCHAR *target) )); printf("OK %s\n", outbuf); + + ensure_ok( + SQL_HANDLE_DBC, conn, "Banana", + SQLDisconnect(conn)); + return 0; } @@ -277,6 +286,10 @@ do_sqlbrowseconnect(SQLCHAR *target) ret == SQL_NEED_DATA ? "BROWSE" : "OK", outbuf ); + + // Do not call SQLDisconnect, SQLBrowseConnect is intended to + // be invoked multiple times without disconnecting inbetween + return 0; } ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Add tests for SQLBrowseConnect
Changeset: c2718b187150 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/c2718b187150 Modified Files: sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Add tests for SQLBrowseConnect diffs (77 lines): diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -56,7 +56,10 @@ class Execution: if self.checks: parts.append('--- test history: ---') for wanted, found in self.checks: -parts.append(f'wanted {wanted!r}, found {found!r}') +if len(wanted) == 1: +parts.append(f'wanted {wanted[0]!r}, found {found!r}') +else: +parts.append(f'wanted all of {wanted!r}, found {found!r}') parts.append('--- end ---') if self.remaining: parts += [ @@ -66,11 +69,13 @@ class Execution: ] return '\n'.join(parts) -def expect(self, pattern): +def expect(self, pattern, *more_patterns): +patterns = [pattern, *more_patterns] line = self.next_line() -self.checks.append((pattern, line)) -if pattern not in line: -raise Exception(f'Wanted {pattern!r}, found {line!r}') +self.checks.append((patterns, line)) +for p in patterns: +if p not in line: +raise Exception(f'Wanted {p!r}, found {line!r}') def next_line(self): if not self.remaining: @@ -169,4 +174,43 @@ ex = Execution('-d', f'DRIVER={{MonetDB} ex.expect('OK') ex.end() +# non-NUL terminated connection string +ex = Execution('-0', '-d', f'DSN={dsn}-Wrong;Database={dbname};Uid={user};Pwd={password}') +ex.expect('OK') +ex.end() + +# Test browsing + +ex = Execution('-b', 'Driver={MonetDB}') +ex.expect('Info') +ex.expect('08001') +# browse not complete, uid and pwd mandatory, database optional +ex.expect('BROWSE', 'UID:User=?', 'PWD:Password=?', '*DATABASE') +ex.end() + +# same as above, but with another iteration of browsing +ex = Execution('-b', 'Driver={MonetDB}', f'Driver={{MonetDB}};UID={user};PWD={password};Port={port}') +# first iteration +ex.expect('Info') +ex.expect('08001') +ex.expect('BROWSE', 'UID:User=?', 'PWD:Password=?', '*DATABASE') +# second iteration +ex.expect('OK', ';', 'HOST=') +ex.end() + +# similar to above, but not NUL-terminated +ex = Execution('-0', '-b', 'Driver={MonetDB}') +ex.expect('Info') +ex.expect('08001') +# browse not complete, uid and pwd mandatory, database optional +ex.expect('BROWSE', 'UID:User=?', 'PWD:Password=?', '*DATABASE') +ex.end() + +# it should also work when the user and password are in the dsn +ex = Execution('-b', f'DSN={dsn}') +ex.expect('OK', ';') +ex.end() + +# clear 'ex', otherwise the atexit handler will write things +# to stderr ex = None ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Mtest: set ODBCSYSINI instead of ODBCINI
Changeset: 766bdabd4d7c for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/766bdabd4d7c Modified Files: testing/Mtest.py.in Branch: Aug2024 Log Message: Mtest: set ODBCSYSINI instead of ODBCINI And split odbc.ini into odbc.ini and odbcinst.ini This insulates Mtest's odbc setup from whatever else is going on in the system. odbc.ini can now just set Driver=MonetDB and does not need any file system paths diffs (64 lines): diff --git a/testing/Mtest.py.in b/testing/Mtest.py.in --- a/testing/Mtest.py.in +++ b/testing/Mtest.py.in @@ -2215,12 +2215,18 @@ def RunTest(env, TST, COND, oktests, len f.close() if odbc: -f = openutf8('odbc.ini', 'w') -f.write(f'''\ -[MonetDB-Test] +with openutf8('odbcinst.ini', 'w') as f: +f.write(f'''\ +[MonetDB] Description = Test MonetDB Data Source Driver = {env["LIBDIR"]}/libMonetODBC.so Setup = {env["LIBDIR"]}/libMonetODBCs.so +''') +with openutf8('odbc.ini', 'w') as f: +f.write(f'''\ +[MonetDB-Test] +Description = Test MonetDB Data Source +Driver = MonetDB Host = localhost Port = {env["MAPIPORT"]} Database = {TSTDB} @@ -2230,16 +2236,17 @@ Debug = [MonetDB-Test-Wrong] Description = Wrong values for Database, Uid and Pwd -Driver = {env["LIBDIR"]}/libMonetODBC.so -Setup = {env["LIBDIR"]}/libMonetODBCs.so +Driver = MonetDB Host = localhost Port = {env["MAPIPORT"]} Database = {TSTDB}-Wrong User = {user or "monetdb"}-Wrong Password = {passwd or "monetdb"}-Wrong ''') -f.close() -os.environ['ODBCINI'] = os.path.join(TSTTRGDIR, 'odbc.ini') +orig_odbcsysini = os.environ.pop('ODBCSYSINI', None) +orig_odbcini = os.environ.pop('ODBCINI', None) +orig_odbcinstini = os.environ.pop('ODBCINSTINI', None) +os.environ['ODBCSYSINI'] = TSTTRGDIR STABLEout,STABLEerr = StableOutErr(env,par,TST,SYST,RELEASE,DIST,VERSION) TIMEOUT = par['TIMEOUT'] @@ -2268,7 +2275,15 @@ Password = {passwd or "monetdb"}-Wrong print(" %7.3fs " % TX, end='') if odbc: -del os.environ['ODBCINI'] +if orig_odbcsysini is not None: +os.environ['ODBCSYSINI'] = orig_odbcsysini +else: +del os.environ['ODBCSYSINI'] +if orig_odbcini is not None: +os.environ['ODBCINI'] = orig_odbcini +if orig_odbcinstini is not None: +os.environ['ODBCINSTINI'] = orig_odbcinstini + if tres == 'timeout': errcode = F_TIME ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Test SQLDriverConnect
Changeset: 7e379cfaffaf for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/7e379cfaffaf Modified Files: sql/odbc/tests/Tests/ODBCconnect.py testing/Mtest.py.in Branch: Aug2024 Log Message: Test SQLDriverConnect diffs (121 lines): diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -14,9 +14,16 @@ # sqlstate lines of the form '- STATE: MESSAGE'. import atexit +import os import subprocess import sys +dsn = 'MonetDB-Test' +dbname = os.environ.get('TSTDB', 'demo') +user = 'monetdb' +password = 'monetdb' +port = os.environ.get('MAPIPORT', 5) + class Execution: def __init__(self, *odbcconnect_args): @@ -97,38 +104,35 @@ def show_context(): print(ex.report(), file=sys.stderr) -dbname = 'MonetDB-Test' - - -ex = Execution(dbname) +ex = Execution(dsn) ex.expect('OK') ex.end() -ex = Execution(dbname + '-nonexistent') +ex = Execution(dsn + '-nonexistent') ex.expect_fail() ex.expect('Error') ex.expect('IM002:') # IM002 not found ex.end() -ex = Execution(dbname, '-p', 'wrongpassword') +ex = Execution(dsn, '-p', 'wrongpassword') ex.expect_fail() ex.expect('Error') ex.expect('28000:') # 28000 bad credentials ex.end() -ex = Execution(dbname, '-u', 'wronguser') +ex = Execution(dsn, '-u', 'wronguser') ex.expect_fail() ex.expect('Error') ex.expect('28000:') # 28000 bad credentials ex.end() -ex = Execution(dbname, '-p', '') +ex = Execution(dsn, '-p', '') ex.expect_fail() ex.expect('Error') ex.expect('28000:') # 28000 bad credentials ex.end() -ex = Execution(dbname, '-u', '') +ex = Execution(dsn, '-u', '') ex.expect_fail() ex.expect('Error') ex.expect('28000:') # 28000 bad credentials @@ -136,13 +140,33 @@ ex.end() # test non-NUL terminated strings -ex = Execution(dbname, '-0') +ex = Execution(dsn, '-0') +ex.expect('OK') +ex.end() + +ex = Execution(dsn, '-0', '-u', user, '-p', password) +ex.expect('OK') +ex.end() + +# test connection strings + +ex = Execution('-d', f'DSN={dsn}') ex.expect('OK') ex.end() -ex = Execution(dbname, '-0', '-u', 'monetdb', '-p', 'monetdb') +# override things that are already set in the dsn +ex = Execution('-d', f'DSN={dsn}-Wrong;Database={dbname};Uid={user};Pwd={password}') ex.expect('OK') ex.end() +# .. even if the DSN= comes last +ex = Execution('-d', f'Database={dbname};Uid={user};Pwd={password};DSN={dsn}-Wrong') +ex.expect('OK') +ex.end() + +# test without DSN= clause +ex = Execution('-d', f'DRIVER={{MonetDB}};Database={dbname};Uid={user};Pwd={password};Port={port}') +ex.expect('OK') +ex.end() ex = None diff --git a/testing/Mtest.py.in b/testing/Mtest.py.in --- a/testing/Mtest.py.in +++ b/testing/Mtest.py.in @@ -2227,6 +2227,16 @@ Database = {TSTDB} User = {user or "monetdb"} Password = {passwd or "monetdb"} Debug = + +[MonetDB-Test-Wrong] +Description = Wrong values for Database, Uid and Pwd +Driver = {env["LIBDIR"]}/libMonetODBC.so +Setup = {env["LIBDIR"]}/libMonetODBCs.so +Host = localhost +Port = {env["MAPIPORT"]} +Database = {TSTDB}-Wrong +User = {user or "monetdb"}-Wrong +Password = {passwd or "monetdb"}-Wrong ''') f.close() os.environ['ODBCINI'] = os.path.join(TSTTRGDIR, 'odbc.ini') ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Copy data, not the pointer
Changeset: 7177f1898fe2 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/7177f1898fe2 Modified Files: clients/odbc/driver/SQLConnect.c Branch: Aug2024 Log Message: Copy data, not the pointer diffs (12 lines): diff --git a/clients/odbc/driver/SQLConnect.c b/clients/odbc/driver/SQLConnect.c --- a/clients/odbc/driver/SQLConnect.c +++ b/clients/odbc/driver/SQLConnect.c @@ -121,7 +121,7 @@ makeNulTerminated(const SQLCHAR **argume SQLCHAR *value = malloc(argument_len + 1); if (value == NULL) return false; - memmove(value, argument, argument_len); + memmove(value, *argument, argument_len); value[argument_len] = '\0'; *argument = value; ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Test non-NUL-terminated arguments
Changeset: 55b7f9555245 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/55b7f9555245 Modified Files: clients/odbc/tests/odbcconnect.c sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Test non-NUL-terminated arguments diffs (172 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -17,6 +17,7 @@ #endif #include +#include #include #include #include @@ -33,6 +34,7 @@ static const char *USAGE = "-l List registered drivers and data sources\n" "-u USER\n" "-p PASSWORD\n" + "-0 use counted strings rather than nul-terminated arguments\n" "-v Be verbose\n" "TARGET DSN or with -d and -b, Connection String\n"; @@ -49,10 +51,16 @@ static int do_listdsns(const char *prefi static void ensure_ok(SQLSMALLINT type, SQLHANDLE handle, const char *message, SQLRETURN ret); +#define MARGIN 100 +static SQLCHAR* sqldup_with_margin(const char *str); +static void fuzz_sql_nts(SQLCHAR **str, SQLSMALLINT *len); int verbose = 0; SQLCHAR *user = NULL; +SQLSMALLINT user_len = SQL_NTS; SQLCHAR *password = NULL; +SQLSMALLINT password_len = SQL_NTS; +bool use_counted_strings = false; SQLHANDLE env = NULL; SQLHANDLE conn = NULL; @@ -89,13 +97,15 @@ main(int argc, char **argv) else if (strcmp(arg, "-l") == 0) action = NULL; else if (strcmp(arg, "-u") == 0 && i + 1 < argc) - user = (SQLCHAR*)argv[++i]; + user = sqldup_with_margin(argv[++i]); else if (strcmp(arg, "-p") == 0 && i + 1 < argc) - password = (SQLCHAR*)argv[++i]; + password = sqldup_with_margin(argv[++i]); + else if (strcmp(arg, "-0") == 0) + use_counted_strings = true; else if (strcmp(arg, "-v") == 0) verbose += 1; else if (arg[0] != '-') - targets[ntargets++] = (SQLCHAR*)arg; + targets[ntargets++] = sqldup_with_margin(arg); else { fprintf(stderr, "\nERROR: invalid argument: %s\n%s", arg, USAGE); ret = 1; @@ -111,6 +121,11 @@ main(int argc, char **argv) SQL_HANDLE_ENV, env, "set odbc version", SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0)); + if (use_counted_strings) { + fuzz_sql_nts(&user, &user_len); + fuzz_sql_nts(&password, &password_len); + } + if (action) { if (ntargets == 0) { fprintf(stderr, "\nERROR: pass at least one target\n%s", USAGE); @@ -130,6 +145,10 @@ main(int argc, char **argv) } end: + free(user); + free(password); + for (int i = 0; i < ntargets; i++) + free(targets[i]); free(targets); cleanup(); @@ -207,9 +226,13 @@ do_actions(action_t action, int ntargets static int do_sqlconnect(SQLCHAR *target) { + SQLSMALLINT target_len = SQL_NTS; + if (use_counted_strings) + fuzz_sql_nts(&target, &target_len); + ensure_ok( SQL_HANDLE_DBC, conn, "SQLConnect", - SQLConnect(conn, target, SQL_NTS, user, SQL_NTS, password, SQL_NTS)); + SQLConnect(conn, target, target_len, user, user_len, password, password_len)); printf("OK\n"); return 0; @@ -219,11 +242,15 @@ static int do_sqldriverconnect(SQLCHAR *target) { SQLSMALLINT n; + SQLSMALLINT target_len = SQL_NTS; + if (use_counted_strings) + fuzz_sql_nts(&target, &target_len); + ensure_ok( SQL_HANDLE_DBC, conn, "SQLDriverConnect", SQLDriverConnect( conn, NULL, - target, SQL_NTS, + target, target_len, outbuf, sizeof(outbuf), &n, SQL_DRIVER_NOPROMPT )); @@ -236,9 +263,13 @@ static int do_sqlbrowseconnect(SQLCHAR *target) { SQLSMALLINT n; + SQLSMALLINT target_len = SQL_NTS; + if (use_counted_strings) + fuzz_sql_nts(&target, &target_len); + SQLRETURN ret = SQLBrowseConnect( conn, - target, SQL_NTS, + target, target_len, outbuf, sizeof(outbuf), &n ); ensure_ok(SQL_HANDLE_DBC, conn, "SQLBrowseConnect", ret); @@ -302,3 +333,27 @@ do_listdsns(const char *prefix, SQLSMALL return 0; } + +static SQLCHAR* +sqldup_with_margin(const char *str) +{ + size_t len = strlen(str); + char *buf = malloc(len + MARGIN); +
MonetDB: Aug2024 - Fix diagnostic in streamcat
Changeset: f20799ff6a30 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f20799ff6a30 Modified Files: clients/examples/C/streamcat.c Branch: Aug2024 Log Message: Fix diagnostic in streamcat diffs (12 lines): diff --git a/clients/examples/C/streamcat.c b/clients/examples/C/streamcat.c --- a/clients/examples/C/streamcat.c +++ b/clients/examples/C/streamcat.c @@ -422,7 +422,7 @@ opener_rstream(char *filename) { stream *s = open_rstream(filename); if (!mnstr_isbinary(s)) - croak(2, "open_rastream returned binary stream"); + croak(2, "open_rstream returned text stream"); return s; } ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Merge with 'Dec2023'
Changeset: a9ca51334e01 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/a9ca51334e01 Modified Files: sql/backends/monet5/vaults/csv/csv.c sql/test/BugTracker-2024/Tests/All sql/test/copy/Tests/All Branch: Aug2024 Log Message: Merge with 'Dec2023' diffs (118 lines): diff --git a/sql/backends/monet5/vaults/csv/csv.c b/sql/backends/monet5/vaults/csv/csv.c --- a/sql/backends/monet5/vaults/csv/csv.c +++ b/sql/backends/monet5/vaults/csv/csv.c @@ -45,6 +45,7 @@ next_delim(const char *s, const char *e, return s; } if (s <= e) + if (s <= e) return s; return NULL; } diff --git a/sql/test/BugTracker-2024/Tests/7542-column-name-resolution.test b/sql/test/BugTracker-2024/Tests/7542-column-name-resolution.test new file mode 100644 --- /dev/null +++ b/sql/test/BugTracker-2024/Tests/7542-column-name-resolution.test @@ -0,0 +1,13 @@ + +-- https://github.com/MonetDB/MonetDB/issues/7542 + +query I nosort +WITH "E" AS ( SELECT 2 AS "F" ) + SELECT 3 AS "Z" FROM ( +SELECT "B"."X" FROM ( SELECT 2 AS "Y" FROM "E" ) AS "A" +LEFT OUTER JOIN ( SELECT 2 AS "X" ) AS "B" ON 1 = 1 + ) AS "C" + ORDER BY "Z" DESC LIMIT 1 + +3 + diff --git a/sql/test/BugTracker-2024/Tests/All b/sql/test/BugTracker-2024/Tests/All --- a/sql/test/BugTracker-2024/Tests/All +++ b/sql/test/BugTracker-2024/Tests/All @@ -68,3 +68,4 @@ 7539-is-distinct-from 7537-prepare_stmt_with_dropped_table 7536-mclient-forgets-to-flush 7541-levenshtein +7542-column-name-resolution diff --git a/sql/test/copy/Tests/All b/sql/test/copy/Tests/All --- a/sql/test/copy/Tests/All +++ b/sql/test/copy/Tests/All @@ -17,3 +17,4 @@ columns no_escape no_escape2 crlf_normalization +select-from-file diff --git a/sql/test/copy/Tests/aapnootmies.csv b/sql/test/copy/Tests/aapnootmies.csv new file mode 100644 --- /dev/null +++ b/sql/test/copy/Tests/aapnootmies.csv @@ -0,0 +1,3 @@ +1|aap +2|noot +3|mies diff --git a/sql/test/copy/Tests/select-from-file.test.in b/sql/test/copy/Tests/select-from-file.test.in new file mode 100644 --- /dev/null +++ b/sql/test/copy/Tests/select-from-file.test.in @@ -0,0 +1,60 @@ +query IT rowsort +SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv'; + +1 +aap +2 +noot +3 +mies + +statement ok +DROP TABLE IF EXISTS foo; + +statement ok +CREATE TABLE foo(i INT, t TEXT); + +statement ok +INSERT INTO foo SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv'; + +query IT rowsort +SELECT * FROM foo; + +1 +aap +2 +noot +3 +mies + +query IT nosort +SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv' ORDER BY name_1; + +1 +aap +3 +mies +2 +noot + +query IT nosort +SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv' WHERE name_1 = 'aap'; + +1 +aap + +query IT rowsort +SELECT count(name_0), name_1 FROM R'$TSTSRCDIR/aapnootmies.csv' GROUP BY name_1; + +1 +aap +1 +mies +1 +noot + +query IT nosort +SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv' a WHERE a.name_1 = 'aap'; + +1 +aap ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Dec2023 - Fix broken test
Changeset: 0eb9a0f779bd for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/0eb9a0f779bd Modified Files: sql/test/copy/Tests/select-from-file.test.in Branch: Dec2023 Log Message: Fix broken test diffs (20 lines): diff --git a/sql/test/copy/Tests/select-from-file.test.in b/sql/test/copy/Tests/select-from-file.test.in --- a/sql/test/copy/Tests/select-from-file.test.in +++ b/sql/test/copy/Tests/select-from-file.test.in @@ -44,13 +44,13 @@ 1 aap query IT rowsort -SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv' GROUP BY name_1; +SELECT count(name_0), name_1 FROM R'$TSTSRCDIR/aapnootmies.csv' GROUP BY name_1; 1 aap -3 +1 mies -2 +1 noot query IT nosort ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Dec2023 - Add some tests for SELECT FROM file
Changeset: a66e4659af96 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/a66e4659af96 Added Files: sql/test/copy/Tests/aapnootmies.csv sql/test/copy/Tests/select-from-file.test.in Modified Files: sql/test/copy/Tests/All Branch: Dec2023 Log Message: Add some tests for SELECT FROM file diffs (81 lines): diff --git a/sql/test/copy/Tests/All b/sql/test/copy/Tests/All --- a/sql/test/copy/Tests/All +++ b/sql/test/copy/Tests/All @@ -16,3 +16,4 @@ columns no_escape no_escape2 crlf_normalization +select-from-file diff --git a/sql/test/copy/Tests/aapnootmies.csv b/sql/test/copy/Tests/aapnootmies.csv new file mode 100644 --- /dev/null +++ b/sql/test/copy/Tests/aapnootmies.csv @@ -0,0 +1,3 @@ +1|aap +2|noot +3|mies diff --git a/sql/test/copy/Tests/select-from-file.test.in b/sql/test/copy/Tests/select-from-file.test.in new file mode 100644 --- /dev/null +++ b/sql/test/copy/Tests/select-from-file.test.in @@ -0,0 +1,60 @@ +query IT rowsort +SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv'; + +1 +aap +2 +noot +3 +mies + +statement ok +DROP TABLE IF EXISTS foo; + +statement ok +CREATE TABLE foo(i INT, t TEXT); + +statement ok +INSERT INTO foo SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv'; + +query IT rowsort +SELECT * FROM foo; + +1 +aap +2 +noot +3 +mies + +query IT nosort +SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv' ORDER BY name_1; + +1 +aap +3 +mies +2 +noot + +query IT nosort +SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv' WHERE name_1 = 'aap'; + +1 +aap + +query IT rowsort +SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv' GROUP BY name_1; + +1 +aap +3 +mies +2 +noot + +query IT nosort +SELECT * FROM R'$TSTSRCDIR/aapnootmies.csv' a WHERE a.name_1 = 'aap'; + +1 +aap ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Dec2023 - Add test for #7542
Changeset: 20a2cc3713af for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/20a2cc3713af Added Files: sql/test/BugTracker-2024/Tests/7542-column-name-resolution.test Modified Files: sql/test/BugTracker-2024/Tests/All Branch: Dec2023 Log Message: Add test for #7542 diffs (26 lines): diff --git a/sql/test/BugTracker-2024/Tests/7542-column-name-resolution.test b/sql/test/BugTracker-2024/Tests/7542-column-name-resolution.test new file mode 100644 --- /dev/null +++ b/sql/test/BugTracker-2024/Tests/7542-column-name-resolution.test @@ -0,0 +1,13 @@ + +-- https://github.com/MonetDB/MonetDB/issues/7542 + +query I nosort +WITH "E" AS ( SELECT 2 AS "F" ) + SELECT 3 AS "Z" FROM ( +SELECT "B"."X" FROM ( SELECT 2 AS "Y" FROM "E" ) AS "A" +LEFT OUTER JOIN ( SELECT 2 AS "X" ) AS "B" ON 1 = 1 + ) AS "C" + ORDER BY "Z" DESC LIMIT 1 + +3 + diff --git a/sql/test/BugTracker-2024/Tests/All b/sql/test/BugTracker-2024/Tests/All --- a/sql/test/BugTracker-2024/Tests/All +++ b/sql/test/BugTracker-2024/Tests/All @@ -59,3 +59,4 @@ 7528-jarowinkler-null 7537-prepare_stmt_with_dropped_table 7536-mclient-forgets-to-flush 7541-levenshtein +7542-column-name-resolution ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Remove duplicate test from All-file
Changeset: 2eebb9b68c36 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/2eebb9b68c36 Modified Files: sql/test/BugTracker-2024/Tests/All Branch: Aug2024 Log Message: Remove duplicate test from All-file diffs (11 lines): diff --git a/sql/test/BugTracker-2024/Tests/All b/sql/test/BugTracker-2024/Tests/All --- a/sql/test/BugTracker-2024/Tests/All +++ b/sql/test/BugTracker-2024/Tests/All @@ -63,7 +63,6 @@ 7524-right-outer-join 7528-jarowinkler-null 7534-is-distinct-from 7535-create-view-groupby-func -7536-mclient-forgets-to-flush 7538-reduce-cast 7539-is-distinct-from 7537-prepare_stmt_with_dropped_table ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Add ChangeLog for ClientInfo
Changeset: c0d93ccdd32f for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/c0d93ccdd32f Modified Files: clients/mapilib/ChangeLog.Aug2024 Branch: Aug2024 Log Message: Add ChangeLog for ClientInfo diffs (14 lines): diff --git a/clients/mapilib/ChangeLog.Aug2024 b/clients/mapilib/ChangeLog.Aug2024 --- a/clients/mapilib/ChangeLog.Aug2024 +++ b/clients/mapilib/ChangeLog.Aug2024 @@ -1,3 +1,10 @@ # ChangeLog file for mapilib # This file is updated with Maddlog +* Wed Jun 19 2024 Joeri van Ruth +- Add new columns to sys.sessions. Column 'language' is usually 'sql'. + Column 'peer' is the network address of the client (something like + '[::1]:46558' or ''). Columns 'hostname', 'application', + 'client', 'clientpid' and 'remark' can be set by the client. + Libmapi/mclient, pymonetdb and monetdb-java have been modified to fill + in sensible default values. ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
monetdb-java: default - Add ClientInfo tests
Changeset: 4a5fb9ddee45 for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/4a5fb9ddee45 Modified Files: tests/JDBC_API_Tester.java Branch: default Log Message: Add ClientInfo tests diffs (163 lines): diff --git a/tests/JDBC_API_Tester.java b/tests/JDBC_API_Tester.java --- a/tests/JDBC_API_Tester.java +++ b/tests/JDBC_API_Tester.java @@ -118,6 +118,8 @@ final public class JDBC_API_Tester { jt.Test_SgeneratedKeys(); jt.Test_Smoreresults(); jt.Test_Wrapper(); + if (jt.isPostDec2023) + jt.Test_ClientInfo(con_URL); jt.bogus_auto_generated_keys(); jt.BugConcurrent_clients_SF_1504657(con_URL); jt.BugConcurrent_sequences(con_URL); @@ -1480,10 +1482,12 @@ final public class JDBC_API_Tester { "TABLE_CAT TABLE_SCHEM TABLE_NAME COLUMN_NAME GRANTOR GRANTEE PRIVILEGE IS_GRANTABLE\n" + "char(1)varchar(1024) varchar(1024) varchar(1024) varchar(1024) varchar(1024) varchar(40) varchar(3)\n"); - compareResultSet(dbmd.getClientInfoProperties(), "getClientInfoProperties()", - "Resultset with 4 columns\n" + - "NAME MAX_LEN DEFAULT_VALUE DESCRIPTION\n" + - "varchar(64)int varchar(128) varchar(128)\n"); + if (!isPostDec2023) { + compareResultSet(dbmd.getClientInfoProperties(), "getClientInfoProperties()", + "Resultset with 4 columns\n" + + "NAME MAX_LEN DEFAULT_VALUE DESCRIPTION\n" + + "varchar(64)int varchar(128) varchar(128)\n"); + } compareResultSet(dbmd.getSuperTables(null, "jdbctst", "pk_uc"), "getSuperTables(null, jdbctst, pk_uc)", "Resultset with 4 columns\n" + @@ -7135,6 +7139,133 @@ final public class JDBC_API_Tester { "\n"); } + private void Test_ClientInfo(String con_URL) { + if (!isPostDec2023) + return; + + sb.setLength(0); + + final String[] known = { + "ApplicationName", "ClientHostname", "ClientLibrary", "ClientPid", "ClientRemark" + }; + + try { + sb.append("Connecting\n"); + try (Connection conn = DriverManager.getConnection(con_URL)) { + + // Server metadata includes list of supported clientinfo properties + sb.append("Fetching supported clientinfo properties\n"); + DatabaseMetaData md = conn.getMetaData(); + try (ResultSet rs = md.getClientInfoProperties()) { + HashSet seen = new HashSet<>(); + while (rs.next()) { + String name = rs.getString(1); + if (name == null || name.isEmpty()) { + sb.append("NAME column contains empty string\n"); + } + seen.add(name); + int width = rs.getInt(2); + if (width <= 0) { + sb.append("MAX_LEN for " + name + " is " + width + "\n"); + } + String description = rs.getString(4); + if (description == null || description.isEmpty()) { + sb.append("DESCRIPTION for " + name + " is empty\n"); + } + } + for (String name: known) { + boolean found = seen.contains(name); + sb.append("- " + name + (found ? " was " : " was not ") + "found\n"); + } + } + + // I cannot think of a way to check the default values that doesn't + // essentially duplicate the code that came up with the default values. + // The best we can do is verify they're not empty. + sb.append("Check initial values.\n"); + Properties initi
monetdb-java: default - Implement DatabaseMetaData.getClientInfo...
Changeset: cc6425e98017 for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/cc6425e98017 Modified Files: src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java src/main/java/org/monetdb/mcl/net/ClientInfo.java Branch: default Log Message: Implement DatabaseMetaData.getClientInfoProperties diffs (76 lines): diff --git a/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java b/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java --- a/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java +++ b/src/main/java/org/monetdb/jdbc/MonetDatabaseMetaData.java @@ -12,6 +12,8 @@ package org.monetdb.jdbc; +import org.monetdb.mcl.net.ClientInfo; + import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.Statement; @@ -3917,17 +3919,36 @@ public final class MonetDatabaseMetaData */ @Override public ResultSet getClientInfoProperties() throws SQLException { - // MonetDB currently does not support any client properties, so return an empty ResultSet + // This query combines the properties we know about with any additional properties that + // may have been added to sys.clientinfo_properties in the mean time. final String query = - "SELECT cast(null as varchar(64)) AS \"NAME\", " + - "cast(0 as int) AS \"MAX_LEN\", " + - "cast(null as varchar(128)) AS \"DEFAULT_VALUE\", " + - "cast(null as varchar(128)) AS \"DESCRIPTION\" " + - "WHERE 1=0"; + "WITH jdbc_info AS (\n" + + "SELECT 'ApplicationName' AS \"NAME\", NULL AS \"MAX_LEN\", " + stringEscape(ClientInfo.defaultApplicationName) + " AS \"DEFAULT_VALUE\", 'Name of the application' AS \"DESCRIPTION\", 0 AS i\n" + + "UNION ALL\n" + + "SELECT 'ClientHostname' AS \"NAME\", NULL AS \"MAX_LEN\", " + stringEscape(ClientInfo.defaultHostname) + " AS \"DEFAULT_VALUE\", 'Host the application is running on' AS \"DESCRIPTION\", 1 AS i\n" + + "UNION ALL\n" + + "SELECT 'ClientRemark' AS \"NAME\", 256 AS \"MAX_LEN\", R'' AS \"DEFAULT_VALUE\", 'Additional information' AS \"DESCRIPTION\", 2 AS i\n" + + "UNION ALL\n" + + "SELECT 'ClientLibrary' AS \"NAME\", NULL AS \"MAX_LEN\", " + stringEscape(ClientInfo.defaultClientLibrary) + " AS \"DEFAULT_VALUE\", 'Name and version of the driver' AS \"DESCRIPTION\", 3 AS i\n" + + "UNION ALL\n" + + "SELECT 'ClientPid' AS \"NAME\", 10 AS \"MAX_LEN\", " + stringEscape(ClientInfo.defaultPid) + " AS \"DEFAULT_VALUE\", 'Process id of the application' AS \"DESCRIPTION\", 4 AS i\n" + + ")\n" + + "SELECT\n" + + "prop AS \"NAME\",\n" + + "COALESCE(\"MAX_LEN\", 24) AS \"MAX_LEN\",\n" + + "\"DEFAULT_VALUE\",\n" + + "\"DESCRIPTION\"\n" + + "FROM sys.clientinfo_properties AS sys_info LEFT OUTER JOIN jdbc_info ON prop = \"NAME\"\n" + + "ORDER BY COALESCE(i, 1000), \"NAME\"\n" + ; return executeMetaDataQuery(query); } + private static String stringEscape(String s) { + return "R'" + s.replaceAll("'", "''") + "'"; + } + /** * Retrieves a description of the system and user functions * available in the given catalog. diff --git a/src/main/java/org/monetdb/mcl/net/ClientInfo.java b/src/main/java/org/monetdb/mcl/net/ClientInfo.java --- a/src/main/java/org/monetdb/mcl/net/ClientInfo.java +++ b/src/main/java/org/monetdb/mcl/net/ClientInfo.java @@ -21,13 +21,13 @@ import java.util.Set; * @{link SQLClientInfoException} if there is a failure */ public class ClientInfo { - private static final String defaultHostname = findHostname(); + public static final String defaultHostname = findHostname(); - private static final String defaultClientLibrary = findClientLibrary(); + public static final String defaultClientLibrary = findClientLibrary(); - private static final String defaultApplicationName = findApplicationName(); + public static final String defaultApplicationName = findApplicationName(); - private static final String defaultPid = findPid(); + public static final String defaultPid = findPid(); private final Properties props; private HashMap problems = null; ___ checkin-list mailing list -- checkin-list@m
monetdb-java: default - Minor changes to JDBC_API_Tester
Changeset: 9c9a6c0a85f6 for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/9c9a6c0a85f6 Modified Files: tests/JDBC_API_Tester.java Branch: default Log Message: Minor changes to JDBC_API_Tester diffs (96 lines): diff --git a/tests/JDBC_API_Tester.java b/tests/JDBC_API_Tester.java --- a/tests/JDBC_API_Tester.java +++ b/tests/JDBC_API_Tester.java @@ -42,9 +42,9 @@ import org.monetdb.jdbc.types.URL; final public class JDBC_API_Tester { private StringBuilder sb; // buffer to collect the test output private Connection con; // main connection shared by all tests - private int dbmsMajorVersion; - private int dbmsMinorVersion; - private boolean isPostDec2023; // flag to support version specific output + final private int dbmsMajorVersion; + final private int dbmsMinorVersion; + final private boolean isPostDec2023;// flag to support version specific output private boolean foundDifferences = false; final private static int sbInitLen = 5468; @@ -52,8 +52,16 @@ final public class JDBC_API_Tester { /** * constructor */ - JDBC_API_Tester() { + JDBC_API_Tester(Connection con_) throws SQLException { + this.con = con_; sb = new StringBuilder(sbInitLen); + + DatabaseMetaData dbmd = con_.getMetaData(); + dbmsMajorVersion = dbmd.getDatabaseMajorVersion(); + dbmsMinorVersion = dbmd.getDatabaseMinorVersion(); + // from version 11.50 on, the MonetDB server returns different metadata for + // integer digits (1 less) and for clob and char columns (now return varchar). + isPostDec2023 = versionIsAtLeast(11, 50); } /** @@ -67,15 +75,9 @@ final public class JDBC_API_Tester { // Test this before trying to connect UrlTester.runAllTests(); - JDBC_API_Tester jt = new JDBC_API_Tester(); - jt.con = DriverManager.getConnection(con_URL); - // we are now connected - DatabaseMetaData dbmd = jt.con.getMetaData(); - jt.dbmsMajorVersion = dbmd.getDatabaseMajorVersion(); - jt.dbmsMinorVersion = dbmd.getDatabaseMinorVersion(); - // from version 11.50 the MonetDB server returns different metadata for - // integer digits (1 less) and for clob and char columns (now return varchar). - jt.isPostDec2023 = !(jt.dbmsMajorVersion == 11 && jt.dbmsMinorVersion <= 49); + Connection conn = DriverManager.getConnection(con_URL); + JDBC_API_Tester jt = new JDBC_API_Tester(conn); + // run the tests jt.Test_Cautocommit(con_URL); @@ -145,7 +147,7 @@ final public class JDBC_API_Tester { ConnectionTests.runTests(con_URL); // invoke running OnClientTester only on Oct2020 (11.39) or older servers - if (jt.dbmsMajorVersion == 11 && jt.dbmsMinorVersion <= 39) { + if (!jt.versionIsAtLeast(11,40)) { OnClientTester oct = new OnClientTester(con_URL, 0); int failures = oct.runTests(); if (failures > 0) @@ -153,6 +155,10 @@ final public class JDBC_API_Tester { } } + private boolean versionIsAtLeast(int major, int minor) { + return (dbmsMajorVersion > major || (dbmsMajorVersion == major && dbmsMinorVersion >= minor)); + } + private void Test_Cautocommit(String arg0) { sb.setLength(0);// clear the output log buffer @@ -7242,16 +7248,18 @@ final public class JDBC_API_Tester { prodLen = pos + 40; System.err.println("Difference found at line " + line + " position " + rowpos + ". Expected:\n\"" + expected.substring(pos < expLen ? pos : expLen-1, expLen-1) - + "\"\nbut gotten:\n\"" + produced.substring(pos < prodLen ? pos : prodLen-1, prodLen-1) + "\""); + + "\"\nFound:\n\"" + produced.substring(pos < prodLen ? pos : prodLen-1, prodLen-1) + "\""); pos = max_pos; } } } System.err.println(); - System.err.println("Expected:"); + System.err.println(" Full Output: ---"); + System.err.println(sb); + System.err.println(" END --"); + System.err.println(" Expe
monetdb-java: default - Older servers don't have clientinfo_prop...
Changeset: 8c8c423dc619 for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/8c8c423dc619 Modified Files: src/main/java/org/monetdb/jdbc/MonetConnection.java Branch: default Log Message: Older servers don't have clientinfo_properties yet diffs (22 lines): diff --git a/src/main/java/org/monetdb/jdbc/MonetConnection.java b/src/main/java/org/monetdb/jdbc/MonetConnection.java --- a/src/main/java/org/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java @@ -1348,11 +1348,13 @@ public class MonetConnection private HashMap getClientInfoAttributeNames() throws SQLException { if (clientInfoAttributeNames == null) { HashMap map = new HashMap<>(); - try (Statement st = createStatement(); ResultSet rs = st.executeQuery("SELECT prop, session_attr FROM sys.clientinfo_properties")) { - while (rs.next()) { - String jdbcName = rs.getString(1); - String attrName = rs.getString(2); - map.put(jdbcName, attrName); + if (server.canClientInfo()) { + try (Statement st = createStatement(); ResultSet rs = st.executeQuery("SELECT prop, session_attr FROM sys.clientinfo_properties")) { + while (rs.next()) { + String jdbcName = rs.getString(1); + String attrName = rs.getString(2); + map.put(jdbcName, attrName); + } } } clientInfoAttributeNames = map; ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
monetdb-java: default - Implement ClientInfo API
Changeset: a52bc2dcdb8c for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/a52bc2dcdb8c Modified Files: src/main/java/org/monetdb/jdbc/MonetConnection.java src/main/java/org/monetdb/mcl/net/ClientInfo.java src/main/java/org/monetdb/mcl/net/MapiSocket.java src/main/java/org/monetdb/mcl/net/Target.java Branch: default Log Message: Implement ClientInfo API And move ClientInfo out out MapiSocket diffs (truncated from 390 to 300 lines): diff --git a/src/main/java/org/monetdb/jdbc/MonetConnection.java b/src/main/java/org/monetdb/jdbc/MonetConnection.java --- a/src/main/java/org/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java @@ -21,6 +21,7 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; @@ -35,6 +36,7 @@ import java.util.concurrent.Executor; import org.monetdb.mcl.io.BufferedMCLReader; import org.monetdb.mcl.io.BufferedMCLWriter; import org.monetdb.mcl.io.LineType; +import org.monetdb.mcl.net.ClientInfo; import org.monetdb.mcl.net.MapiSocket; import org.monetdb.mcl.net.Target; import org.monetdb.mcl.parser.HeaderLineParser; @@ -118,6 +120,11 @@ public class MonetConnection /** A template to apply to each command (like pre and post fixes), filled in constructor */ private final String[] commandTempl = new String[2]; // pre, post + /** A mapping of ClientInfo property names such as 'ClientHostname' to columns of the +* sessions table, such as 'hostname'. +*/ + private HashMap clientInfoAttributeNames = null; + /** the SQL language */ private static final int LANG_SQL = 0; /** the MAL language (officially *NOT* supported) */ @@ -224,9 +231,16 @@ public class MonetConnection throw sqle; } - // send any clientinfo - if (server.hasClientInfo()) { - sendControlCommand("clientinfo " + server.getClientInfo().format()); + if (server.canClientInfo() && target.sendClientInfo()) { + ClientInfo info = new ClientInfo(); + info.setDefaults(); + String clientApplication = target.getClientApplication(); + String clientRemark = target.getClientRemark(); + if (!clientApplication.isEmpty()) + info.set("ApplicationName", clientApplication); + if (!clientRemark.isEmpty()) + info.set("ClientRemark", clientRemark); + sendClientInfo(info); } // Now take care of any options not handled during the handshake @@ -1270,8 +1284,16 @@ public class MonetConnection */ @Override public String getClientInfo(final String name) throws SQLException { - // MonetDB doesn't support any Client Info Properties yet - return null; + String attrName = getClientInfoAttributeNames().get(name); + if (attrName == null) + return null; + String query = "SELECT " + attrName + " FROM sys.sessions WHERE sessionid = current_sessionid()"; + try (Statement st = createStatement(); ResultSet rs = st.executeQuery(query)) { + if (rs.next()) + return rs.getString(1); + else + return null; + } } /** @@ -1289,7 +1311,53 @@ public class MonetConnection @Override public Properties getClientInfo() throws SQLException { // MonetDB doesn't support any Client Info Properties yet - return new Properties(); + Properties props = new Properties(); + + if (server.canClientInfo()) { + StringBuilder builder = new StringBuilder("SELECT "); + String sep = ""; + for (Entry entry: getClientInfoAttributeNames().entrySet()) { + String jdbcName = entry.getKey(); + String attrName = entry.getValue(); + builder.append(sep); + sep = ", "; + builder.append(attrName); + builder.append(" AS \""); + builder.append(jdbcName); + builder.append("\""); + } + builder.append(" FROM sys.sessions WHERE sessionid = current_sessionid()"); + + try ( +
MonetDB: Aug2024 - Add column 'session_attr' to sys.clientinfo_p...
Changeset: bbc110e2e56a for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/bbc110e2e56a Modified Files: sql/backends/monet5/sql_upgrades.c sql/scripts/22_clients.sql sql/test/emptydb-previous-upgrade-chain-hge/Tests/upgrade.stable.out.int128 sql/test/emptydb-previous-upgrade-chain/Tests/upgrade.stable.out sql/test/emptydb-previous-upgrade-chain/Tests/upgrade.stable.out.int128 sql/test/emptydb-previous-upgrade-hge/Tests/upgrade.stable.out.int128 sql/test/emptydb-previous-upgrade/Tests/upgrade.stable.out sql/test/emptydb-previous-upgrade/Tests/upgrade.stable.out.int128 sql/test/emptydb-upgrade-chain-hge/Tests/upgrade.stable.out.int128 sql/test/emptydb-upgrade-chain/Tests/upgrade.stable.out sql/test/emptydb-upgrade-chain/Tests/upgrade.stable.out.int128 sql/test/emptydb-upgrade-hge/Tests/upgrade.stable.out.int128 sql/test/emptydb-upgrade/Tests/upgrade.stable.out sql/test/emptydb-upgrade/Tests/upgrade.stable.out.int128 sql/test/testdb-previous-upgrade-chain-hge/Tests/upgrade.stable.out.int128 sql/test/testdb-previous-upgrade-chain/Tests/upgrade.stable.out sql/test/testdb-previous-upgrade-chain/Tests/upgrade.stable.out.int128 sql/test/testdb-previous-upgrade-hge/Tests/upgrade.stable.out.int128 sql/test/testdb-previous-upgrade/Tests/upgrade.stable.out sql/test/testdb-previous-upgrade/Tests/upgrade.stable.out.int128 sql/test/testdb-upgrade-chain-hge/Tests/upgrade.stable.out.int128 sql/test/testdb-upgrade-chain/Tests/upgrade.stable.out sql/test/testdb-upgrade-chain/Tests/upgrade.stable.out.int128 sql/test/testdb-upgrade-hge/Tests/upgrade.stable.out.int128 sql/test/testdb-upgrade/Tests/upgrade.stable.out sql/test/testdb-upgrade/Tests/upgrade.stable.out.int128 Branch: Aug2024 Log Message: Add column 'session_attr' to sys.clientinfo_properties So clients can figure out the relationship between the JDBC-style ClientInfo property names used in the MAPI protocol and the corresponding columns of the sessions table. diffs (truncated from 598 to 300 lines): diff --git a/sql/backends/monet5/sql_upgrades.c b/sql/backends/monet5/sql_upgrades.c --- a/sql/backends/monet5/sql_upgrades.c +++ b/sql/backends/monet5/sql_upgrades.c @@ -7101,13 +7101,13 @@ sql_update_aug2024(Client c, mvc *sql, s "create procedure sys.setclientinfo(property string, value string)\n" " external name clients.setinfo;\n" "grant execute on procedure sys.setclientinfo(string, string) to public;\n" - "create table sys.clientinfo_properties(prop string);\n" + "create table sys.clientinfo_properties(prop string, session_attr string);\n" "insert into sys.clientinfo_properties values\n" - " ('ClientHostname'),\n" - " ('ApplicationName'),\n" - " ('ClientLibrary'),\n" - " ('ClientRemark'),\n" - " ('ClientPid');\n" + " ('ClientHostname', 'hostname'),\n" + " ('ApplicationName', 'application'),\n" + " ('ClientLibrary', 'client'),\n" + " ('ClientRemark', 'remark'),\n" + " ('ClientPid', 'clientpid');\n" "update sys.functions set system = true where schema_id = 2000 and name in ('setclientinfo', 'sessions');\n" "update sys._tables set system = true where schema_id = 2000 and name in ('clientinfo_properties', 'sessions');\n"; diff --git a/sql/scripts/22_clients.sql b/sql/scripts/22_clients.sql --- a/sql/scripts/22_clients.sql +++ b/sql/scripts/22_clients.sql @@ -44,13 +44,13 @@ create view sys.sessions as select * fro create procedure sys.setclientinfo(property string, value string) external name clients.setinfo; grant execute on procedure sys.setclientinfo(string, string) to public; -create table sys.clientinfo_properties(prop string); +create table sys.clientinfo_properties(prop string, session_attr string); insert into sys.clientinfo_properties values - ('ClientHostname'), - ('ApplicationName'), - ('ClientLibrary'), - ('ClientRemark'), - ('ClientPid'); + ('ClientHostname', 'hostname'), + ('ApplicationName', 'application'), + ('ClientLibrary', 'client'), +
MonetDB: Aug2024 - Write 'ClientHostname', not 'ClientHostName'
Changeset: e0abc7044ed5 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/e0abc7044ed5 Modified Files: clients/mapilib/connect.c Branch: Aug2024 Log Message: Write 'ClientHostname', not 'ClientHostName' diffs (12 lines): diff --git a/clients/mapilib/connect.c b/clients/mapilib/connect.c --- a/clients/mapilib/connect.c +++ b/clients/mapilib/connect.c @@ -429,7 +429,7 @@ send_all_clientinfo(Mapi mid) size_t pos = 0, cap = 200; if (hostname[0]) - reallocprintf(&buf, &pos, &cap, "ClientHostName=%s\n", hostname); + reallocprintf(&buf, &pos, &cap, "ClientHostname=%s\n", hostname); if (application_name[0]) reallocprintf(&buf, &pos, &cap, "ApplicationName=%s\n", application_name); reallocprintf(&buf, &pos, &cap, "ClientLibrary="); ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Dec2023 - mclient: close redirected output stream befor...
Changeset: ed39e0bf9e67 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/ed39e0bf9e67 Added Files: sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py Modified Files: clients/mapiclient/mclient.c sql/test/BugTracker-2024/Tests/All Branch: Dec2023 Log Message: mclient: close redirected output stream before exiting Fixes #7536 diffs (56 lines): diff --git a/clients/mapiclient/mclient.c b/clients/mapiclient/mclient.c --- a/clients/mapiclient/mclient.c +++ b/clients/mapiclient/mclient.c @@ -3763,6 +3763,8 @@ main(int argc, char **argv) } mapi_destroy(mid); + if (toConsole != stdout_stream && toConsole != stderr_stream) + close_stream(toConsole); mnstr_destroy(stdout_stream); mnstr_destroy(stderr_stream); if (priv.buf != NULL) diff --git a/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py new file mode 100644 --- /dev/null +++ b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py @@ -0,0 +1,31 @@ +import gzip +import os +import tempfile +import subprocess + + +# This SQL script redirects the output to a file (the %s). +# We will check that all output arrives there, even if it's a gzipped file. +SCRIPT = r""" +\>%s +SELECT 'Donald Knuth'; +""" + + +with tempfile.TemporaryDirectory('mtest') as dir: +outputfile = os.path.join(dir, 'output.txt.gz') +inputfile = os.path.join(dir, 'input.sql') + +with open(inputfile, 'w') as f: +f.write(SCRIPT % outputfile) + +subprocess.check_call([ +'mclient', '-i', +'-p', os.environ['MAPIPORT'], +inputfile, +]) + +with gzip.open(outputfile, 'rt', encoding='utf-8') as f: +content = f.read() + +assert 'Donald Knuth' in content diff --git a/sql/test/BugTracker-2024/Tests/All b/sql/test/BugTracker-2024/Tests/All --- a/sql/test/BugTracker-2024/Tests/All +++ b/sql/test/BugTracker-2024/Tests/All @@ -57,3 +57,4 @@ 7512-concurrent-globaltmp-instantiate-cr 7513-uri-authority-parse-issue 7528-jarowinkler-null 7537-prepare_stmt_with_dropped_table +7536-mclient-forgets-to-flush ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
monetdb-java: default - Try to use reasonable defaults for Clien...
Changeset: 2d880f90be2a for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/2d880f90be2a Modified Files: src/main/java/org/monetdb/mcl/net/ClientInfo.java src/main/java/org/monetdb/mcl/net/MapiSocket.java Branch: default Log Message: Try to use reasonable defaults for ClientInfo diffs (97 lines): diff --git a/src/main/java/org/monetdb/mcl/net/ClientInfo.java b/src/main/java/org/monetdb/mcl/net/ClientInfo.java --- a/src/main/java/org/monetdb/mcl/net/ClientInfo.java +++ b/src/main/java/org/monetdb/mcl/net/ClientInfo.java @@ -2,6 +2,11 @@ package org.monetdb.mcl.net; import org.monetdb.jdbc.MonetDriver; +import java.io.File; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.sql.ClientInfoStatus; import java.sql.SQLClientInfoException; import java.util.Collections; @@ -13,7 +18,9 @@ public class ClientInfo { private static final String defaultClientLibrary = findClientLibrary(); - private static final int defaultPid = findPid(); + private static final String defaultApplicationName = findApplicationName(); + + private static final String defaultPid = findPid(); private final Properties props; @@ -21,17 +28,47 @@ public class ClientInfo { props = new Properties(); props.setProperty("ClientHostname", defaultHostname); props.setProperty("ClientLibrary", defaultClientLibrary); - props.setProperty("ClientPid", "" + defaultPid); - props.setProperty("ApplicationName", ""); + props.setProperty("ClientPid", defaultPid); + props.setProperty("ApplicationName", defaultApplicationName); props.setProperty("ClientRemark", ""); } private static String findHostname() { - return "my host"; + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + return ""; + } } - private static int findPid() { - return 42; + private static String findApplicationName() { + String appName = ""; + try { + String prop = System.getProperty("sun.java.command"); + if (prop != null) { + // we want only the command, and not the arguments + prop = prop.split("\\s", 2)[0]; + // keep only the basename5 + int idx = prop.lastIndexOf(File.separatorChar); + if (idx >= 0) + prop = prop.substring(idx + 1); + appName = prop; + } + } catch (SecurityException e) { + // ignore + } + + return appName; + } + + private static String findPid() { + try { + RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean(); + String pidAtHostname = mxbean.getName(); + return pidAtHostname.split("@", 2)[0]; + } catch (RuntimeException e) { + return ""; + } } private static String findClientLibrary() { diff --git a/src/main/java/org/monetdb/mcl/net/MapiSocket.java b/src/main/java/org/monetdb/mcl/net/MapiSocket.java --- a/src/main/java/org/monetdb/mcl/net/MapiSocket.java +++ b/src/main/java/org/monetdb/mcl/net/MapiSocket.java @@ -502,8 +502,12 @@ public final class MapiSocket { if (parts.length > 9 && target.isClientInfo()) { clientInfo = new ClientInfo(); try { - clientInfo.set("ApplicationName", target.getClientApplication()); - clientInfo.set("ClientRemark", target.getClientRemark()); + String clientApplication = target.getClientApplication(); + String clientRemark = target.getClientRemark(); + if (!clientApplication.isEmpty()) + clientInfo.set("ApplicationName", clientApplication); + if (!clientRemark.isEmpty()) + clientInfo.set("ClientRemark", clientRemark); } catch (SQLClientInfoException e) { String keys = String.join(", ", e.getFailedProperties().keySet()); throw new MCLException("Could not set ClientInfo properties: " + keys, e); ___ checkin-list mailing list -- checkin-list@monet
monetdb-java: default - Send ClientInfo on startup
Changeset: 778959b2e0a4 for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/778959b2e0a4 Added Files: src/main/java/org/monetdb/mcl/net/ClientInfo.java Modified Files: src/main/java/org/monetdb/jdbc/MonetConnection.java src/main/java/org/monetdb/mcl/net/MapiSocket.java src/main/java/org/monetdb/mcl/net/Parameter.java src/main/java/org/monetdb/mcl/net/Target.java tests/javaspecific.md Branch: default Log Message: Send ClientInfo on startup Configurable through the client_info=bool, client_application=NAME, client_remark=MESSAGE properties. diffs (271 lines): diff --git a/src/main/java/org/monetdb/jdbc/MonetConnection.java b/src/main/java/org/monetdb/jdbc/MonetConnection.java --- a/src/main/java/org/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java @@ -224,6 +224,11 @@ public class MonetConnection throw sqle; } + // send any clientinfo + if (server.hasClientInfo()) { + sendControlCommand("clientinfo " + server.getClientInfo().format()); + } + // Now take care of any options not handled during the handshake curReplySize = defaultFetchSize; if (lang == LANG_SQL) { diff --git a/src/main/java/org/monetdb/mcl/net/ClientInfo.java b/src/main/java/org/monetdb/mcl/net/ClientInfo.java new file mode 100644 --- /dev/null +++ b/src/main/java/org/monetdb/mcl/net/ClientInfo.java @@ -0,0 +1,74 @@ +package org.monetdb.mcl.net; + +import org.monetdb.jdbc.MonetDriver; + +import java.sql.ClientInfoStatus; +import java.sql.SQLClientInfoException; +import java.util.Collections; +import java.util.Map; +import java.util.Properties; + +public class ClientInfo { + private static final String defaultHostname = findHostname(); + + private static final String defaultClientLibrary = findClientLibrary(); + + private static final int defaultPid = findPid(); + + private final Properties props; + + public ClientInfo() { + props = new Properties(); + props.setProperty("ClientHostname", defaultHostname); + props.setProperty("ClientLibrary", defaultClientLibrary); + props.setProperty("ClientPid", "" + defaultPid); + props.setProperty("ApplicationName", ""); + props.setProperty("ClientRemark", ""); + } + + private static String findHostname() { + return "my host"; + } + + private static int findPid() { + return 42; + } + + private static String findClientLibrary() { + return "monetdb-java " + MonetDriver.getDriverVersion(); + } + + public String format() { + StringBuilder builder = new StringBuilder(200); + for (String name : props.stringPropertyNames()) { + String value = props.getProperty(name); + builder.append(name); + builder.append('='); + builder.append(value); + builder.append('\n'); + } + return builder.toString(); + } + + public Properties get() { + Properties ret = new Properties(); + ret.putAll(props); + return ret; + } + + public boolean set(String name, String value) throws SQLClientInfoException { + if (value == null) + value = ""; + if (value.contains("\n")) { + Map map = Collections.singletonMap(name, ClientInfoStatus.REASON_VALUE_INVALID); + throw new SQLClientInfoException(map); + } + if (props.containsKey(name)) { + props.setProperty(name, value); + return true; + } else { + return false; + } + } + +} diff --git a/src/main/java/org/monetdb/mcl/net/MapiSocket.java b/src/main/java/org/monetdb/mcl/net/MapiSocket.java --- a/src/main/java/org/monetdb/mcl/net/MapiSocket.java +++ b/src/main/java/org/monetdb/mcl/net/MapiSocket.java @@ -25,6 +25,7 @@ import java.net.*; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.sql.SQLClientInfoException; import java.util.*; import javax.net.ssl.SSLException; @@ -117,6 +118,7 @@ public final class MapiSocket { private BufferedMCLWriter writer; /** protocol version of the connection */ private int version; + private ClientInfo clientInfo; /** Whether we should follow redirects. * Not sure why this needs to be separate @@ -497,6 +499,17 @@ public final class MapiSocket { String optionsPart = parts.length > 6 ? parts[6] : null; //
MonetDB: Aug2024 - Extend MAX_MEMORY to accept strings of the fo...
Changeset: 5d0aa8898992 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/5d0aa8898992 Modified Files: clients/mapiclient/mhelp.c sql/ChangeLog.Aug2024 sql/server/sql_parser.y sql/test/Users/Tests/create_user_options.test Branch: Aug2024 Log Message: Extend MAX_MEMORY to accept strings of the form '10MiB', '10G', etc. diffs (185 lines): diff --git a/clients/mapiclient/mhelp.c b/clients/mapiclient/mhelp.c --- a/clients/mapiclient/mhelp.c +++ b/clients/mapiclient/mhelp.c @@ -88,7 +88,7 @@ SQLhelp sqlhelp1[] = { "ALTER USER ident\n" "[WITH [ENCRYPTED | UNENCRYPTED] PASSWORD string]\n" "[SET SCHEMA ident] [SCHEMA PATH string] [DEFAULT ROLE ident]\n" -"[MAX_MEMORY posbytes | NO MAX_MEMORY] [MAX_WORKERS poscount | NO MAX_WORKERS]", +"[MAX_MEMORY posbytes | MAX_MEMORY sizestr | NO MAX_MEMORY] [MAX_WORKERS poscount | NO MAX_WORKERS]", "ident", "See also https://www.monetdb.org/documentation/user-guide/sql-manual/data-definition/privileges/"}, {"ANALYZE", @@ -252,7 +252,7 @@ SQLhelp sqlhelp1[] = { {"CREATE USER", "Create a new database user", "CREATE USER ident WITH [ENCRYPTED | UNENCRYPTED] PASSWORD string NAME string [SCHEMA ident] [SCHEMA PATH string]\n" -"[MAX_MEMORY posbytes | NO MAX_MEMORY] [MAX_WORKERS poscount | NO MAX_WORKERS]\n" +"[MAX_MEMORY posbytes | MAX_MEMORY sizestr | NO MAX_MEMORY] [MAX_WORKERS poscount | NO MAX_WORKERS]\n" "[OPTIMIZER string] [DEFAULT ROLE ident]", "ident", "See also https://www.monetdb.org/documentation/user-guide/sql-manual/data-definition/privileges/"}, diff --git a/sql/ChangeLog.Aug2024 b/sql/ChangeLog.Aug2024 --- a/sql/ChangeLog.Aug2024 +++ b/sql/ChangeLog.Aug2024 @@ -1,6 +1,10 @@ # ChangeLog file for sql # This file is updated with Maddlog +* Fri Jun 14 2024 Joeri van Ruth +- Extend CREATE USER MAX_MEMORY and ALTER USER MAX_MEMORY to accept + strings of the form '10MiB', '10G', etc. + * Mon May 13 2024 Niels Nes - Extended sys.generate_series() to generate dates. Added 2 new functions: sys.generate_series(first date, "limit" date, stepsize interval month) and diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y --- a/sql/server/sql_parser.y +++ b/sql/server/sql_parser.y @@ -165,6 +165,27 @@ uescape_xform(char *restrict s, const ch return s; } +static lng +size_unit(const char *suffix) +{ + if (suffix[0] == '\0') + return 1; + else if (strcasecmp("k", suffix) == 0) + return 1000L; + else if (strcasecmp("kib", suffix) == 0) + return 1024L; + else if (strcasecmp("m", suffix) == 0) + return 1000L * 1000L; + else if (strcasecmp("mib", suffix) == 0) + return 1024L * 1024L; + else if (strcasecmp("g", suffix) == 0) + return 1000L * 1000L * 1000L; + else if (strcasecmp("gib", suffix) == 0) + return 1024L * 1024L * 1024L; + else + return -1; +} + %} /* KNOWN NOT DONE OF sql'99 * @@ -1619,6 +1640,17 @@ opt_max_memory: /* empty */ { $$ = -1; } | NO MAX_MEMORY { $$ = 0; } | MAX_MEMORY poslng { $$ = $2; } + | MAX_MEMORY string { + char *end = NULL; + lng size = strtoll($2, &end, 10); + lng unit = size_unit(end); + if (unit < 0 || size < 0) { + $$ = -1; + yyerror(m, "Invalid size"); + YYABORT; + } + $$ = size * unit; + } ; opt_max_workers: diff --git a/sql/test/Users/Tests/create_user_options.test b/sql/test/Users/Tests/create_user_options.test --- a/sql/test/Users/Tests/create_user_options.test +++ b/sql/test/Users/Tests/create_user_options.test @@ -259,3 +259,97 @@ query TTITIITI rowsort select name, fullname, default_schema > 2000, schema_path, max_memory, max_workers, optimizer, default_role > 2000 from sys.users where name like 'test%' order by name + +statement ok +create user testmaxmem10 with password 'foo' name 'testmaxmem' max_memory '10'; + +statement ok +create user testmaxmem10g with password 'foo' name 'testmaxmem' max_memory '10G'; + +statement ok +create user testmaxmem10g_lower with password 'foo' name 'testmaxmem' max_memory '10g'; + +statement ok +create user testmaxmem10gib with password 'foo' name 'testmaxmem' max_memory '10GiB'; + +state
MonetDB: Aug2024 - Python 3.6 doesn't support subprocess.Popen(c...
Changeset: 77cf6936ff2d for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/77cf6936ff2d Modified Files: sql/odbc/tests/Tests/ODBCconnect.py Branch: Aug2024 Log Message: Python 3.6 doesn't support subprocess.Popen(capture_output=) diffs (14 lines): diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py --- a/sql/odbc/tests/Tests/ODBCconnect.py +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -22,7 +22,9 @@ class Execution: def __init__(self, *odbcconnect_args): cmd = self.cmd = ['odbcconnect', *odbcconnect_args] proc = self.proc = subprocess.run( -cmd, capture_output=True, encoding='utf-8') +cmd, +stderr=subprocess.PIPE, stdout=subprocess.PIPE, +encoding='utf-8') self.expected_exitcode = 0 self.remaining = proc.stdout.splitlines() self.checks = [] ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Remove fancy type signature
Changeset: f66c54d25182 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f66c54d25182 Modified Files: testing/tlstester.py Branch: Aug2024 Log Message: Remove fancy type signature Old Python versions don't support it diffs (12 lines): diff --git a/testing/tlstester.py b/testing/tlstester.py --- a/testing/tlstester.py +++ b/testing/tlstester.py @@ -542,7 +542,7 @@ class WebHandler(http.server.BaseHTTPReq self.end_headers() self.wfile.write(content) -def log_request(self, code: int | str = "-", size: int | str = "-") -> None: +def log_request(self, code = "-", size = "-"): # be silent pass ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Add list drivers and list dns's to odbcconnect
Changeset: 230778a77ea1 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/230778a77ea1 Modified Files: clients/odbc/samples/odbcconnect.c Branch: Aug2024 Log Message: Add list drivers and list dns's to odbcconnect Fix a small memory leak in the process diffs (204 lines): diff --git a/clients/odbc/samples/odbcconnect.c b/clients/odbc/samples/odbcconnect.c --- a/clients/odbc/samples/odbcconnect.c +++ b/clients/odbc/samples/odbcconnect.c @@ -15,6 +15,8 @@ #include #endif + +#include #include #include #include @@ -29,14 +31,22 @@ static const char *USAGE = "-d Target is DSN, call SQLConnect()\n" "-c Target is connection string, call SQLDriverConnect()\n" "-b Target is connection string, call SQLBrowseConnect()\n" + "-l List registered drivers and data sources\n" "-u USER\n" "-p PASSWORD\n" "-v Be verbose\n" "TARGET Connection String or DSN\n"; -static int do_sqlconnect(SQLCHAR *target); -static int do_sqldriverconnect(SQLCHAR *target); -static int do_sqlbrowseconnect(SQLCHAR *target); +typedef int (action_t)(SQLCHAR *); + +static int do_actions(action_t action, int ntargets, SQLCHAR **targets); + +static action_t do_sqlconnect; +static action_t do_sqldriverconnect; +static action_t do_sqlbrowseconnect; + +static int do_listdrivers(void); +static int do_listdsns(const char *prefix, SQLSMALLINT dir); static void ensure_ok(SQLSMALLINT type, SQLHANDLE handle, const char *message, SQLRETURN ret); @@ -49,6 +59,7 @@ SQLHANDLE env = NULL; SQLHANDLE conn = NULL; SQLCHAR outbuf[4096]; +SQLCHAR attrbuf[4096]; static void cleanup(void) @@ -68,7 +79,7 @@ main(int argc, char **argv) action = do_sqlconnect; SQLCHAR **targets = calloc(argc, sizeof(argv[0])); int ntargets = 0; - int ret = 0; + int ret; for (int i = 1; i < argc; i++) { char *arg = argv[i]; @@ -78,6 +89,8 @@ main(int argc, char **argv) action = do_sqldriverconnect; else if (strcmp(arg, "-b") == 0) action = do_sqlbrowseconnect; + else if (strcmp(arg, "-l") == 0) + action = NULL; else if (strcmp(arg, "-u") == 0 && i + 1 < argc) user = (SQLCHAR*)argv[++i]; else if (strcmp(arg, "-p") == 0 && i + 1 < argc) @@ -88,15 +101,11 @@ main(int argc, char **argv) targets[ntargets++] = (SQLCHAR*)arg; else { fprintf(stderr, "\nERROR: invalid argument: %s\n%s", arg, USAGE); - return 1; + ret = 1; + goto end; } } - if (ntargets == 0) { - fprintf(stderr, "\nERROR: pass at least one target\n%s", USAGE); - return 1; - } - ensure_ok( SQL_HANDLE_ENV, NULL, "allocate env handle", SQLAllocHandle(SQL_HANDLE_ENV, NULL, &env)); @@ -105,20 +114,25 @@ main(int argc, char **argv) SQL_HANDLE_ENV, env, "set odbc version", SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0)); - ensure_ok( - SQL_HANDLE_ENV, env, "allocate conn handle", - SQLAllocHandle(SQL_HANDLE_DBC, env, &conn)); - - for (int i = 0; i < ntargets; i++) { - SQLCHAR *t = targets[i]; - if (verbose) - printf("\nTarget: %s\n", t); - outbuf[0] = '\0'; - int ret = action(t); - if (ret) - break; + if (action) { + if (ntargets == 0) { + fprintf(stderr, "\nERROR: pass at least one target\n%s", USAGE); + ret = 1; + goto end; + } + ret = do_actions(action, ntargets, targets); + } else { + if (ntargets != 0) { + fprintf(stderr, "\nERROR: -l does not take arguments\n%s", USAGE); + ret = 1; + goto end; + } + ret = do_listdrivers(); + ret |= do_listdsns("SYSTEM", SQL_FETCH_FIRST_SYSTEM); + ret |= do_listdsns("SYSTEM", SQL_FETCH_FIRST_USER); } +end: free(targets); cleanup(); @@ -174,6 +188,26 @@ ensure_ok(SQLSMALLINT type, SQLHANDLE ha static int +do_actions(action_t action, int ntargets, SQLCHAR **targets) +{ + ensure_ok( + SQL_HANDLE_ENV, env, "allocate conn handle", + SQLAllocHandle(SQL_HANDLE_DBC, env, &conn)); + + for (int i = 0; i < ntargets; i++) { + SQLCHAR *t = targets[i]; + if (verbose) +
MonetDB: Aug2024 - Don't write certs to TSTTRGDIR, it may not ex...
Changeset: 5eb6a7727787 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/5eb6a7727787 Modified Files: testing/Mtest.py.in Branch: Aug2024 Log Message: Don't write certs to TSTTRGDIR, it may not exist yet diffs (26 lines): diff --git a/testing/Mtest.py.in b/testing/Mtest.py.in --- a/testing/Mtest.py.in +++ b/testing/Mtest.py.in @@ -3250,14 +3250,6 @@ def StartTlsTester(tsttrgdir): from MonetDBtesting import tlstester hostnames = ['localhost'] certs = tlstester.Certs(hostnames) -certsdir = os.path.join(tsttrgdir, "certs") -try: -os.mkdir(certsdir) -except FileExistsError: -pass -for name, content in certs.all().items(): -with open(os.path.join(certsdir, name), "wb") as f: -f.write(content) server = tlstester.TLSTester( certs = certs, listen_addr='localhost', @@ -3267,7 +3259,6 @@ def StartTlsTester(tsttrgdir): server_thread = threading.Thread(target=server.serve_forever, daemon=True) server_thread.start() return server.get_port('base') - ### StartTlsTester() # # ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Use Mtest's TLSTester to test JDBC TLS
Changeset: e0c0dbd3e852 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/e0c0dbd3e852 Added Files: sql/jdbc/tests/Tests/TLSTester.py Modified Files: sql/jdbc/tests/Tests/All Branch: Aug2024 Log Message: Use Mtest's TLSTester to test JDBC TLS diffs (32 lines): diff --git a/sql/jdbc/tests/Tests/All b/sql/jdbc/tests/Tests/All --- a/sql/jdbc/tests/Tests/All +++ b/sql/jdbc/tests/Tests/All @@ -1,4 +1,5 @@ HAVE_JDBCTESTS?JDBC_API_Tester +HAVE_JDBCTESTS?TLSTester HAVE_JDBCTESTS?OnClientTester HAVE_JDBCCLIENT_JAR?Test_JdbcClient # next test should be done AFTER all the other tests have completed diff --git a/sql/jdbc/tests/Tests/TLSTester.py b/sql/jdbc/tests/Tests/TLSTester.py new file mode 100644 --- /dev/null +++ b/sql/jdbc/tests/Tests/TLSTester.py @@ -0,0 +1,18 @@ +import os, sys +from subprocess import run, PIPE, CalledProcessError + +PORT=os.environ['TST_TLSTESTERPORT'] + +cmd = [ +'java', 'TLSTester', +# '-v', +f'localhost:{PORT}', +'-a', 'localhost.localdomain' +] +try: +p = run(cmd, stdout=PIPE, stderr=PIPE, check=True, encoding='utf-8') +sys.stderr.write(p.stdout) +sys.stderr.write(p.stderr) +except CalledProcessError as e: +raise SystemExit(e.stderr) + ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Move tlstester to testing/ directory
Changeset: d3c75b4b83c6 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/d3c75b4b83c6 Added Files: testing/tlstester.py Removed Files: clients/mapilib/Tests/tlstester.py Modified Files: clients/mapilib/Tests/tlssecurity.py testing/CMakeLists.txt Branch: Aug2024 Log Message: Move tlstester to testing/ directory diffs (27 lines): diff --git a/clients/mapilib/Tests/tlssecurity.py b/clients/mapilib/Tests/tlssecurity.py --- a/clients/mapilib/Tests/tlssecurity.py +++ b/clients/mapilib/Tests/tlssecurity.py @@ -16,8 +16,7 @@ import subprocess import sys import threading -sys.path.append(os.environ.get('TSTSRCDIR','.')) -import tlstester +from MonetDBtesting import tlstester level = logging.WARNING # if sys.platform == 'win32': diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt --- a/testing/CMakeLists.txt +++ b/testing/CMakeLists.txt @@ -147,6 +147,7 @@ if(PYTHON3_LIBDIR) malmapi.py helpers.py sqltest.py +tlstester.py utils.py DESTINATION ${PYTHON3_LIBDIR}/MonetDBtesting COMPONENT pytesting) diff --git a/clients/mapilib/Tests/tlstester.py b/testing/tlstester.py rename from clients/mapilib/Tests/tlstester.py rename to testing/tlstester.py ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Move TLSTesterClient from tlssecurity,py to t...
Changeset: 61f71d59ed8d for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/61f71d59ed8d Modified Files: clients/mapilib/Tests/tlssecurity.py testing/tlstester.py Branch: Aug2024 Log Message: Move TLSTesterClient from tlssecurity,py to testing/tlstester.py So we can use it from other tests as well diffs (129 lines): diff --git a/clients/mapilib/Tests/tlssecurity.py b/clients/mapilib/Tests/tlssecurity.py --- a/clients/mapilib/Tests/tlssecurity.py +++ b/clients/mapilib/Tests/tlssecurity.py @@ -14,9 +14,8 @@ import os import re import subprocess import sys -import urllib.request -from MonetDBtesting import tlstester +from MonetDBtesting.tlstester import TLSTesterClient level = logging.WARNING # if sys.platform == 'win32': @@ -32,50 +31,6 @@ assert os.path.isdir(tgtdir) scratchdir = os.path.join(tgtdir, "scratch") logging.debug(f"scratchdir={scratchdir}") -class TLSTesterClient: -"""Connect to TLSTester to figure out port numbers and download certificates""" -def __init__(self, scratchdir, base_port=None, host='localhost'): -if not base_port: -base_port = os.environ['TST_TLSTESTERPORT'] -self.url = f'http://{host}:{base_port}/' -self.scratch = scratchdir -try: -os.mkdir(scratchdir) -except FileExistsError: -pass -self.filenames = dict() -self.contents = dict() -self.portmap = dict() -for line in self.fetch('').splitlines(): -name, port = str(line, 'ascii').split(':', 1) -self.portmap[name] = int(port) -logging.debug(f'port {name} = {port}') - -def get_port(self, name): -return self.portmap[name] - -def fetch(self, name): -cached = self.contents.get(name) -if cached is not None: -return cached -url = self.url + name -logging.debug(f'fetch {url}') -with urllib.request.urlopen(url) as response: -content = response.read() -self.contents[name] = content -return content - -def download(self, name): -cached = self.filenames.get(name) -if cached: -return cached -content = self.fetch(name) -path = os.path.join(self.scratch, name) -with open(path, 'wb') as f: -f.write(content) -self.filenames[name] = path -return path - tlstester = TLSTesterClient(scratchdir) diff --git a/testing/tlstester.py b/testing/tlstester.py --- a/testing/tlstester.py +++ b/testing/tlstester.py @@ -27,6 +27,7 @@ import tempfile from threading import Thread import threading from typing import Any, Callable, Dict, List, Optional, Tuple, Union +import urllib.request # Our TLS implementation never uses anything less than TLSv1.3. assert ssl.HAS_TLSv1_3 @@ -98,6 +99,52 @@ argparser.add_argument( ) + +class TLSTesterClient: +"""Connect to TLSTester to figure out port numbers and download certificates""" +def __init__(self, scratchdir, base_port=None, host='localhost'): +if not base_port: +base_port = os.environ['TST_TLSTESTERPORT'] +self.url = f'http://{host}:{base_port}/' +self.scratch = scratchdir +try: +os.mkdir(scratchdir) +except FileExistsError: +pass +self.filenames = dict() +self.contents = dict() +self.portmap = dict() +for line in self.fetch('').splitlines(): +name, port = str(line, 'ascii').split(':', 1) +self.portmap[name] = int(port) +logging.debug(f'port {name} = {port}') + +def get_port(self, name): +return self.portmap[name] + +def fetch(self, name): +cached = self.contents.get(name) +if cached is not None: +return cached +url = self.url + name +logging.debug(f'fetch {url}') +with urllib.request.urlopen(url) as response: +content = response.read() +self.contents[name] = content +return content + +def download(self, name): +cached = self.filenames.get(name) +if cached: +return cached +content = self.fetch(name) +path = os.path.join(self.scratch, name) +with open(path, 'wb') as f: +f.write(content) +self.filenames[name] = path +return path + + class Certs: hostnames: str _files: Dict[str, bytes] ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Add test for SQLConnect/DriverConnect/BrowseC...
Changeset: 0ad8b1cc201d for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/0ad8b1cc201d Added Files: sql/odbc/tests/Tests/ODBCconnect.py Modified Files: sql/odbc/tests/Tests/All Branch: Aug2024 Log Message: Add test for SQLConnect/DriverConnect/BrowseConnect still incomplete diffs (149 lines): diff --git a/sql/odbc/tests/Tests/All b/sql/odbc/tests/Tests/All --- a/sql/odbc/tests/Tests/All +++ b/sql/odbc/tests/Tests/All @@ -2,4 +2,5 @@ HAVE_ODBC?ODBCgetInfo HAVE_ODBC?ODBCmetadata HAVE_ODBC?ODBCStmtAttr HAVE_ODBC?ODBCtester +HAVE_ODBC?ODBCconnect HAVE_PYODBC&!SANITIZER?pyodbc-test diff --git a/sql/odbc/tests/Tests/ODBCconnect.py b/sql/odbc/tests/Tests/ODBCconnect.py new file mode 100755 --- /dev/null +++ b/sql/odbc/tests/Tests/ODBCconnect.py @@ -0,0 +1,135 @@ +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# Copyright 2024 MonetDB Foundation; +# Copyright August 2008 - 2023 MonetDB B.V.; +# Copyright 1997 - July 2008 CWI. + + +# For each target, odbcconnect first prints a status line, +# either 'OK' or 'Error FUNCNAME', followed by zero or more +# sqlstate lines of the form '- STATE: MESSAGE'. + +import atexit +import subprocess +import sys + + +class Execution: +def __init__(self, *odbcconnect_args): +cmd = self.cmd = ['odbcconnect', *odbcconnect_args] +proc = self.proc = subprocess.run( +cmd, capture_output=True, encoding='utf-8') +self.expected_exitcode = 0 +self.remaining = proc.stdout.splitlines() +self.checks = [] + +def report(self): +parts = [f'COMMAND: {self.cmd}', + f'EXIT CODE: {self.proc.returncode}', ''] +if self.proc.stdout: +parts += [ +'--- stdout: ---', +self.proc.stdout.rstrip(), +'--- end ---', +'' +] +if self.proc.stderr: +parts += [ +'--- stderr: ---', +self.proc.stderr.rstrip(), +'--- end ---', +'' +] +if self.checks: +parts.append('--- test history: ---') +for wanted, found in self.checks: +parts.append(f'wanted {wanted!r}, found {found!r}') +parts.append('--- end ---') +if self.remaining: +parts += [ +'--- remaining output: ---', +*self.remaining, +'--- end ---' +] +return '\n'.join(parts) + +def expect(self, pattern): +line = self.next_line() +self.checks.append((pattern, line)) +if pattern not in line: +raise Exception(f'Wanted {pattern!r}, found {line!r}') + +def next_line(self): +if not self.remaining: +raise Exception(f"Unexpected end of output") +line = self.remaining[0] +del self.remaining[0] +return line + +def expect_fail(self, exitcode=1): +self.expected_exitcode = exitcode + +def end(self): +if self.remaining: +raise Exception(f'Unexpected output remaining: {self.remaining}') +code = self.proc.returncode +expected = self.expected_exitcode +if code != expected: +raise Exception( +f'Process exited with code {code!r}, expected {expected!r}') + + +ex = None + + +@atexit.register +def show_context(): +global ex +if ex: +# ex.end() +print(file=sys.stderr) +print(ex.report(), file=sys.stderr) + + +dbname = 'MonetDB-Test' + + +ex = Execution(dbname) +ex.expect('OK') +ex.end() + +ex = Execution(dbname + '-nonexistent') +ex.expect_fail() +ex.expect('Error') +ex.expect('IM002:') # IM002 not found +ex.end() + +ex = Execution(dbname, '-p', 'wrongpassword') +ex.expect_fail() +ex.expect('Error') +ex.expect('28000:') # 28000 bad credentials +ex.end() + +ex = Execution(dbname, '-u', 'wronguser') +ex.expect_fail() +ex.expect('Error') +ex.expect('28000:') # 28000 bad credentials +ex.end() + +ex = Execution(dbname, '-p', '') +ex.expect_fail() +ex.expect('Error') +ex.expect('28000:') # 28000 bad credentials +ex.end() + +ex = Execution(dbname, '-u', '') +ex.expect_fail() +ex.expect('Error') +ex.expect('28000:') # 28000 bad credentials +ex.end() + +ex = None ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Add tests for client_{info,application,remark...
Changeset: f17ab4c9405d for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f17ab4c9405d Modified Files: sql/test/mapi/Tests/clientinfo-mclient.SQL.py Branch: Aug2024 Log Message: Add tests for client_{info,application,remark} properties diffs (116 lines): diff --git a/sql/test/mapi/Tests/clientinfo-mclient.SQL.py b/sql/test/mapi/Tests/clientinfo-mclient.SQL.py --- a/sql/test/mapi/Tests/clientinfo-mclient.SQL.py +++ b/sql/test/mapi/Tests/clientinfo-mclient.SQL.py @@ -1,5 +1,6 @@ import os import subprocess +import urllib.parse TSTDB = os.environ['TSTDB'] MAPIPORT = os.environ['MAPIPORT'] @@ -10,26 +11,27 @@ FROM sys.sessions WHERE sessionid = current_sessionid() """ -cmd = [ -'mclient', -'-d', TSTDB, -'-p', MAPIPORT, -'-fexpanded', -'-s', QUERY, -] - -out = subprocess.check_output(cmd, encoding='latin1') +def run_mclient(**extra_args): +url = f'monetdb://localhost:{MAPIPORT}/{TSTDB}' +if extra_args: +url += '?' + urllib.parse.urlencode(extra_args) +cmd = [ 'mclient', '-d', url, '-fexpanded', '-s', QUERY ] +out = subprocess.check_output(cmd, encoding='latin1') +fields = dict() +for line in out.splitlines()[1:]: +line = line.strip() +if line: +k, v = line.split('|', 1) +k = k.strip() +v = v.strip() +fields[k] = v +return fields -# print(out) -fields = dict() -for line in out.splitlines()[1:]: -line = line.strip() -if line: -k, v = line.split('|', 1) -k = k.strip() -v = v.strip() -fields[k] = v +### +# By default, most fields get filled in + +fields = run_mclient() assert fields['language'] == 'sql',\ f'Found {fields["language"]!r}' @@ -52,3 +54,59 @@ assert fields['clientpid'] != 'null' and assert fields['remark'] == 'null',\ f'Found {fields["remark"]!r}' + + +### +# client_info=off suppresses everything sent by the client. +# Server still fills in language and peer + +fields = run_mclient(client_info='off') + +assert fields['language'] == 'sql',\ +f'Found {fields["language"]!r}' + +assert fields['peer'] == '' or ']:' in fields['peer'],\ +f'Found {fields["peer"]!r}' + +assert fields['hostname'] == 'null',\ +f'Found {fields["hostname"]!r}' + +# could be mclient-11.51.0, mclient.exe, or whatever +assert fields['application'] == 'null',\ +f'Found {fields["application"]!r}' + +assert fields['client'] == 'null',\ +f'Found {fields["client"]!r}' + +assert fields['clientpid'] == 'null',\ +f'Found {fields["clientpid"]!r}' + +assert fields['remark'] == 'null',\ +f'Found {fields["remark"]!r}' + +### +# We can override application and remark + +fields = run_mclient(client_application='app', client_remark='mark') + +# could be mclient-11.51.0, mclient.exe, or whatever +assert fields['application'] == 'app',\ +f'Found {fields["application"]!r}' + +assert fields['remark'] == 'mark',\ +f'Found {fields["remark"]!r}' + + +### +# We can override application and remark, but client_info=off +# suppresses that. + +fields = run_mclient(client_application='app', client_remark='mark', client_info='off') + +# could be mclient-11.51.0, mclient.exe, or whatever +assert fields['application'] == 'null',\ +f'Found {fields["application"]!r}' + +assert fields['remark'] == 'null',\ +f'Found {fields["remark"]!r}' + ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Use raw string to suppress Python warning
Changeset: 750de1fa87e2 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/750de1fa87e2 Modified Files: sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py Branch: Aug2024 Log Message: Use raw string to suppress Python warning diffs (12 lines): diff --git a/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py --- a/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py +++ b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py @@ -6,7 +6,7 @@ import subprocess # This SQL script redirects the output to a file (the %s). # We will check that all output arrives there, even if it's a gzipped file. -SCRIPT = """\ +SCRIPT = r""" \>%s SELECT 'Donald Knuth'; """ ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - odbc: Map InvalidCredentialsException to SQLS...
Changeset: 58c7bfa4dbc9 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/58c7bfa4dbc9 Modified Files: clients/odbc/driver/SQLConnect.c Branch: Aug2024 Log Message: odbc: Map InvalidCredentialsException to SQLSTATE 28000 diffs (17 lines): diff --git a/clients/odbc/driver/SQLConnect.c b/clients/odbc/driver/SQLConnect.c --- a/clients/odbc/driver/SQLConnect.c +++ b/clients/odbc/driver/SQLConnect.c @@ -487,8 +487,12 @@ MNDBConnectSettings(ODBCDbc *dbc, const mapi_reconnect(mid); } if (mid == NULL || mapi_error(mid)) { - const char *error_state = "08001"; + const char *error_state; const char *error_explanation = mid ? mapi_error_str(mid) : NULL; + if (error_explanation && strncmp(error_explanation, "InvalidCredentialsException:", 28) == 0) + error_state = "28000"; + else + error_state = "08001"; addDbcError(dbc, error_state, error_explanation, 0); if (mid) mapi_destroy(mid); ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Make odbcconnect flags more straightforward
Changeset: 48e8d738ef63 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/48e8d738ef63 Modified Files: clients/odbc/tests/odbcconnect.c Branch: Aug2024 Log Message: Make odbcconnect flags more straightforward -d for driver, -b for browse diffs (29 lines): diff --git a/clients/odbc/tests/odbcconnect.c b/clients/odbc/tests/odbcconnect.c --- a/clients/odbc/tests/odbcconnect.c +++ b/clients/odbc/tests/odbcconnect.c @@ -28,14 +28,13 @@ static const char *USAGE = "Usage:\n" "odbcconnect [-d | -c | -b ] [-v] [-u USER] [-p PASSWORD] TARGET..\n" "Options:\n" - "-d Target is DSN, call SQLConnect()\n" - "-c Target is connection string, call SQLDriverConnect()\n" + "-d Target is connection string, call SQLDriverConnect()\n" "-b Target is connection string, call SQLBrowseConnect()\n" "-l List registered drivers and data sources\n" "-u USER\n" "-p PASSWORD\n" "-v Be verbose\n" - "TARGET Connection String or DSN\n"; + "TARGET DSN or with -d and -b, Connection String\n"; typedef int (action_t)(SQLCHAR *); @@ -84,8 +83,6 @@ main(int argc, char **argv) for (int i = 1; i < argc; i++) { char *arg = argv[i]; if (strcmp(arg, "-d") == 0) - action = do_sqlconnect; - else if (strcmp(arg, "-c") == 0) action = do_sqldriverconnect; else if (strcmp(arg, "-b") == 0) action = do_sqlbrowseconnect; ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - ODBCtester.SQL.sh does not need to create odb...
Changeset: e88194ba7d08 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/e88194ba7d08 Modified Files: sql/odbc/tests/Tests/ODBCtester.SQL.sh Branch: Aug2024 Log Message: ODBCtester.SQL.sh does not need to create odbc.ini Mtest takes care of that diffs (23 lines): diff --git a/sql/odbc/tests/Tests/ODBCtester.SQL.sh b/sql/odbc/tests/Tests/ODBCtester.SQL.sh --- a/sql/odbc/tests/Tests/ODBCtester.SQL.sh +++ b/sql/odbc/tests/Tests/ODBCtester.SQL.sh @@ -1,19 +1,3 @@ #!/bin/sh -ODBCINI=$PWD/odbc.ini -trap "rm $ODBCINI" 0 15 -cat > $ODBCINI <
MonetDB: Aug2024 - Run a dummy server if the cryptography module...
Changeset: 6d3098fd2db1 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/6d3098fd2db1 Modified Files: testing/Mtest.py.in Branch: Aug2024 Log Message: Run a dummy server if the cryptography module cannot be found diffs (52 lines): diff --git a/testing/Mtest.py.in b/testing/Mtest.py.in --- a/testing/Mtest.py.in +++ b/testing/Mtest.py.in @@ -35,6 +35,8 @@ import socket import struct import signal import fnmatch +import http +import http.server import glob import pymonetdb # check for pymonetdb early: it is essential for our work @@ -3240,13 +3242,26 @@ def SetExecEnv(exe,port,verbose) : print(end='', flush=True) ### SetExecEnv(exe,port,procdebug) # -def StartTlsTester(tsttrgdir): +def DummyTlsTester(): +class DummyHTTPRequestHandler(http.server.BaseHTTPRequestHandler): +def handle(self): +self.requestline = '' +self.request_version = '' +self.command = '' +self.send_error(http.HTTPStatus.INTERNAL_SERVER_ERROR, f"{sys.argv[0]} is not running TLSTestter because the 'cryptography' module is not present") +server = http.server.HTTPServer(('localhost', 0), DummyHTTPRequestHandler) +port = server.server_address[1] +server_thread = threading.Thread(target=server.serve_forever, daemon=True) +server_thread.start() +return port +### DummyTlsTester(exe,port,procdebug) # + +def StartTlsTester(): try: import cryptography except: -# continue without so we can at least run the other tests -print("cryptography not found!", file=sys.stderr) -return None +# Start a dummy server that only returns errors. +return DummyTlsTester() from MonetDBtesting import tlstester hostnames = ['localhost'] certs = tlstester.Certs(hostnames) @@ -3808,7 +3823,7 @@ def main(argv) : # start tlstester if not env.get('TST_TLSTESTERPORT'): -tlstester_port = StartTlsTester(os.path.join(TSTTRGBASE, TSTPREF)) +tlstester_port = StartTlsTester() if tlstester_port: env['TST_TLSTESTERPORT'] = str(tlstester_port) if env.get('TST_TLSTESTERPORT'): ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Move odbcconnect from clients/odbc/samples to...
Changeset: e8186ee84c8e for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/e8186ee84c8e Added Files: clients/odbc/tests/odbcconnect.c Removed Files: clients/odbc/samples/odbcconnect.c Modified Files: clients/odbc/samples/CMakeLists.txt clients/odbc/tests/CMakeLists.txt Branch: Aug2024 Log Message: Move odbcconnect from clients/odbc/samples to clients/odbc/tests diffs (63 lines): diff --git a/clients/odbc/samples/CMakeLists.txt b/clients/odbc/samples/CMakeLists.txt --- a/clients/odbc/samples/CMakeLists.txt +++ b/clients/odbc/samples/CMakeLists.txt @@ -26,17 +26,9 @@ target_link_libraries(arraytest PRIVATE ODBC::ODBC) -add_executable(odbcconnect - odbcconnect.c) - -target_link_libraries(odbcconnect - PRIVATE - ODBC::ODBC) - install(TARGETS odbcsample1 arraytest - odbcconnect RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} @@ -46,7 +38,6 @@ if(WIN32) install(FILES $ $ -$ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) endif() diff --git a/clients/odbc/tests/CMakeLists.txt b/clients/odbc/tests/CMakeLists.txt --- a/clients/odbc/tests/CMakeLists.txt +++ b/clients/odbc/tests/CMakeLists.txt @@ -39,11 +39,19 @@ target_link_libraries(ODBCtester PRIVATE ODBC::ODBC) +add_executable(odbcconnect + odbcconnect.c) + +target_link_libraries(odbcconnect + PRIVATE + ODBC::ODBC) + install(TARGETS ODBCgetInfo ODBCStmtAttr ODBCmetadata ODBCtester + odbcconnect RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} @@ -55,6 +63,7 @@ if(WIN32) $ $ $ +$ DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) endif() diff --git a/clients/odbc/samples/odbcconnect.c b/clients/odbc/tests/odbcconnect.c rename from clients/odbc/samples/odbcconnect.c rename to clients/odbc/tests/odbcconnect.c ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Incorporate TLSTester in Mtest.py
Changeset: 9b8c0e6feeb5 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/9b8c0e6feeb5 Modified Files: clients/mapilib/Tests/tlssecurity.py testing/Mtest.py.in testing/tlstester.py Branch: Aug2024 Log Message: Incorporate TLSTester in Mtest.py diffs (196 lines): diff --git a/clients/mapilib/Tests/tlssecurity.py b/clients/mapilib/Tests/tlssecurity.py --- a/clients/mapilib/Tests/tlssecurity.py +++ b/clients/mapilib/Tests/tlssecurity.py @@ -14,7 +14,7 @@ import os import re import subprocess import sys -import threading +import urllib.request from MonetDBtesting import tlstester @@ -26,45 +26,64 @@ if '-v' in sys.argv: #level = logging.DEBUG logging.basicConfig(level=level) +# A tmpdir to write certificates to tgtdir = os.environ['TSTTRGDIR'] assert os.path.isdir(tgtdir) +scratchdir = os.path.join(tgtdir, "scratch") +logging.debug(f"scratchdir={scratchdir}") -hostnames = ['localhost'] -# Generate certificates and write them to the scratch dir -# Write them to the scratch dir for inspection by the user. -certs = tlstester.Certs(hostnames) -certsdir = os.path.join(tgtdir, "certs") -try: -os.mkdir(certsdir) -except FileExistsError: -pass -count = 0 -for name, content in certs.all().items(): -with open(os.path.join(certsdir, name), "wb") as a: -a.write(content) -count += 1 -logging.debug(f"Wrote {count} files to {certsdir}") +class TLSTesterClient: +"""Connect to TLSTester to figure out port numbers and download certificates""" +def __init__(self, scratchdir, base_port=None, host='localhost'): +if not base_port: +base_port = os.environ['TST_TLSTESTERPORT'] +self.url = f'http://{host}:{base_port}/' +self.scratch = scratchdir +try: +os.mkdir(scratchdir) +except FileExistsError: +pass +self.filenames = dict() +self.contents = dict() +self.portmap = dict() +for line in self.fetch('').splitlines(): +name, port = str(line, 'ascii').split(':', 1) +self.portmap[name] = int(port) +logging.debug(f'port {name} = {port}') + +def get_port(self, name): +return self.portmap[name] + +def fetch(self, name): +cached = self.contents.get(name) +if cached is not None: +return cached +url = self.url + name +logging.debug(f'fetch {url}') +with urllib.request.urlopen(url) as response: +content = response.read() +self.contents[name] = content +return content + +def download(self, name): +cached = self.filenames.get(name) +if cached: +return cached +content = self.fetch(name) +path = os.path.join(self.scratch, name) +with open(path, 'wb') as f: +f.write(content) +self.filenames[name] = path +return path + +tlstester = TLSTesterClient(scratchdir) + def certpath(name): -return os.path.join(certsdir, name) -def certbytes(name): -filename = certpath(name) -with open(filename, 'rb') as f: -return f.read() - -# Start the worker threads - -server = tlstester.TLSTester( -certs=certs, -listen_addr='127.0.0.1', -preassigned=dict(), -sequential=False, -hostnames=hostnames) -server_thread = threading.Thread(target=server.serve_forever, daemon=True) -server_thread.start() +return tlstester.download(name) def attempt(experiment: str, portname: str, expected_error_regex: str, tls=True, host='localhost', **params): -port = server.get_port(portname) +port = tlstester.get_port(portname) scheme = 'monetdbs' if tls else 'monetdb' url = f"{scheme}://{host}:{port}/demo" if params: @@ -196,7 +215,7 @@ attempt('connect_server_name', 'sni', No # Connect to port 'server1' over TLS, with certhash set to a prefix of the hash # of the server certificate in DER form. Have a succesful MAPI exchange. -server1hash = sha256(certs.get_file('server1.der')).hexdigest() +server1hash = sha256(tlstester.fetch('server1.der')).hexdigest() attempt('connect_right_hash', 'server1', None, certhash='sha256:' + server1hash[:6]) # connect_wrong_hash @@ -217,7 +236,7 @@ attempt('connect_wrong_hash', 'server1', # Connect to port 'server1' over TLS, with certhash set to a prefix of the hash # of the CA1 certificate in DER form. This should fail. -ca1hash = sha256(certs.get_file('ca1.der')).hexdigest() +ca1hash = sha256(tlstester.fetch('ca1.der')).hexdigest() attempt('connect_ca_hash', 'server1', "does not match certhash", certhash='sha256:' + ca1hash[:6]) diff --git a/testing/Mtest.py.in b/testing/Mtest.py.in --- a/testing/Mtest.py.in +++ b/testing/Mtest.py.in @@ -3240,6 +3240,36 @@ def SetExecEnv(exe,port,verbose) : print(end='', flush=True) ### SetExecEnv(exe,port,procdebug) # +def StartTlsTester(tsttrgdir): +try: +import cryptography +except: +# co
MonetDB: Aug2024 - Add test for clientinfo
Changeset: 42d6226ac18f for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/42d6226ac18f Added Files: sql/test/mapi/Tests/clientinfo-mclient.SQL.py Modified Files: sql/test/mapi/Tests/All Branch: Aug2024 Log Message: Add test for clientinfo It uses mclient so it doesn't require pymonetdb updates diffs (67 lines): diff --git a/sql/test/mapi/Tests/All b/sql/test/mapi/Tests/All --- a/sql/test/mapi/Tests/All +++ b/sql/test/mapi/Tests/All @@ -9,3 +9,4 @@ HAVE_HGE?sql_int128 HAVE_HGE?python3_int128 HAVE_HGE?sql_dec38 HAVE_HGE?python3_dec38 +clientinfo-mclient diff --git a/sql/test/mapi/Tests/clientinfo-mclient.SQL.py b/sql/test/mapi/Tests/clientinfo-mclient.SQL.py new file mode 100644 --- /dev/null +++ b/sql/test/mapi/Tests/clientinfo-mclient.SQL.py @@ -0,0 +1,54 @@ +import os +import subprocess + +TSTDB = os.environ['TSTDB'] +MAPIPORT = os.environ['MAPIPORT'] + +QUERY = """\ +SELECT * +FROM sys.sessions +WHERE sessionid = current_sessionid() +""" + +cmd = [ +'mclient', +'-d', TSTDB, +'-p', MAPIPORT, +'-fexpanded', +'-s', QUERY, +] + +out = subprocess.check_output(cmd, encoding='latin1') + +# print(out) + +fields = dict() +for line in out.splitlines()[1:]: +line = line.strip() +if line: +k, v = line.split('|', 1) +k = k.strip() +v = v.strip() +fields[k] = v + +assert fields['language'] == 'sql',\ +f'Found {fields["language"]!r}' + +assert fields['peer'] == '' or ']:' in fields['peer'],\ +f'Found {fields["peer"]!r}' + +assert fields['hostname'] != 'null',\ +f'Found {fields["hostname"]!r}' + +# could be mclient-11.51.0, mclient.exe, or whatever +assert fields['application'].startswith('mclient'),\ +f'Found {fields["application"]!r}' + +assert fields['client'].startswith('libmapi '),\ +f'Found {fields["client"]!r}' + +assert fields['clientpid'] != 'null' and int(fields['clientpid']) > 0,\ +f'Found {fields["clientpid"]!r}' + +assert fields['remark'] == 'null',\ +f'Found {fields["remark"]!r}' ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Simplify mclient flush test
Changeset: e55267399f84 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/e55267399f84 Modified Files: sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py Branch: Aug2024 Log Message: Simplify mclient flush test diffs (34 lines): diff --git a/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py --- a/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py +++ b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py @@ -6,7 +6,7 @@ import subprocess # This SQL script redirects the output to a file (the %s). # We will check that all output arrives there, even if it's a gzipped file. -SCRIPT = f"""\ +SCRIPT = """\ \>%s SELECT 'Donald Knuth'; """ @@ -19,16 +19,13 @@ with tempfile.TemporaryDirectory('mtest' with open(inputfile, 'w') as f: f.write(SCRIPT % outputfile) -with open(inputfile) as f: -subprocess.check_call([ -'mclient', '-i', -inputfile, -'-p', os.environ['MAPIPORT'], -]) +subprocess.check_call([ +'mclient', '-i', +'-p', os.environ['MAPIPORT'], +inputfile, +]) with gzip.open(outputfile, 'rt', encoding='utf-8') as f: content = f.read() -# print(content) - assert 'Donald Knuth' in content ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - Remove debugging leftover
Changeset: bc602abd10b2 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/bc602abd10b2 Modified Files: sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py Branch: Aug2024 Log Message: Remove debugging leftover diffs (11 lines): diff --git a/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py --- a/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py +++ b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py @@ -13,7 +13,6 @@ SELECT 'Donald Knuth'; with tempfile.TemporaryDirectory('mtest') as dir: -dir = '/tmp/jvr' outputfile = os.path.join(dir, 'output.txt.gz') inputfile = os.path.join(dir, 'input.sql') ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: Aug2024 - mclient: close redirected output stream befor...
Changeset: 75970a2bc94e for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/75970a2bc94e Added Files: sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py Modified Files: clients/mapiclient/mclient.c sql/test/BugTracker-2024/Tests/All Branch: Aug2024 Log Message: mclient: close redirected output stream before exiting Fixes #7536 diffs (60 lines): diff --git a/clients/mapiclient/mclient.c b/clients/mapiclient/mclient.c --- a/clients/mapiclient/mclient.c +++ b/clients/mapiclient/mclient.c @@ -3879,6 +3879,8 @@ main(int argc, char **argv) } mapi_destroy(mid); + if (toConsole != stdout_stream && toConsole != stderr_stream) + close_stream(toConsole); mnstr_destroy(stdout_stream); mnstr_destroy(stderr_stream); if (priv.buf != NULL) diff --git a/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py new file mode 100644 --- /dev/null +++ b/sql/test/BugTracker-2024/Tests/7536-mclient-forgets-to-flush.SQL.py @@ -0,0 +1,35 @@ +import gzip +import os +import tempfile +import subprocess + + +# This SQL script redirects the output to a file (the %s). +# We will check that all output arrives there, even if it's a gzipped file. +SCRIPT = f"""\ +\>%s +SELECT 'Donald Knuth'; +""" + + +with tempfile.TemporaryDirectory('mtest') as dir: +dir = '/tmp/jvr' +outputfile = os.path.join(dir, 'output.txt.gz') +inputfile = os.path.join(dir, 'input.sql') + +with open(inputfile, 'w') as f: +f.write(SCRIPT % outputfile) + +with open(inputfile) as f: +subprocess.check_call([ +'mclient', '-i', +inputfile, +'-p', os.environ['MAPIPORT'], +]) + +with gzip.open(outputfile, 'rt', encoding='utf-8') as f: +content = f.read() + +# print(content) + +assert 'Donald Knuth' in content diff --git a/sql/test/BugTracker-2024/Tests/All b/sql/test/BugTracker-2024/Tests/All --- a/sql/test/BugTracker-2024/Tests/All +++ b/sql/test/BugTracker-2024/Tests/All @@ -63,3 +63,4 @@ 7524-right-outer-join 7528-jarowinkler-null 7534-is-distinct-from 7535-create-view-groupby-func +7536-mclient-forgets-to-flush ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
monetdb-java: default - Add TLSTester.java to jdbctests.jar
Changeset: 65d42db0c831 for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java/rev/65d42db0c831 Modified Files: tests/build.xml Branch: default Log Message: Add TLSTester.java to jdbctests.jar So we can test it from Mtest, which now has TLSTester.py built in. diffs (12 lines): diff --git a/tests/build.xml b/tests/build.xml --- a/tests/build.xml +++ b/tests/build.xml @@ -82,6 +82,8 @@ Copyright 1997 - July 2008 CWI. + + ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - More efficient implementation of text_pump_in()
Changeset: 064ab92cd39d for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/064ab92cd39d Modified Files: common/stream/text_stream.c Branch: default Log Message: More efficient implementation of text_pump_in() diffs (105 lines): diff --git a/common/stream/text_stream.c b/common/stream/text_stream.c --- a/common/stream/text_stream.c +++ b/common/stream/text_stream.c @@ -89,42 +89,69 @@ take_byte(inner_state_t *ist) static pump_result text_pump_in(inner_state_t *ist, pump_action action) { - bool crlf_pending = ist->crlf_pending; + assert(ist->dst_win.count > 0); + assert(ist->src_win.count > 0 || action == PUMP_FINISH); - while (ist->src_win.count > 0 && ist->dst_win.count > 0) { - char c = take_byte(ist); - switch (c) { - case '\r': - if (crlf_pending) { - // put the previous one, which is clearly not followed by an \n - put_byte(ist, '\r'); - } - crlf_pending = true; - continue; - case '\n': - put_byte(ist, c); - crlf_pending = false; - continue; - default: - if (crlf_pending) { - put_byte(ist, '\r'); - crlf_pending = false; - // if dst_win.count was 1, there is no room for another put_byte(). - if (ist->dst_win.count > 0) { - put_byte(ist, c); - } else { - // no room anymore for char c, put it back! - ist->src_win.start--; - ist->src_win.count++; - } - } else { - put_byte(ist, c); - } - continue; + if (ist->crlf_pending) { + if (ist->src_win.count > 0) { + if (ist->src_win.start[0] != '\n') { + // CR not followed by a LF, emit it + put_byte(ist, '\r'); + } + } else { + assert(action == PUMP_FINISH); + // CR followed by end of file, not LF, so emit it + put_byte(ist, '\r'); } + // in any case, the CR is no longer pending + ist->crlf_pending = false; } - ist->crlf_pending = crlf_pending; + while (1) { + size_t span = ist->src_win.count < ist->dst_win.count + ? ist->src_win.count + : ist->dst_win.count; + if (span == 0) + break; + + if (ist->src_win.start[0] == '\r') { + // Looking at a CR. We'll handle just that, then make another round of the while loop + if (ist->src_win.count == 1) { + // Don't know what will follow, move it to the flag. + // Then stop, as all available input has been consumed + take_byte(ist); + ist->crlf_pending = true; + break; + } + assert(ist->src_win.count > 1); // We can safely look ahead + if (ist->src_win.start[1] == '\n') { + // Drop the CR, move the LF + take_byte(ist); + put_byte(ist, take_byte(ist)); + } else { + // Move the CR + put_byte(ist, take_byte(ist)); + } + // progress has been made, consider the situation anew + continue; + } else { + // The remaining input data does not start with a CR. + // Move all non-CR data to the output buffer + char *cr = memchr(ist->src_win.start, '\r', span); + if (cr != NULL) { + span = cr - ist->src_win.start; + } + assert(span > 0); + memcpy(ist->dst_win.start, ist->src_win.start, span); + ist->src_win.start += span; + ist->s
MonetDB: default - Use of text_pump_in_with_putback is supposed ...
Changeset: 9ff9f083b319 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/9ff9f083b319 Modified Files: common/stream/text_stream.c Branch: default Log Message: Use of text_pump_in_with_putback is supposed to be temporary diffs (49 lines): diff --git a/common/stream/text_stream.c b/common/stream/text_stream.c --- a/common/stream/text_stream.c +++ b/common/stream/text_stream.c @@ -30,6 +30,7 @@ struct inner_state { pump_buffer src_win; pump_buffer dst_win; pump_buffer putback_win; + pump_state *outer_state; char putback_buf[UTF8BOMLENGTH]; bool crlf_pending; char buffer[BUFFER_SIZE]; @@ -150,16 +151,20 @@ text_pump_in(inner_state_t *ist, pump_ac static pump_result text_pump_in_with_putback(inner_state_t *ist, pump_action action) { - if (ist->putback_win.count > 0) { - pump_buffer tmp = ist->src_win; - ist->src_win = ist->putback_win; - pump_result ret = text_pump_in(ist, PUMP_NO_FLUSH); - ist->putback_win = ist->src_win; - ist->src_win = tmp; - if (ret == PUMP_ERROR) - return PUMP_ERROR; + if (ist->putback_win.count == 0) { + // no need for this function anymore + assert(ist->outer_state->worker == text_pump_in_with_putback); + ist->outer_state->worker = text_pump_in; + return text_pump_in(ist, action); } - return text_pump_in(ist, action); + + // first empty the putback buffer + pump_buffer tmp = ist->src_win; + ist->src_win = ist->putback_win; + pump_result ret = text_pump_in(ist, PUMP_NO_FLUSH); + ist->putback_win = ist->src_win; + ist->src_win = tmp; + return ret; } @@ -295,6 +300,7 @@ create_text_stream(stream *inner) state->finalizer = text_end; state->get_error = get_error; + inner_state->outer_state = state; inner_state->putback_win.start = inner_state->putback_buf; inner_state->putback_win.count = 0; if (inner->readonly) { ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - Mention 'ODBC' in ClientLibrary if connecting...
Changeset: 21bd5080c348 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/21bd5080c348 Modified Files: clients/Tests/exports.stable.out clients/mapilib/connect.c clients/mapilib/mapi.c clients/mapilib/mapi.h clients/mapilib/mapi_intern.h clients/odbc/driver/SQLConnect.c Branch: default Log Message: Mention 'ODBC' in ClientLibrary if connecting through ODBC diffs (96 lines): diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out --- a/clients/Tests/exports.stable.out +++ b/clients/Tests/exports.stable.out @@ -721,6 +721,7 @@ MapiMsg mapi_set_columnar_protocol(Mapi MapiMsg mapi_set_size_header(Mapi mid, bool value) __attribute__((__nonnull__(1))); MapiMsg mapi_set_time_zone(Mapi mid, int seconds_east_of_utc) __attribute__((__nonnull__(1))); MapiMsg mapi_set_timeout(Mapi mid, unsigned int timeout, bool (*callback)(void *), void *callback_data) __attribute__((__nonnull__(1))); +void mapi_setclientprefix(Mapi mid, const char *prefix); void mapi_setfilecallback(Mapi mid, char *(*getfunc)(void *priv, const char *filename, bool binary, uint64_t offset, size_t *size), char *(*putfunc)(void *priv, const char *filename, const void *data, size_t size), void *priv) __attribute__((__nonnull__(1))); void mapi_setfilecallback2(Mapi mid, char *(*getfunc)(void *priv, const char *filename, bool binary, uint64_t offset, size_t *size), char *(*putfunc)(void *priv, const char *filename, bool binary, const void *data, size_t size), void *priv) __attribute__((__nonnull__(1))); Mapi mapi_settings(msettings *settings) __attribute__((__nonnull__(1))); diff --git a/clients/mapilib/connect.c b/clients/mapilib/connect.c --- a/clients/mapilib/connect.c +++ b/clients/mapilib/connect.c @@ -406,7 +406,6 @@ send_all_clientinfo(Mapi mid) application_name = (const char*) basename((char*)application_name); } } - const char *client_library = "libmapi " MONETDB_VERSION; const char *client_remark = msetting_string(mp, MP_CLIENT_REMARK); long pid = getpid(); @@ -417,7 +416,10 @@ send_all_clientinfo(Mapi mid) reallocprintf(&buf, &pos, &cap, "ClientHostName=%s\n", hostname); if (application_name[0]) reallocprintf(&buf, &pos, &cap, "ApplicationName=%s\n", application_name); - reallocprintf(&buf, &pos, &cap, "ClientLibrary=%s\n", client_library); + reallocprintf(&buf, &pos, &cap, "ClientLibrary="); + if (mid->clientprefix) + reallocprintf(&buf, &pos, &cap, "%s / ", mid->clientprefix); + reallocprintf(&buf, &pos, &cap, "libmapi %s\n", MONETDB_VERSION); if (client_remark[0]) reallocprintf(&buf, &pos, &cap, "ClientRemark=%s\n", client_remark); if (pid > 0) diff --git a/clients/mapilib/mapi.c b/clients/mapilib/mapi.c --- a/clients/mapilib/mapi.c +++ b/clients/mapilib/mapi.c @@ -2021,6 +2021,7 @@ mapi_destroy(Mapi mid) free(mid->noexplain); if (mid->errorstr && mid->errorstr != mapi_nomem) free(mid->errorstr); + free(mid->clientprefix); msettings_destroy(mid->settings); @@ -2246,6 +2247,17 @@ mapi_setfilecallback(Mapi mid, mid->filecontentprivate_old = filecontentprivate; } +void +mapi_setclientprefix(Mapi mid, const char *prefix) +{ + free(mid->clientprefix); + if (prefix == NULL) + mid->clientprefix = NULL; + else + mid->clientprefix = strdup(prefix); + +} + #define testBinding(hdl,fnr) \ do {\ mapi_hdl_check(hdl);\ diff --git a/clients/mapilib/mapi.h b/clients/mapilib/mapi.h --- a/clients/mapilib/mapi.h +++ b/clients/mapilib/mapi.h @@ -105,6 +105,7 @@ mapi_export void mapi_setfilecallback( const void *data, size_t size), void *priv) __attribute__((__nonnull__(1))); +mapi_export void mapi_setclientprefix(Mapi mid, const char *prefix); mapi_export MapiMsg mapi_error(Mapi mid) __attribute__((__nonnull__(1))); diff --git a/clients/mapilib/mapi_intern.h b/clients/mapilib/mapi_intern.h --- a/clients/mapilib/mapi_intern.h +++ b/clients/mapilib/mapi_intern.h @@ -238,6 +238,7 @@ struct MapiStruct { MapiMsg error; /* Error occurred */ char *errorstr; /* error from server */ const char *action; /* pointer to constant string */ + char *clientprefix; /* prefix for 'client' clientinfo; NULL or allocated string */ struct BlockCache blk; bool connected; diff --git a/clients/odbc/driver/SQLConnect.c b/clients/odbc/driver/SQLConnect.c --- a/clients/odbc/driver/SQLConnect.c +++ b/clients/odbc/driver/SQLConnect.c @@ -481,6 +481,7 @@ MNDBConnectSettings(ODBCDbc *dbc, const Mapi mid = mapi_setting
MonetDB: default - Support clientinfo msettings from odbc
Changeset: f218fe31ac43 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f218fe31ac43 Modified Files: clients/odbc/driver/ODBCAttrs.c Branch: default Log Message: Support clientinfo msettings from odbc diffs (13 lines): diff --git a/clients/odbc/driver/ODBCAttrs.c b/clients/odbc/driver/ODBCAttrs.c --- a/clients/odbc/driver/ODBCAttrs.c +++ b/clients/odbc/driver/ODBCAttrs.c @@ -47,6 +47,9 @@ const struct attr_setting attr_settings[ { "LOGFILE", "Log File", MP_LOGFILE }, { "LOGINTIMEOUT", "Login Timeout", MP_CONNECT_TIMEOUT}, { "CONNECTIONTIMEOUT", "Connection Timeout", MP_REPLY_TIMEOUT}, + { "CLIENTINFO", "Send Client Info", MP_CLIENT_INFO }, + { "APPNAME", "Application Name", MP_CLIENT_APPLICATION }, + { "CLIENTREMARK", "Client Remark", MP_CLIENT_REMARK }, }; const int attr_setting_count = sizeof(attr_settings) / sizeof(attr_settings[0]); ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org
MonetDB: default - Replace mapi_set_application_name() with a ca...
Changeset: adafe325ac29 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/adafe325ac29 Modified Files: clients/Tests/exports.stable.out clients/mapiclient/mclient.c clients/mapiclient/msqldump.c clients/mapilib/connect.c clients/mapilib/mapi.c clients/mapilib/mapi.h clients/mapilib/mapi_intern.h tools/merovingian/daemon/snapshot.c Branch: default Log Message: Replace mapi_set_application_name() with a call to get_bin_path() diffs (134 lines): diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out --- a/clients/Tests/exports.stable.out +++ b/clients/Tests/exports.stable.out @@ -717,7 +717,6 @@ int64_t mapi_rows_affected(MapiHdl hdl) MapiMsg mapi_seek_row(MapiHdl hdl, int64_t rowne, int whence) __attribute__((__nonnull__(1))); MapiHdl mapi_send(Mapi mid, const char *cmd) __attribute__((__nonnull__(1))); MapiMsg mapi_setAutocommit(Mapi mid, bool autocommit) __attribute__((__nonnull__(1))); -void mapi_set_application_name(const char *name); MapiMsg mapi_set_columnar_protocol(Mapi mid, bool columnar_protocol) __attribute__((__nonnull__(1))); MapiMsg mapi_set_size_header(Mapi mid, bool value) __attribute__((__nonnull__(1))); MapiMsg mapi_set_time_zone(Mapi mid, int seconds_east_of_utc) __attribute__((__nonnull__(1))); diff --git a/clients/mapiclient/mclient.c b/clients/mapiclient/mclient.c --- a/clients/mapiclient/mclient.c +++ b/clients/mapiclient/mclient.c @@ -3682,7 +3682,6 @@ main(int argc, char **argv) } else { mid = mapi_mapi(host, port, user, passwd, language, dbname); } - mapi_set_application_name("mclient"); free(user_allocated); user_allocated = NULL; free(passwd_allocated); diff --git a/clients/mapiclient/msqldump.c b/clients/mapiclient/msqldump.c --- a/clients/mapiclient/msqldump.c +++ b/clients/mapiclient/msqldump.c @@ -237,7 +237,6 @@ main(int argc, char **argv) } else { mid = mapi_mapi(host, port, user, passwd, "sql", dbname); } - mapi_set_application_name("msqldump"); free(user_allocated); user_allocated = NULL; free(passwd_allocated); diff --git a/clients/mapilib/connect.c b/clients/mapilib/connect.c --- a/clients/mapilib/connect.c +++ b/clients/mapilib/connect.c @@ -385,6 +385,7 @@ static void send_all_clientinfo(Mapi mid) { msettings *mp = mid->settings; + void *free_this = NULL; if (!mid->clientinfo_supported) return; if (!msetting_bool(mp, MP_CLIENT_INFO)) @@ -398,8 +399,13 @@ send_all_clientinfo(Mapi mid) hostname[sizeof(hostname) - 1] = '\0'; } const char *application_name = msetting_string(mp, MP_CLIENT_APPLICATION); - if (!application_name[0]) - application_name = mapi_application_name; + if (!application_name[0]) { + application_name = get_bin_path(); + if (application_name) { + free_this = strdup(application_name); + application_name = (const char*) basename((char*)application_name); + } + } const char *client_library = "libmapi " MONETDB_VERSION; const char *client_remark = msetting_string(mp, MP_CLIENT_REMARK); long pid = getpid(); @@ -425,7 +431,9 @@ send_all_clientinfo(Mapi mid) if (pos <= cap) mapi_Xcommand(mid, "clientinfo", buf); + free(buf); + free(free_this); } static MapiMsg diff --git a/clients/mapilib/mapi.c b/clients/mapilib/mapi.c --- a/clients/mapilib/mapi.c +++ b/clients/mapilib/mapi.c @@ -794,8 +794,6 @@ static void mapi_store_bind(struct MapiR static ATOMIC_FLAG mapi_initialized = ATOMIC_FLAG_INIT; -char mapi_application_name[256] = { 0 }; - /* * Blocking * @@ -2121,15 +2119,6 @@ mapi_disconnect(Mapi mid) return MOK; } -void -mapi_set_application_name(const char *name) -{ - if (name) - strncpy(mapi_application_name, name, sizeof(mapi_application_name)-1); - else - mapi_application_name[0] = '\0'; -} - /* Set callback function to retrieve or send file content for COPY * INTO queries. * diff --git a/clients/mapilib/mapi.h b/clients/mapilib/mapi.h --- a/clients/mapilib/mapi.h +++ b/clients/mapilib/mapi.h @@ -76,9 +76,6 @@ extern "C" { # endif #endif -/* global state */ -mapi_export void mapi_set_application_name(const char *name); - /* connection-oriented functions */ mapi_export Mapi mapi_mapi(const char *host, int port, const char *username, const char *password, const char *lang, const char *dbname); mapi_export Mapi mapi_mapiuri(const char *url, const char *user, const char *pass, const char *lang); diff --git a/clients/mapilib/mapi_intern.h b/clients/mapilib/mapi_intern.h --- a/clients/mapilib/mapi_intern.h +++ b/clients/mapilib/mapi_intern.h @@ -310,8 +310,6 @@ MapiMsg mapi_Xcommand(Mapi
MonetDB: clientinfo - Add mapi_set_application_name and call it ...
Changeset: 7d6f6753c8f3 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/7d6f6753c8f3 Modified Files: clients/mapiclient/mclient.c clients/mapiclient/msqldump.c clients/mapilib/connect.c clients/mapilib/mapi.c clients/mapilib/mapi.h clients/mapilib/mapi_intern.h tools/merovingian/daemon/snapshot.c Branch: clientinfo Log Message: Add mapi_set_application_name and call it in mclient etc. diffs (99 lines): diff --git a/clients/mapiclient/mclient.c b/clients/mapiclient/mclient.c --- a/clients/mapiclient/mclient.c +++ b/clients/mapiclient/mclient.c @@ -3682,6 +3682,7 @@ main(int argc, char **argv) } else { mid = mapi_mapi(host, port, user, passwd, language, dbname); } + mapi_set_application_name("mclient"); free(user_allocated); user_allocated = NULL; free(passwd_allocated); diff --git a/clients/mapiclient/msqldump.c b/clients/mapiclient/msqldump.c --- a/clients/mapiclient/msqldump.c +++ b/clients/mapiclient/msqldump.c @@ -237,6 +237,7 @@ main(int argc, char **argv) } else { mid = mapi_mapi(host, port, user, passwd, "sql", dbname); } + mapi_set_application_name("msqldump"); free(user_allocated); user_allocated = NULL; free(passwd_allocated); diff --git a/clients/mapilib/connect.c b/clients/mapilib/connect.c --- a/clients/mapilib/connect.c +++ b/clients/mapilib/connect.c @@ -398,6 +398,8 @@ send_all_clientinfo(Mapi mid) hostname[sizeof(hostname) - 1] = '\0'; } const char *application_name = msetting_string(mp, MP_CLIENT_APPLICATION); + if (!application_name[0]) + application_name = mapi_application_name; const char *client_library = "libmapi " MONETDB_VERSION; const char *client_remark = msetting_string(mp, MP_CLIENT_REMARK); long pid = getpid(); diff --git a/clients/mapilib/mapi.c b/clients/mapilib/mapi.c --- a/clients/mapilib/mapi.c +++ b/clients/mapilib/mapi.c @@ -793,6 +793,9 @@ static int mapi_slice_row(struct MapiRes static void mapi_store_bind(struct MapiResultSet *result, int cr); static ATOMIC_FLAG mapi_initialized = ATOMIC_FLAG_INIT; + +char mapi_application_name[256] = { 0 }; + /* * Blocking * @@ -2118,6 +2121,15 @@ mapi_disconnect(Mapi mid) return MOK; } +void +mapi_set_application_name(const char *name) +{ + if (name) + strncpy(mapi_application_name, name, sizeof(mapi_application_name)); + else + mapi_application_name[0] = '\0'; +} + /* Set callback function to retrieve or send file content for COPY * INTO queries. * diff --git a/clients/mapilib/mapi.h b/clients/mapilib/mapi.h --- a/clients/mapilib/mapi.h +++ b/clients/mapilib/mapi.h @@ -76,6 +76,9 @@ extern "C" { # endif #endif +/* global state */ +mapi_export void mapi_set_application_name(const char *name); + /* connection-oriented functions */ mapi_export Mapi mapi_mapi(const char *host, int port, const char *username, const char *password, const char *lang, const char *dbname); mapi_export Mapi mapi_mapiuri(const char *url, const char *user, const char *pass, const char *lang); diff --git a/clients/mapilib/mapi_intern.h b/clients/mapilib/mapi_intern.h --- a/clients/mapilib/mapi_intern.h +++ b/clients/mapilib/mapi_intern.h @@ -310,6 +310,8 @@ MapiMsg mapi_Xcommand(Mapi mid, const ch extern const struct MapiStruct MapiStructDefaults; +extern char mapi_application_name[]; + // 'settings' will be newly allocated if NULL Mapi mapi_new(msettings *settings); diff --git a/tools/merovingian/daemon/snapshot.c b/tools/merovingian/daemon/snapshot.c --- a/tools/merovingian/daemon/snapshot.c +++ b/tools/merovingian/daemon/snapshot.c @@ -114,6 +114,7 @@ snapshot_database_stream(char *dbname, s e = newErr("connection error: %s", mapi_error_str(conn)); goto bailout; } + mapi_set_application_name("monetdbd"); mapi_reconnect(conn); if (mapi_error(conn) != MOK) { e = newErr("connection error: %s", mapi_error_str(conn)); ___ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org