void DiffSQLGeneratorBE::generate_alter_stmt()

in modules/db.mysql/src/db_mysql_diffsqlgen.cpp [766:1085]


void DiffSQLGeneratorBE::generate_alter_stmt(db_mysql_TableRef table, const grt::DiffChange *diffchange,
                                             AlterTableFlags alter_table_flags) {
  if (table->isStub())
    return;

  const grt::ChangeSet *cs = diffchange->subchanges();

  if ((alter_table_flags & EverythingButForeignKeys)) {
    // process table triggers
    for (grt::ChangeSet::const_iterator e = cs->end(), it = cs->begin(); it != e; it++) {
      const grt::ObjectAttrModifiedChange *attr_change = static_cast<const grt::ObjectAttrModifiedChange *>(it->get());

      if (attr_change->get_attr_name().compare("triggers") == 0) {
        const grt::MultiChange *list_change = static_cast<const grt::MultiChange *>(attr_change->get_subchange().get());

        const grt::ChangeSet *triggers_cs = list_change->subchanges();

        for (grt::ChangeSet::const_iterator e2 = triggers_cs->end(), jt = triggers_cs->begin(); jt != e2; jt++) {
          const grt::DiffChange *trigger_change = jt->get();

          switch (trigger_change->get_change_type()) {
            case grt::ListItemAdded: {
              db_mysql_TriggerRef trigger(db_mysql_TriggerRef::cast_from(
                static_cast<const grt::ListItemAddedChange *>(trigger_change)->get_value()));
              generate_create_stmt(trigger, true);
            } break;
            case grt::ListItemRemoved: {
              db_mysql_TriggerRef trigger(db_mysql_TriggerRef::cast_from(
                static_cast<const grt::ListItemRemovedChange *>(trigger_change)->get_value()));
              generate_drop_stmt(trigger, true);
            } break;
            case grt::ListItemModified: {
              db_mysql_TriggerRef old_trigger = db_mysql_TriggerRef::cast_from(
                grt::ValueRef(static_cast<const grt::ListItemModifiedChange *>(trigger_change)->get_old_value()));
              db_mysql_TriggerRef new_trigger = db_mysql_TriggerRef::cast_from(
                grt::ValueRef(static_cast<const grt::ListItemModifiedChange *>(trigger_change)->get_new_value()));

              generate_drop_stmt(old_trigger, true);
              generate_create_stmt(new_trigger, true);
            } break;
            case grt::ListItemOrderChanged: {
              const grt::ListItemOrderChange *order_change =
                dynamic_cast<const grt::ListItemOrderChange *>(trigger_change);

              if (order_change) // && order_change->get_subchange())
              {
                //                const grt::ListItemModifiedChange *change = dynamic_cast<const
                //                grt::ListItemModifiedChange *>(order_change->get_subchange().get());

                //                if (change)
                {
                  generate_drop_stmt(db_mysql_TriggerRef::cast_from(order_change->get_old_value()), true);
                  generate_create_stmt(db_mysql_TriggerRef::cast_from(order_change->get_new_value()), true);
                }
              }
            }
            default:
              break;
          }
        }
      }
    }
  }

  const std::string table_name_for_filter(get_old_object_name_for_key(table, _case_sensitive));
  if (_use_filtered_lists && (_filtered_tables.find(table_name_for_filter) == _filtered_tables.end()))
    return;

  bool partitions_processed = false;
  cs = diffchange->subchanges();

  // check whether all changes detected for this table are dummy changes (index reorders or fk reorders)
  bool dummy_changes_only = true;
  for (grt::ChangeSet::const_iterator e = cs->end(), it = cs->begin(); it != e; it++) {
    const grt::ObjectAttrModifiedChange *attr_change = dynamic_cast<const grt::ObjectAttrModifiedChange *>(it->get());

    if (attr_change->get_attr_name().compare("indices") == 0 ||
        attr_change->get_attr_name().compare("foreignKeys") == 0) {
      const grt::MultiChange *list_change = dynamic_cast<const grt::MultiChange *>(attr_change->get_subchange().get());
      // ignore changes if they're only reorderings (with no subchanges)
      if (list_change && list_change->subchanges()) {
        const grt::ListItemOrderChange *order_change = NULL;
        if (list_change->subchanges()->changes.size() == 1)
          order_change = dynamic_cast<const grt::ListItemOrderChange *>(list_change->subchanges()->begin()->get());
        if (!order_change || order_change->get_subchange()) {
          dummy_changes_only = false;
          break;
        }
      }
    } else
      dummy_changes_only = false;
  }
  if (dummy_changes_only)
    return;

  callback->alter_table_props_begin(table);

  for (grt::ChangeSet::const_iterator e = cs->end(), it = cs->begin(); it != e; it++) {
    const grt::ObjectAttrModifiedChange *attr_change = static_cast<const grt::ObjectAttrModifiedChange *>(it->get());

    if (!(alter_table_flags & OnlyForeignKeys) && attr_change->get_attr_name().compare("foreignKeys") == 0)
      continue;
    else if (!(alter_table_flags & EverythingButForeignKeys) &&
             attr_change->get_attr_name().compare("foreignKeys") != 0)
      continue;

    if (attr_change->get_attr_name().compare("name") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_name(table, str);
    }
    if (attr_change->get_attr_name().compare("columns") == 0) {
      const grt::MultiChange *list_change = static_cast<const grt::MultiChange *>(attr_change->get_subchange().get());
      generate_alter(table->columns(), list_change);
    } else if (attr_change->get_attr_name().compare("indices") == 0) {
      const grt::MultiChange *list_change = static_cast<const grt::MultiChange *>(attr_change->get_subchange().get());
      // ignore changes if they're only reorderings
      if (list_change && list_change->subchanges()) {
        const grt::ListItemOrderChange *order_change = NULL;
        if (list_change->subchanges()->changes.size() == 1)
          order_change = dynamic_cast<const grt::ListItemOrderChange *>(list_change->subchanges()->begin()->get());
        if (!order_change || order_change->get_subchange()) {
          callback->alter_table_indexes_begin(table);
          generate_alter(table->indices(), list_change);
          callback->alter_table_indexes_end(table);
        }
      }
    } else if (attr_change->get_attr_name().compare("foreignKeys") == 0) {
      const grt::MultiChange *list_change = static_cast<const grt::MultiChange *>(attr_change->get_subchange().get());
      // ignore changes if they're only reorderings
      if (list_change && list_change->subchanges()) {
        const grt::ListItemOrderChange *order_change = NULL;
        if (list_change->subchanges()->changes.size() == 1)
          order_change = dynamic_cast<const grt::ListItemOrderChange *>(list_change->subchanges()->begin()->get());
        if (!order_change || order_change->get_subchange()) {
          callback->alter_table_fks_begin(table);
          generate_alter(table->foreignKeys(), list_change);
          callback->alter_table_fks_end(table);
        }
      }
    } else if (attr_change->get_attr_name().compare("tableEngine") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      if (!str.empty())
        callback->alter_table_engine(table, str);
    } else if (attr_change->get_attr_name().compare("nextAutoInc") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_next_auto_inc(table, str);
    } else if (attr_change->get_attr_name().compare("password") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_password(table, str);
    } else if (attr_change->get_attr_name().compare("delayKeyWrite") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::IntegerRef n = grt::IntegerRef::cast_from(change->get_new_value());
      callback->alter_table_delay_key_write(table, n);
    } else if (attr_change->get_attr_name().compare("defaultCharacterSetName") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_charset(table, str);
    } else if (attr_change->get_attr_name().compare("defaultCollationName") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_collate(table, str);
    } else if (attr_change->get_attr_name().compare("mergeUnion") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_merge_union(table, str);
    } else if (attr_change->get_attr_name().compare("mergeInsert") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_merge_insert(table, str);
    }
// ALTER TABLE silently ignores these attributes
#if 0
    else if(attr_change->get_attr_name().compare("tableDataDir") == 0)
    {
      const grt::SimpleValueChange *change= static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str= grt::StringRef::cast_from(change->get_new_value());
      alter_sql.append("DATA DIRECTORY = '").append(str.c_str()).append("' ");
    }
    else if(attr_change->get_attr_name().compare("tableIndexDir") == 0)
    {
      const grt::SimpleValueChange *change= static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str= grt::StringRef::cast_from(change->get_new_value());
      alter_sql.append("INDEX DIRECTORY = '").append(str.c_str()).append("' ");
    }
#endif
    else if (attr_change->get_attr_name().compare("packKeys") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_pack_keys(table, str);
    } else if (attr_change->get_attr_name().compare("checksum") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::IntegerRef n = grt::IntegerRef::cast_from(change->get_new_value());
      callback->alter_table_checksum(table, n);
    } else if (attr_change->get_attr_name().compare("comment") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_comment(table, str);
    } else if (attr_change->get_attr_name().compare("rowFormat") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_row_format(table, str);
    } else if (attr_change->get_attr_name().compare("keyBlockSize") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_key_block_size(table, str);
    } else if (attr_change->get_attr_name().compare("avgRowLength") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_avg_row_length(table, str);
    } else if (attr_change->get_attr_name().compare("minRows") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_min_rows(table, str);
    } else if (attr_change->get_attr_name().compare("maxRows") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_max_rows(table, str);
    }
// to be added later, probably needs support for CREATE/ALTER SERVER
#if 0
    else if(attr_change->get_attr_name().compare("connection") == 0)
    {
    }
#endif
    else if (attr_change->get_attr_name().compare("connectionString") == 0) {
      const grt::SimpleValueChange *change =
        static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
      grt::StringRef str = grt::StringRef::cast_from(change->get_new_value());
      callback->alter_table_connection_string(table, str);
    } else if (!partitions_processed && ((attr_change->get_attr_name().compare("partitionType") == 0) ||
                                         (attr_change->get_attr_name().compare("partitionExpression") == 0) ||
                                         (attr_change->get_attr_name().compare("subpartitionType") == 0) ||
                                         (attr_change->get_attr_name().compare("subpartitionExpression") == 0) ||
                                         (attr_change->get_attr_name().compare("subpartitionCount") == 0))) {
      generate_set_partitioning(table, diffchange);
      partitions_processed = true;
    }
  }

  if (alter_table_flags & EverythingButForeignKeys) {
    bool is_range = (strcmp(table->partitionType().c_str(), "RANGE") == 0);

    // partitioning options that dont require PARTITION BY clause
    for (grt::ChangeSet::const_iterator e = cs->end(), it = cs->begin(); (it != e) && !partitions_processed; it++) {
      const grt::ObjectAttrModifiedChange *attr_change = static_cast<const grt::ObjectAttrModifiedChange *>(it->get());

      if (attr_change->get_attr_name().compare("partitionCount") == 0) {
        const grt::SimpleValueChange *change =
          static_cast<const grt::SimpleValueChange *>(attr_change->get_subchange().get());
        grt::IntegerRef old_count = grt::IntegerRef::cast_from(change->get_old_value());

        // std::string part_count_sql(generate_change_partition_count(table, new_count));

        //// partition count alone can be changed only for HASH/KEY partitions
        //// generate_change_partition_count() will return empty string otherwise
        //// for RANGE/LIST we ignore change of this attribute and rely solely on
        //// partition definitions change
        std::string part_type(table->partitionType().c_str());
        if ((part_type.find("HASH") != std::string::npos) || (part_type.find("KEY") != std::string::npos)) {
          callback->alter_table_partition_count(table, old_count);
          partitions_processed = true;
        }
      } else if (attr_change->get_attr_name().compare("partitionDefinitions") == 0) {
        const grt::MultiChange *list_change = static_cast<const grt::MultiChange *>(attr_change->get_subchange().get());
        const grt::ChangeSet *part_cs = list_change->subchanges();
        for (grt::ChangeSet::const_iterator e2 = part_cs->end(), jt = part_cs->begin(); jt != e2; jt++) {
          const grt::DiffChange *part_change = jt->get();
          switch (part_change->get_change_type()) {
            case grt::ListItemAdded: {
              db_mysql_PartitionDefinitionRef part(db_mysql_PartitionDefinitionRef::cast_from(
                static_cast<const grt::ListItemAddedChange *>(part_change)->get_value()));
              callback->alter_table_add_partition(part, is_range);
            } break;
            case grt::ListItemRemoved: {
              db_mysql_PartitionDefinitionRef part = db_mysql_PartitionDefinitionRef::cast_from(
                static_cast<const grt::ListItemRemovedChange *>(part_change)->get_value());

              callback->alter_table_drop_partition(part->name().c_str());
            } break;
            case grt::ListItemModified: {
              db_mysql_PartitionDefinitionRef old_part(db_mysql_PartitionDefinitionRef::cast_from(
                static_cast<const grt::ListItemModifiedChange *>(part_change)->get_old_value()));
              db_mysql_PartitionDefinitionRef new_part(db_mysql_PartitionDefinitionRef::cast_from(
                static_cast<const grt::ListItemModifiedChange *>(part_change)->get_new_value()));

              callback->alter_table_reorganize_partition(old_part, new_part, is_range);
            } break;
            default:
              break;
          }

          partitions_processed = true;
        }
      }
    }
  }

  callback->alter_table_props_end(table);
}