예제 #1
0
 protected Column getColumn(Table catalog_tbl, int col_idx) {
   int num_columns = catalog_tbl.getColumns().size();
   if (col_idx < 0) col_idx = num_columns + col_idx; // Python!
   assert (col_idx >= 0 && col_idx < num_columns)
       : "Invalid column index for " + catalog_tbl + ": " + col_idx;
   Column catalog_col = catalog_tbl.getColumns().get(col_idx);
   assert (catalog_col != null)
       : "Failed to retrieve Column at '"
           + col_idx
           + "' from Table '"
           + catalog_tbl.getName()
           + "'";
   return (catalog_col);
 }
예제 #2
0
 @Override
 public String getColumnName(int columnIndex) {
   if (m_columns == null) {
     m_columns = CatalogUtil.getSortedCatalogItems(m_table.getColumns(), "index");
   }
   return m_columns.get(columnIndex).getTypeName();
 }
예제 #3
0
 public static MaterializedViewInfo addVerticalPartition(
     final Database catalog_db,
     final String tableName,
     final List<String> columnNames,
     final boolean createIndex)
     throws Exception {
   Table catalog_tbl = catalog_db.getTables().get(tableName);
   if (catalog_tbl == null) {
     throw new Exception("Invalid vertical partition table '" + tableName + "'");
   } else if (catalog_tbl.getIsreplicated()) {
     throw new Exception(
         "Cannot create vertical partition for replicated table '" + tableName + "'");
   }
   ArrayList<Column> catalog_cols = new ArrayList<Column>();
   for (String columnName : columnNames) {
     Column catalog_col = catalog_tbl.getColumns().get(columnName);
     if (catalog_col == null) {
       throw new Exception(
           "Invalid vertical partition column '" + columnName + "' for table '" + tableName + "'");
     } else if (catalog_cols.contains(catalog_col)) {
       throw new Exception(
           "Duplicate vertical partition column '"
               + columnName
               + "' for table '"
               + tableName
               + "'");
     }
     catalog_cols.add(catalog_col);
   } // FOR
   return (addVerticalPartition(catalog_tbl, catalog_cols, createIndex));
 }
예제 #4
0
 protected Column getColumn(Database catalog_db, Table catalog_tbl, String col_name) {
   assertNotNull(catalog_db);
   assertNotNull(catalog_tbl);
   Column catalog_col = catalog_tbl.getColumns().getIgnoreCase(col_name);
   assert (catalog_col != null)
       : "Failed to retrieve Column '" + col_name + "' from Table '" + catalog_tbl.getName() + "'";
   return (catalog_col);
 }
예제 #5
0
 @Override
 public void resolveForTable(Table table) {
   assert (table != null);
   // It MAY be that for the case in which this function is called (expression indexes), the
   // column's
   // table name is not specified (and not missed?).
   // It is possible to "correct" that here by cribbing it from the supplied table (base table for
   // the index)
   // -- not bothering for now.
   Column column = table.getColumns().getExact(m_columnName);
   assert (column != null);
   m_tableName = table.getTypeName();
   m_columnIndex = column.getIndex();
   setTypeSizeAndInBytes(column);
 }
