[Tarantool-patches] [PATCH v4 5/5] sql: support column addition

Nikita Pettik korablev at tarantool.org
Fri Nov 6 18:57:19 MSK 2020


On 09 Oct 16:45, Roman Khabibov wrote:
> diff --git a/src/box/errcode.h b/src/box/errcode.h
> index e6957d612..5a59f477f 100644
> --- a/src/box/errcode.h
> +++ b/src/box/errcode.h
> @@ -273,6 +273,8 @@ struct errcode_record {
>  	/*218 */_(ER_TUPLE_METADATA_IS_TOO_BIG,	"Can't create tuple: metadata size %u is too big") \
>  	/*219 */_(ER_XLOG_GAP,			"%s") \
>  	/*220 */_(ER_TOO_EARLY_SUBSCRIBE,	"Can't subscribe non-anonymous replica %s until join is done") \
> +	/*221 */_(ER_SQL_CANT_ADD_AUTOINC,	"Can't add AUTOINCREMENT: space %s can't feature more than one AUTOINCREMENT field") \
> +

Extra empty line.
  
>  /*
>   * !IMPORTANT! Please follow instructions at start of the file
> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> index fd8e7ed1e..597608bea 100644
> --- a/src/box/sql/build.c
> +++ b/src/box/sql/build.c
> @@ -285,48 +285,110 @@ sql_field_retrieve(Parse *parser, struct space_def *space_def, uint32_t id)
>  	return field;
>  }
>  
> +static struct space *
> +sql_shallow_space_copy(struct Parse *parse, struct space *space)
> +{
> +	assert(space->def != NULL);
> +	struct space *ret = sql_ephemeral_space_new(parse, space->def->name);
> +	if (ret == NULL)
> +		goto error;
> +	ret->index_count = space->index_count;
> +	ret->index_id_max = space->index_id_max;
> +	size_t size = 0;
> +	ret->index = region_alloc_array(&parse->region, typeof(struct index *),
> +					ret->index_count, &size);
> +	if (ret->index == NULL) {
> +		diag_set(OutOfMemory, size, "region_alloc_array", "ret->index");
> +		goto error;
> +	}


You don't need all indexes from space..What you only need from space -          
count of indexes (to generate name if it is required). The same for
field defs. Mb it is worth avoiding copying space at all - just
store in create_column_def list of ck/fk constraints, single
field_def, index/field count - these objects seem to be enough.
Please consider this suggestion.
> +
> +	struct region *region = &parse->region;
> +	struct Token *name = &create_column_def->base.name;
> +	char *column_name =
> +		sql_normalized_name_region_new(region, name->z, name->n);
> +	if (column_name == NULL)
> +		goto tnt_error;
> +
>  	/*
> -	 * As sql_field_retrieve will allocate memory on region
> -	 * ensure that def is also temporal and would be dropped.
> +	 * Format can be set in Lua, then exact_field_count can be
> +	 * zero, but field_count is not.
>  	 */
> -	assert(def->opts.is_ephemeral);
> -	if (sql_field_retrieve(pParse, def, def->field_count) == NULL)
> +	if (def->exact_field_count == 0)
> +		def->exact_field_count = def->field_count;

assert(is_alter);

> +	struct Vdbe *v = sqlGetVdbe(parse);
> +	assert(v != NULL);
> +
> +	struct space *system_space = space_by_id(BOX_SPACE_ID);

-> you can call it simply _space or s_space

> +	assert(system_space != NULL);
> +	int cursor = parse->nTab++;
> +	vdbe_emit_open_cursor(parse, cursor, 0, system_space);
> +	sqlVdbeChangeP5(v, OPFLAG_SYSTEMSP);
> +
>  void
>  sql_column_add_nullable_action(struct Parse *parser,
>  			       enum on_conflict_action nullable_action)
>  {
> -	struct space *space = parser->create_table_def.new_space;
> -	if (space == NULL || NEVER(space->def->field_count < 1))
> +	assert(parser->create_column_def.space != NULL);
> +	struct space_def *def = parser->create_column_def.space->def;
> +	if (NEVER(def->field_count < 1))
>  		return;

Let's use standard facilities: assert(def->field_count > 0);

>  	if (space == NULL)
>  		goto primary_key_exit;
>  	if (sql_space_primary_key(space) != NULL) {
> @@ -574,8 +707,10 @@ sql_create_check_contraint(struct Parse *parser)
>  		(struct alter_entity_def *) create_ck_def;
>  	assert(alter_def->entity_type == ENTITY_TYPE_CK);
>  	(void) alter_def;
> -	struct space *space = parser->create_table_def.new_space;
> -	bool is_alter = space == NULL;
> +	struct space *space = parser->create_column_def.space;

Consider tiny refactoring:

is_alter = space == NULL;
if (is_alter)
	space = ...
assert(space != NULL);

> +	if (space == NULL)
> +		space = parser->create_table_def.new_space;
> +	bool is_alter_add_constr = space == NULL;
>  
> -		assert(! is_alter);
> +		assert(!is_alter_add_constr);

What's the point of this renaming?

>  		uint32_t ck_idx = ++parser->create_checks_def.count;
> +		/*
> @@ -1149,15 +1302,28 @@ resolve_link(struct Parse *parse_context, const struct space_def *def,
>  
>  /**
>   * Emit code to create sequences, indexes, check and foreign key
> - * constraints appeared in <CREATE TABLE>.
> + * constraints appeared in <CREATE TABLE> or
> + * <ALTER TABLE ADD COLUMN>.
>   */
>  static void
>  vdbe_emit_create_constraints(struct Parse *parse, int reg_space_id)
>  {
>  	assert(reg_space_id != 0);
>  	struct space *space = parse->create_table_def.new_space;
> -	assert(space != NULL);
> +	bool is_alter = space == NULL;
>  	uint32_t i = 0;
> +	/*
> +	 * If it is an <ALTER TABLE ADD COLUMN>, then we have to
> +	 * create all indexes added by this statement. These

AFAIK only one index (corresponding to unique constraint).                      

> +	 * indexes are in the array, starting with old index_count
> +	 * (inside space object) and ending with new index_count
> +	 * (inside ephemeral space).
> +	 */
> +	if (is_alter) {
> +		space = parse->create_column_def.space;
> +		i = space_by_name(space->def->name)->index_count;
> +	}
> @@ -1176,6 +1342,21 @@ vdbe_emit_create_constraints(struct Parse *parse, int reg_space_id)
>  		sqlVdbeAddOp2(v, OP_NextSequenceId, 0, reg_seq_id);
>  		int reg_seq_rec = emitNewSysSequenceRecord(parse, reg_seq_id,
>  							   space->def->name);
> +		if (is_alter) {
> +			int errcode = ER_SQL_CANT_ADD_AUTOINC;
> +			const char *error_msg =
> +				tt_sprintf(tnt_errcode_desc(errcode),
> +					   space->def->name);
> +			if (vdbe_emit_halt_with_presence_test(parse,
> +							      BOX_SEQUENCE_ID,
> +							      2,
> +							      reg_seq_rec + 3,
> +							      1, errcode,
> +							      error_msg, false,
> +							      OP_NoConflict)
> +			    != 0)

Oh please leave !=0 cond on previous line. This way looks disgusting.

> +				return;
> +		}
>  		sqlVdbeAddOp2(v, OP_SInsert, BOX_SEQUENCE_ID, reg_seq_rec);
>  		/* Do an insertion into _space_sequence. */
>  		int reg_space_seq_record =
> +	 * CONSTRAINT> statement handling.
>  	 */
> -	bool is_alter = space == NULL;
> +	bool is_alter_add_constr = space == NULL;

Again, what's the point of this renaming?



More information about the Tarantool-patches mailing list