📄 subsql.cpp
字号:
}
tableId = table->next;
}
existedTables = tables;
if (!completeDescriptorsInitialization()) {
error("Reference to undefined table");
}
char* backupName = getenv("FASTDB_BACKUP_NAME");
if (backupName != NULL) {
char* backupPeriod = getenv("FASTDB_BACKUP_PERIOD");
time_t period = 60*60*24; // one day
if (backupPeriod != NULL) {
period = atoi(backupPeriod);
}
printf("Schedule backup to file %s each %u seconds\n",
backupName, (unsigned)period);
scheduleBackup(backupName, period);
}
}
delete[] databaseName;
}
continue;
case tkn_drop:
if (!opened) {
error("Database not opened");
continue;
}
if (monitor->users != 1) {
error("Can not perform operation with active appliations");
continue;
}
switch (scan()) {
case tkn_table:
if (expect("table name", tkn_ident)) {
desc = findTable(name);
if (desc == NULL) {
error("No such table in database");
} else {
dropTable(desc);
if (desc == existedTables) {
existedTables = desc->nextDbTable;
}
unlinkTable(desc);
desc->nextDbTable = droppedTables;
droppedTables = desc;
}
}
continue;
case tkn_hash:
fd = readFieldName();
if (fd != NULL) {
if (fd->hashTable == 0) {
error("This field is not hashed");
} else {
dropHashTable(fd);
}
}
continue;
case tkn_index:
fd = readFieldName();
if (fd != NULL) {
if (fd->tTree == 0) {
error("There is no index for this field");
} else {
dropIndex(fd);
}
}
continue;
default:
error("Expecting 'table', 'hash' or 'index' keyword");
}
continue;
case tkn_backup:
if (!opened) {
error("Database not opened");
continue;
}
compactify = false;
if ((tkn = scan()) == tkn_compactify) {
compactify = true;
tkn = scan();
}
if (tkn != tkn_sconst) {
error("Backup file name expected");
} else {
if (!backup(buf, compactify)) {
printf("Backup failed\n");
} else {
while (droppedTables != NULL) {
dbTableDescriptor* next = droppedTables->nextDbTable;
delete droppedTables;
droppedTables = next;
}
commit();
existedTables = tables;
}
}
continue;
case tkn_create:
if (!opened) {
error("Database not opened");
continue;
}
if (monitor->users != 1) {
error("Can not perform operation with active appliations\n");
continue;
}
switch (scan()) {
case tkn_hash:
if (!expect("on", tkn_on)) {
continue;
}
fd = readFieldName();
if (fd != NULL) {
if (fd->hashTable != 0) {
error("This field is already hashed");
} else {
createHashTable(fd);
}
}
continue;
case tkn_index:
if (!expect("on", tkn_on)) {
continue;
}
fd = readFieldName();
if (fd != NULL) {
if (fd->tTree != 0) {
error("Index already exists");
} else {
createIndex(fd);
}
}
continue;
case tkn_table:
createTable();
continue;
default:
error("Expecting 'table', 'hash' or 'index' keyword");
}
continue;
case tkn_insert:
if (!opened) {
error("Database not opened");
continue;
}
if (expect("into", tkn_into) && expect("table name", tkn_ident)) {
if ((desc = findTable(name)) == NULL) {
error("No such table in database");
continue;
}
if (!expect("values", tkn_values)) {
continue;
}
beginTransaction(true);
modified = true;
while (expect("(", tkn_lpar)) {
dbList* list = NULL;
int n = readValues(&list);
if (n <= 0 || !insertRecord(list, desc)) {
if (n == 0) {
error("Empty fields list");
}
tkn = tkn_semi; // just avoid extra error messages
} else {
tkn = scan();
}
while (list != NULL) {
dbList* tail = list->next;
delete list;
list = tail;
}
if (tkn == tkn_semi) {
break;
} else if (tkn != tkn_comma) {
error("';' or ',' expected");
}
}
}
continue;
case tkn_delete:
if (!opened) {
error("Database not opened");
continue;
}
if (expect("FROM", tkn_from) && expect("table name", tkn_ident)) {
if ((desc = findTable(name)) == NULL) {
error("No such table in database");
} else {
deleteTable(desc);
}
}
continue;
case tkn_commit:
if (!opened) {
error("Database not opened");
} else {
while (droppedTables != NULL) {
dbTableDescriptor* next = droppedTables->nextDbTable;
delete droppedTables;
droppedTables = next;
}
commit();
existedTables = tables;
}
continue;
case tkn_rollback:
if (!opened) {
error("Database not opened");
} else {
while (droppedTables != NULL) {
dbTableDescriptor* next = droppedTables->nextDbTable;
linkTable(droppedTables, droppedTables->tableId);
droppedTables = next;
}
rollback();
while (tables != existedTables) {
dbTableDescriptor* table = tables;
unlinkTable(table);
delete table;
}
}
continue;
case tkn_show:
if (!opened) {
error("Database not opened");
} else {
printf("Database file size: %lu Kb\n"
"Object index size : %lu handles\n"
"Used part of index: %lu handles\n"
"Number of users : %d\n"
"Number of readers : %d\n"
"Number of writers : %d\n"
"Number of blocked readers : %d\n"
"Number of blocked writers : %d\n",
(unsigned long)(header->size/1024),
(unsigned long)header->root[1-header->curr].indexSize,
(unsigned long)header->root[1-header->curr].indexUsed,
monitor->users,
monitor->nReaders,
monitor->nWriters,
monitor->nWaitReaders,
monitor->nWaitWriters + monitor->waitForUpgrade);
printf("\nTABLES:\n");
printf("OID FixedSize Fields Columns TableName\n");
printf("---------------------------------------------------------\n");
for (dbTableDescriptor* desc=tables; desc != NULL; desc=desc->nextDbTable)
{
printf("0x%06x %8d %8d %8d %s\n",
desc->tableId, desc->fixedSize,
desc->nFields, desc->nColumns, desc->name);
}
}
continue;
case tkn_describe:
if (!opened) {
error("Database not opened");
continue;
}
if (expect("table name", tkn_ident)) {
if ((desc = findTable(name)) == NULL) {
error("No such table in database");
continue;
}
printf("\nOID=0x%06x, TableName=%s\n",desc->tableId, desc->name);
printf("FieldNo FieldType RefTableName FieldName\n");
printf("----------------------------------------------------\n");
dbFieldDescriptor* fd = desc->columns;
for (int i = desc->nColumns; --i >= 0;) {
printf("%6d %-16s %-16s %s\n", fd->fieldNo,
typeMnem[fd->type],
fd->refTableName ? fd->refTableName : "(null)",
fd->name);
fd = fd->next;
}
}
continue;
case tkn_help:
fprintf(stderr, "SubSQL commands:\n\n\
open 'database-name' ( 'database-file-name' ) ';'\n\
select ('*') from <table-name> where <condition> ';'\n\
update <table-name> set <field-name> '=' <expression> {',' <field-name> '=' <expression>} where <condition> ';'\n\
delete from <table-name>\n\
drop table <table-name>\n\
drop index <table-name> {'.' <field-name>} ';'\n\
create index on <table-name> {'.' <field-name>} ';'\n\
drop hash <table-name> {'.' <field-name>};\n\
create hash on <table-name> {'.' <field-name>}field> ';'\n\
insert into <table-name> values '(' <value>{',' <value>} ')' ';'\n\
backup [compactify] 'file-name'\n\
start server URL number-of-threads\n\
stop server URL\n\
describe <table-name>\n\
show\n\
commit\n\
rollback\n\
exit\n\
help\n\n");
continue;
case tkn_start:
if (!opened) {
error("Database not opened");
} else {
commit(); // allow server therads to process
existedTables = tables;
if (expect("server", tkn_server)
&& expect("server URL", tkn_sconst))
{
#if !THREADS_SUPPORTED
error("Database was build without pthread support");
#else
dbServer* server = dbServer::find(buf);
if (server == NULL) {
char* serverURL = new char[strlen(buf)+1];
strcpy(serverURL, buf);
if (expect("number of threads", tkn_iconst)) {
server = new dbServer(this, serverURL, (int)ival);
printf("Server started for URL %s\n", serverURL);
}
delete[] serverURL;
}
if (server != NULL) {
server->start();
}
#endif
}
}
continue;
case tkn_stop:
if (expect("server", tkn_server)
&& expect("server URL", tkn_sconst))
{
#if !THREADS_SUPPORTED
error("Database was build without pthread support");
#else
dbServer* server = dbServer::find(buf);
if (server != NULL) {
server->stop();
printf("Server stopped for URL %s\n", buf);
} else {
fprintf(stderr, "No server was started for URL %s\n", buf);
}
#endif
}
continue;
case tkn_semi:
putchar('\n');
// no break
case tkn_error:
continue;
case tkn_exit:
return false;
case tkn_eof:
return true;
default:
error("Unexpected token");
}
}
}
void dbSubSql::handleError(dbErrorClass error, char const* msg, int arg)
{
dbDatabaseThreadContext* ctx = threadContext.get();
if (ctx == NULL || ctx->interactive) {
const int screenWidth = 80;
int col;
switch (error) {
case QueryError:
col = arg % screenWidth;
if (in == stdin) {
while (--col >= 0) putc('-', stderr);
fprintf(stderr, "^\n%s\n", msg);
} else {
fprintf(stderr, "%s at line %d position %d\n", msg, line, arg);
}
break;
case ArithmeticError:
fprintf(stderr, "%s\n", msg);
break;
case IndexOutOfRangeError:
fprintf(stderr, "Index %d is out of range\n", arg);
break;
case NullReferenceError:
fprintf(stderr, "Null object reference is accessed\n");
break;
default:
dbDatabase::handleError(error, msg, arg);
}
//
// Recovery
//
if (in == stdin) {
int ch;
while ((ch = get()) != '\n' && ch != EOF);
} else {
fseek(in, 0, SEEK_END);
}
}
#ifdef THROW_EXCEPTION_ON_ERROR
throw dbException(error, msg, arg);
#else
if (ctx != NULL) {
if (ctx->catched) {
longjmp(ctx->unwind, error);
} else {
abort();
}
}
#endif
}
void dbSubSql::run(int argc, char* argv[])
{
for (int i = 1; i < argc; i++) {
in = fopen(argv[i], "r");
if (in == NULL) {
fprintf(stderr, "Failed to open '%s' file\n", argv[i]);
} else {
if (!parse()) {
if (opened) {
close();
}
#if THREADS_SUPPORTED
dbServer::cleanup();
#endif
return;
}
}
}
in = stdin;
parse();
if (opened) {
close();
}
#if THREADS_SUPPORTED
dbServer::cleanup();
#endif
}
int main(int argc, char* argv[])
{
printf("SubSQL interactive utility for FastDB\n"
"Type 'help' for more information\n");
dbSubSql db;
db.run(argc, argv);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -