LCOV - code coverage report
Current view: top level - monetdb5/modules/mal - clients.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 217 458 47.4 %
Date: 2024-12-20 20:06:10 Functions: 19 32 59.4 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * author Martin Kersten, Fabian Groffen
      15             :  * Client Management
      16             :  * Each online client is represented with an entry in the clients table.
      17             :  * The client may inspect his record at run-time and partially change its properties.
      18             :  * The administrator sees all client records and has the right to adjust global properties.
      19             :  */
      20             : 
      21             : 
      22             : #include "monetdb_config.h"
      23             : #include "clients.h"
      24             : #include "mcrypt.h"
      25             : #include "mal_scenario.h"
      26             : #include "mal_instruction.h"
      27             : #include "mal_runtime.h"
      28             : #include "mal_client.h"
      29             : #include "mal_authorize.h"
      30             : #include "mal_internal.h"
      31             : #include "opt_pipes.h"
      32             : #include "gdk_time.h"
      33             : 
      34             : static str
      35           1 : CLTsetListing(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      36             : {
      37           1 :         (void) mb;
      38           1 :         *getArgReference_int(stk, pci, 0) = cntxt->listing;
      39           1 :         cntxt->listing = *getArgReference_int(stk, pci, 1);
      40           1 :         return MAL_SUCCEED;
      41             : }
      42             : 
      43             : static str
      44           1 : CLTgetClientId(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      45             : {
      46           1 :         (void) mb;
      47           1 :         if (cntxt - mal_clients < 0 || cntxt - mal_clients >= MAL_MAXCLIENTS)
      48           0 :                 throw(MAL, "clients.getClientId", "Illegal client index");
      49           1 :         *getArgReference_int(stk, pci, 0) = (int) (cntxt - mal_clients);
      50           1 :         return MAL_SUCCEED;
      51             : }
      52             : 
      53             : static str
      54           0 : CLTgetScenario(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      55             : {
      56           0 :         (void) mb;
      57           0 :         if (cntxt->scenario)
      58           0 :                 *getArgReference_str(stk, pci, 0) = GDKstrdup(cntxt->scenario);
      59             :         else
      60           0 :                 *getArgReference_str(stk, pci, 0) = GDKstrdup("nil");
      61           0 :         if (*getArgReference_str(stk, pci, 0) == NULL)
      62           0 :                 throw(MAL, "clients.getScenario", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      63             :         return MAL_SUCCEED;
      64             : }
      65             : 
      66             : static str
      67           0 : CLTsetScenario(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      68             : {
      69           0 :         str msg = MAL_SUCCEED;
      70             : 
      71           0 :         (void) mb;
      72           0 :         msg = setScenario(cntxt, *getArgReference_str(stk, pci, 1));
      73           0 :         *getArgReference_str(stk, pci, 0) = 0;
      74           0 :         if (msg == NULL) {
      75           0 :                 *getArgReference_str(stk, pci, 0) = GDKstrdup(cntxt->scenario);
      76           0 :                 if (*getArgReference_str(stk, pci, 0) == NULL)
      77           0 :                         throw(MAL, "clients.setScenario", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      78             :         }
      79             :         return msg;
      80             : }
      81             : 
      82             : static void
      83           1 : CLTtimeConvert(time_t l, char *s)
      84             : {
      85           1 :         struct tm localt = (struct tm) { 0 };
      86             : 
      87           1 :         (void) localtime_r(&l, &localt);
      88             : 
      89             : #ifdef HAVE_ASCTIME_R3
      90             :         asctime_r(&localt, s, 26);
      91             : #else
      92           1 :         asctime_r(&localt, s);
      93             : #endif
      94           1 :         s[24] = 0;                                      /* remove newline */
      95           1 : }
      96             : 
      97             : static str
      98           1 : CLTInfo(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      99             : {
     100           1 :         bat *ret = getArgReference_bat(stk, pci, 0);
     101           1 :         bat *ret2 = getArgReference_bat(stk, pci, 1);
     102           1 :         BAT *b = COLnew(0, TYPE_str, 12, TRANSIENT);
     103           1 :         BAT *bn = COLnew(0, TYPE_str, 12, TRANSIENT);
     104           1 :         char buf[32];                           /* 32 bytes are enough */
     105             : 
     106           1 :         (void) mb;
     107           1 :         if (b == 0 || bn == 0) {
     108           0 :                 BBPreclaim(b);
     109           0 :                 BBPreclaim(bn);
     110           0 :                 throw(MAL, "clients.info", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     111             :         }
     112             : 
     113           1 :         (void) snprintf(buf, sizeof(buf), "" LLFMT "", (lng) cntxt->user);
     114           2 :         if (BUNappend(b, "user", false) != GDK_SUCCEED ||
     115           1 :                 BUNappend(bn, buf, false) != GDK_SUCCEED)
     116           0 :                 goto bailout;
     117             : 
     118           2 :         if (BUNappend(b, "scenario", false) != GDK_SUCCEED ||
     119           1 :                 BUNappend(bn, cntxt->scenario, false) != GDK_SUCCEED)
     120           0 :                 goto bailout;
     121             : 
     122           1 :         (void) snprintf(buf, sizeof(buf), "%d", cntxt->listing);
     123           2 :         if (BUNappend(b, "listing", false) != GDK_SUCCEED ||
     124           1 :                 BUNappend(bn, buf, false) != GDK_SUCCEED)
     125           0 :                 goto bailout;
     126             : 
     127           1 :         CLTtimeConvert(cntxt->login, buf);
     128           2 :         if (BUNappend(b, "login", false) != GDK_SUCCEED ||
     129           1 :                 BUNappend(bn, buf, false) != GDK_SUCCEED)
     130           0 :                 goto bailout;
     131           1 :         *ret = b->batCacheid;
     132           1 :         BBPkeepref(b);
     133           1 :         *ret2 = bn->batCacheid;
     134           1 :         BBPkeepref(bn);
     135           1 :         return MAL_SUCCEED;
     136             : 
     137           0 :   bailout:
     138           0 :         BBPunfix(b->batCacheid);
     139           0 :         BBPunfix(bn->batCacheid);
     140           0 :         throw(MAL, "clients.info", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     141             : }
     142             : 
     143             : static str
     144           0 : CLTLogin(bat *nme, bat *ret)
     145             : {
     146           0 :         BAT *b = COLnew(0, TYPE_str, 12, TRANSIENT);
     147           0 :         BAT *u = COLnew(0, TYPE_oid, 12, TRANSIENT);
     148           0 :         int i;
     149           0 :         char s[32];
     150             : 
     151           0 :         if (b == 0 || u == 0)
     152           0 :                 goto bailout;
     153             : 
     154           0 :         for (i = 0; i < MAL_MAXCLIENTS; i++) {
     155           0 :                 Client c = mal_clients + i;
     156           0 :                 if (c->mode >= RUNCLIENT && !is_oid_nil(c->user)) {
     157           0 :                         CLTtimeConvert(c->login, s);
     158           0 :                         if (BUNappend(b, s, false) != GDK_SUCCEED ||
     159           0 :                                 BUNappend(u, &c->user, false) != GDK_SUCCEED)
     160           0 :                                 goto bailout;
     161             :                 }
     162             :         }
     163           0 :         *ret = b->batCacheid;
     164           0 :         BBPkeepref(b);
     165           0 :         *nme = u->batCacheid;
     166           0 :         BBPkeepref(u);
     167           0 :         return MAL_SUCCEED;
     168             : 
     169           0 :   bailout:
     170           0 :         BBPreclaim(b);
     171           0 :         BBPreclaim(u);
     172           0 :         throw(MAL, "clients.getLogins", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     173             : }
     174             : 
     175             : static str
     176           1 : CLTquit(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     177             : {
     178           1 :         str msg = MAL_SUCCEED;
     179           1 :         int idx = cntxt->idx;
     180           1 :         (void) mb;                                      /* fool compiler */
     181             : 
     182           1 :         if (pci->argc == 2) {
     183           0 :                 if (cntxt->user == MAL_ADMIN)
     184           0 :                         idx = *getArgReference_int(stk, pci, 1);
     185             :                 else
     186           0 :                         throw(MAL, "clients.quit",
     187             :                                   SQLSTATE(42000) "Administrator rights required");
     188             :         }
     189             : 
     190           1 :         if (idx < 0 || idx > MAL_MAXCLIENTS)
     191           0 :                 throw(MAL, "clients.quit", "Illegal session id");
     192             : 
     193             :         /* A user can only quit a session under the same id */
     194           1 :         MT_lock_set(&mal_contextLock);
     195           1 :         if (mal_clients[idx].mode == FREECLIENT)
     196           0 :                 msg = createException(MAL, "clients.stop",
     197             :                                                           "Session not active anymore");
     198             :         else
     199           1 :                 mal_clients[idx].mode = FINISHCLIENT;
     200           1 :         MT_lock_unset(&mal_contextLock);
     201           1 :         return msg;
     202             : }
     203             : 
     204             : /* Stopping a client in a soft manner by setting the time out marker */
     205             : static str
     206           0 : CLTstop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     207             : {
     208           0 :         int idx = cntxt->idx;
     209           0 :         str msg = MAL_SUCCEED;
     210             : 
     211           0 :         (void) mb;
     212           0 :         if (cntxt->user != MAL_ADMIN)
     213           0 :                 throw(MAL, "clients.stop",
     214             :                           SQLSTATE(42000) "Administrator rights required");
     215             : 
     216           0 :         idx = *getArgReference_int(stk, pci, 1);
     217             : 
     218           0 :         if (idx < 0 || idx > MAL_MAXCLIENTS)
     219           0 :                 throw(MAL, "clients.stop", "Illegal session id");
     220             : 
     221           0 :         MT_lock_set(&mal_contextLock);
     222           0 :         if (mal_clients[idx].mode == FREECLIENT)
     223           0 :                 msg = createException(MAL, "clients.stop",
     224             :                                                           "Session not active anymore");
     225             :         else
     226           0 :                 mal_clients[idx].qryctx.endtime = 1;    /* stop client now */
     227             :         /* this forces the designated client to stop at the next instruction */
     228           0 :         MT_lock_unset(&mal_contextLock);
     229           0 :         return msg;
     230             : }
     231             : 
     232             : static str
     233           4 : CLTsetoptimizer(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     234             : {
     235           4 :         int idx = cntxt->idx;
     236           4 :         str opt, msg = MAL_SUCCEED;
     237             : 
     238           4 :         (void) mb;
     239           4 :         if (pci->argc == 3) {
     240           0 :                 if (cntxt->user == MAL_ADMIN) {
     241           0 :                         idx = *getArgReference_int(stk, pci, 1);
     242           0 :                         opt = *getArgReference_str(stk, pci, 2);
     243             :                 } else {
     244           0 :                         throw(MAL, "clients.setoptimizer",
     245             :                                   SQLSTATE(42000) "Administrator rights required");
     246             :                 }
     247             :         } else {
     248           4 :                 opt = *getArgReference_str(stk, pci, 1);
     249             :         }
     250             : 
     251           4 :         if (idx < 0 || idx > MAL_MAXCLIENTS)
     252           0 :                 throw(MAL, "clients.setoptimizer", "Illegal session id");
     253           4 :         if (strNil(opt))
     254           0 :                  throw(MAL, "clients.setoptimizer", "Input string cannot be NULL");
     255           4 :         if (strlen(opt) >= sizeof(mal_clients[idx].optimizer))
     256           0 :                  throw(MAL, "clients.setoptimizer", "Input string is too large");
     257           4 :         if (!isOptimizerPipe(opt))
     258           1 :                  throw(MAL, "clients.setoptimizer", "Valid optimizer pipe expected");
     259             : 
     260           3 :         MT_lock_set(&mal_contextLock);
     261           3 :         if (mal_clients[idx].mode == FREECLIENT)
     262           0 :                 msg = createException(MAL, "clients.setoptimizer",
     263             :                                                           "Session not active anymore");
     264             :         else
     265           3 :                 strcpy_len(mal_clients[idx].optimizer, opt,
     266             :                                    sizeof(mal_clients[idx].optimizer));
     267           3 :         MT_lock_unset(&mal_contextLock);
     268           3 :         return msg;
     269             : }
     270             : 
     271             : static str
     272           4 : CLTsetworkerlimit(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     273             : {
     274           4 :         str msg = MAL_SUCCEED;
     275           4 :         int idx = cntxt->idx, limit;
     276             : 
     277           4 :         (void) mb;
     278           4 :         if (pci->argc == 3) {
     279           0 :                 if (cntxt->user == MAL_ADMIN) {
     280           0 :                         idx = *getArgReference_int(stk, pci, 1);
     281           0 :                         limit = *getArgReference_int(stk, pci, 2);
     282             :                 } else {
     283           0 :                         throw(MAL, "clients.setworkerlimit",
     284             :                                   SQLSTATE(42000) "Administrator rights required");
     285             :                 }
     286             :         } else {
     287           4 :                 limit = *getArgReference_int(stk, pci, 1);
     288             :         }
     289             : 
     290           4 :         if (idx < 0 || idx > MAL_MAXCLIENTS)
     291           0 :                 throw(MAL, "clients.setworkerlimit", "Illegal session id");
     292           4 :         if (is_int_nil(limit))
     293           0 :                 throw(MAL, "clients.setworkerlimit",
     294             :                           "The number of workers cannot be NULL");
     295           4 :         if (limit < 0)
     296           1 :                 throw(MAL, "clients.setworkerlimit",
     297             :                           "The number of workers cannot be negative");
     298             : 
     299           3 :         MT_lock_set(&mal_contextLock);
     300           3 :         if (mal_clients[idx].mode == FREECLIENT)
     301           0 :                 msg = createException(MAL, "clients.setworkerlimit",
     302             :                                                           "Session not active anymore");
     303             :         else {
     304           3 :                 if (limit == 0) {
     305           0 :                         if (mal_clients[idx].maxworkers > 0)
     306             :                                 limit = mal_clients[idx].maxworkers;
     307           3 :                 } else if (cntxt->user != MAL_ADMIN &&
     308           0 :                                    mal_clients[idx].maxworkers > 0 &&
     309             :                                    mal_clients[idx].maxworkers < limit) {
     310           3 :                         limit = mal_clients[idx].maxworkers;
     311             :                 }
     312           3 :                 mal_clients[idx].workerlimit = limit;
     313             :         }
     314           3 :         MT_lock_unset(&mal_contextLock);
     315           3 :         return msg;
     316             : }
     317             : 
     318             : static str
     319           0 : CLTsetmemorylimit(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     320             : {
     321           0 :         str msg = MAL_SUCCEED;
     322           0 :         int idx = cntxt->idx, limit;
     323             : 
     324           0 :         (void) mb;
     325           0 :         if (pci->argc == 3) {
     326           0 :                 if (cntxt->user == MAL_ADMIN) {
     327           0 :                         idx = *getArgReference_sht(stk, pci, 1);
     328           0 :                         limit = *getArgReference_int(stk, pci, 2);
     329             :                 } else {
     330           0 :                         throw(MAL, "clients.setmemorylimit",
     331             :                                   SQLSTATE(42000) "Administrator rights required");
     332             :                 }
     333             :         } else {
     334           0 :                 limit = *getArgReference_int(stk, pci, 1);
     335             :         }
     336             : 
     337           0 :         if (idx < 0 || idx > MAL_MAXCLIENTS)
     338           0 :                 throw(MAL, "clients.setmemorylimit", "Illegal session id");
     339           0 :         if (is_int_nil(limit))
     340           0 :                 throw(MAL, "clients.setmemorylimit",
     341             :                           "The memory limit cannot be NULL");
     342           0 :         if (limit < 0)
     343           0 :                 throw(MAL, "clients.setmemorylimit",
     344             :                           "The memory limit cannot be negative");
     345             : 
     346           0 :         lng mlimit = (lng) limit << 20;
     347             : 
     348           0 :         MT_lock_set(&mal_contextLock);
     349           0 :         if (mal_clients[idx].mode == FREECLIENT)
     350           0 :                 msg = createException(MAL, "clients.setmemorylimit",
     351             :                                                           "Session not active anymore");
     352             :         else {
     353           0 :                 if (mlimit == 0) {
     354           0 :                         if (mal_clients[idx].maxmem > 0)
     355             :                                 mlimit = mal_clients[idx].maxmem;
     356           0 :                 } else if (cntxt->user != MAL_ADMIN &&
     357           0 :                                    mal_clients[idx].maxmem > 0 &&
     358             :                                    mal_clients[idx].maxmem < mlimit) {
     359           0 :                         mlimit = mal_clients[idx].maxmem;
     360             :                 }
     361           0 :                 mal_clients[idx].memorylimit = (int) (mlimit >> 20);
     362           0 :                 mal_clients[idx].qryctx.maxmem = (ATOMIC_BASE_TYPE) mlimit;
     363             :         }
     364           0 :         MT_lock_unset(&mal_contextLock);
     365           0 :         return msg;
     366             : }
     367             : 
     368             : static str
     369           0 : CLTstopSession(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     370             : {
     371           0 :         str msg = MAL_SUCCEED;
     372           0 :         int idx = cntxt->idx;
     373           0 :         (void) mb;
     374             : 
     375           0 :         if (cntxt->user != MAL_ADMIN) {
     376           0 :                 throw(MAL, "clients.stopsession",
     377             :                           SQLSTATE(42000) "Administrator rights required");
     378             :         }
     379           0 :         idx = *getArgReference_int(stk, pci, 1);
     380           0 :         if (idx < 0 || idx > MAL_MAXCLIENTS)
     381           0 :                 throw(MAL, "clients.stopSession", "Illegal session id");
     382             : 
     383           0 :         MT_lock_set(&mal_contextLock);
     384           0 :         if (mal_clients[idx].mode == FREECLIENT) {
     385           0 :                 msg = createException(MAL, "clients.stopSession",
     386             :                                                           "Session not active anymore");
     387             :         } else {
     388           0 :                 mal_clients[idx].qryctx.endtime = 1;    /* stop client now */
     389           0 :                 mal_clients[idx].sessiontimeout = 1;    /* stop client session */
     390             :         }
     391           0 :         MT_lock_unset(&mal_contextLock);
     392             :         /* this forces the designated client to stop at the next instruction */
     393           0 :         return msg;
     394             : }
     395             : 
     396             : /* Queries can be temporarily suspended */
     397             : static str
     398           0 : CLTsuspend(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     399             : {
     400           0 :         str msg = MAL_SUCCEED;
     401           0 :         int idx = cntxt->idx;
     402             : 
     403           0 :         if (cntxt->user != MAL_ADMIN)
     404           0 :                 throw(MAL, "clients.suspend",
     405             :                           SQLSTATE(42000) "Administrator rights required");
     406             : 
     407           0 :         idx = *getArgReference_int(stk, pci, 1);
     408           0 :         (void) mb;
     409             : 
     410           0 :         if (idx < 0 || idx > MAL_MAXCLIENTS)
     411           0 :                 throw(MAL, "clients.suspend", "Illegal session id");
     412             : 
     413           0 :         MT_lock_set(&mal_contextLock);
     414           0 :         if (mal_clients[idx].mode == FREECLIENT)
     415           0 :                 msg = createException(MAL, "clients.suspend",
     416             :                                                           "Session not active anymore");
     417             :         else
     418           0 :                 msg = MCsuspendClient(idx);
     419           0 :         MT_lock_unset(&mal_contextLock);
     420           0 :         return msg;
     421             : }
     422             : 
     423             : static str
     424           0 : CLTwakeup(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     425             : {
     426           0 :         str msg = MAL_SUCCEED;
     427           0 :         int idx = cntxt->idx;
     428             : 
     429           0 :         if (cntxt->user != MAL_ADMIN)
     430           0 :                 throw(MAL, "clients.wakeup",
     431             :                           SQLSTATE(42000) "Administrator rights required");
     432             : 
     433           0 :         idx = *getArgReference_int(stk, pci, 1);
     434           0 :         (void) mb;
     435             : 
     436           0 :         if (idx < 0 || idx > MAL_MAXCLIENTS)
     437           0 :                 throw(MAL, "clients.wakeup", "Illegal session id");
     438             : 
     439           0 :         MT_lock_set(&mal_contextLock);
     440           0 :         if (mal_clients[idx].mode == FREECLIENT)
     441           0 :                 msg = createException(MAL, "clients.wakeup",
     442             :                                                           "Session not active anymore");
     443             :         else
     444           0 :                 msg = MCawakeClient(idx);
     445           0 :         MT_lock_unset(&mal_contextLock);
     446           0 :         return msg;
     447             : }
     448             : 
     449             : /* set query timeout based in seconds, converted into microseconds */
     450             : static str
     451          19 : CLTqueryTimeout(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     452             : {
     453          19 :         str msg = MAL_SUCCEED;
     454          19 :         int qto, idx = cntxt->idx;
     455          19 :         (void) mb;
     456             : 
     457          19 :         if (pci->argc == 3) {
     458           0 :                 if (cntxt->user == MAL_ADMIN) {
     459           0 :                         idx = *getArgReference_int(stk, pci, 1);
     460           0 :                         qto = *getArgReference_int(stk, pci, 2);
     461             :                 } else {
     462           0 :                         throw(MAL, "clients.setquerytimeout",
     463             :                                   SQLSTATE(42000) "Administrator rights required");
     464             :                 }
     465             :         } else {
     466          19 :                 qto = *getArgReference_int(stk, pci, 1);
     467             :         }
     468          19 :         if (is_int_nil(qto))
     469           0 :                 throw(MAL, "clients.setquerytimeout", "Query timeout cannot be NULL");
     470          19 :         if (qto < 0)
     471           1 :                 throw(MAL, "clients.setquerytimeout", "Query timeout should be >= 0");
     472             : 
     473          18 :         MT_lock_set(&mal_contextLock);
     474          18 :         if (mal_clients[idx].mode == FREECLIENT)
     475           0 :                 msg = createException(MAL, "clients.setquerytimeout",
     476             :                                                           "Session not active anymore");
     477             :         else {
     478             :                 /* when testing (TESTINGMASK), reduce timeout of 1 sec to 1 msec */
     479          36 :                 lng timeout_micro = ATOMIC_GET(&GDKdebug) & TESTINGMASK
     480          18 :                                 && qto == 1 ? 1000 : (lng) qto * 1000000;
     481          18 :                 mal_clients[idx].querytimeout = timeout_micro;
     482             :         }
     483          18 :         MT_lock_unset(&mal_contextLock);
     484          18 :         return msg;
     485             : }
     486             : 
     487             : // set query timeout based in microseconds
     488             : static str
     489           2 : CLTqueryTimeoutMicro(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     490             : {
     491           2 :         str msg = MAL_SUCCEED;
     492           2 :         int idx = cntxt->idx;
     493           2 :         lng qto = *getArgReference_lng(stk, pci, 1);
     494           2 :         (void) mb;
     495             : 
     496           2 :         if (is_lng_nil(qto))
     497           0 :                 throw(MAL, "clients.queryTimeout", "Query timeout cannot be NULL");
     498           2 :         if (qto < 0)
     499           0 :                 throw(MAL, "clients.queryTimeout", "Query timeout should be >= 0");
     500             : 
     501           2 :         MT_lock_set(&mal_contextLock);
     502           2 :         if (mal_clients[idx].mode == FREECLIENT)
     503           0 :                 msg = createException(MAL, "clients.queryTimeout",
     504             :                                                           "Session not active anymore");
     505             :         else {
     506           2 :                 mal_clients[idx].querytimeout = qto;
     507           2 :                 QryCtx *qry_ctx = MT_thread_get_qry_ctx();
     508           2 :                 if (qry_ctx) {
     509           2 :                         qry_ctx->endtime = qry_ctx->starttime && qto ? qry_ctx->starttime + qto : 0;
     510             :                 }
     511             :         }
     512           2 :         MT_lock_unset(&mal_contextLock);
     513           2 :         return msg;
     514             : }
     515             : 
     516             : /* Set the current session timeout in seconds */
     517             : static str
     518        2914 : CLTsessionTimeout(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     519             : {
     520        2914 :         str msg = MAL_SUCCEED;
     521        2914 :         int sto = -1, idx = cntxt->idx;
     522        2914 :         (void) mb;
     523             : 
     524        2914 :         if (pci->argc == 3) {
     525           0 :                 if (cntxt->user == MAL_ADMIN) {
     526           0 :                         idx = *getArgReference_int(stk, pci, 1);
     527           0 :                         sto = *getArgReference_int(stk, pci, 2);
     528             :                 } else {
     529           0 :                         throw(MAL, "clients.setsessiontimeout",
     530             :                                   SQLSTATE(42000) "Administrator rights required");
     531             :                 }
     532             :         } else {
     533        2914 :                 sto = *getArgReference_int(stk, pci, 1);
     534             :         }
     535        2914 :         if (is_int_nil(sto))
     536           0 :                 throw(MAL, "clients.setsessiontimeout",
     537             :                           "Session timeout cannot be NULL");
     538        2914 :         if (sto < 0)
     539           1 :                 throw(MAL, "clients.setsessiontimeout",
     540             :                           "Session timeout should be >= 0");
     541        2913 :         if (idx < 0 || idx > MAL_MAXCLIENTS)
     542           0 :                 throw(MAL, "clients.setsessiontimeout", "Illegal session id %d", idx);
     543             : 
     544        2913 :         MT_lock_set(&mal_contextLock);
     545        2913 :         if (mal_clients[idx].mode == FREECLIENT)
     546           0 :                 msg = createException(MAL, "clients.setsessiontimeout",
     547             :                                                           "Session not active anymore");
     548             :         else {
     549        2913 :                 mal_clients[idx].sessiontimeout = sto > 0 ? (lng) sto *1000000 + (GDKusec() - mal_clients[idx].session) : 0;
     550        2913 :                 mal_clients[idx].logical_sessiontimeout = (lng) sto;
     551             :         }
     552        2913 :         MT_lock_unset(&mal_contextLock);
     553        2913 :         return msg;
     554             : }
     555             : 
     556             : /* Retrieve the session time out */
     557             : static str
     558           0 : CLTgetProfile(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     559             : {
     560           0 :         str *opt = getArgReference_str(stk, pci, 0);
     561           0 :         int *qto = getArgReference_int(stk, pci, 1);
     562           0 :         int *sto = getArgReference_int(stk, pci, 2);
     563           0 :         int *wlim = getArgReference_int(stk, pci, 3);
     564           0 :         int *mlim = getArgReference_int(stk, pci, 4);
     565           0 :         (void) mb;
     566           0 :         if (!(*opt = GDKstrdup(cntxt->optimizer)))
     567           0 :                 throw(MAL, "clients.getProfile", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     568           0 :         *qto = (int) (cntxt->querytimeout / 1000000);
     569           0 :         *sto = (int) (cntxt->sessiontimeout / 1000000);
     570           0 :         *wlim = cntxt->workerlimit;
     571           0 :         *mlim = cntxt->memorylimit;
     572           0 :         return MAL_SUCCEED;
     573             : }
     574             : 
     575             : /* Long running queries are traced in the logger
     576             :  * with a message from the interpreter.
     577             :  * This value should be set to minutes to avoid a lengthy log */
     578             : static str
     579           0 : CLTsetPrintTimeout(void *ret, const int *secs)
     580             : {
     581           0 :         (void) ret;
     582           0 :         if (is_int_nil(*secs))
     583           0 :                 setqptimeout(0);
     584             :         else
     585           0 :                 setqptimeout((lng) *secs * 60 * 1000000);
     586           0 :         return MAL_SUCCEED;
     587             : }
     588             : 
     589             : static str
     590          14 : CLTmd5sum(str *ret, const char *const *pw)
     591             : {
     592          14 :         if (strNil(*pw)) {
     593           1 :                 *ret = GDKstrdup(str_nil);
     594             :         } else {
     595          13 :                 char *mret = mcrypt_MD5Sum(*pw, strlen(*pw));
     596             : 
     597          13 :                 if (!mret)
     598           0 :                         throw(MAL, "clients.md5sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     599          13 :                 *ret = GDKstrdup(mret);
     600          13 :                 free(mret);
     601             :         }
     602          14 :         if (*ret == NULL)
     603           0 :                 throw(MAL, "clients.md5sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     604             :         return MAL_SUCCEED;
     605             : }
     606             : 
     607             : static str
     608           1 : CLTsha1sum(str *ret, const char *const *pw)
     609             : {
     610           1 :         if (strNil(*pw)) {
     611           0 :                 *ret = GDKstrdup(str_nil);
     612             :         } else {
     613           1 :                 char *mret = mcrypt_SHA1Sum(*pw, strlen(*pw));
     614             : 
     615           1 :                 if (!mret)
     616           0 :                         throw(MAL, "clients.sha1sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     617           1 :                 *ret = GDKstrdup(mret);
     618           1 :                 free(mret);
     619             :         }
     620           1 :         if (*ret == NULL)
     621           0 :                 throw(MAL, "clients.sha1sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     622             :         return MAL_SUCCEED;
     623             : }
     624             : 
     625             : static str
     626           1 : CLTripemd160sum(str *ret, const char *const *pw)
     627             : {
     628           1 :         if (strNil(*pw)) {
     629           0 :                 *ret = GDKstrdup(str_nil);
     630             :         } else {
     631           1 :                 char *mret = mcrypt_RIPEMD160Sum(*pw, strlen(*pw));
     632             : 
     633           1 :                 if (!mret)
     634           0 :                         throw(MAL, "clients.ripemd160sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     635           1 :                 *ret = GDKstrdup(mret);
     636           1 :                 free(mret);
     637             :         }
     638           1 :         if (*ret == NULL)
     639           0 :                 throw(MAL, "clients.ripemd160sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     640             :         return MAL_SUCCEED;
     641             : }
     642             : 
     643             : static str
     644           4 : CLTsha2sum(str *ret, const char *const *pw, const int *bits)
     645             : {
     646           8 :         if (strNil(*pw) || is_int_nil(*bits)) {
     647           0 :                 *ret = GDKstrdup(str_nil);
     648             :         } else {
     649           4 :                 char *mret = 0;
     650           4 :                 switch (*bits) {
     651           1 :                 case 512:
     652           1 :                         mret = mcrypt_SHA512Sum(*pw, strlen(*pw));
     653           1 :                         break;
     654           1 :                 case 384:
     655           1 :                         mret = mcrypt_SHA384Sum(*pw, strlen(*pw));
     656           1 :                         break;
     657           1 :                 case 256:
     658           1 :                         mret = mcrypt_SHA256Sum(*pw, strlen(*pw));
     659           1 :                         break;
     660           1 :                 case 224:
     661           1 :                         mret = mcrypt_SHA224Sum(*pw, strlen(*pw));
     662           1 :                         break;
     663           0 :                 default:
     664           0 :                         (void) mret;
     665           0 :                         throw(ILLARG, "clients.sha2sum", "wrong number of bits "
     666             :                                   "for SHA2 sum: %d", *bits);
     667             :                 }
     668           4 :                 if (!mret)
     669           0 :                         throw(MAL, "clients.sha2sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     670           4 :                 *ret = GDKstrdup(mret);
     671           4 :                 free(mret);
     672             :         }
     673           4 :         if (*ret == NULL)
     674           0 :                 throw(MAL, "clients.sha2sum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     675             :         return MAL_SUCCEED;
     676             : }
     677             : 
     678             : static str
     679           0 : CLTbackendsum(str *ret, const char *const *pw)
     680             : {
     681           0 :         if (strNil(*pw)) {
     682           0 :                 *ret = GDKstrdup(str_nil);
     683             :         } else {
     684           0 :                 char *mret = mcrypt_BackendSum(*pw, strlen(*pw));
     685           0 :                 if (mret == NULL)
     686           0 :                         throw(MAL, "clients.backendsum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     687           0 :                 *ret = GDKstrdup(mret);
     688           0 :                 free(mret);
     689             :         }
     690           0 :         if (*ret == NULL)
     691           0 :                 throw(MAL, "clients.backendsum", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     692             :         return MAL_SUCCEED;
     693             : }
     694             : 
     695             : static str
     696           5 : CLTgetUsername(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     697             : {
     698           5 :         str *ret = getArgReference_str(stk, pci, 0);
     699           5 :         (void) mb;
     700             : 
     701           5 :         *ret = GDKstrdup(cntxt->username);
     702           5 :         return MAL_SUCCEED;
     703             : }
     704             : 
     705             : static str
     706           0 : CLTgetPasswordHash(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     707             : {
     708           0 :         (void) cntxt;
     709           0 :         (void) mb;
     710           0 :         (void) stk;
     711           0 :         (void) pci;
     712             : 
     713           0 :         throw(MAL, "clients.getPassword",
     714             :                   SQLSTATE(0A000) PROGRAM_NYI);
     715             : }
     716             : 
     717             : static str
     718           0 : CLTcheckPermission(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     719             : {
     720           0 :         (void) cntxt;
     721           0 :         (void) mb;
     722           0 :         (void) stk;
     723           0 :         (void) pci;
     724             : 
     725           0 :         throw(MAL, "clients.checkPermission",
     726             :                   SQLSTATE(0A000) PROGRAM_NYI);
     727             : }
     728             : 
     729             : str
     730           2 : CLTshutdown(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     731             : {
     732           2 :         str *ret = getArgReference_str(stk, pci, 0);
     733           2 :         int delay;
     734           2 :         bit force = FALSE;
     735           2 :         int leftover;
     736           2 :         char buf[1024] = { "safe to stop last connection" };
     737             : 
     738           2 :         if (pci->argc == 3)
     739           1 :                 force = *getArgReference_bit(stk, pci, 2);
     740             : 
     741           2 :         (void) mb;
     742             : 
     743           2 :         delay = *getArgReference_bte(stk, pci, 1);
     744             : 
     745           2 :         if (cntxt->user != MAL_ADMIN)
     746           0 :                 throw(MAL, "mal.shutdown",
     747             :                           SQLSTATE(42000) "Administrator rights required");
     748           2 :         if (is_int_nil(delay))
     749             :                 throw(MAL, "mal.shutdown", "Delay cannot be NULL");
     750           2 :         if (delay < 0)
     751           0 :                 throw(MAL, "mal.shutdown", "Delay cannot be negative");
     752           2 :         if (is_bit_nil(force))
     753           0 :                 throw(MAL, "mal.shutdown", "Force cannot be NULL");
     754           2 :         MCstopClients(cntxt);
     755           2 :         do {
     756           2 :                 if ((leftover = MCactiveClients() - 1))
     757           0 :                         MT_sleep_ms(1000);
     758           2 :                 delay--;
     759           2 :         } while (delay > 0 && leftover > 1);
     760           2 :         if (delay == 0 && leftover > 1)
     761           0 :                 snprintf(buf, 1024, "%d client sessions still running", leftover);
     762           2 :         *ret = GDKstrdup(buf);
     763           2 :         if (force)
     764           1 :                 GDKprepareExit();
     765           2 :         if (*ret == NULL)
     766           0 :                 throw(MAL, "mal.shutdown", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     767             :         return MAL_SUCCEED;
     768             : }
     769             : 
     770             : static str
     771          15 : CLTgetSessionID(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     772             : {
     773          15 :         (void) mb;
     774          15 :         (void) stk;
     775          15 :         (void) pci;
     776          15 :         *getArgReference_int(stk, pci, 0) = cntxt->idx;
     777          15 :         return MAL_SUCCEED;
     778             : }
     779             : 
     780             : static str
     781           4 : CLTsetClientInfo(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     782             : {
     783           4 :         (void)mb;
     784           4 :         str property = *getArgReference_str(stk, pci, 1);
     785           4 :         str value = *getArgReference_str(stk, pci, 2);
     786             : 
     787           4 :         MCsetClientInfo(cntxt, property, value);
     788           4 :         return MAL_SUCCEED;
     789             : }
     790             : 
     791             : #include "mel.h"
     792             : mel_func clients_init_funcs[] = {
     793             :  pattern("clients", "setListing", CLTsetListing, true, "Turn on/off echo of MAL instructions:\n1 - echo input,\n2 - show mal instruction,\n4 - show details of type resolutoin, \n8 - show binding information.", args(1,2, arg("",int),arg("flag",int))),
     794             :  pattern("clients", "getId", CLTgetClientId, false, "Return a number that uniquely represents the current client.", args(1,1, arg("",int))),
     795             :  pattern("clients", "getInfo", CLTInfo, false, "Pseudo bat with client attributes.", args(2,2, batarg("",str),batarg("",str))),
     796             :  pattern("clients", "getScenario", CLTgetScenario, false, "Retrieve current scenario name.", args(1,1, arg("",str))),
     797             :  pattern("clients", "setScenario", CLTsetScenario, true, "Switch to other scenario handler, return previous one.", args(1,2, arg("",str),arg("msg",str))),
     798             :  pattern("clients", "quit", CLTquit, true, "Terminate the client session.", args(1,1, arg("",void))),
     799             :  pattern("clients", "quit", CLTquit, true, "Terminate the session for a single client using a soft error.\nIt is the privilege of the console user.", args(1,2, arg("",void),arg("idx",int))),
     800             :  command("clients", "getLogins", CLTLogin, false, "Pseudo bat of client id and login time.", args(2,2, batarg("user",oid),batarg("start",str))),
     801             :  pattern("clients", "stop", CLTstop, true, "Stop the query execution at the next eligible statement.", args(0,1, arg("id",int))),
     802             :  pattern("clients", "suspend", CLTsuspend, true, "Put a client process to sleep for some time.\nIt will simple sleep for a second at a time, until\nthe awake bit has been set in its descriptor", args(1,2, arg("",void),arg("id",int))),
     803             :  pattern("clients", "wakeup", CLTwakeup, true, "Wakeup a client process", args(1,2, arg("",void),arg("id",int))),
     804             :  pattern("clients", "getprofile", CLTgetProfile, false, "Retrieve the profile settings for a client", args(5,5, arg("opt",str),arg("q",int),arg("s",int),arg("w",int),arg("m",int))),
     805             :  pattern("clients", "setQryTimeoutMicro", CLTqueryTimeoutMicro, true, "", args(1,2, arg("",void),arg("n",lng))),
     806             :  pattern("clients", "setquerytimeout", CLTqueryTimeout, true, "", args(1,2, arg("",void),arg("n",int))),
     807             :  pattern("clients", "setquerytimeout", CLTqueryTimeout, true, "A query is aborted after q seconds (q=0 means run undisturbed).", args(1,3, arg("",void),arg("sid",int),arg("n",int))),
     808             :  pattern("clients", "setsessiontimeout", CLTsessionTimeout, true, "", args(1,2, arg("",void),arg("n",int))),
     809             :  pattern("clients", "setsessiontimeout", CLTsessionTimeout, true, "Set the session timeout for a particulat session id", args(1,3, arg("",void),arg("sid",int),arg("n",int))),
     810             :  pattern("clients", "setoptimizer", CLTsetoptimizer, true, "", args(1,2, arg("",void),arg("opt",str))),
     811             :  pattern("clients", "setoptimizer", CLTsetoptimizer, true, "Set the session optimizer", args(1,3, arg("",void),arg("sid",int),arg("opt",str))),
     812             :  pattern("clients", "setworkerlimit", CLTsetworkerlimit, true, "", args(1,2, arg("",void),arg("n",int))),
     813             :  pattern("clients", "setworkerlimit", CLTsetworkerlimit, true, "Limit the number of worker threads per query", args(1,3, arg("",void),arg("sid",int),arg("n",int))),
     814             :  pattern("clients", "setmemorylimit", CLTsetmemorylimit, true, "", args(1,2, arg("",void),arg("n",int))),
     815             :  pattern("clients", "setmemorylimit", CLTsetmemorylimit, true, "Limit the memory claim in MB per query", args(1,3, arg("",void),arg("sid",int),arg("n",int))),
     816             :  pattern("clients", "stopsession", CLTstopSession, true, "Stop a particular session", args(1,2, arg("",void),arg("sid",int))),
     817             :  command("clients", "setprinttimeout", CLTsetPrintTimeout, true, "Print running query every so many seconds.", args(1,2, arg("",void),arg("n",int))),
     818             :  pattern("clients", "shutdown", CLTshutdown, true, "", args(1,2, arg("",str),arg("delay",bte))),
     819             :  pattern("clients", "shutdown", CLTshutdown, true, "Close all other client connections. Return if it succeeds.\nIf forced is set then always stop the system the hard way", args(1,3, arg("",str),arg("delay",bte),arg("forced",bit))),
     820             :  command("clients", "md5sum", CLTmd5sum, false, "Return hex string representation of the MD5 hash of the given string", args(1,2, arg("",str),arg("pw",str))),
     821             :  command("clients", "sha1sum", CLTsha1sum, false, "Return hex string representation of the SHA-1 hash of the given string", args(1,2, arg("",str),arg("pw",str))),
     822             :  command("clients", "sha2sum", CLTsha2sum, false, "Return hex string representation of the SHA-2 hash with bits of the given string", args(1,3, arg("",str),arg("pw",str),arg("bits",int))),
     823             :  command("clients", "ripemd160sum", CLTripemd160sum, false, "Return hex string representation of the RIPEMD160 hash of the given string", args(1,2, arg("",str),arg("pw",str))),
     824             :  command("clients", "backendsum", CLTbackendsum, false, "Return hex string representation of the currently used hash of the given string", args(1,2, arg("",str),arg("pw",str))),
     825             :  pattern("clients", "getUsername", CLTgetUsername, false, "Return the username of the currently logged in user", args(1,1, arg("",str))),
     826             :  pattern("clients", "getPasswordHash", CLTgetPasswordHash, false, "Return the password hash of the given user", args(1,2, arg("",str),arg("user",str))),
     827             :  pattern("clients", "checkPermission", CLTcheckPermission, false, "Check permission for a user, requires hashed password (backendsum)", args(1,3, arg("",void),arg("usr",str),arg("pw",str))),
     828             :  pattern("clients", "current_sessionid", CLTgetSessionID, false, "return current session ID", args(1,1, arg("",int))),
     829             :  pattern("clients", "setinfo", CLTsetClientInfo, true, "set a clientinfo property", args(1, 3, arg("",str), arg("property", str), arg("value", str))),
     830             :  { .imp=NULL }
     831             : };
     832             : #include "mal_import.h"
     833             : #ifdef _MSC_VER
     834             : #undef read
     835             : #pragma section(".CRT$XCU",read)
     836             : #endif
     837         325 : LIB_STARTUP_FUNC(init_clients_mal)
     838         325 : { mal_module("clients", NULL, clients_init_funcs); }

Generated by: LCOV version 1.14