subsql.cpp

来自「FastDb是高效的内存数据库系统」· C++ 代码 · 共 3,037 行 · 第 1/5 页

CPP
3,037
字号
      default:
        error("Expecting 'table', 'hash' or 'index' keyword");
        continue;
      }

      break;

    case tkn_alter:

      if (!opened)
      {
        error("Database not opened");
        continue;
      }

      if (accessType == dbReadOnly)
      {
        error("Operation is not possible in read-only mode");
        continue;
      }

      if (monitor->users != 1)
      {
        error("Can not perform operation with active appliations\n");
        continue;
      }

      switch (scan())
      {

      case tkn_table:
        updateTable(false);
        break;

      default:
        error("Expecting 'table' keyword");
        continue;
      }

      break;

    case tkn_insert:

      if (!opened)
      {
        error("Database not opened");
        continue;
      }

      if (accessType == dbReadOnly)
      {
        error("Operation is not possible in read-only mode");
        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(dbExclusiveLock);
        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");
          }
        }
      }

      break;

    case tkn_delete:

      if (!opened)
      {
        error("Database not opened");
        continue;
      }

      if (accessType == dbReadOnly)
      {
        error("Operation is not possible in read-only mode");
        continue;
      }

      if (expect("FROM", tkn_from) && expect("table name", tkn_ident))
      {
        if ((desc = findTable(name)) == NULL)
        {
          error("No such table in database");
          continue;
        }

        dbAnyCursor cursor(*desc, dbCursorForUpdate, NULL);
        dbDatabaseThreadContext* ctx = threadContext.get();
        ctx->interactive = true;
        ctx->catched = true;

#ifdef THROW_EXCEPTION_ON_ERROR

        try
        {
#else

        if (setjmp(ctx->unwind) == 0)
        {
#endif

          if (readCondition())
          {
            query = (char const*)buf;
            cursor.reset();
            select(&cursor, query);

            if (!query.compiled())
            {
              dbExprNodeAllocator::instance.reset();
              ctx->catched = false;
              continue;
            }
          }
          else
          {
            ctx->catched = false;
            continue;
          }

          int n_deleted = cursor.getNumberOfRecords();
          cursor.removeAllSelected();
          printf("\n\t%d records deleted\n", n_deleted);
#ifdef THROW_EXCEPTION_ON_ERROR

        }
        catch(dbException const&)
        {}

#else

        }
        else
        {
          if (query.mutexLocked)
          {
            query.mutexLocked = false;
            query.mutex.unlock();
          }
        }

#endif
        ctx->catched = false;
      }

      break;

    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("FastDB   version  :  %d.%02d\n"
               "Database version  :  %d.%02d\n"
               "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",
               FASTDB_MAJOR_VERSION, FASTDB_MINOR_VERSION,
               header->majorVersion, header->minorVersion,
               (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        InverseFieldName\n");
        printf("----------------------------------------------------------------------------\n");
        dbFieldDescriptor* fd = desc->columns;

        for (int i = desc->nColumns; --i >= 0;)
        {
          printf("%6d   %-16s %-16s %-16s %s\n",
                 fd->fieldNo,
                 typeMnem[fd->type],
                 fd->refTableName != NULL
                 ? fd->refTableName
                 : (fd->type == dbField::tpArray && fd->components->refTableName != NULL)
                 ? fd->components->refTableName
                 : "(null)",
                 fd->name,
                 (fd->inverseRefName != NULL ? fd->inverseRefName : "(null)"));
          fd = fd->next;
        }
      }

      continue;

    case tkn_export:

      if (!opened)
      {
        error("Database not opened");
        continue;
      }

      if (expect("xml file name", tkn_sconst))
      {
        FILE* f;

        if (strcmp(buf, "-") == 0)
        {
          f = stdout;
        }
        else
        {
          f = fopen(buf, "w");
        }

        if (f != NULL)
        {
          exportDatabase(f);
          fclose(f);
        }
        else
        {
          error("Failed to open output file");
        }
      }

      continue;

    case tkn_import:

      if (!opened)
      {
        error("Database not opened");
        continue;
      }

      if (accessType == dbReadOnly)
      {
        error("Operation is not possible in read-only mode");
        continue;
      }

      if (expect("xml file name", tkn_sconst))
      {
        FILE* f;

        if (strcmp(buf, "-") == 0)
        {
          f = stdin;
        }
        else
        {
          f = fopen(buf, "r");
        }

        if (f != NULL)
        {
          if (!importDatabase(f))
          {
            error("Import from XML file failed: incorrect file format");
          }

          fclose(f);
        }
        else
        {
          error("Failed to open input file");
        }
      }

      break;

    case tkn_autocommit:

      switch (scan())
      {

      case tkn_on:
        autocommit = true;
        break;

      case tkn_off:
        autocommit = false;
        break;

      default:
        error("ON or OFF expected");
      }

      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\
              create table <table-name> '('<field-name> <field-type> {',' <field-name> <field-type>}')' ';' \n\
              alter table <table-name> '('<field-name> <field-type> {',' <field-name> <field-type>}')' ';' \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\
              start http server URL\n\
              stop http server\n\
              describe <table-name>\n\
              import 'xml-file-name'\n\
              export 'xml-file-name'\n\
              show\n\
              commit\n\
              rollback\n\
              autocommit (on|off)\n\
              exit\n\
              help\n\n");
      continue;

    case tkn_start:

      if (!opened)
      {
        error("Database not opened");
      }
      else
      {
        commit(); // allow server threads to process
        existedTables = tables;
        tkn = scan();

        if (tkn == tkn_http)
        {
          if (expect("server", tkn_server)
              && expect("HTTP server URL", tkn_sconst))
          {
#if !THREADS_SUPPORTED
            error("Database was build without pthread support");
#else

            startHttpServer(buf);
#endif

          }
        }
        else if (tkn == 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

        }
        else
        {
          error("Token 'server' expected");
        }
      }

      continue;

    case tkn_stop:
      tkn = scan();

      if (tkn == tkn_http)
      {
        if (expect("server", tkn_server) && expect("HTTP server URL", tkn_sconst))
        {
#if !THREADS_SUPPORTED
          error("Database was build without pthread support");
#else

          stopHttpServer(buf);
#endif

        }
      }
      else if (tkn == tkn_server)
      {
        if (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

        }
      }
      else
      {
        error("Token 'server' expected");
      }

      continue;

    case tkn_semi:
      putchar('\n');
      // no break

    case tkn_error:
      continue;

    case tkn_exit:
      return false;

    case tkn_version:
      printf("FastDB version %d.%02d\n", FASTDB_MAJOR_VERSION, FASTDB_MINOR_VERSION);
      continue;

    case tkn_eof:
      return true;

    default:
      error("Unexpected token");
      continue;
    }

    if (autocommit)
    {
      commit();
    }
  }
}



void exportString(FILE* out, char* src, int len)
{
  fprintf(out, "\"");

  while (--len > 0)
  {
    byte b = (byte)*src++;

    switch (b)
    {

    case '&':
      fprintf(out, "&

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?