1
/* Free ISQL - An isql for DB-Library (C) 2007 Nicholas S. Castellano
3
* This program is free software; you can redistribute it and/or
4
* modify it under the terms of the GNU General Public
5
* License as published by the Free Software Foundation; either
6
* version 2 of the License, or (at your option) any later version.
8
* This library is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
* Library General Public License for more details.
13
* You should have received a copy of the GNU General Public
14
* License along with this library; if not, write to the
15
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16
* Boston, MA 02111-1307, USA.
21
#endif /* HAVE_CONFIG_H */
31
#include <readline/readline.h>
32
#include <readline/history.h>
39
#include "interrupt.h"
40
#include "replacements.h"
42
#define READPASSPHRASE_MAXLEN 128
45
static FILE *rl_outstream = NULL;
46
static FILE *rl_instream = NULL;
47
static const char *rl_readline_name = NULL;
50
fisql_readline(char *prompt)
57
line = (char*) malloc(sz);
61
if (prompt && prompt[0])
62
fprintf(rl_outstream ? rl_outstream : stdout, "%s", prompt);
65
if (fgets(line + pos, sz - pos, rl_instream ? rl_instream : stdin) == NULL) {
71
/* got end-of-line ? */
72
p = strchr(line + pos, '\n');
78
/* allocate space if needed */
79
pos += strlen(line + pos);
80
if (pos + 1024 >= sz) {
82
p = (char*) realloc(line, sz);
93
fisql_add_history(const char *s)
97
#define readline fisql_readline
98
#define add_history fisql_add_history
100
#define rl_bind_key(c,f) do {} while(0)
101
#define rl_reset_line_state() do {} while(0)
102
#define rl_on_new_line() do {} while(0)
106
#if !HAVE_RL_ON_NEW_LINE && !defined(rl_on_new_line)
107
#define rl_on_new_line() do {} while(0)
110
#if !HAVE_RL_RESET_LINE_STATE && !defined(rl_reset_line_state)
111
#define rl_reset_line_state() do {} while(0)
114
static void *xmalloc(size_t s);
115
static void *xrealloc(void *p, size_t s);
116
static int get_printable_size(int type, int size);
117
static int get_printable_column_size(DBPROCESS * dbproc, int col);
125
fprintf(stderr, "Out of memory\n");
132
xrealloc(void *p, size_t s)
136
fprintf(stderr, "Out of memory\n");
142
/* adapted from src/dblib/dblib.c (via src/apps/bsqldb.c) */
144
get_printable_size(int type, int size)
170
return 11; /* FIX ME -- we do not track precision */
172
return 11; /* FIX ME -- we do not track precision */
174
return 12; /* FIX ME */
176
return 12; /* FIX ME */
178
return 26; /* FIX ME */
180
return 26; /* FIX ME */
181
#if 0 /* seems not to be exported to sybdb.h */
186
/* FIX ME -- not all types present */
193
get_printable_column_size(DBPROCESS * dbproc, int col)
197
collen = get_printable_size(dbcoltype(dbproc, col), dbcollen(dbproc, col));
198
if (strlen(dbcolname(dbproc, col)) > collen) {
199
collen = strlen(dbcolname(dbproc, col));
205
main(int argc, char *argv[])
210
int print_statistics = 0;
215
int use_encryption = 0;
216
int chained_transactions = 0;
217
const char *display_charset = "";
218
const char *cmdend = "go";
220
char *columnwidth = NULL;
221
const char *colseparator = " ";
222
const char *lineseparator = "\n";
224
char *username = NULL;
225
char *password = NULL;
227
DBCHAR *char_set = NULL;
229
char *hostname = NULL;
231
char *interfaces_filename = NULL;
232
char *input_filename = NULL;
233
char *output_filename = NULL;
235
char *language = NULL;
266
int printedcompute = 0;
271
editor = getenv("EDITOR");
273
editor = getenv("VISUAL");
281
while (!errflg && (c = getopt(argc, argv, "eFgpnvXYa:c:E:h:H:i:I:J:l:m:o:P:s:S:t:U:w:y:z:A:"))
301
puts("fisql, a free isql replacement by Nicholas S. Castellano");
305
/* XXX: We get a different error message than isql gives; neither seems
311
chained_transactions = 1;
314
display_charset = optarg;
324
headers = atoi(optarg);
330
input_filename = optarg;
333
interfaces_filename = optarg;
339
logintime = atoi(optarg);
342
global_errorlevel = atoi(optarg);
345
output_filename = optarg;
351
colseparator = optarg;
357
timeout = atoi(optarg);
363
columnwidth = optarg;
366
/* XXX: this doesn't seem to be what isql does with -y...it doesn't
367
* seem to do anything actually
369
sybenv = (char *) xmalloc((strlen(optarg) + 8) * sizeof(char));
370
strcpy(sybenv, "SYBASE=");
371
strcat(sybenv, optarg);
387
fprintf(stderr, "usage: fisql [-e] [-F] [-g] [-p] [-n] [-v] [-X] [-Y]\n");
388
fprintf(stderr, "\t[-a display_charset] [-c cmdend] [-E editor]\n");
389
fprintf(stderr, "\t[-h headers] [-H hostname] [-i inputfile]\n");
390
fprintf(stderr, "\t[-I interfaces_file] [-J client character set]\n");
391
fprintf(stderr, "\t[-l login_timeout] [-m errorlevel]\n");
392
fprintf(stderr, "\t[-o outputfile]\n");
393
fprintf(stderr, "\t[-P password] [-s colseparator] [-S server]\n");
394
fprintf(stderr, "\t[-t timeout] [-U username] [-w columnwidth]\n");
395
fprintf(stderr, "\t[-y sybase_dir] [-z language]\n");
398
if (!(isatty(fileno(stdin)))) {
400
rl_outstream = fopen("/dev/null", "rw");
402
rl_readline_name = "fisql";
403
rl_bind_key('\t', rl_insert);
404
if (password == NULL) {
405
password = (char *) xmalloc(READPASSPHRASE_MAXLEN);
406
readpassphrase("Password: ", password, READPASSPHRASE_MAXLEN, RPP_ECHO_OFF);
408
if (input_filename) {
409
if (freopen(input_filename, "r", stdin) == NULL) {
410
/* XXX: sybase isql generates this error while parsing the options,
411
* but doesn't redirect the input until after the Password: prompt
413
/* lack of newline for bug-compatibility with isql */
414
fprintf(stderr, "Unable to open input file '%s'.", optarg);
418
if (output_filename) {
419
if (freopen(output_filename, "w", stdout) == NULL) {
420
/* XXX: sybase isql generates this error while parsing the options,
421
* but doesn't redirect the output until after the Password: prompt
423
/* lack of newline for bug-compatibility with isql */
424
fprintf(stderr, "Unable to open output file '%s'.", output_filename);
428
if (isatty(fileno(stdin))) {
429
rl_outstream = stdout;
434
dbsetversion(DBVERSION_100);
437
if ((login = dblogin()) == NULL) {
441
dbmsghandle(msg_handler);
442
dberrhandle(err_handler);
443
DBSETLAPP(login, "fisql");
445
DBSETLUSER(login, username);
447
DBSETLPWD(login, password);
449
DBSETLCHARSET(login, char_set);
451
if (use_encryption) {
452
DBSETLENCRYPT(login, TRUE);
455
DBSETLHOST(login, hostname);
458
DBSETLNATLANG(login, language);
461
DBSETLPACKET(login, (short) size);
463
if (interfaces_filename) {
464
dbsetifile(interfaces_filename);
467
if (logintime >= 0) {
468
dbsetlogintime(logintime);
470
if ((dbproc = dbopen(login, server)) == NULL) {
471
fprintf(stderr, "fisql: dbopen() failed.\n");
476
dbsetopt(dbproc, DBPRLINESEP, lineseparator, strlen(lineseparator));
478
dbsetopt(dbproc, DBPRCOLSEP, colseparator, strlen(colseparator));
481
dbsetopt(dbproc, DBPRLINELEN, columnwidth, 0);
483
if (chained_transactions) {
484
dbsetopt(dbproc, DBCHAINXACTS, NULL, 0);
487
dbsetopt(dbproc, DBFIPSFLAG, NULL, 0);
490
dbsetopt(dbproc, DBSTAT, "time", 0);
494
if (sigsetjmp(restart, 1)) {
496
for (i = 0; i < ibuflines; i++) {
505
rl_reset_line_state();
508
signal(SIGINT, inactive_interrupt_handler);
509
ibuf = (char **) xmalloc(sizeof(char *));
515
sprintf(foobuf, "%d>> ", ibuflines + 1);
517
line = readline(foobuf);
521
for (cp = line; *cp && isspace((unsigned char) *cp); cp++);
525
if (!(strncasecmp(line, "!!", 2))) {
530
/* XXX: isql off-by-one line count error for :r not duplicated */
531
if (!(strncasecmp(line, ":r", 2))) {
532
for (cp = line + 2; *cp && (isspace((unsigned char) *cp)); cp++);
534
for (; *cp && !(isspace((unsigned char) *cp)); cp++);
536
if ((fp = fopen(tfn, "r")) == NULL) {
537
printf("Operating system error: Failed to open %s.\n", tfn);
541
tmpfp2 = rl_outstream;
543
rl_outstream = fopen("/dev/null", "w");
544
while ((line = readline("")) != NULL) {
545
ibuf[ibuflines++] = line;
546
ibuf = (char **) xrealloc(ibuf, (ibuflines + 1) * sizeof(char *));
549
fclose(rl_outstream);
550
rl_outstream = tmpfp2;
556
firstword = (char *) xmalloc((strlen(line) + 1) * sizeof(char));
557
strcpy(firstword, line);
558
for (cp = firstword; *cp; cp++) {
559
if (isspace((unsigned char) *cp)) {
564
if ((!(strcasecmp(firstword, "exit")))
565
|| (!(strcasecmp(firstword, "quit")))) {
570
if (!(strcasecmp(firstword, "reset"))) {
571
for (i = 0; i < ibuflines; i++) {
577
if (!(strcasecmp(firstword, cmdend))) {
578
if (ibuflines == 0) {
584
if ((!(strcasecmp(firstword, "vi")))
585
|| (!(strcasecmp(firstword, editor)))) {
588
strcpy(tmpfn, "/tmp/fisqlXXXXXX");
589
tmpfd = mkstemp(tmpfn);
590
if ((fp = fdopen(tmpfd, "w")) == NULL) {
597
for (i = 0; i < ibuflines; i++) {
603
for (i = 0; ((sqlch = dbgetchar(dbproc, i)) != NULL); i++) {
608
if (!(strcmp(firstword, "vi"))) {
614
fp = fopen(tmpfn, "r");
617
strcpy(foobuf, "1>> ");
618
while ((line = readline(foobuf)) != NULL) {
619
ibuf[ibuflines++] = line;
620
sprintf(foobuf, "%d>> ", ibuflines + 1);
621
ibuf = (char **) xrealloc(ibuf, (ibuflines + 1) * sizeof(char *));
631
ibuf[ibuflines++] = line;
632
ibuf = (char **) xrealloc(ibuf, (ibuflines + 1) * sizeof(char *));
635
for (i = 0; i < ibuflines; i++) {
639
dbcmd(dbproc, ibuf[i]);
645
signal(SIGINT, active_interrupt_handler);
646
dbsetinterrupt(dbproc, (void *) active_interrupt_pending, (void *) active_interrupt_servhandler);
647
if (dbsqlexec(dbproc) == SUCCEED) {
648
maybe_handle_active_interrupt();
649
while ((dbrc = dbresults(dbproc)) != NO_MORE_RESULTS) {
651
#define USE_DBPRROW 0
656
if ((dbrc == SUCCEED) && (DBROWS(dbproc) == SUCCEED)) {
657
prbuflen = dbspr1rowlen(dbproc);
658
prbuf = (char *) xmalloc(prbuflen * sizeof(char));
659
dbsprhead(dbproc, prbuf, prbuflen);
660
fputs(prbuf, stdout);
662
dbsprline(dbproc, prbuf, prbuflen, '-');
663
fputs(prbuf, stdout);
665
maybe_handle_active_interrupt();
666
while ((dbrc = dbnextrow(dbproc)) != NO_MORE_ROWS) {
670
if (dbrc != REG_ROW) {
671
num_cols = dbnumalts(dbproc, dbrc);
672
for (selcol = col = 1; col <= num_cols; col++) {
673
colid = dbaltcolid(dbproc, dbrc, col);
674
while (selcol < colid) {
675
collen = get_printable_column_size(dbproc, selcol);
676
for (i = 0; i < collen; i++) {
680
printf("%s", colseparator);
682
opname = dbprtype(dbaltop(dbproc, dbrc, col));
683
printf("%s", opname);
684
collen = get_printable_column_size(dbproc, colid);
685
collen -= strlen(opname);
686
while (collen-- > 0) {
690
printf("%s", colseparator);
692
printf("%s", lineseparator);
693
for (selcol = col = 1; col <= num_cols; col++) {
694
colid = dbaltcolid(dbproc, dbrc, col);
695
while (selcol < colid) {
696
collen = get_printable_column_size(dbproc, selcol);
697
for (i = 0; i < collen; i++) {
701
printf("%s", colseparator);
703
collen = get_printable_column_size(dbproc, colid);
705
bylist = dbbylist(dbproc, dbrc, &nby);
709
for (i = 0; i < collen; i++) {
713
printf("%s", colseparator);
715
printf("%s", lineseparator);
716
for (selcol = col = 1; col <= num_cols; col++) {
717
colid = dbaltcolid(dbproc, dbrc, col);
718
while (selcol < colid) {
719
collen = get_printable_column_size(dbproc, selcol);
720
for (i = 0; i < collen; i++) {
724
printf("%s", colseparator);
726
convlen = dbconvert(dbproc,
727
dbalttype(dbproc, dbrc, col),
728
dbadata(dbproc, dbrc, col),
729
dbadlen(dbproc, dbrc, col),
730
SYBCHAR, (BYTE *) adbuf, sizeof(adbuf));
731
printf("%.*s", (int) convlen, adbuf);
732
collen = get_printable_column_size(dbproc, colid);
734
while (collen-- > 0) {
738
printf("%s", colseparator);
740
printf("%s", lineseparator);
744
if (printedcompute || (headers && (printedlines >= headers)
745
&& ((printedlines % headers) == 0))) {
747
dbsprhead(dbproc, prbuf, prbuflen);
748
fputs(prbuf, stdout);
750
dbsprline(dbproc, prbuf, prbuflen, '-');
751
fputs(prbuf, stdout);
756
dbspr1row(dbproc, prbuf, prbuflen);
757
fputs(prbuf, stdout);
759
maybe_handle_active_interrupt();
763
maybe_handle_active_interrupt();
767
if ((DBCOUNT(dbproc) >= 0) || dbhasretstat(dbproc)) {
768
if (DBCOUNT(dbproc) >= 0) {
769
fprintf(stdout, "(%d rows affected", (int) DBCOUNT(dbproc));
770
if (dbhasretstat(dbproc)) {
771
dbrc = dbretstatus(dbproc);
772
fprintf(stdout, ", return status = %d", dbrc);
774
fprintf(stdout, ")\n");
776
if (dbhasretstat(dbproc)) {
777
dbrc = dbretstatus(dbproc);
778
fprintf(stdout, "(return status = %d)\n", dbrc);