예제 #6
0
  /**
   * Return the name of the vertical partition for the given table name
   *
   * @param tableName
   * @return
   */
  private static String getNextVerticalPartitionName(
      Table catalog_tbl, Collection<Column> catalog_cols) {
    Database catalog_db = ((Database) catalog_tbl.getParent());

    Collection<String> colNames = new HashSet<String>();
    for (Column catalog_col : catalog_cols) {
      colNames.add(catalog_col.getName());
    }

    // Figure out how many vertical partition tables already exist for this table
    int next = 0;
    String prefix = "SYS_VP_" + catalog_tbl.getName() + "_";
    Pattern p = Pattern.compile(Pattern.quote(prefix) + "[\\d]+");
    for (Table otherTable : CatalogUtil.getSysTables(catalog_db)) {
      if (debug.get())
        LOG.debug(String.format("Checking whether '%s' matches prefix '%s'", otherTable, prefix));
      Matcher m = p.matcher(otherTable.getName());
      if (m.matches() == false) continue;

      // Check to make sure it's not the same vertical partition
      Collection<Column> otherColumns = otherTable.getColumns();
      if (debug.get())
        LOG.debug(
            String.format(
                "%s.%s <-> %s.%s",
                catalog_tbl.getName(), catalog_cols, otherTable.getName(), otherColumns));
      if (otherColumns.size() != colNames.size()) continue;
      boolean fail = false;
      for (Column otherCol : otherColumns) {
        if (colNames.contains(otherCol.getName()) == false) {
          fail = true;
          break;
        }
      }
      if (fail) continue;

      next++;
    } // FOR
    String viewName = String.format("%s%02d", prefix, next);
    assert (catalog_tbl.getViews().contains(viewName) == false);

    if (debug.get())
      LOG.debug(String.format("Next VerticalPartition name '%s' for %s", viewName, catalog_tbl));
    return (viewName);
  }
예제 #7
0
  void parseTargetColumns(
      VoltXMLElement columnsNode, Table table, HashMap<Column, AbstractExpression> columns) {
    for (VoltXMLElement child : columnsNode.children) {
      assert (child.name.equals("column"));

      String name = child.attributes.get("name");
      assert (name != null);
      Column col = table.getColumns().getIgnoreCase(name.trim());

      assert (child.children.size() == 1);
      VoltXMLElement subChild = child.children.get(0);
      AbstractExpression expr = parseExpressionTree(subChild);
      assert (expr != null);
      expr.refineValueType(VoltType.get((byte) col.getType()));
      ExpressionUtil.finalizeValueTypes(expr);
      columns.put(col, expr);
    }
  }
예제 #8
0
  public SEATSProfile(CatalogContext catalogContext, AbstractRandomGenerator rng) {
    this.catalogContext = catalogContext;
    this.rng = rng;

    // Tuple Code to Tuple Id Mapping
    for (String xref[] : SEATSConstants.CODE_TO_ID_COLUMNS) {
      assert (xref.length == 3);
      String tableName = xref[0];
      String codeCol = xref[1];
      String idCol = xref[2];

      if (this.code_columns.containsKey(codeCol) == false) {
        this.code_columns.put(codeCol, idCol);
        this.code_id_xref.put(idCol, new HashMap<String, Long>());
        if (debug.val)
          LOG.debug(
              String.format(
                  "Added %s mapping from Code Column '%s' to Id Column '%s'",
                  tableName, codeCol, idCol));
      }
    } // FOR

    // Foreign Key Code to Ids Mapping
    // In this data structure, the key will be the name of the dependent column
    // and the value will be the name of the foreign key parent column
    // We then use this in conjunction with the Key->Id mapping to turn a code into
    // a foreign key column id. For example, if the child table AIRPORT has a column with a foreign
    // key reference to COUNTRY.CO_ID, then the data file for AIRPORT will have a value
    // 'USA' in the AP_CO_ID column. We can use mapping to get the id number for 'USA'.
    // Long winded and kind of screwy, but hey what else are you going to do?
    for (Table catalog_tbl : catalogContext.database.getTables()) {
      for (Column catalog_col : catalog_tbl.getColumns()) {
        Column catalog_fkey_col = CatalogUtil.getForeignKeyParent(catalog_col);
        if (catalog_fkey_col != null && this.code_id_xref.containsKey(catalog_fkey_col.getName())) {
          this.fkey_value_xref.put(catalog_col.getName(), catalog_fkey_col.getName());
          if (debug.val)
            LOG.debug(
                String.format(
                    "Added ForeignKey mapping from %s to %s",
                    catalog_col.fullName(), catalog_fkey_col.fullName()));
        }
      } // FOR
    } // FOR
  }
