Status QueryPlanner::applyTypes(TableColumns& columns) {
  std::map<size_t, ColumnType> column_types;
  for (const auto& row : program_) {
    if (row.at("opcode") == "ResultRow") {
      // The column parsing is finished.
      auto k = boost::lexical_cast<size_t>(row.at("p1"));
      for (const auto& type : column_types) {
        if (type.first - k < columns.size()) {
          std::get<1>(columns[type.first - k]) = type.second;
        }
      }
    }

    if (row.at("opcode") == "Copy") {
      // Copy P1 -> P1 + P3 into P2 -> P2 + P3.
      auto from = boost::lexical_cast<size_t>(row.at("p1"));
      auto to = boost::lexical_cast<size_t>(row.at("p2"));
      auto size = boost::lexical_cast<size_t>(row.at("p3"));
      for (size_t i = 0; i <= size; i++) {
        if (column_types.count(from + i)) {
          column_types[to + i] = std::move(column_types[from + i]);
          column_types.erase(from + i);
        }
      }
    } else if (row.at("opcode") == "Cast") {
      auto value = boost::lexical_cast<size_t>(row.at("p1"));
      auto to = boost::lexical_cast<size_t>(row.at("p2"));
      switch (to) {
      case 'A': // BLOB
        column_types[value] = BLOB_TYPE;
        break;
      case 'B': // TEXT
        column_types[value] = TEXT_TYPE;
        break;
      case 'C': // NUMERIC
        // We don't exactly have an equivalent to NUMERIC (which includes such
        // things as DATETIME and DECIMAL
        column_types[value] = UNKNOWN_TYPE;
        break;
      case 'D': // INTEGER
        column_types[value] = BIGINT_TYPE;
        break;
      case 'E': // REAL
        column_types[value] = DOUBLE_TYPE;
        break;
      default:
        column_types[value] = UNKNOWN_TYPE;
        break;
      }
    }

    if (kSQLOpcodes.count(row.at("opcode"))) {
      const auto& op = kSQLOpcodes.at(row.at("opcode"));
      auto k = boost::lexical_cast<size_t>(row.at(Opcode::regString(op.reg)));
      column_types[k] = op.type;
    }
  }

  return Status(0);
}
Status QueryPlanner::applyTypes(TableColumns& columns) {
  std::map<size_t, ColumnType> column_types;
  for (const auto& row : program_) {
    if (row.at("opcode") == "ResultRow") {
       
      auto k = boost::lexical_cast<size_t>(row.at("p1"));
      for (const auto& type : column_types) {
        if (type.first - k < columns.size()) {
          std::get<1>(columns[type.first - k]) = type.second;
        }
      }
    }

    if (row.at("opcode") == "Copy") {
       
      auto from = boost::lexical_cast<size_t>(row.at("p1"));
      auto to = boost::lexical_cast<size_t>(row.at("p2"));
      auto size = boost::lexical_cast<size_t>(row.at("p3"));
      for (size_t i = 0; i <= size; i++) {
        if (column_types.count(from + i)) {
          column_types[to + i] = std::move(column_types[from + i]);
          column_types.erase(from + i);
        }
      }
    } else if (row.at("opcode") == "Cast") {
      auto value = boost::lexical_cast<size_t>(row.at("p1"));
      auto to = boost::lexical_cast<size_t>(row.at("p2"));
      switch (to) {
      case 'A':  
        column_types[value] = BLOB_TYPE;
        break;
      case 'B':  
        column_types[value] = TEXT_TYPE;
        break;
      case 'C':  
         
         
        column_types[value] = UNKNOWN_TYPE;
        break;
      case 'D':  
        column_types[value] = BIGINT_TYPE;
        break;
      case 'E':  
        column_types[value] = DOUBLE_TYPE;
        break;
      default:
        column_types[value] = UNKNOWN_TYPE;
        break;
      }
    }

    if (kSQLOpcodes.count(row.at("opcode"))) {
      const auto& op = kSQLOpcodes.at(row.at("opcode"));
      auto k = boost::lexical_cast<size_t>(row.at(Opcode::regString(op.reg)));
      column_types[k] = op.type;
    }
  }

  return Status(0);
}