refactor tests to use the microtest framework
This commit is contained in:
parent
2890cd368e
commit
681fbe42d2
14
Makefile
14
Makefile
|
@ -7,18 +7,18 @@ SRCPARSER = src/parser
|
||||||
PARSERFILES = $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp
|
PARSERFILES = $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp
|
||||||
LIBCPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp
|
LIBCPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp
|
||||||
LIBOBJ = $(LIBCPP:%.cpp=%.o)
|
LIBOBJ = $(LIBCPP:%.cpp=%.o)
|
||||||
TESTCPP = $(shell find test/lib/ -name '*.cpp')
|
TESTCPP = $(shell find test/ -name '*.cpp')
|
||||||
|
|
||||||
ALLLIB = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*")
|
ALLLIB = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*")
|
||||||
ALLTEST = $(shell find test/lib/ -name '*.cpp') $(shell find test/lib/ -name '*.h')
|
ALLTEST = $(shell find test/lib/ -name '*.cpp') $(shell find test/lib/ -name '*.h')
|
||||||
|
|
||||||
# compile & link flages
|
# compile & link flages
|
||||||
CFLAGS = -std=c++11 -Wall -fPIC
|
CFLAGS = -std=c++11 -Wall -fPIC -g
|
||||||
LIBFLAGS = -shared
|
LIBFLAGS = -shared
|
||||||
TARGET = libsqlparser.so
|
TARGET = libsqlparser.so
|
||||||
INSTALL = /usr/local
|
INSTALL = /usr/local
|
||||||
|
|
||||||
CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11 -lstdc++
|
CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11 -lstdc++ -g
|
||||||
|
|
||||||
all: library
|
all: library
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ format:
|
||||||
### Test ###
|
### Test ###
|
||||||
############
|
############
|
||||||
|
|
||||||
test: $(BIN)/sql_tests $(BIN)/sql_grammar_test
|
test: $(BIN)/sql_tests
|
||||||
bash test/test.sh
|
bash test/test.sh
|
||||||
|
|
||||||
# test whete
|
# test whete
|
||||||
|
@ -68,8 +68,4 @@ test_install:
|
||||||
|
|
||||||
$(BIN)/sql_tests: library
|
$(BIN)/sql_tests: library
|
||||||
@mkdir -p $(BIN)/
|
@mkdir -p $(BIN)/
|
||||||
$(CXX) $(CTESTFLAGS) $(TESTCPP) test/sql_tests.cpp -o $(BIN)/sql_tests -lsqlparser
|
$(CXX) $(CTESTFLAGS) $(TESTCPP) -o $(BIN)/sql_tests -lsqlparser
|
||||||
|
|
||||||
$(BIN)/sql_grammar_test: library
|
|
||||||
@mkdir -p $(BIN)/
|
|
||||||
$(CXX) $(CTESTFLAGS) test/sql_grammar_test.cpp -o $(BIN)/sql_grammar_test -lsqlparser
|
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
|
|
||||||
#include "test.h"
|
|
||||||
|
|
||||||
|
|
||||||
class TestsManager {
|
|
||||||
// Note: static initialization fiasco
|
|
||||||
// http://www.parashift.com/c++-faq-lite/static-init-order.html
|
|
||||||
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
|
|
||||||
public:
|
|
||||||
static std::vector<std::string>& testNames() {
|
|
||||||
static std::vector<std::string> testNames;
|
|
||||||
return testNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<void (*)(void)>& tests() {
|
|
||||||
static std::vector<void (*)(void)> tests;
|
|
||||||
return tests;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AddTest(void (*foo)(void), std::string name) {
|
|
||||||
TestsManager::tests().push_back(foo);
|
|
||||||
TestsManager::testNames().push_back(name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
size_t RunTests() {
|
|
||||||
size_t numFailed = 0;
|
|
||||||
for (size_t i = 0; i < TestsManager::tests().size(); ++i) {
|
|
||||||
printf("\033[0;32m{ running}\033[0m %s\n", TestsManager::testNames()[i].c_str());
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Run test
|
|
||||||
(*TestsManager::tests()[i])();
|
|
||||||
printf("\033[0;32m{ ok}\033[0m %s\n", TestsManager::testNames()[i].c_str());
|
|
||||||
|
|
||||||
} catch (AssertionFailedException& e) {
|
|
||||||
printf("\033[1;31m{ failed} %s\n", TestsManager::testNames()[i].c_str());
|
|
||||||
printf("\tAssertion failed: %s\n\033[0m", e.what());
|
|
||||||
numFailed++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return numFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
size_t numFailed = RunTests();
|
|
||||||
if (numFailed == 0) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
#ifndef __TEST_H__
|
|
||||||
#define __TEST_H__
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
|
||||||
#define TEST(name) \
|
|
||||||
void name();\
|
|
||||||
namespace g_dummy {\
|
|
||||||
int _##name = AddTest(name, #name);\
|
|
||||||
}\
|
|
||||||
void name()
|
|
||||||
|
|
||||||
|
|
||||||
#define ASSERT(cond) if (!(cond)) throw AssertionFailedException(#cond);
|
|
||||||
|
|
||||||
#define ASSERT_TRUE(cond) ASSERT(cond);
|
|
||||||
#define ASSERT_FALSE(cond) if (cond) throw AssertionFailedException(#cond);
|
|
||||||
|
|
||||||
#define ASSERT_NULL(value) ASSERT_TRUE(value == NULL);
|
|
||||||
#define ASSERT_NOTNULL(value) ASSERT_TRUE(value != NULL);
|
|
||||||
|
|
||||||
#define ASSERT_STREQ(a, b) \
|
|
||||||
if (std::string(a).compare(std::string(b)) != 0) throw AssertionFailedException(#a " == " #b)
|
|
||||||
#define ASSERT_EQ(a, b) \
|
|
||||||
if (a != b) { \
|
|
||||||
std::cout << "Actual values: " << a << " != " << b << std::endl; \
|
|
||||||
} \
|
|
||||||
ASSERT(a == b);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AssertionFailedException: public std::exception {
|
|
||||||
public:
|
|
||||||
AssertionFailedException(std::string msg) :
|
|
||||||
std::exception(),
|
|
||||||
_msg(msg) {};
|
|
||||||
|
|
||||||
virtual const char* what() const throw() {
|
|
||||||
return _msg.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::string _msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
int AddTest(void (*foo)(void), std::string name);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "test.h"
|
#include "thirdparty/microtest/microtest.h"
|
||||||
#include "helper.h"
|
#include "sql_asserts.h"
|
||||||
#include "SQLParser.h"
|
#include "SQLParser.h"
|
||||||
|
|
||||||
using namespace hsql;
|
using namespace hsql;
|
|
@ -5,6 +5,8 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "thirdparty/microtest/microtest.h"
|
||||||
#include "SQLParser.h"
|
#include "SQLParser.h"
|
||||||
|
|
||||||
using namespace hsql;
|
using namespace hsql;
|
||||||
|
@ -30,10 +32,11 @@ std::vector<std::string> readlines(std::string path) {
|
||||||
|
|
||||||
#define STREQ(a, b) (std::string(a).compare(std::string(b)) == 0)
|
#define STREQ(a, b) (std::string(a).compare(std::string(b)) == 0)
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
TEST(AutoGrammarTest) {
|
||||||
if (argc <= 1) {
|
const std::vector<std::string>& args = mt::Runtime::args();
|
||||||
|
if (args.size() <= 1) {
|
||||||
fprintf(stderr, "Usage: grammar_test [--false] [-f path] query, ...\n");
|
fprintf(stderr, "Usage: grammar_test [--false] [-f path] query, ...\n");
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool globalExpectFalse = false;
|
bool globalExpectFalse = false;
|
||||||
|
@ -41,12 +44,12 @@ int main(int argc, char *argv[]) {
|
||||||
std::string filePath = "";
|
std::string filePath = "";
|
||||||
|
|
||||||
// Parse command line arguments
|
// Parse command line arguments
|
||||||
int i = 1;
|
uint i = 1;
|
||||||
for (; i < argc; ++i) {
|
for (; i < args.size(); ++i) {
|
||||||
if (STREQ(argv[i], "--false")) globalExpectFalse = true;
|
if (STREQ(args[i], "--false")) globalExpectFalse = true;
|
||||||
else if (STREQ(argv[i], "-f")) {
|
else if (STREQ(args[i], "-f")) {
|
||||||
useFile = true;
|
useFile = true;
|
||||||
filePath = argv[++i];
|
filePath = args[++i];
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +61,7 @@ int main(int argc, char *argv[]) {
|
||||||
if (useFile) {
|
if (useFile) {
|
||||||
queries = readlines(filePath);
|
queries = readlines(filePath);
|
||||||
} else {
|
} else {
|
||||||
for (; i < argc; ++i) queries.push_back(argv[i]);
|
for (; i < args.size(); ++i) queries.push_back(args[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,9 +100,9 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
if (numFailed == 0) {
|
if (numFailed == 0) {
|
||||||
printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size());
|
printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size());
|
||||||
return 0;
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", numFailed, queries.size());
|
fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", numFailed, queries.size());
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
ASSERT_EQ(numFailed, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
* sql_tests.cpp
|
* sql_tests.cpp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/test.h"
|
#include "thirdparty/microtest/microtest.h"
|
||||||
#include "lib/helper.h"
|
#include "sql_asserts.h"
|
||||||
#include "SQLParser.h"
|
#include "SQLParser.h"
|
||||||
#include "sqlhelper.h"
|
#include "sqlhelper.h"
|
||||||
|
|
||||||
|
@ -166,3 +166,5 @@ TEST(ExecuteStatementTest) {
|
||||||
|
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_MAIN();
|
21
test/test.sh
21
test/test.sh
|
@ -6,23 +6,16 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
|
||||||
|
|
||||||
RET=0
|
RET=0
|
||||||
|
|
||||||
# Running the tests.
|
bin/sql_tests -f "test/valid_queries.sql"
|
||||||
bin/sql_grammar_test -f "test/lib/valid_queries.sql"
|
RET=$?
|
||||||
RET=$(($RET + $?))
|
|
||||||
|
|
||||||
bin/sql_tests
|
|
||||||
RET=$(($RET + $?))
|
|
||||||
|
|
||||||
|
if [ $RET -eq 0 ]; then
|
||||||
# Running memory leak checks.
|
# Running memory leak checks.
|
||||||
echo ""
|
echo ""
|
||||||
echo "Running memory leak checks..."
|
echo "Running memory leak checks..."
|
||||||
|
valgrind --leak-check=full --error-exitcode=1 --log-fd=3 \
|
||||||
valgrind --leak-check=full --error-exitcode=1 \
|
./bin/sql_tests -f "test/valid_queries.sql" 3>&1 >/dev/null 2>/dev/null
|
||||||
./bin/sql_grammar_test -f "test/lib/valid_queries.sql" >> /dev/null
|
RET=$?
|
||||||
RET=$(($RET + $?))
|
fi
|
||||||
|
|
||||||
valgrind --leak-check=full --error-exitcode=1 \
|
|
||||||
./bin/sql_tests -f "test/lib/valid_queries.sql" >> /dev/null
|
|
||||||
RET=$(($RET + $?))
|
|
||||||
|
|
||||||
exit $RET
|
exit $RET
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
//
|
||||||
|
// microtest
|
||||||
|
//
|
||||||
|
// URL: https://github.com/torpedro/microtest
|
||||||
|
// Author: Pedro Flemming (http://torpedro.com/)
|
||||||
|
// License: MIT License (https://github.com/torpedro/microtest/blob/master/LICENSE)
|
||||||
|
// Copyright (c) 2017 Pedro Flemming
|
||||||
|
//
|
||||||
|
// This is a small header-only C++ unit testing framework.
|
||||||
|
// It allows to define small unit tests with set of assertions available.
|
||||||
|
//
|
||||||
|
#ifndef __MICROTEST_H__
|
||||||
|
#define __MICROTEST_H__
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// Assertions //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
#define ASSERT(cond)\
|
||||||
|
ASSERT_TRUE(cond);
|
||||||
|
|
||||||
|
#define ASSERT_TRUE(cond)\
|
||||||
|
if (!(cond)) throw mt::AssertFailedException(#cond, __FILE__, __LINE__);
|
||||||
|
|
||||||
|
#define ASSERT_FALSE(cond)\
|
||||||
|
if (cond) throw mt::AssertFailedException(#cond, __FILE__, __LINE__);
|
||||||
|
|
||||||
|
#define ASSERT_NULL(value)\
|
||||||
|
ASSERT_TRUE(value == NULL);
|
||||||
|
|
||||||
|
#define ASSERT_NOTNULL(value)\
|
||||||
|
ASSERT_TRUE(value != NULL);
|
||||||
|
|
||||||
|
#define ASSERT_STREQ(a, b)\
|
||||||
|
if (std::string(a).compare(std::string(b)) != 0)\
|
||||||
|
throw mt::AssertFailedException(#a " == " #b, __FILE__, __LINE__);
|
||||||
|
|
||||||
|
#define ASSERT_EQ(a, b)\
|
||||||
|
if (a != b) {\
|
||||||
|
printf("%s{ info} %s", mt::yellow(), mt::def());\
|
||||||
|
std::cout << "Actual values: " << a << " != " << b << std::endl;\
|
||||||
|
}\
|
||||||
|
ASSERT(a == b);
|
||||||
|
|
||||||
|
#define ASSERT_NEQ(a, b)\
|
||||||
|
if (a == b) {\
|
||||||
|
printf("%s{ info} %s", mt::yellow(), mt::def());\
|
||||||
|
std::cout << "Actual values: " << a << " == " << b << std::endl;\
|
||||||
|
}\
|
||||||
|
ASSERT(a != b);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// Unit Tests //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
#define TEST(name) \
|
||||||
|
void name();\
|
||||||
|
namespace {\
|
||||||
|
bool __##name = mt::TestsManager::AddTest(name, #name);\
|
||||||
|
}\
|
||||||
|
void name()
|
||||||
|
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
// Framework //
|
||||||
|
///////////////
|
||||||
|
|
||||||
|
namespace mt {
|
||||||
|
|
||||||
|
inline const char* red() {
|
||||||
|
return "\033[1;31m";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* green() {
|
||||||
|
return "\033[0;32m";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* yellow() {
|
||||||
|
return "\033[0;33m";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* def() {
|
||||||
|
return "\033[0m";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void printRunning(const char* message, FILE* file = stdout) {
|
||||||
|
fprintf(file, "%s{ running}%s %s\n", green(), def(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void printOk(const char* message, FILE* file = stdout) {
|
||||||
|
fprintf(file, "%s{ ok}%s %s\n", green(), def(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void printFailed(const char* message, FILE* file = stdout) {
|
||||||
|
fprintf(file, "%s{ failed} %s%s\n", red(), message, def());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exception that is thrown when an assertion fails.
|
||||||
|
class AssertFailedException : public std::exception {
|
||||||
|
public:
|
||||||
|
AssertFailedException(std::string description, std::string filepath, int line) :
|
||||||
|
std::exception(),
|
||||||
|
description_(description),
|
||||||
|
filepath_(filepath),
|
||||||
|
line_(line) {};
|
||||||
|
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return description_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* getFilepath() {
|
||||||
|
return filepath_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int getLine() {
|
||||||
|
return line_;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string description_;
|
||||||
|
std::string filepath_;
|
||||||
|
int line_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestsManager {
|
||||||
|
// Note: static initialization fiasco
|
||||||
|
// http://www.parashift.com/c++-faq-lite/static-init-order.html
|
||||||
|
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
|
||||||
|
public:
|
||||||
|
struct Test {
|
||||||
|
const char* name;
|
||||||
|
void (*fn)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<Test>& tests() {
|
||||||
|
static std::vector<Test> tests_;
|
||||||
|
return tests_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a new test to the current set of tests.
|
||||||
|
// Returns false if a test with the same name already exists.
|
||||||
|
inline static bool AddTest(void (*fn)(void), const char* name) {
|
||||||
|
tests().push_back({ name, fn });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run all tests that are registered.
|
||||||
|
// Returns the number of tests that failed.
|
||||||
|
inline static size_t RunAllTests(FILE* file = stdout) {
|
||||||
|
size_t num_failed = 0;
|
||||||
|
|
||||||
|
for (const Test& test : tests()) {
|
||||||
|
// Run the test.
|
||||||
|
// If an AsserFailedException is thrown, the test has failed.
|
||||||
|
try {
|
||||||
|
printRunning(test.name, file);
|
||||||
|
|
||||||
|
(*test.fn)();
|
||||||
|
|
||||||
|
printOk(test.name, file);
|
||||||
|
|
||||||
|
} catch (AssertFailedException& e) {
|
||||||
|
printFailed(test.name, file);
|
||||||
|
fprintf(file, " %sAssertion failed: %s%s\n",
|
||||||
|
red(), e.what(), def());
|
||||||
|
fprintf(file, " %s%s:%d%s\n",
|
||||||
|
red(), e.getFilepath(), e.getLine(), def());
|
||||||
|
++num_failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_failed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class that will capture the arguments passed to the program.
|
||||||
|
class Runtime {
|
||||||
|
public:
|
||||||
|
static const std::vector<std::string>& args(int argc = -1, char** argv = NULL) {
|
||||||
|
static std::vector<std::string> args_;
|
||||||
|
if (argc >= 0) {
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
args_.push_back(argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define TEST_MAIN() \
|
||||||
|
int main(int argc, char *argv[]) {\
|
||||||
|
mt::Runtime::args(argc, argv);\
|
||||||
|
\
|
||||||
|
size_t num_failed = mt::TestsManager::RunAllTests(stdout);\
|
||||||
|
if (num_failed == 0) {\
|
||||||
|
fprintf(stdout, "%s{ summary} All tests succeeded!%s\n", mt::green(), mt::def());\
|
||||||
|
return 0;\
|
||||||
|
} else {\
|
||||||
|
double percentage = 100.0 * num_failed / mt::TestsManager::tests().size();\
|
||||||
|
fprintf(stderr, "%s{ summary} %lu tests failed (%.2f%%)%s\n", mt::red(), num_failed, percentage, mt::def());\
|
||||||
|
return -1;\
|
||||||
|
}\
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __MICROTEST_H__
|
|
@ -44,3 +44,4 @@ DEALLOCATE PREPARE prep;
|
||||||
!SELECT abc;
|
!SELECT abc;
|
||||||
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';SELECT 1
|
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';SELECT 1
|
||||||
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';1
|
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';1
|
||||||
|
!INSERT INTO test_table VALUESd (1, 2, 'test');
|
Loading…
Reference in New Issue