예제 #9
0
  // silly helper to add datasources for a table catalog object
  private void addDataSources(Table table, int hostId, List<Pair<Integer, Long>> partitions) {
    for (Pair<Integer, Long> p : partitions) {
      Integer partition = p.getFirst();
      Long site = p.getSecond();

      /*
       * IOException can occur if there is a problem
       * with the persistent aspects of the datasource storage
       */
      try {
        HashMap<String, ExportDataSource> dataSourcesForPartition =
            m_dataSourcesByPartition.get(partition);
        if (dataSourcesForPartition == null) {
          dataSourcesForPartition = new HashMap<String, ExportDataSource>();
          m_dataSourcesByPartition.put(partition, dataSourcesForPartition);
        }
        ExportDataSource exportDataSource =
            new ExportDataSource(
                m_onSourceDrained,
                "database",
                table.getTypeName(),
                partition,
                site,
                table.getSignature(),
                m_timestamp,
                table.getColumns(),
                m_directory.getPath());
        m_numSources++;
        exportLog.info(
            "Creating ExportDataSource for table "
                + table.getTypeName()
                + " signature "
                + table.getSignature()
                + " partition id "
                + partition);
        dataSourcesForPartition.put(table.getSignature(), exportDataSource);
      } catch (IOException e) {
        VoltDB.crashLocalVoltDB(
            "Error creating datasources for table " + table.getTypeName() + " host id " + hostId,
            true,
            e);
      }
    }
  }
예제 #10
0
  /** Determine which parameter is the partition indicator */
  static void parsePartitionInfo(
      VoltCompiler compiler, Database db, Procedure procedure, String info)
      throws VoltCompilerException {

    assert (procedure.getSinglepartition() == true);

    // check this isn't empty
    if (info.length() == 0) {
      String msg =
          "Missing or Truncated PartitionInfo in attribute for procedure: "
              + procedure.getClassname();
      throw compiler.new VoltCompilerException(msg);
    }

    // split on the colon
    String[] parts = info.split(":");

    // if the colon doesn't split well, we have a problem
    if (parts.length != 2) {
      String msg =
          "Possibly invalid PartitionInfo in attribute for procedure: " + procedure.getClassname();
      throw compiler.new VoltCompilerException(msg);
    }

    // relabel the parts for code readability
    String columnInfo = parts[0].trim();
    int paramIndex = Integer.parseInt(parts[1].trim());

    int paramCount = procedure.getParameters().size();
    if ((paramIndex < 0) || (paramIndex >= paramCount)) {
      String msg =
          "PartitionInfo specifies invalid parameter index for procedure: "
              + procedure.getClassname();
      throw compiler.new VoltCompilerException(msg);
    }

    // locate the parameter
    procedure.setPartitionparameter(paramIndex);

    // split the columninfo
    parts = columnInfo.split("\\.");
    if (parts.length != 2) {
      String msg =
          "Possibly invalid PartitionInfo in attribute for procedure: " + procedure.getClassname();
      throw compiler.new VoltCompilerException(msg);
    }

    // relabel the parts for code readability
    String tableName = parts[0].trim();
    String columnName = parts[1].trim();

    // locate the partition column
    CatalogMap<Table> tables = db.getTables();
    for (Table table : tables) {
      if (table.getTypeName().equalsIgnoreCase(tableName)) {
        CatalogMap<Column> columns = table.getColumns();
        Column partitionColumn = table.getPartitioncolumn();
        if (partitionColumn == null) {
          String msg =
              String.format(
                  "PartitionInfo for procedure %s references table %s which has no partition column (may be replicated).",
                  procedure.getClassname(), table.getTypeName());
          throw compiler.new VoltCompilerException(msg);
        }

        for (Column column : columns) {
          if (column.getTypeName().equalsIgnoreCase(columnName)) {
            if (partitionColumn.getTypeName().equals(column.getTypeName())) {
              procedure.setPartitioncolumn(column);
              procedure.setPartitiontable(table);
              return;
            } else {
              String msg =
                  "PartitionInfo for procedure "
                      + procedure.getClassname()
                      + " refers to a column in schema which is not a partition key.";
              throw compiler.new VoltCompilerException(msg);
            }
          }
        }
      }
    }

    String msg =
        "PartitionInfo for procedure "
            + procedure.getClassname()
            + " refers to a column in schema which can't be found.";
    throw compiler.new VoltCompilerException(msg);
  }
예제 #11
0
  static String generateSchemaRow(Table table, boolean isExportTable) {
    StringBuilder sb = new StringBuilder();
    sb.append("<tr class='primaryrow'>");

    // column 1: table name
    String anchor = table.getTypeName().toLowerCase();
    sb.append(
        "<td style='white-space: nowrap;'><i id='s-"
            + anchor
            + "--icon' class='icon-chevron-right'></i> <a href='#' id='s-");
    sb.append(anchor).append("' class='togglex'>");
    sb.append(table.getTypeName());
    sb.append("</a></td>");

    // column 2: type
    sb.append("<td>");
    if (table.getMaterializer() != null) {
      tag(sb, "info", "Materialized View");
    } else {
      if (isExportTable) {
        tag(sb, "inverse", "Export Table");
      } else {
        tag(sb, null, "Table");
      }
    }
    sb.append("</td>");

    // column 3: partitioning
    sb.append("<td style='whitespace: nowrap;'>");
    if (table.getIsreplicated()) {
      tag(sb, "warning", "Replicated");
    } else {
      tag(sb, "success", "Partitioned");
      Column partitionCol = table.getPartitioncolumn();
      if (partitionCol != null) {
        sb.append("<small> on " + partitionCol.getName() + "</small>");
      } else {
        Table matSrc = table.getMaterializer();
        if (matSrc != null) {
          sb.append("<small> with " + matSrc.getTypeName() + "</small>");
        }
      }
    }
    sb.append("</td>");

    // column 4: column count
    sb.append("<td>");
    sb.append(table.getColumns().size());
    sb.append("</td>");

    // column 5: index count
    sb.append("<td>");
    sb.append(table.getIndexes().size());
    sb.append("</td>");

    // column 6: has pkey
    sb.append("<td>");
    boolean found = false;
    for (Constraint constraint : table.getConstraints()) {
      if (ConstraintType.get(constraint.getType()) == ConstraintType.PRIMARY_KEY) {
        found = true;
        break;
      }
    }
    if (found) {
      tag(sb, "info", "Has-PKey");
    } else {
      tag(sb, null, "No-PKey");
    }
    sb.append("</td>");

    // column 6: has tuple limit
    sb.append("<td>");
    if (table.getTuplelimit() != Integer.MAX_VALUE) {
      tag(sb, "info", String.valueOf(table.getTuplelimit()));
    } else {
      tag(sb, null, "No-limit");
    }
    sb.append("</td>");

    sb.append("</tr>\n");

    // BUILD THE DROPDOWN FOR THE DDL / INDEXES DETAIL

    sb.append(
        "<tr class='tablesorter-childRow'><td class='invert' colspan='7' id='s-"
            + table.getTypeName().toLowerCase()
            + "--dropdown'>\n");

    TableAnnotation annotation = (TableAnnotation) table.getAnnotation();
    if (annotation != null) {
      // output the DDL
      if (annotation.ddl == null) {
        sb.append("<p>MISSING DDL</p>\n");
      } else {
        String ddl = annotation.ddl;
        sb.append("<p><pre>" + ddl + "</pre></p>\n");
      }

      // make sure procs appear in only one category
      annotation.proceduresThatReadThis.removeAll(annotation.proceduresThatUpdateThis);

      if (annotation.proceduresThatReadThis.size() > 0) {
        sb.append("<p>Read-only by procedures: ");
        List<String> procs = new ArrayList<String>();
        for (Procedure proc : annotation.proceduresThatReadThis) {
          procs.add("<a href='#p-" + proc.getTypeName() + "'>" + proc.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(procs, ", "));
        sb.append("</p>");
      }
      if (annotation.proceduresThatUpdateThis.size() > 0) {
        sb.append("<p>Read/Write by procedures: ");
        List<String> procs = new ArrayList<String>();
        for (Procedure proc : annotation.proceduresThatUpdateThis) {
          procs.add("<a href='#p-" + proc.getTypeName() + "'>" + proc.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(procs, ", "));
        sb.append("</p>");
      }
    }

    if (table.getIndexes().size() > 0) {
      sb.append(generateIndexesTable(table));
    } else {
      sb.append("<p>No indexes defined on table.</p>\n");
    }

    sb.append("</td></tr>\n");

    return sb.toString();
  }
예제 #12
0
  public static MaterializedViewInfo addVerticalPartition(
      final Table catalog_tbl, final Collection<Column> catalog_cols, final boolean createIndex)
      throws Exception {
    assert (catalog_cols.isEmpty() == false);
    Database catalog_db = ((Database) catalog_tbl.getParent());

    String viewName = getNextVerticalPartitionName(catalog_tbl, catalog_cols);
    if (debug.get())
      LOG.debug(
          String.format(
              "Adding Vertical Partition %s for %s: %s", viewName, catalog_tbl, catalog_cols));

    // Create a new virtual table
    Table virtual_tbl = catalog_db.getTables().get(viewName);
    if (virtual_tbl == null) {
      virtual_tbl = catalog_db.getTables().add(viewName);
    }
    virtual_tbl.setIsreplicated(true);
    virtual_tbl.setMaterializer(catalog_tbl);
    virtual_tbl.setSystable(true);
    virtual_tbl.getColumns().clear();

    // Create MaterializedView and link it to the virtual table
    MaterializedViewInfo catalog_view = catalog_tbl.getViews().add(viewName);
    catalog_view.setVerticalpartition(true);
    catalog_view.setDest(virtual_tbl);
    List<Column> indexColumns = new ArrayList<Column>();

    Column partition_col = catalog_tbl.getPartitioncolumn();
    if (partition_col instanceof VerticalPartitionColumn) {
      partition_col = ((VerticalPartitionColumn) partition_col).getHorizontalColumn();
    }
    if (debug.get()) LOG.debug(catalog_tbl.getName() + " Partition Column: " + partition_col);

    int i = 0;
    assert (catalog_cols != null);
    assert (catalog_cols.isEmpty() == false)
        : "No vertical partitioning columns for " + catalog_view.fullName();
    for (Column catalog_col : catalog_cols) {
      // MaterializedView ColumnRef
      ColumnRef catalog_ref = catalog_view.getGroupbycols().add(catalog_col.getName());
      catalog_ref.setColumn(catalog_col);
      catalog_ref.setIndex(i++);

      // VirtualTable Column
      Column virtual_col = virtual_tbl.getColumns().add(catalog_col.getName());
      virtual_col.setDefaulttype(catalog_col.getDefaulttype());
      virtual_col.setDefaultvalue(catalog_col.getDefaultvalue());
      virtual_col.setIndex(catalog_col.getIndex());
      virtual_col.setNullable(catalog_col.getNullable());
      virtual_col.setSize(catalog_col.getSize());
      virtual_col.setType(catalog_col.getType());
      if (debug.get())
        LOG.debug(String.format("Added VerticalPartition column %s", virtual_col.fullName()));

      // If they want an index, then we'll make one based on every column except for the column
      // that the table is partitioned on
      if (createIndex) {
        boolean include = true;
        if (partition_col instanceof MultiColumn) {
          include = (((MultiColumn) partition_col).contains(catalog_col) == false);
        } else if (catalog_col.equals(partition_col)) {
          include = false;
        }
        if (include) indexColumns.add(virtual_col);
      }
    } // FOR

    if (createIndex) {
      if (indexColumns.isEmpty()) {
        Map<String, Object> m = new ListOrderedMap<String, Object>();
        m.put("Partition Column", partition_col);
        m.put("VP Table Columns", virtual_tbl.getColumns());
        m.put("Passed-in Columns", CatalogUtil.debug(catalog_cols));
        LOG.error("Failed to find index columns\n" + StringUtil.formatMaps(m));
        throw new Exception(String.format("No columns selected for index on %s", viewName));
      }
      String idxName = "SYS_IDX_" + viewName;
      Index virtual_idx = virtual_tbl.getIndexes().get(idxName);
      if (virtual_idx == null) {
        virtual_idx = virtual_tbl.getIndexes().add(idxName);
      }
      virtual_idx.getColumns().clear();

      IndexType idxType =
          (indexColumns.size() == 1 ? IndexType.HASH_TABLE : IndexType.BALANCED_TREE);
      virtual_idx.setType(idxType.getValue());
      i = 0;
      for (Column catalog_col : indexColumns) {
        ColumnRef cref = virtual_idx.getColumns().add(catalog_col.getTypeName());
        cref.setColumn(catalog_col);
        cref.setIndex(i++);
      } // FOR

      if (debug.get())
        LOG.debug(
            String.format(
                "Created %s index '%s' for vertical partition '%s'", idxType, idxName, viewName));
    }
    return (catalog_view);
  }
예제 #13
0
  void compileDatabaseNode(DatabaseType database) throws VoltCompilerException {
    final ArrayList<String> programs = new ArrayList<String>();
    final ArrayList<String> schemas = new ArrayList<String>();
    final ArrayList<ProcedureDescriptor> procedures = new ArrayList<ProcedureDescriptor>();
    final ArrayList<Class<?>> classDependencies = new ArrayList<Class<?>>();
    final ArrayList<String[]> partitions = new ArrayList<String[]>();

    final String databaseName = database.getName();

    // schema does not verify that the database is named "database"
    if (databaseName.equals("database") == false) {
      final String msg =
          "VoltDB currently requires all database elements to be named "
              + "\"database\" (found: \""
              + databaseName
              + "\")";
      throw new VoltCompilerException(msg);
    }

    // create the database in the catalog
    m_catalog.execute("add /clusters[cluster] databases " + databaseName);
    Database db = m_catalog.getClusters().get("cluster").getDatabases().get(databaseName);

    SnapshotType snapshotSettings = database.getSnapshot();
    if (snapshotSettings != null) {
      SnapshotSchedule schedule = db.getSnapshotschedule().add("default");
      String frequency = snapshotSettings.getFrequency();
      if (!frequency.endsWith("s") && !frequency.endsWith("m") && !frequency.endsWith("h")) {
        throw new VoltCompilerException(
            "Snapshot frequency "
                + frequency
                + " needs to end with time unit specified"
                + " that is one of [s, m, h] (seconds, minutes, hours)");
      }

      int frequencyInt = 0;
      String frequencySubstring = frequency.substring(0, frequency.length() - 1);
      try {
        frequencyInt = Integer.parseInt(frequencySubstring);
      } catch (Exception e) {
        throw new VoltCompilerException("Frequency " + frequencySubstring + " is not an integer ");
      }

      String prefix = snapshotSettings.getPrefix();
      if (prefix == null || prefix.isEmpty()) {
        throw new VoltCompilerException("Snapshot prefix " + prefix + " is not a valid prefix ");
      }

      if (prefix.contains("-") || prefix.contains(",")) {
        throw new VoltCompilerException("Snapshot prefix " + prefix + " cannot include , or - ");
      }

      String path = snapshotSettings.getPath();
      if (path == null || path.isEmpty()) {
        throw new VoltCompilerException("Snapshot path " + path + " is not a valid path ");
      }

      if (snapshotSettings.getRetain() == null) {
        throw new VoltCompilerException("Snapshot retain value not provided");
      }

      int retain = snapshotSettings.getRetain().intValue();
      if (retain < 1) {
        throw new VoltCompilerException(
            "Snapshot retain value " + retain + " is not a valid value. Must be 1 or greater.");
      }

      schedule.setFrequencyunit(frequency.substring(frequency.length() - 1, frequency.length()));
      schedule.setFrequencyvalue(frequencyInt);
      schedule.setPath(path);
      schedule.setPrefix(prefix);
      schedule.setRetain(retain);
    }

    // schemas/schema
    for (SchemasType.Schema schema : database.getSchemas().getSchema()) {
      LOG.l7dlog(
          Level.DEBUG,
          LogKeys.compiler_VoltCompiler_CatalogPath.name(),
          new Object[] {schema.getPath()},
          null);
      schemas.add(schema.getPath());
    }

    // groups/group.
    if (database.getGroups() != null) {
      for (GroupsType.Group group : database.getGroups().getGroup()) {
        org.voltdb.catalog.Group catGroup = db.getGroups().add(group.getName());
        catGroup.setAdhoc(group.isAdhoc());
        catGroup.setSysproc(group.isSysproc());
      }
    }

    // users/user
    if (database.getUsers() != null) {
      for (UsersType.User user : database.getUsers().getUser()) {
        org.voltdb.catalog.User catUser = db.getUsers().add(user.getName());
        catUser.setAdhoc(user.isAdhoc());
        catUser.setSysproc(user.isSysproc());
        byte passwordHash[] = extractPassword(user.getPassword());
        catUser.setShadowpassword(Encoder.hexEncode(passwordHash));

        // process the @groups comma separated list
        if (user.getGroups() != null) {
          String grouplist[] = user.getGroups().split(",");
          for (final String group : grouplist) {
            final GroupRef groupRef = catUser.getGroups().add(group);
            final Group catalogGroup = db.getGroups().get(group);
            if (catalogGroup != null) {
              groupRef.setGroup(catalogGroup);
            }
          }
        }
      }
    }

    // procedures/procedure
    for (ProceduresType.Procedure proc : database.getProcedures().getProcedure()) {
      procedures.add(getProcedure(proc));
    }

    // classdependencies/classdependency
    if (database.getClassdependencies() != null) {
      for (Classdependency dep : database.getClassdependencies().getClassdependency()) {
        classDependencies.add(getClassDependency(dep));
      }
    }

    // partitions/table
    if (database.getPartitions() != null) {
      for (org.voltdb.compiler.projectfile.PartitionsType.Partition table :
          database.getPartitions().getPartition()) {
        partitions.add(getPartition(table));
      }
    }

    String msg = "Database \"" + databaseName + "\" ";
    // TODO: schema allows 0 procedures. Testbase relies on this.
    if (procedures.size() == 0) {
      msg +=
          "needs at least one \"procedure\" element "
              + "(currently has "
              + String.valueOf(procedures.size())
              + ")";
      throw new VoltCompilerException(msg);
    }
    if (procedures.size() < 1) {
      msg += "is missing the \"procedures\" element";
      throw new VoltCompilerException(msg);
    }

    // shutdown and make a new hsqldb
    m_hsql = HSQLInterface.loadHsqldb();

    // Actually parse and handle all the programs
    for (final String programName : programs) {
      m_catalog.execute("add " + db.getPath() + " programs " + programName);
    }

    // Actually parse and handle all the DDL
    final DDLCompiler ddlcompiler = new DDLCompiler(this, m_hsql);

    for (final String schemaPath : schemas) {
      File schemaFile = null;

      if (schemaPath.contains(".jar!")) {
        String ddlText = null;
        try {
          ddlText = JarReader.readFileFromJarfile(schemaPath);
        } catch (final Exception e) {
          throw new VoltCompilerException(e);
        }
        schemaFile = VoltProjectBuilder.writeStringToTempFile(ddlText);
      } else {
        schemaFile = new File(schemaPath);
      }

      if (!schemaFile.isAbsolute()) {
        // Resolve schemaPath relative to the database definition xml file
        schemaFile = new File(new File(m_projectFileURL).getParent(), schemaPath);
      }

      // add the file object's path to the list of files for the jar
      m_ddlFilePaths.put(schemaFile.getName(), schemaFile.getPath());

      ddlcompiler.loadSchema(schemaFile.getAbsolutePath());
    }
    ddlcompiler.compileToCatalog(m_catalog, db);

    // Actually parse and handle all the partitions
    // this needs to happen before procedures are compiled
    msg = "In database \"" + databaseName + "\", ";
    final CatalogMap<Table> tables = db.getTables();
    for (final String[] partition : partitions) {
      final String tableName = partition[0];
      final String colName = partition[1];
      final Table t = tables.getIgnoreCase(tableName);
      if (t == null) {
        msg += "\"partition\" element has unknown \"table\" attribute '" + tableName + "'";
        throw new VoltCompilerException(msg);
      }
      final Column c = t.getColumns().getIgnoreCase(colName);
      // make sure the column exists
      if (c == null) {
        msg += "\"partition\" element has unknown \"column\" attribute '" + colName + "'";
        throw new VoltCompilerException(msg);
      }
      // make sure the column is marked not-nullable
      if (c.getNullable() == true) {
        msg +=
            "Partition column '"
                + tableName
                + "."
                + colName
                + "' is nullable. "
                + "Partition columns must be constrained \"NOT NULL\".";
        throw new VoltCompilerException(msg);
      }
      t.setPartitioncolumn(c);
      t.setIsreplicated(false);

      // Set the destination tables of associated views non-replicated.
      // If a view's source table is replicated, then a full scan of the
      // associated view is singled-sited. If the source is partitioned,
      // a full scan of the view must be distributed.
      final CatalogMap<MaterializedViewInfo> views = t.getViews();
      for (final MaterializedViewInfo mvi : views) {
        mvi.getDest().setIsreplicated(false);
      }
    }

    // add vertical partitions
    if (database.getVerticalpartitions() != null) {
      for (Verticalpartition vp : database.getVerticalpartitions().getVerticalpartition()) {
        try {
          addVerticalPartition(db, vp.getTable(), vp.getColumn(), vp.isIndexed());
        } catch (Exception ex) {
          throw new VoltCompilerException(
              "Failed to create vertical partition for " + vp.getTable(), ex);
        }
      }
    }

    // this should reorder the tables and partitions all alphabetically
    String catData = m_catalog.serialize();
    m_catalog = new Catalog();
    m_catalog.execute(catData);
    db = m_catalog.getClusters().get("cluster").getDatabases().get(databaseName);

    // add database estimates info
    addDatabaseEstimatesInfo(m_estimates, db);
    addSystemProcsToCatalog(m_catalog, db);

    // Process and add exports and connectors to the catalog
    // Must do this before compiling procedures to deny updates
    // on append-only tables.
    if (database.getExports() != null) {
      // currently, only a single connector is allowed
      Connector conn = database.getExports().getConnector();
      compileConnector(conn, db);
    }

    // Actually parse and handle all the Procedures
    for (final ProcedureDescriptor procedureDescriptor : procedures) {
      final String procedureName = procedureDescriptor.m_className;
      m_currentFilename = procedureName.substring(procedureName.lastIndexOf('.') + 1);
      m_currentFilename += ".class";
      ProcedureCompiler.compile(this, m_hsql, m_estimates, m_catalog, db, procedureDescriptor);
    }

    // Add all the class dependencies to the output jar
    for (final Class<?> classDependency : classDependencies) {
      addClassToJar(classDependency, this);
    }

    m_hsql.close();
  }