ndbsql.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:27k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /*******************************************************************************
  14.  *  NDB Cluster NDB SQL -- A simple SQL Command-line Interface
  15.  *
  16.  ******************************************************************************/
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #ifdef NDB_MACOSX
  21. #include <stdlib.h>
  22. #else
  23. #include <malloc.h>
  24. #endif
  25. #include <errno.h>
  26. #include <editline/editline.h>
  27. #include <NdbOut.hpp>
  28. #include <ctype.h>
  29. #include <wctype.h>
  30. #ifndef SQL_BLOB
  31. #define SQL_BLOB                30
  32. #endif
  33. #ifndef SQL_CLOB
  34. #define SQL_CLOB                40
  35. #endif
  36. /**************************************************************************
  37.  * ------------------------------------------------------------------------
  38.  *  MODULE:       Readline and string handling
  39.  * ------------------------------------------------------------------------
  40.  **************************************************************************/
  41. #define MAXBUF 2048
  42. static char* s_readBuf;
  43. static int s_bufSize = MAXBUF;
  44. static char*
  45. readSQL_File(FILE* inputFile)
  46. {
  47.   int c;
  48.   int i = 0;
  49.   if (feof(inputFile))
  50.     return 0;
  51.   while ((c = getc(inputFile)) != EOF) {
  52.     if (i == s_bufSize-1) {
  53.       s_bufSize *= 2;
  54.       s_readBuf = (char*)realloc(s_readBuf, s_bufSize);
  55.     }
  56.     s_readBuf[i] = c;
  57.     if (c == 'n')
  58.       break;
  59.     i++;
  60.   }
  61.   s_readBuf[i] = 0;
  62.   return s_readBuf;
  63. }
  64.   
  65. static char*
  66. readline_gets(const char* prompt, bool batchMode, FILE* inputFile)
  67. {
  68.   static char *line_read = (char *)NULL;
  69.   
  70.   // Disable the default file-name completion action of TAB
  71.   // rl_bind_key ('t', rl_insert);
  72.   
  73.   if (batchMode)
  74.     /* Read one line from a file. */
  75.     line_read = readSQL_File(inputFile);
  76.   else
  77.     /* Get a line from the user. */
  78.     line_read = readline(prompt);
  79.   
  80.   /* If the line has any text in it, save it in the history. */
  81.   if (!batchMode)
  82.     if (line_read && *line_read) add_history(line_read);
  83.     
  84.   return (line_read);
  85. }
  86. #ifdef NDB_WIN32
  87. extern "C" 
  88. {
  89.   char* readline(const char* prompt)
  90.   {
  91.     fputs(prompt, stdout);
  92.     return fgets(s_readBuf, MAXBUF, stdin);
  93.   }
  94.   void add_history(char*)
  95.   {
  96.   }
  97. }
  98. #endif
  99. bool emptyString(const char* s) {
  100.   if (s == NULL) {
  101.     return true;
  102.   }
  103.   for (unsigned int i = 0; i < strlen(s); ++i) {
  104.     if (! isspace(s[i])) {
  105.       return false;
  106.     }
  107.   }
  108.   return true;
  109. }
  110. /**************************************************************************
  111.  * ------------------------------------------------------------------------
  112.  *  MODULE:       ODBC Handling
  113.  * ------------------------------------------------------------------------
  114.  **************************************************************************/
  115. #include <sqlext.h>
  116. #include <stdio.h>
  117. #include <string.h>
  118. #ifdef NDB_MACOSX
  119. #include <stdlib.h>
  120. #else
  121. #include <malloc.h>
  122. #endif
  123. /**
  124.  * In the case where the user types a SELECT statement, 
  125.  * the function fetches and displays all rows of the result set.
  126.  *
  127.  * This example illustrates the use of GetDiagField to identify the
  128.  * type of SQL statement executed and, for SQL statements where the
  129.  * row count is defined on all implementations, the use of GetDiagField
  130.  * to obtain the row count.
  131.  */
  132. #define MAXCOLS 100
  133. #undef max
  134. #define max(a,b) ((a)>(b)?(a):(b))
  135. #define MAX_MESSAGE 500
  136. void getDiag(SQLSMALLINT type, SQLHANDLE handle, unsigned k, unsigned count) 
  137. {
  138.   char message[MAX_MESSAGE];
  139.   char state[6];
  140.   SQLINTEGER native;
  141.   SQLSMALLINT length = -1;
  142.   memset(message, 0, MAX_MESSAGE);
  143.   int ret = SQLGetDiagRec(type, handle, k, (SQLCHAR*)state, 
  144.   &native, (SQLCHAR*)message, MAX_MESSAGE, &length);
  145.   if (ret == SQL_NO_DATA) {
  146.     ndbout << "No error diagnostics available" << endl;
  147.     return;
  148.   }
  149.   ndbout << message << endl;
  150.   if (k <= count && ret != SQL_SUCCESS)
  151.     ndbout_c("SQLGetDiagRec %d of %d: return %d != SQL_SUCCESS", 
  152.      k, count, (int)ret);
  153.   if (k <= count && (SQLSMALLINT) strlen(message) != length)
  154.     ndbout_c("SQLGetDiagRec %d of %d: message length %d != %d", 
  155.      k, count, strlen(message), length);
  156.   if (k > count && ret != SQL_NO_DATA)
  157.     ndbout_c("SQLGetDiagRec %d of %d: return %d != SQL_NO_DATA", 
  158.      k, count, (int)ret);
  159. }
  160. int print_err(SQLSMALLINT handletype, SQLHDBC hdbc) {
  161.   getDiag(handletype, hdbc, 1, 1);
  162.   return -1;
  163. }
  164. /***************************************************************
  165.  * The following functions are given for completeness, but are
  166.  * not relevant for understanding the database processing
  167.  * nature of CLI
  168.  ***************************************************************/
  169. #define MAX_NUM_PRECISION 15
  170. /*#define max length of char string representation of no. as:
  171. = max(precision) + leading sign +E +expsign + max exp length
  172. = 15 +1 +1 +1 +2
  173. = 15 +5
  174. */
  175. #define MAX_NUM_STRING_SIZE (MAX_NUM_PRECISION + 5)
  176. int build_indicator_message(SQLCHAR *errmsg, SQLPOINTER *data,
  177.     SQLINTEGER collen, SQLINTEGER *outlen, 
  178.     SQLSMALLINT colnum) {
  179.   if (*outlen == SQL_NULL_DATA) {
  180.     (void)strcpy((char *)data, "NULL");
  181.     *outlen=4;
  182.   } else {
  183.     sprintf((char *)errmsg+strlen((char *)errmsg),
  184.     "%ld chars truncated, col %dn", *outlen-collen+1,
  185.     colnum);
  186.     *outlen=255;
  187.   }
  188.   return 0;
  189. }
  190. SQLINTEGER display_length(SQLSMALLINT coltype, SQLINTEGER collen, 
  191.   SQLCHAR *colname) {
  192.   switch (coltype) {
  193.   case SQL_VARCHAR:
  194.   case SQL_CHAR:
  195.   case SQL_VARBINARY:
  196.   case SQL_BINARY:
  197.   case SQL_BLOB:
  198.   case SQL_CLOB:
  199.   case SQL_BIT:
  200.     //case SQL_REF:
  201.     //case SQL_BIT_VARYING:
  202.     return(max(collen,(SQLINTEGER) strlen((char *)colname))+1);
  203.   case SQL_FLOAT:
  204.   case SQL_DOUBLE:
  205.   case SQL_NUMERIC:
  206.   case SQL_REAL:
  207.   case SQL_DECIMAL:
  208.     return(max(MAX_NUM_STRING_SIZE,strlen((char *)colname))+1);
  209.   case SQL_TYPE_DATE:
  210.   case SQL_TYPE_TIME:
  211.     //case SQL_TYPE_TIME_WITH_TIMEZONE:
  212.   case SQL_TYPE_TIMESTAMP:
  213.     //case SQL_TYPE_TIMESTAMP_WITH_TIMEZONE:
  214.   case SQL_INTERVAL_YEAR:
  215.   case SQL_INTERVAL_MONTH:
  216.   case SQL_INTERVAL_DAY:
  217.   case SQL_INTERVAL_HOUR:
  218.   case SQL_INTERVAL_MINUTE:
  219.   case SQL_INTERVAL_SECOND:
  220.   case SQL_INTERVAL_YEAR_TO_MONTH:
  221.   case SQL_INTERVAL_DAY_TO_HOUR:
  222.   case SQL_INTERVAL_DAY_TO_MINUTE:
  223.   case SQL_INTERVAL_DAY_TO_SECOND:
  224.   case SQL_INTERVAL_HOUR_TO_MINUTE:
  225.   case SQL_INTERVAL_HOUR_TO_SECOND:
  226.   case SQL_INTERVAL_MINUTE_TO_SECOND:
  227.     return(max(collen,(SQLINTEGER) strlen((char *)colname))+1);
  228.   case SQL_INTEGER:
  229.     //case SQL_BLOB_LOCATOR:
  230.     //case SQL_CLOB_LOCATOR:
  231.     //case SQL_UDT_LOCATOR:
  232.     //case SQL_ARRAY_LOCATOR:
  233.     return(max(11,strlen((char *)colname))+1);
  234.   case SQL_BIGINT:
  235.     return(max(21,strlen((char *)colname))+1);
  236.   case SQL_SMALLINT:
  237.     return(max(5,strlen((char *)colname))+1);
  238.   default:
  239.     (void)printf("Unknown datatype, %dn", coltype);
  240.     return(0);
  241.   }
  242. }
  243. struct Con {
  244.   const char* dsn;
  245.   SQLHENV henv;
  246.   SQLHDBC hdbc;
  247.   Con(const char* _dsn) :
  248.     dsn(_dsn), henv(SQL_NULL_HANDLE), hdbc(SQL_NULL_HANDLE) {}
  249. };
  250. static int
  251. do_connect(Con& con)
  252. {
  253.   int ret;
  254.   // allocate an environment handle
  255.   ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &con.henv);
  256.   if (ret != SQL_SUCCESS)
  257.     return -1;
  258.   
  259.   // set odbc version (required)
  260.   ret = SQLSetEnvAttr(con.henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); 
  261.   if (ret != SQL_SUCCESS)
  262.     return -1;
  263.   
  264.   // allocate a connection handle
  265.   ret = SQLAllocHandle(SQL_HANDLE_DBC, con.henv, &con.hdbc);
  266.   if (ret != SQL_SUCCESS)
  267.     return -1;
  268.   
  269.   // connect to database
  270.   SQLCHAR szConnStrOut[256];
  271.   SQLSMALLINT cbConnStrOut;
  272.   ret = SQLDriverConnect(con.hdbc, 0, (SQLCHAR*)con.dsn, SQL_NTS,
  273.       szConnStrOut, sizeof(szConnStrOut), &cbConnStrOut, SQL_DRIVER_COMPLETE);
  274.   if (ret != SQL_SUCCESS) {
  275.     ndbout << "Connection failure: Could not connect to database" << endl;
  276.     print_err(SQL_HANDLE_DBC, con.hdbc);
  277.     return -1;
  278.   }  
  279.   return 0;
  280. }
  281. static int
  282. do_disconnect(Con& con)
  283. {
  284.   // disconnect from database
  285.   SQLDisconnect(con.hdbc);
  286.   // free connection handle
  287.   SQLFreeHandle(SQL_HANDLE_DBC, con.hdbc);
  288.   con.hdbc = SQL_NULL_HANDLE;
  289.   // free environment handle
  290.   SQLFreeHandle(SQL_HANDLE_ENV, con.henv);
  291.   con.henv = SQL_NULL_HANDLE;
  292.   return 0;
  293. }
  294. static int
  295. get_autocommit(Con& con)
  296. {
  297.   int ret;
  298.   SQLUINTEGER v;
  299.   ret = SQLGetConnectAttr(con.hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)&v, SQL_IS_UINTEGER, 0);
  300.   if (ret != SQL_SUCCESS) {
  301.     ndbout << "Get autocommit failed" << endl;
  302.     print_err(SQL_HANDLE_DBC, con.hdbc);
  303.     return -1;
  304.   }
  305.   return v;
  306. }
  307. static int
  308. set_autocommit(Con& con, SQLUINTEGER v)
  309. {
  310.   int ret;
  311.   ret = SQLSetConnectAttr(con.hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)v, SQL_IS_UINTEGER);
  312.   if (ret != SQL_SUCCESS) {
  313.     ndbout << "Set autocommit failed" << endl;
  314.     print_err(SQL_HANDLE_DBC, con.hdbc);
  315.     return -1;
  316.   }
  317.   return 0;
  318. }
  319. static int
  320. do_commit(Con& con)
  321. {
  322.   int ret = SQLEndTran(SQL_HANDLE_DBC, con.hdbc, SQL_COMMIT);
  323.   if (ret != SQL_SUCCESS) {
  324.     ndbout << "Commit failed" << endl;
  325.     print_err(SQL_HANDLE_DBC, con.hdbc);
  326.     return -1;
  327.   }
  328.   return 0;
  329. }
  330. static int
  331. do_rollback(Con& con)
  332. {
  333.   int ret = SQLEndTran(SQL_HANDLE_DBC, con.hdbc, SQL_ROLLBACK);
  334.   if (ret != SQL_SUCCESS) {
  335.     ndbout << "Rollback failed" << endl;
  336.     print_err(SQL_HANDLE_DBC, con.hdbc);
  337.     return -1;
  338.   }
  339.   return 0;
  340. }
  341. static int
  342. do_stmt(Con& con, const char *sqlstr)
  343. {
  344.   SQLHSTMT hstmt;
  345.   SQLCHAR errmsg[256];
  346.   SQLCHAR colname[32];
  347.   SQLSMALLINT coltype;
  348.   SQLSMALLINT colnamelen;
  349.   SQLSMALLINT nullable;
  350.   SQLUINTEGER collen[MAXCOLS];
  351.   SQLSMALLINT scale;
  352.   SQLINTEGER outlen[MAXCOLS];
  353.   SQLCHAR *data[MAXCOLS];
  354.   SQLSMALLINT nresultcols = 0;
  355.   SQLINTEGER rowcount;
  356.   SQLINTEGER stmttype;
  357.   SQLRETURN rc;
  358.   /* allocate a statement handle */
  359.   SQLAllocHandle(SQL_HANDLE_STMT, con.hdbc, &hstmt);
  360.   /* execute the SQL statement */
  361.   rc = SQLExecDirect(hstmt, (SQLCHAR*)sqlstr, SQL_NTS);
  362.   if (rc == SQL_ERROR) {
  363.     ndbout << "Operation failed" << endl;
  364.     print_err(SQL_HANDLE_STMT, hstmt);
  365.     return -1;
  366.   }
  367.   if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NO_DATA_FOUND) {
  368.     ndbout << "Operation returned unknown code " << rc << endl;
  369.     return -1;
  370.   }
  371.   /* see what kind of statement it was */
  372.   SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0,
  373.   SQL_DIAG_DYNAMIC_FUNCTION_CODE,
  374.   (SQLPOINTER)&stmttype, SQL_IS_INTEGER, (SQLSMALLINT *)NULL);
  375.   switch (stmttype) {
  376.     /* SELECT statement */
  377.   case SQL_DIAG_SELECT_CURSOR:
  378.     /* determine number of result columns */
  379.     SQLNumResultCols(hstmt, &nresultcols);
  380.     /***********************
  381.      * Display column names 
  382.      ***********************/
  383.     /* Print vertical divider */
  384.     printf("|");
  385.     for (int i=0; i<nresultcols; i++) {
  386.       SQLDescribeCol(hstmt, i+1, colname, sizeof(colname),
  387.      &colnamelen, &coltype, &collen[i], &scale, &nullable);
  388.       collen[i] = display_length(coltype, collen[i], colname);
  389.       for (SQLUINTEGER j=0; j<collen[i]; j++) printf("-");
  390.       printf("--+");
  391.     }
  392.     printf("n");
  393.     printf("|");
  394.     for (int i=0; i<nresultcols; i++) {
  395.       SQLDescribeCol(hstmt, i+1, colname, sizeof(colname),
  396.      &colnamelen, &coltype, &collen[i], &scale, &nullable);
  397.       
  398.       /* assume there is a display_length function which
  399.  computes correct length given the data type */
  400.       collen[i] = display_length(coltype, collen[i], colname);
  401.       (void)printf(" %*.*s |", (int)collen[i], (int)collen[i], (char *)colname);
  402.       
  403.       /* allocate memory to bind column */
  404.       data[i] = (SQLCHAR *) malloc(collen[i]);
  405.       if (data[i] == NULL) {
  406. ndbout << "Failed to allocate malloc memory in NDB SQL program" 
  407.        << endl;
  408. exit(-1);
  409.       }
  410.       
  411.       /* bind columns to program vars, converting all types to CHAR */
  412.       SQLBindCol(hstmt, i+1, SQL_C_CHAR, data[i], collen[i], &outlen[i]);
  413.     }
  414.     printf("n");
  415.     /* Print vertical divider */
  416.     printf("|");
  417.     for (int i=0; i<nresultcols; i++) {
  418.       SQLDescribeCol(hstmt, i+1, colname, sizeof(colname),
  419.      &colnamelen, &coltype, &collen[i], &scale, &nullable);
  420.       collen[i] = display_length(coltype, collen[i], colname);
  421.       for (SQLUINTEGER j=0; j<collen[i]; j++) printf("-");
  422.       printf("--+");
  423.     }
  424.     printf("n");
  425.     /**********************
  426.      * Display result rows 
  427.      **********************/
  428.     {
  429.       int no_of_rows_fetched=0;
  430.       while (1) {
  431. rc=SQLFetch(hstmt);
  432. errmsg[0] = '';
  433. if (rc == SQL_ERROR) {
  434.   print_err(SQL_HANDLE_STMT, hstmt);
  435.   break;
  436. }
  437. if (rc == SQL_NO_DATA) break;
  438. if (rc == SQL_SUCCESS) {
  439.   printf("|");
  440.   for (int i=0; i<nresultcols; i++) {
  441.     if (outlen[i] == SQL_NULL_DATA
  442. || outlen[i] >= (SQLINTEGER) collen[i])
  443.       build_indicator_message(errmsg,
  444.       (SQLPOINTER *)data[i], collen[i],
  445.       &outlen[i], i);
  446.     (void)printf(" %*.*s |", (int)collen[i], (int)collen[i],
  447.  (char *)data[i]);
  448.   } 
  449.   /* print any truncation messages */
  450.   (void)printf("n%s", (char *)errmsg);
  451. } else if (rc == SQL_SUCCESS_WITH_INFO) {
  452.   printf("|");
  453.   for (int i=0; i<nresultcols; i++) {
  454.     if (outlen[i] == SQL_NULL_DATA
  455. || outlen[i] >= (SQLINTEGER) collen[i])
  456.       build_indicator_message(errmsg,
  457.       (SQLPOINTER *)data[i], collen[i],
  458.       &outlen[i], i);
  459.     (void)printf(" %*.*s |", (int)collen[i], (int)collen[i],
  460.  (char *)data[i]);
  461.   } /* for all columns in this row */
  462.   /* print any truncation messages */
  463.   (void)printf("n%s", (char *)errmsg);
  464. }
  465. no_of_rows_fetched++;
  466.       } /* while rows to fetch */
  467.       /* Print vertical divider */
  468.       printf("|");
  469.       for (int i=0; i<nresultcols; i++) {
  470. SQLDescribeCol(hstmt, i+1, colname, sizeof(colname),
  471.        &colnamelen, &coltype, &collen[i], &scale, &nullable);
  472. collen[i] = display_length(coltype, collen[i], colname);
  473. for (SQLUINTEGER j=0; j<collen[i]; j++) printf("-");
  474. printf("--+");
  475.       }
  476.       printf("n");
  477.       ndbout << no_of_rows_fetched << " rows fetched" << endl;
  478.     }
  479.     SQLCloseCursor(hstmt);
  480.     break;
  481.     /* searched DELETE, INSERT or searched UPDATE statement */
  482.   case SQL_DIAG_DELETE_WHERE:
  483.   case SQL_DIAG_INSERT:
  484.   case SQL_DIAG_UPDATE_WHERE:
  485.     /* check rowcount */
  486.     SQLRowCount(hstmt, (SQLINTEGER*)&rowcount);
  487.     ndbout << (int)rowcount << " rows affected" << endl;
  488.     break;
  489.     /* other statements */
  490.   case SQL_DIAG_ALTER_TABLE:
  491.   case SQL_DIAG_CREATE_TABLE:
  492.   case SQL_DIAG_CREATE_VIEW:
  493.   case SQL_DIAG_DROP_TABLE:
  494.   case SQL_DIAG_DROP_VIEW:
  495.   case SQL_DIAG_CREATE_INDEX:
  496.   case SQL_DIAG_DROP_INDEX:
  497.   case SQL_DIAG_DYNAMIC_DELETE_CURSOR:
  498.   case SQL_DIAG_DYNAMIC_UPDATE_CURSOR:
  499.   case SQL_DIAG_GRANT:
  500.   case SQL_DIAG_REVOKE:
  501.     ndbout << "Operation successful" << endl;
  502.     break;
  503.     /* implementation-defined statement */
  504.   default:
  505.     (void)printf("Unknown Statement type=%ldn", stmttype);
  506.     break;
  507.   }
  508.   /* free data buffers */
  509.   for (int i=0; i<nresultcols; i++) {
  510.     (void)free(data[i]);
  511.   }
  512.   
  513.   SQLFreeHandle(SQL_HANDLE_STMT, hstmt);  // free statement handle 
  514.   return(0);
  515. }
  516. /**************************************************************************
  517.  * ------------------------------------------------------------------------
  518.  *  MODULE:       Help
  519.  * ------------------------------------------------------------------------
  520.  **************************************************************************/
  521. void print_help() {
  522.   ndbout << "Commands:" << endl
  523.  << "set                Print currect settings" << endl
  524.  << "set trace N        Set NDB ODBC trace level to N (0-5)" << endl
  525.  << "set autocommit on  Commit each statement (default)" << endl
  526.  << "set autocommit off Use explicit commit/rollback - may time out!" << endl
  527.  << "commit             Commit changes to database" << endl
  528.  << "rollback           Rollback (undo) any changes" << endl
  529.          << "whenever sqlerror  Define action: exit or continue (default)" << endl
  530.  << endl
  531.  << "help               Print this help" << endl
  532.  << "help create        Print create table examples" << endl
  533.  << "help insert        Print insert examples" << endl
  534.  << "help select        Print select examples" << endl
  535.  << "help delete        Print delete examples" << endl
  536.  << "help update        Print update examples" << endl
  537.  << "help virtual       Print help on NDB ODBC virtual tables" << endl
  538.  << "list tables        Lists all table names" << endl
  539.  << endl
  540.  << "All other commands are sent to the NDB ODBC SQL executor" 
  541.  << endl << endl;
  542. }
  543. void print_help_create() {  
  544.   ndbout << "Create Table Examples" << endl << endl 
  545.  << "create table t ( a integer not null, b char(20) not null," << endl
  546.  << "                 c float, primary key(a, b) )" << endl
  547.  << "create table t ( ndb$tid bigint unsigned primary key," << endl
  548.  << "                 b char(20) not null, c float )" << endl
  549.  << "create table t ( a int auto_increment primary key," << endl
  550.  << "                 b char(20) not null, c float )" << endl
  551.  << "create table t ( a int primary key," << endl
  552.  << "                 b int default 100 )" << endl
  553.  << endl 
  554.  << "For more information read NDB Cluster ODBC Manual."
  555.  << endl;
  556. }
  557. void print_help_insert() {  
  558.   ndbout << "Insert Examples" << endl << endl 
  559.  << "insert into t(a, c) values (123, 'abc')" << endl
  560.  << "insert into t1(a, c) select a + 10 * b, c from t2" << endl
  561.  << "insert into t values(null, 'abc', 1.23)" << endl
  562.  << "insert into t(b, c) values('abc', 1.23)" << endl
  563.  << endl 
  564.  << "For more information read NDB Cluster ODBC Manual."
  565.  << endl;
  566. }
  567. void print_help_select() {  
  568.   ndbout << "Select Examples" << endl << endl 
  569.  << "select a + b * c from t where a <= b + c and (b > c or c > 10)"
  570.  << endl
  571.  << "select a.x, b.y, c.z from t1 a, t2 b, t2 c where a.x + b.y < c.z" 
  572.  << endl
  573.  << "select * from t1, t2 where a1 > 5 order by b1 + b2, c1 desc" 
  574.  << endl
  575.  << "select count(*), max(a), 1 + sum(b) + avg(c * d) from t" << endl
  576.  << "select * from t where a < 10 or b > 10" << endl
  577.  << "select * from t where pk = 5 and b > 10" << endl
  578.  << "select * from t1, t2, t3 where t1.pk = t2.x and t2.pk = t3.y" 
  579.  << endl  << endl 
  580.  << "For more information read NDB Cluster ODBC Manual."
  581.  << endl;
  582. }
  583. void print_help_update() {  
  584.   ndbout << "Update and Delete Examples" << endl << endl 
  585.  << "update t set a = b + 5, c = d where c > 10" << endl
  586.  << "update t set a = b + 5, c = d where pk = 5 and c > 10" << endl
  587.  << "update t set a = 5, c = 7 where pk = 5" << endl
  588.  << "delete from t where c > 10" << endl
  589.  << "delete from t where pk = 5 and c > 10" << endl
  590.  << "delete from t where pk = 5" << endl 
  591.  << endl
  592.  << "For more information read NDB Cluster ODBC Manual."
  593.  << endl;
  594. }
  595. void print_help_virtual() {  
  596.   ndbout << "Virtual tables" << endl << endl 
  597.  << "* DUAL" 
  598.  << "  a 1-row table - example: select SYSDATE from DUAL" << endl
  599.  << "* ODBC$TYPEINFO" << endl
  600.  << "  corresponds to SQLGetTypeInfo" << endl
  601.  << "* ODBC$TABLES" << endl
  602.  << "  corresponds to SQLTables (ordered by NDB table id)" << endl
  603.  << "* ODBC$COLUMNS" << endl
  604.  << "  corresponds to SQLColumns (ordered by NDB table id)" << endl
  605.  << "* ODBC$PRIMARYKEYS" << endl
  606.  << "  corresponds to SQLPrimaryKeys (ordered by NDB table id)" << endl
  607.  << endl
  608.  << "For more information read NDB Cluster ODBC Manual."
  609.  << endl;
  610. }
  611. /**************************************************************************
  612.  * ------------------------------------------------------------------------
  613.  *  MODULE:       Main
  614.  * ------------------------------------------------------------------------
  615.  **************************************************************************/
  616. int main(int argc, const char** argv)
  617. {
  618.   ndb_init();
  619.   const char* usage = "Usage: ndbsql [-h] [-d dsn] [-f file] [stmt]n-h helpn-d <database name or connect string>n-f <file name> batch modenstmt single SQL statementn";
  620.   const char* dsn = "TEST_DB";
  621.   bool helpFlg = false, batchMode = false;
  622.   const char* fileName = 0;
  623.   FILE* inputFile = stdin;
  624.   const char* singleStmt = 0;
  625.   s_readBuf = (char*)malloc(s_bufSize);
  626.   while (++argv, --argc > 0) {
  627.     const char* arg = argv[0];
  628.     if (arg[0] != '-')
  629.       break;
  630.     if (strcmp(arg, "-d") == 0) {
  631.       if (++argv, --argc > 0) {
  632.         dsn = argv[0];
  633.         continue;
  634.       }
  635.     }
  636.     if (strcmp(arg, "-h") == 0) {
  637.       helpFlg = true;
  638.       continue;
  639.     }
  640.     if (strcmp(arg, "-f") == 0) {
  641.       if (++argv, --argc > 0) {
  642. fileName = argv[0];
  643. continue;
  644.       }
  645.     }
  646.     ndbout << usage;
  647.     return 1;
  648.   }
  649.   if (helpFlg) {
  650.     ndbout << usage << "n";
  651.     print_help();
  652.     return 0;
  653.   }
  654.   if (fileName != 0) {
  655.     if (argc > 0) {
  656.       ndbout << usage;
  657.       return 1;
  658.     }
  659.     if ((inputFile = fopen(fileName, "r")) == 0) {
  660.       ndbout << "Could not read file " << fileName << ": " << strerror(errno) << endl;
  661.       return 1;
  662.     }
  663.     batchMode = true;
  664.   }
  665.   if (argc > 0) {
  666.     singleStmt = argv[0];
  667.     batchMode = true;
  668.   }
  669.   if (! batchMode)
  670.     ndbout << "NDB Cluster NDB SQL -- A simple SQL Command-line Interfacenn";
  671.   Con con(dsn);
  672.   if (do_connect(con) < 0)
  673.     return 1;
  674.   if (! batchMode)
  675.     ndbout << "Terminate SQL statements with a semi-colon ';'n";
  676.   char* line = 0;
  677.   char* line2 = 0;
  678.   char* line3 = 0;
  679.   unsigned lineno = 0;
  680.   bool has_semi;
  681.   bool exit_on_error = false;
  682.   int exit_code = 0;
  683.   while (1) {
  684.     free(line);
  685.     line = 0;
  686.     lineno = 0;
  687. more_lines:
  688.     free(line2);
  689.     free(line3);
  690.     line2 = line3 = 0;
  691.     lineno++;
  692.     has_semi = false;
  693.     char prompt[20];
  694.     if (lineno == 1)
  695.       strcpy(prompt, "SQL> ");
  696.     else
  697.       sprintf(prompt, "%4d ", lineno);
  698.     if (singleStmt != 0) {
  699.       line = strdup(singleStmt);
  700.       int n = strlen(line);
  701.       while (n > 0 && isspace(line[n - 1])) {
  702.         line[--n] = 0;
  703.       }
  704.       if (n > 0 && line[n - 1] == ';')
  705.         line[n - 1] = 0;
  706.       has_semi = true;  // regardless
  707.     } else {
  708.       const char *line1 = readline_gets(prompt, batchMode, inputFile); 
  709.       if (line1 != 0) {
  710.         if (line == 0)
  711.           line = strdup(line1);
  712.         else {
  713.           line = (char*)realloc(line, strlen(line) + 1 + strlen(line1) + 1);
  714.           strcat(line, "n");
  715.           strcat(line, line1);
  716.         }
  717.         if (batchMode)
  718.           ndbout << prompt << line1 << endl;
  719.       } else {
  720.         if (! batchMode)
  721.           ndbout << endl;
  722.         if (line != 0)
  723.           ndbout << "Ignored unterminated SQL statement" << endl;
  724.         break;
  725.       }
  726.     }
  727.     line2 = (char*)malloc(strlen(line) + 1);
  728.     {
  729.       char* p = line2;
  730.       char* q = line;
  731.       bool str = false;
  732.       while (*q != 0) {
  733.         if (*q == ''') {
  734.           str = !str;
  735.           *p++ = *q++;
  736.         } else if (!str && *q == '-' && *(q + 1) == '-') {
  737.           while (*q != 0 && *q != 'n')
  738.             q++;
  739.         } else
  740.           *p++ = *q++;
  741.       }
  742.       *p = 0;
  743.       int n = strlen(line2);
  744.       while (n > 0 && isspace(line2[n - 1]))
  745.         line2[--n] = 0;
  746.       if (n > 0 && line2[n - 1] == ';') {
  747.         line2[--n] = 0;
  748.         has_semi = true;
  749.       }
  750.     }
  751.     line3 = strdup(line2);
  752.     char* tok[10];
  753.     int ntok = 0;
  754.     tok[ntok] = strtok(line3, " ");
  755.     while (tok[ntok] != 0) {
  756.       ntok++;
  757.       if (ntok == 10)
  758.         break;
  759.       tok[ntok] = strtok(0, " ");
  760.     }
  761.     if (ntok == 0)
  762.       continue;
  763.     if (!strcasecmp(tok[0], "help") || !strcmp(tok[0], "?")) {
  764.       if (ntok != 2)
  765. print_help();
  766.       else if (!strcasecmp(tok[1], "create"))
  767. print_help_create();
  768.       else if (!strcasecmp(tok[1], "insert"))
  769. print_help_insert();
  770.       else if (strcasecmp(tok[1], "select"))
  771. print_help_select();
  772.       else if (!strcasecmp(tok[1], "delete"))
  773. print_help_update();
  774.       else if (!strcasecmp(tok[1], "update"))
  775. print_help_update();
  776.       else if (!strcasecmp(tok[1], "virtual"))
  777. print_help_virtual();
  778.       else
  779. print_help();
  780.       continue;
  781.     }
  782.     if (!strcasecmp(tok[0], "list")) {
  783.       if (ntok == 2 && !strcasecmp(tok[1], "tables")) {
  784. free(line2);
  785. line2 = strdup("SELECT TABLE_NAME FROM ODBC$TABLES");
  786.         has_semi = true;
  787.       } else {
  788.         ndbout << "Invalid list option - try help" << endl;
  789.         continue;
  790.       }
  791.     }
  792.     if (ntok == 1 && !strcasecmp(tok[0], "quit"))
  793.       break;
  794.     if (ntok == 1 && !strcasecmp(tok[0], "exit"))
  795.       break;
  796.     if (ntok == 1 && !strcasecmp(tok[0], "bye"))
  797.       break;
  798.     if (!strcasecmp(tok[0], "set")) {
  799.       if (ntok == 1) {
  800. char* p;
  801. p = getenv("NDB_ODBC_TRACE");
  802. ndbout << "Trace level is " << (p ? atoi(p) : 0) << endl;
  803. int ret = get_autocommit(con);
  804. if (ret != -1)
  805.   ndbout << "Autocommit is " << (ret == SQL_AUTOCOMMIT_ON ? "on" : "off") << endl;
  806.       } else if (ntok == 3 && !strcasecmp(tok[1], "trace")) {
  807. static char env[40];
  808. int n = tok[2] ? atoi(tok[2]) : 0;
  809. sprintf(env, "NDB_ODBC_TRACE=%d", n);
  810. putenv(env);
  811. ndbout << "Trace level set to " << n << endl;
  812.       } else if (ntok == 3 && !strcasecmp(tok[1], "autocommit")) {
  813. if (tok[2] && !strcasecmp(tok[2], "on")) {
  814.   int ret = set_autocommit(con, SQL_AUTOCOMMIT_ON);
  815.   if (ret != -1)
  816.     ndbout << "Autocommit set to ON" << endl;
  817. } else if (tok[2] && !strcasecmp(tok[2], "off")) {
  818.   int ret = set_autocommit(con, SQL_AUTOCOMMIT_OFF);
  819.   if (ret != -1)
  820.     ndbout << "Autocommit set to OFF - transaction may time out" << endl;
  821. } else {
  822.   ndbout << "Invalid autocommit option - try help" << endl;
  823. }
  824.       } else {
  825. ndbout << "Invalid set command - try help" << endl;
  826.       }
  827.       continue;
  828.     }
  829.     if (ntok >= 2 &&
  830.         !strcasecmp(tok[0], "whenever") && !strcasecmp(tok[1], "sqlerror")) {
  831.       if (ntok == 3 && !strcasecmp(tok[2], "exit"))
  832.         exit_on_error = true;
  833.       else if (ntok == 3 && !strcasecmp(tok[2], "continue"))
  834.         exit_on_error = false;
  835.       else {
  836.         ndbout << "Invalid whenever clause - try help" << endl;
  837.       }
  838.       continue;
  839.     }
  840.     if (!strcasecmp(tok[0], "commit")) {
  841.       if (ntok == 1) {
  842.         if (do_commit(con) != -1)
  843.           ndbout << "Commit done" << endl;
  844.         else {
  845.           exit_code = 1;
  846.           if (exit_on_error) {
  847.             ndbout << "Exit on error" << endl;
  848.             break;
  849.           }
  850.         }
  851.       } else {
  852.         ndbout << "Invalid commit command - try help" << endl;
  853.       }
  854.       continue;
  855.     }
  856.     if (!strcasecmp(tok[0], "rollback")) {
  857.       if (ntok == 1) {
  858.         if (do_rollback(con) != -1)
  859.           ndbout << "Rollback done" << endl;
  860.         else {
  861.           exit_code = 1;
  862.           if (exit_on_error) {
  863.             ndbout << "Exit on error" << endl;
  864.             break;
  865.           }
  866.         }
  867.       } else {
  868.         ndbout << "Invalid commit command - try help" << endl;
  869.       }
  870.       continue;
  871.     }
  872.     if (! has_semi)
  873.       goto more_lines;
  874.     if (do_stmt(con, line2) != 0) {
  875.       exit_code = 1;
  876.       if (exit_on_error) {
  877.         ndbout << "Exit on error" << endl;
  878.         break;
  879.       }
  880.     }
  881.     if (singleStmt)
  882.       break;
  883.   }
  884.   do_disconnect(con);
  885.   return exit_code;
  886. }
  887. // vim: set sw=2 et: