📄 mapiclient.mx
字号:
@' The contents of this file are subject to the MonetDB Public License@' Version 1.1 (the "License"); you may not use this file except in@' compliance with the License. You may obtain a copy of the License at@' http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html@'@' Software distributed under the License is distributed on an "AS IS"@' basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the@' License for the specific language governing rights and limitations@' under the License.@'@' The Original Code is the MonetDB Database System.@'@' The Initial Developer of the Original Code is CWI.@' Portions created by CWI are Copyright (C) 1997-2007 CWI.@' All Rights Reserved.@a Sjoerd Mullender, based on code by M. Kersten and Peter Boncz and Niels Nes@v 5@f MapiClient@* The Mapi Client interface A textual interface to the Monet server using the Mapi library,providing command-line access for its users. It is the preferredinterface for non-DBAs.@+ Manual PageThe @code{MapiClient} program provides a textualinterface to the MonetDB server. Unlike the Mserver console, the@code{MapiClient} program is intended not only for the databaseadministrator, but for all users. It is more comfortable than theconsole, since it provides a command history and automatic file namecompletion. @verbatimMapiClient [options] [inputfile+]@end verbatimThe following options are supported:@multitable @columnfractions .25 .25 .25 @verb @verb @verb@item -b t/f @tab --blocked=true/false@tab blocked mode @item -e @tab --error @tab exit on error @item -h hostname @tab --host=hostname @tab host to connect to @item -l language @tab --language=lang @tab {mal,sql,mil} @item -P passwd @tab --passwd=passwd @tab password @item -p portnr @tab --port=portnr @tab port to connect to @item -s stmt @tab --statement=stmt @tab run single statement @item -t @tab --trace@tab trace mapi network interaction@item -T @tab --time @tab time commands @item -u user @tab --user=user @tab user id @item -H @tab --history @tab load/save cmdline history (default off) @item -? @tab --help @tab show this usage message @end multitableCalling "MapiClient -l sql" establishes a SQL connection with anMserver server running on the local machine. The default user'monetdb' is used, which provides administrative rights.To protect your database you may want to introduce another DBA name andlimit the access permisions of 'monetdb' to the level of a guest account.@{@+ Implementation@c#include "clients_config.h"#include <monet_options.h>#include "Mapi.h"#include <unistd.h>#include <stdlib.h>#include <ctype.h>#include <sys/stat.h>#include <errno.h>#include <string.h>#ifdef HAVE_LIBREADLINE#include <readline/readline.h>#include <readline/history.h>#include "ReadlineTools.h"#endif#include "msqldump.h"#include "mprompt.h"#ifndef S_ISCHR#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)#endif#ifdef NATIVE_WIN32/* Windows doesn't declare chdir, even though it does provide the function */extern int chdir(const char *);#define strdup _strdup#endif#ifndef HAVE_GETLOGIN#define getlogin() "win32"#endifstatic FILE *toConsole;static char *language = "mil";char *command = NULL;static long t0, t1; /* used for timing */static char *mark, *mark2;/* stolen piece */#ifdef HAVE_FTIME#include <sys/timeb.h>#endif#if TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# if HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endifstatic longgettime(void){#ifdef HAVE_GETTIMEOFDAY struct timeval tp; gettimeofday(&tp, NULL); return (long) tp.tv_sec * 1000000 + (long) tp.tv_usec;#else#ifdef HAVE_FTIME struct timeb tb; ftime(&tb); return (long) tb.time * 1000000 + (long) tb.millitm * 1000;#endif#endif}static voidtimerStart(void){ t0 = gettime();}static voidtimerEnd(void){ t1 = gettime(); if (mark) { fprintf(toConsole, "%s % 7ld.%03ld msec %s\n", mark, (t1 - t0) / 1000, (t1 - t0) % 1000, mark2 ? mark2 : ""); fflush(toConsole); }}static intdoRequest(Mapi mid, const char *buf, int interactive){ MapiHdl hdl; if ((hdl = mapi_quick_query(mid, buf, toConsole)) == NULL) { mapi_explain(mid, stderr); return 1; } if (mapi_result_error(hdl)) { mapi_explain_result(hdl, stderr); mapi_close_handle(hdl); return 1; } if (mapi_error(mid)) { mapi_explain_query(hdl, stderr); mapi_close_handle(hdl); return 1; } if (! (mapi_get_active(mid) && interactive )) mapi_close_handle(hdl); return 0;}#define CHECK_RESULT(mid, hdl, buf, break_or_continue) \ switch (mapi_error(mid)) { \ case MOK: \ /* everything A OK */ \ break; \ case MERROR: \ /* some error, but try to continue */ \ if (hdl) { \ mapi_explain_query(hdl, stderr); \ mapi_close_handle(hdl); \ hdl = NULL; \ } else \ mapi_explain(mid, stderr); \ break_or_continue; \ case MTIMEOUT: \ /* lost contact with the server */ \ if (hdl) { \ mapi_explain_query(hdl, stderr); \ mapi_close_handle(hdl); \ hdl = NULL; \ } else \ mapi_explain(mid, stderr); \ timerEnd(); \ free(buf); \ return 1; \ }static intdoFile(Mapi mid, const char *file, int xquery){ FILE *fp; char *buf = NULL; size_t length; MapiHdl hdl = NULL; MapiMsg rc = MOK; int bufsize = 0; if (file == NULL) fp = stdin; else if ((fp = fopen(file, "r")) == NULL) { fprintf(stderr, "%s: cannot open\n", file); return 1; } bufsize = BUFSIZ; buf = malloc(bufsize); if (!buf) { fprintf(stderr, "cannot allocate memory for send buffer\n"); if (file != NULL) fclose(fp); return 1; } timerStart(); do { if ((length = fread(buf, 1, bufsize, fp)) == 0) { /* end of file */ if (file != NULL) { fclose(fp); file = NULL; } if (hdl == NULL) { /* nothing more to do */ timerEnd(); free(buf); return 0; } /* hdl != NULL, we should finish the current query */ } if (hdl == NULL) { hdl = mapi_query_prep(mid); CHECK_RESULT(mid, hdl, buf, continue); } if (length > 0) { assert(hdl != NULL); mapi_query_part(hdl, buf, length); CHECK_RESULT(mid, hdl, buf, continue); /* in case of xquery; do the whole file in one go */ if (xquery && !feof(fp)) continue; } assert(hdl != NULL); /* If the server wants more but we're at the end of file (length == 0), notify the server that we don't have anything more. If the server still wants more (shouldn't happen according to the protocol) we break out of the loop (via the continue). The assertion at the end will then go off. */ if (mapi_query_done(hdl) == MMORE && (length > 0 || mapi_query_done(hdl) == MMORE)) continue; /* get more data */ CHECK_RESULT(mid, hdl, buf, continue); do { char *reply; if ((reply = mapi_result_error(hdl)) != NULL) mapi_explain_result(hdl, stderr); if (mapi_get_querytype(hdl) == Q_UPDATE) { fprintf(toConsole, "[ %d\t]\n", mapi_rows_affected(hdl)); } else { while ((reply = mapi_fetch_line(hdl)) != NULL) { if (xquery && *reply == '=') reply++; fprintf(toConsole, "%s\n", reply); } } } while ((rc = mapi_needmore(hdl)) == MOK && (rc = mapi_next_result(hdl)) == 1); if (rc == MMORE && (length > 0 || mapi_query_done(hdl) != MOK)) continue; /* get more data */ CHECK_RESULT(mid, hdl, buf, continue); mapi_close_handle(hdl); hdl = NULL; } while (length > 0); /* reached on end of file */ assert(hdl == NULL); timerEnd(); free(buf); if (file != NULL) fclose(fp); fflush(stdout); return 0;}static voidshowCommands(void){ fprintf(toConsole, "?\t - show this message\n"); fprintf(toConsole, "?text\t - send help message\n"); fprintf(toConsole, "!\t - shell escape\n"); fprintf(toConsole, "<file\t - read input from file\n"); fprintf(toConsole, ">file\t - save response in file\n"); fprintf(toConsole, ">\t - response to terminal\n"); fprintf(toConsole, "cd\t - change directory\n"); fprintf(toConsole, "\\l\t- line is sent immediately\n"); fprintf(toConsole, "\\q\t- terminate session\n"); fprintf(toConsole, "\\T\t- toggle timer\n"); fprintf(toConsole, "\\D\t- dump database\n"); fprintf(toConsole, "\\Dtable\t- dump table\n"); fprintf(toConsole, "\\A\t- enable auto commit\n"); fprintf(toConsole, "\\a\t- disable auto commit\n"); fprintf(toConsole, "\\t\t- toggle interaction trace\n");}static intdoFileByLines(Mapi mid, FILE *fp, const char *prompt, int linemode, int exit_on_error, int xquery){ char *line = NULL; char *buf = NULL; size_t length; MapiHdl hdl = mapi_get_active(mid); MapiMsg rc = MOK; int sent = 0; /* whether we sent any data to the server */#ifdef HAVE_LIBREADLINE if (prompt == NULL)#endif buf = malloc(BUFSIZ); do {#ifdef HAVE_LIBREADLINE if (prompt) { rl_completion_func_t *func = NULL; if (buf) free(buf); if (hdl) func = suspend_completion(); buf = readline(hdl ? "more>" : prompt); if (hdl) continue_completion(func); /* add a newline to the end since that makes further processing easier */ if (buf) { add_history(buf); length = strlen(buf); buf = realloc(buf, length + 2); buf[length++] = '\n'; buf[length] = 0; } line = buf; } else#endif {#ifndef HAVE_LIBREADLINE if (prompt) { fputs(hdl ? "more>" : prompt, stdout); fflush(stdout); }#endif line = fgets(buf, BUFSIZ, fp); } if (line == NULL) { /* end of file */ if (hdl == NULL) { /* nothing more to do */ return 0; } /* hdl != NULL, we should finish the current query */ line = NULL; length = 0; } else length = strlen(line); if (length > 0 && (!linemode || (hdl == NULL && length > 0 && line[length - 1] == '\n'))) { /* test for special commands */ while (length > 0 && (*line & ~0x7F) == 0 && isspace((int) *line)) { line++; length--; } /* in the switch, use continue if the line was processed, use break to send to server */ switch (*line) { case '\0': /* empty line */ break; case '\\': switch (line[1]) { case 'q': free(buf); return 0; case 'T': mark = mark ? NULL : "Timer"; if (mark2) free(mark2); mark2 = strdup(line + 2); continue; case 't': /* toggle interaction trace */ mapi_trace(mid, !mapi_get_trace(mid)); continue; case 'l': linemode = 1; line = ""; length = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -