subsql.cpp

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

CPP
3,037
字号
            {
              error("Field can not be updated");
              goto updateCleanup;
            }

            elem->field = fd;
            elem->next = elems;
            elems = elem;

            if (!expect("=", tkn_eq))
            {
              goto updateCleanup;
            }

            startPos = pos;
            int ch = readExpression();

            if (ch == EOF)
            {
              error("unexpected end of input");
              goto updateCleanup;
            }

            condition = strstr(buf, "where");

            if (condition != NULL)
            {
              *condition = '\0';
            }

            dbExprNode* expr = ctx->compiler.compileExpression(desc, buf, startPos);

            if (expr == NULL)
            {
              goto updateCleanup;
            }

            if (expr->type > tpString)
            {
              error("Invalid expression type");
              goto updateCleanup;
            }

            elem->value = expr;

            if (condition == NULL && ch == ',')
            {
              if (!expect("field name", tkn_ident))
              {
                goto updateCleanup;
              }
            }
            else
            {
              break;
            }
          }

          dbAnyCursor cursor(*desc, dbCursorForUpdate, record);
          cursor.reset();

          if (condition != NULL)
          {
            query.pos = startPos + (condition - buf) + 5;
            query = (char const*)(condition + 5);
            select(&cursor, query);

            if (!query.compiled())
            {
              goto updateCleanup;
            }
          }
          else
          {
            select(&cursor);
          }

          if (cursor.gotoFirst())
          {
            do
            {
              cursor.fetch();

              if (!updateFields(&cursor, elems))
              {
                goto updateCleanup;
              }

              cursor.update();
            }
            while (cursor.gotoNext());
          }

          printf("\n\t%d records updated\n", cursor.getNumberOfRecords());
#ifdef THROW_EXCEPTION_ON_ERROR

        }
        catch(dbException const&)
        {}

#else

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

#endif

updateCleanup:
        query.reset();

        while (elems != NULL)
        {
          dbUpdateElement* elem = elems;
          elems = elems->next;
          delete elem;
        }

        if (autocommit || !modified)
        {
          commit(); // release locks
        }

        dbExprNodeAllocator::instance.reset();
        ctx->catched = false;
        dbFree(record);
      }

      continue;

    case tkn_select:

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

      outputOid = true;
      count = false;

      if ((tkn = scan()) == tkn_all)
      {
        outputOid = false;
        tkn = scan();
      }
      else if (tkn == tkn_count)
      {
        if (!expect("'('", tkn_lpar)
            || !expect("'*'", tkn_all)
            || !expect("')'", tkn_rpar))
        {
          continue;
        }

        count = true;
        tkn = scan();
      }

      if (tkn != tkn_from)
      {
        error("'from' keyword expected");
        continue;
      }

      if (scan() != tkn_ident)
      {
        error("Table name expected");
        continue;
      }

      if ((desc = findTable(name)) != NULL)
      {
        dbAnyCursor cursor(*desc, dbCursorViewOnly, NULL);
        query.pos = pos;
        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;
          }

          if (count)
          {
            printf("%d records selected\n",
                   cursor.getNumberOfRecords());
          }
          else
          {
            if (cursor.gotoFirst())
            {
              dbFieldDescriptor* fd = desc->columns;

              do
              {
                printf("%s ", fd->name);
              }
              while ((fd = fd->next) != desc->columns);

              if (outputOid)
              {
                printf("\n#%x: (", cursor.currId);
              }
              else
              {
                printf("\n(");
              }

              dumpRecord((byte*)getRow(cursor.currId),
                         cursor.table->columns);
              printf(")");

              while (cursor.gotoNext())
              {
                if (outputOid)
                {
                  printf(",\n#%x: (", cursor.currId);
                }
                else
                {
                  printf(",\n(");
                }

                dumpRecord((byte*)getRow(cursor.currId),
                           cursor.table->columns);
                printf(")");
              }

              printf("\n\t%d records selected\n",
                     cursor.getNumberOfRecords());
            }
            else
            {
              fprintf(stderr, "No records selected\n");
            }
          }

#ifdef THROW_EXCEPTION_ON_ERROR

        }
        catch(dbException const&)
        {}

#else

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

#endif
        ctx->catched = false;

        if (!modified || autocommit)
        {
          commit(); // release locks
        }
      }
      else
      {
        error("No such table in database");
      }

      continue;

    case tkn_open:

      if (expect("database name", tkn_sconst))
      {
        char* databaseName = new char[strlen(buf)+1];
        strcpy(databaseName, buf);
        char* fileName = NULL;

        if ((tkn = scan()) == tkn_sconst)
        {
          fileName = buf;
        }
        else if (tkn != tkn_semi)
        {
          delete[] databaseName;
          error("database file name expected");
          continue;
        }

        if (opened)
        {
          close();

          while (droppedTables != NULL)
          {
            dbTableDescriptor* next = droppedTables->nextDbTable;
            delete droppedTables;
            droppedTables = next;
          }

          opened = false;
          dbTableDescriptor::cleanup();
        }

        time_t transactionCommitDelay = 0;
        char* delay = getenv("FASTDB_COMMIT_DELAY");

        if (delay != NULL)
        {
          transactionCommitDelay = atoi(delay);
        }

        if (!open(databaseName, fileName, INFINITE, transactionCommitDelay))
        {
          fprintf(stderr, "Database not opened\n");
        }
        else
        {
          opened = true;
          dbTable* table = (dbTable*)getRow(dbMetaTableId);
          dbTableDescriptor* desc = new dbTableDescriptor(table);
          linkTable(desc, dbMetaTableId);
          oid_t tableId = table->firstRow;

          while (tableId != 0)
          {
            table = (dbTable*)getRow(tableId);

            for (desc = tables; desc != NULL && desc->tableId != tableId; desc = desc->nextDbTable)

              ;
            if (desc == NULL)
            {
              dbTableDescriptor* desc = new dbTableDescriptor(table);
              linkTable(desc, tableId);
              desc->setFlags();
            }

            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;
      }

      break;

    case tkn_drop:

      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");
        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;
          }
        }

        break;

      case tkn_hash:
        fd = readFieldName();

        if (fd != NULL)
        {
          if (fd->hashTable == 0)
          {
            error("This field is not hashed");
          }
          else
          {
            dropHashTable(fd);
          }
        }

        break;

      case tkn_index:
        fd = readFieldName();

        if (fd != NULL)
        {
          if (fd->tTree == 0)
          {
            error("There is no index for this field");
          }
          else
          {
            dropIndex(fd);
          }
        }

        break;

      default:
        error("Expecting 'table', 'hash' or 'index' keyword");
        continue;
      }

      break;

    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 (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_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);
          }
        }

        break;

      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);
          }
        }

        break;

      case tkn_table:
        updateTable(true);
        break;

⌨️ 快捷键说明

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