int main(int argc, const char** argv) { ndb_init(); const char* usage = "Usage: ndbsql [-h] [-d dsn] [-f file] [stmt]\n-h help\n-d <database name or connect string>\n-f <file name> batch mode\nstmt single SQL statement\n"; const char* dsn = "TEST_DB"; bool helpFlg = false, batchMode = false; const char* fileName = 0; FILE* inputFile = stdin; const char* singleStmt = 0; s_readBuf = (char*)malloc(s_bufSize); while (++argv, --argc > 0) { const char* arg = argv[0]; if (arg[0] != '-') break; if (strcmp(arg, "-d") == 0) { if (++argv, --argc > 0) { dsn = argv[0]; continue; } } if (strcmp(arg, "-h") == 0) { helpFlg = true; continue; } if (strcmp(arg, "-f") == 0) { if (++argv, --argc > 0) { fileName = argv[0]; continue; } } ndbout << usage; return 1; } if (helpFlg) { ndbout << usage << "\n"; print_help(); return 0; } if (fileName != 0) { if (argc > 0) { ndbout << usage; return 1; } if ((inputFile = fopen(fileName, "r")) == 0) { ndbout << "Could not read file " << fileName << ": " << strerror(errno) << endl; return 1; } batchMode = true; } if (argc > 0) { singleStmt = argv[0]; batchMode = true; } if (! batchMode) ndbout << "NDB Cluster NDB SQL -- A simple SQL Command-line Interface\n\n"; Con con(dsn); if (do_connect(con) < 0) return 1; if (! batchMode) ndbout << "Terminate SQL statements with a semi-colon ';'\n"; char* line = 0; char* line2 = 0; char* line3 = 0; unsigned lineno = 0; bool has_semi; bool exit_on_error = false; int exit_code = 0; while (1) { free(line); line = 0; lineno = 0; more_lines: free(line2); free(line3); line2 = line3 = 0; lineno++; has_semi = false; char prompt[20]; if (lineno == 1) strcpy(prompt, "SQL> "); else sprintf(prompt, "%4d ", lineno); if (singleStmt != 0) { line = strdup(singleStmt); int n = strlen(line); while (n > 0 && isspace(line[n - 1])) { line[--n] = 0; } if (n > 0 && line[n - 1] == ';') line[n - 1] = 0; has_semi = true; // regardless } else { const char *line1 = readline_gets(prompt, batchMode, inputFile); if (line1 != 0) { if (line == 0) line = strdup(line1); else { line = (char*)realloc(line, strlen(line) + 1 + strlen(line1) + 1); strcat(line, "\n"); strcat(line, line1); } if (batchMode) ndbout << prompt << line1 << endl; } else { if (! batchMode) ndbout << endl; if (line != 0) ndbout << "Ignored unterminated SQL statement" << endl; break; } } line2 = (char*)malloc(strlen(line) + 1); { char* p = line2; char* q = line; bool str = false; while (*q != 0) { if (*q == '\'') { str = !str; *p++ = *q++; } else if (!str && *q == '-' && *(q + 1) == '-') { while (*q != 0 && *q != '\n') q++; } else *p++ = *q++; } *p = 0; int n = strlen(line2); while (n > 0 && isspace(line2[n - 1])) line2[--n] = 0; if (n > 0 && line2[n - 1] == ';') { line2[--n] = 0; has_semi = true; } } line3 = strdup(line2); char* tok[10]; int ntok = 0; tok[ntok] = strtok(line3, " "); while (tok[ntok] != 0) { ntok++; if (ntok == 10) break; tok[ntok] = strtok(0, " "); } if (ntok == 0) continue; if (!strcasecmp(tok[0], "help") || !strcmp(tok[0], "?")) { if (ntok != 2) print_help(); else if (!strcasecmp(tok[1], "create")) print_help_create(); else if (!strcasecmp(tok[1], "insert")) print_help_insert(); else if (strcasecmp(tok[1], "select")) print_help_select(); else if (!strcasecmp(tok[1], "delete")) print_help_update(); else if (!strcasecmp(tok[1], "update")) print_help_update(); else if (!strcasecmp(tok[1], "virtual")) print_help_virtual(); else print_help(); continue; } if (!strcasecmp(tok[0], "list")) { if (ntok == 2 && !strcasecmp(tok[1], "tables")) { free(line2); line2 = strdup("SELECT TABLE_NAME FROM ODBC$TABLES"); has_semi = true; } else { ndbout << "Invalid list option - try help" << endl; continue; } } if (ntok == 1 && !strcasecmp(tok[0], "quit")) break; if (ntok == 1 && !strcasecmp(tok[0], "exit")) break; if (ntok == 1 && !strcasecmp(tok[0], "bye")) break; if (!strcasecmp(tok[0], "set")) { if (ntok == 1) { char* p; p = getenv("NDB_ODBC_TRACE"); ndbout << "Trace level is " << (p ? atoi(p) : 0) << endl; int ret = get_autocommit(con); if (ret != -1) ndbout << "Autocommit is " << (ret == SQL_AUTOCOMMIT_ON ? "on" : "off") << endl; } else if (ntok == 3 && !strcasecmp(tok[1], "trace")) { static char env[40]; int n = tok[2] ? atoi(tok[2]) : 0; sprintf(env, "NDB_ODBC_TRACE=%d", n); putenv(env); ndbout << "Trace level set to " << n << endl; } else if (ntok == 3 && !strcasecmp(tok[1], "autocommit")) { if (tok[2] && !strcasecmp(tok[2], "on")) { int ret = set_autocommit(con, SQL_AUTOCOMMIT_ON); if (ret != -1) ndbout << "Autocommit set to ON" << endl; } else if (tok[2] && !strcasecmp(tok[2], "off")) { int ret = set_autocommit(con, SQL_AUTOCOMMIT_OFF); if (ret != -1) ndbout << "Autocommit set to OFF - transaction may time out" << endl; } else { ndbout << "Invalid autocommit option - try help" << endl; } } else { ndbout << "Invalid set command - try help" << endl; } continue; } if (ntok >= 2 && !strcasecmp(tok[0], "whenever") && !strcasecmp(tok[1], "sqlerror")) { if (ntok == 3 && !strcasecmp(tok[2], "exit")) exit_on_error = true; else if (ntok == 3 && !strcasecmp(tok[2], "continue")) exit_on_error = false; else { ndbout << "Invalid whenever clause - try help" << endl; } continue; } if (!strcasecmp(tok[0], "commit")) { if (ntok == 1) { if (do_commit(con) != -1) ndbout << "Commit done" << endl; else { exit_code = 1; if (exit_on_error) { ndbout << "Exit on error" << endl; break; } } } else { ndbout << "Invalid commit command - try help" << endl; } continue; } if (!strcasecmp(tok[0], "rollback")) { if (ntok == 1) { if (do_rollback(con) != -1) ndbout << "Rollback done" << endl; else { exit_code = 1; if (exit_on_error) { ndbout << "Exit on error" << endl; break; } } } else { ndbout << "Invalid commit command - try help" << endl; } continue; } if (! has_semi) goto more_lines; if (do_stmt(con, line2) != 0) { exit_code = 1; if (exit_on_error) { ndbout << "Exit on error" << endl; break; } } if (singleStmt) break; } do_disconnect(con); return exit_code; }
int main(int argc, char *argv[]) { _bcc_status bcc; void *buf; bool client = false; int count_read; int count_written; int count_xferred; #ifdef USE_SB_FC int err; #endif // USE_SB_FC int ferr; short filenumr; short filenums[MAX_SRV]; #ifdef USE_SB_FC short info_count; #endif // USE_SB_FC int inx; int len; #ifdef USE_SB_FC short list_inx; #endif // USE_SB_FC int loop = 10; char *p; char recv_buffer[BUFSIZ]; char send_buffer[MAX_SRV][BUFSIZ]; #ifdef USE_SB_FC int socka1; int socka2; int sockc1[MAX_SRV]; int sockc2[MAX_SRV]; int sockl; #endif // USE_SB_FC int srv; SB_Tag_Type tag; short tfilenum; int timeout = -1; TAD zargs[] = { { "-client", TA_Bool, TA_NOMAX, &client }, { "-loop", TA_Int, TA_NOMAX, &loop }, { "-maxcp", TA_Next, TA_NOMAX, NULL }, { "-maxsp", TA_Next, TA_NOMAX, NULL }, { "-server", TA_Ign, TA_NOMAX, NULL }, { "-v", TA_Bool, TA_NOMAX, &verbose }, { "", TA_End, TA_NOMAX, NULL } }; ferr = file_init(&argc, &argv); TEST_CHK_FEOK(ferr); msfs_util_init_fs(&argc, &argv, file_debug_hook); arg_proc_args(zargs, false, argc, argv); util_test_start(client); ferr = file_mon_process_startup(!client); // system messages TEST_CHK_FEOK(ferr); if (client) { #ifdef USE_SB_FC // check empty list ferr = BFILE_COMPLETE_GETINFO_((short *) info_list, MAX_INFO_LIST, &info_count); TEST_CHK_FEOK(ferr); assert(info_count == 0); // add bogus add_list[0].z_fnum_fd = 99; add_list[0].u_z_options.z_options.z_set_file = 0; // set add_list[0].u_z_options.z_options.z_filetype = 0; // guardian ferr = BFILE_COMPLETE_SET_((short *) add_list, 1, &list_inx); assert(ferr == XZFIL_ERR_NOTFOUND); assert(list_inx == 0); #endif // USE_SB_FC for (srv = 0; srv < MAX_SRV; srv++) { sprintf(send_buffer[srv], "$srv%d", srv); len = (int) strlen(send_buffer[srv]); ferr = BFILE_OPEN_((char *) send_buffer[srv], (short) len, &filenums[srv], 0, 0, 1, 0, 0, 0, 0, NULL); TEST_CHK_FEOK(ferr); } #ifdef USE_SB_FC do_set_guardian(filenums[0], 0, 1); // add do_set_guardian(filenums[0], 1, 0); // remove (specific) do_set_guardian(filenums[0], 0, 1); // add do_set_guardian(-1, 1, 0); // remove (all) do_set_guardian(-1, 0, 1); // add (all) #endif // USE_SB_FC for (srv = 0; srv < MAX_SRV; srv++) { for (inx = 0; inx < loop; inx++) { sprintf(send_buffer[srv], "inx=%d", inx); bcc = BWRITEREADX(filenums[srv], send_buffer[srv], (short) (strlen(send_buffer[srv]) + 1), BUFSIZ, &count_read, 1); TEST_CHK_BCCEQ(bcc); #ifdef USE_SB_FC ferr = BFILE_COMPLETE_((short *) &info, timeout, NULL, 0, NULL); TEST_CHK_FEOK(ferr); assert(info.z_tag == 1); #else tfilenum = -1; bcc = BAWAITIOX(&tfilenum, &buf, &count_xferred, &tag, timeout, NULL); TEST_CHK_BCCEQ(bcc); #endif } } for (srv = 0; srv < MAX_SRV; srv++) { p = strchr(send_buffer[srv], ':'); *p = 0; p++; strcpy(host[srv], send_buffer[srv]); port[srv] = (unsigned short) atoi(p); if (verbose) printf("server[%d] returned host=%s, port=%d\n", srv, host[srv], port[srv]); } #ifdef USE_SB_FC if (verbose) printf("client connecting up\n"); // connect up, and setup fds for (srv = 0; srv < MAX_SRV; srv++) { sockc1[srv] = do_connect(srv); sockc2[srv] = do_connect(srv); } do_set_guardian(-1, 1, 0); // remove (all) do_set_linux(sockc1[0], 0, 0, 0, 0, 1); // add-no rr/wr/exc // nothing should be ready timeout = 0; ferr = BFILE_COMPLETE_((short *) &info, timeout, NULL, 0, NULL); assert(ferr == XZFIL_ERR_TIMEDOUT); // server has sent something, so rr should be on sleep(1); do_set_linux(sockc1[0], 0, 1, 0, 0, 1); // rr timeout = -1; ferr = BFILE_COMPLETE_((short *) &info, timeout, NULL, 0, NULL); TEST_CHK_FEOK(ferr); assert(info.z_filetype); // linux assert(info.z_error == XZFIL_ERR_OK); assert(info.z_fnum_fd == sockc1[0]); assert(info.u_z_return_value.z_return_value.z_read_ready); assert(!info.u_z_return_value.z_return_value.z_write_ready); assert(!info.u_z_return_value.z_return_value.z_exception); // wr should be on do_set_linux(sockc1[0], 0, 0, 1, 0, 1); // wr timeout = -1; ferr = BFILE_COMPLETE_((short *) &info, timeout, NULL, 0, NULL); TEST_CHK_FEOK(ferr); assert(info.z_filetype); // linux assert(info.z_error == XZFIL_ERR_OK); assert(info.z_fnum_fd == sockc1[0]); assert(!info.u_z_return_value.z_return_value.z_read_ready); assert(info.u_z_return_value.z_return_value.z_write_ready); assert(!info.u_z_return_value.z_return_value.z_exception); do_set_linux(sockc1[0], 0, 0, 0, 0, 1); // clear ready do_set_linux(sockc2[0], 0, 0, 0, 0, 2); // add-no rr/wr/exc // nothing should be ready timeout = 0; ferr = BFILE_COMPLETE_((short *) &info, timeout, NULL, 0, NULL); assert(ferr == XZFIL_ERR_TIMEDOUT); // rr should NOT be ready do_set_linux(sockc2[0], 0, 1, 0, 0, 2); // rr timeout = 100; ferr = BFILE_COMPLETE_((short *) &info, timeout, NULL, 0, NULL); assert(ferr == XZFIL_ERR_TIMEDOUT); // test fairness (check trace) do_set_linux(-1, 1, 0, 0, 0, 0); // clear linux for (srv = 0; srv < MAX_SRV; srv++) do_set_guardian(filenums[srv], 0, srv + 1); // add for (srv = 0; srv < MAX_SRV; srv++) { bcc = BWRITEREADX(filenums[srv], NULL, 0, BUFSIZ, &count_read, 1); TEST_CHK_BCCEQ(bcc); } usleep(10000); for (srv = 0; srv < MAX_SRV; srv++) { timeout = -1; ferr = BFILE_COMPLETE_((short *) &info, timeout, NULL, 0, NULL); TEST_CHK_FEOK(ferr); assert(!info.z_filetype); // guardian assert(info.z_error == XZFIL_ERR_OK); assert(info.z_fnum_fd == filenums[srv]); } #endif // USE_SB_FC if (verbose) printf("client closing\n"); for (srv = 0; srv < MAX_SRV; srv++) { ferr = BFILE_CLOSE_(filenums[srv], 0); TEST_CHK_FEOK(ferr); } printf("if there were no asserts, all is well\n"); } else { #ifdef USE_SB_FC sockl = do_listen(); assert(sockl != -1); #endif // USE_SB_FC ferr = BFILE_OPEN_((char *) "$RECEIVE", 8, &filenumr, 0, 0, 1, 1, 1, // no sys msg 0, 0, NULL); TEST_CHK_FEOK(ferr); for (inx = 0; inx < loop; inx++) { bcc = BREADUPDATEX(filenumr, recv_buffer, BUFSIZ, &count_read, 1); TEST_CHK_BCCEQ(bcc); tfilenum = filenumr; bcc = BAWAITIOX(&tfilenum, &buf, &count_xferred, &tag, timeout, NULL); TEST_CHK_BCCEQ(bcc); assert(tag == 1); sprintf(recv_buffer, "%s:%d\n", host[0], port[0]); count_read = (short) (strlen(recv_buffer) + 1); bcc = BREPLYX(recv_buffer, count_read, &count_written, 0, XZFIL_ERR_OK); TEST_CHK_BCCEQ(bcc); } #ifdef USE_SB_FC if (verbose) printf("server accepting\n"); socka1 = do_accept(sockl); socka2 = do_accept(sockl); err = write(socka1, recv_buffer, 1); assert(err == 1); for (inx = 0; inx < 1; inx++) { bcc = BREADUPDATEX(filenumr, recv_buffer, BUFSIZ, &count_read, 1); TEST_CHK_BCCEQ(bcc); tfilenum = filenumr; bcc = BAWAITIOX(&tfilenum, &buf, &count_xferred, &tag, timeout, NULL); TEST_CHK_BCCEQ(bcc); bcc = BREPLYX(recv_buffer, 0, &count_written, 0, XZFIL_ERR_OK); TEST_CHK_BCCEQ(bcc); } #endif // USE_SB_FC if (verbose) printf("server closing\n"); ferr = BFILE_CLOSE_(filenumr, 0); TEST_CHK_FEOK(ferr); } ferr = file_mon_process_shutdown(); TEST_CHK_FEOK(ferr); util_test_finish(client); return 0; }