Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: tarantool-patches@freelists.org,
	Kirill Shcherbatov <kshcherbatov@tarantool.org>
Subject: [tarantool-patches] Re: [PATCH v5 4/6] schema: add new system space for CHECK constraints
Date: Sun, 26 May 2019 15:06:46 +0300	[thread overview]
Message-ID: <c48a4885-faa3-77b0-f2e8-69c4e24a43f9@tarantool.org> (raw)
In-Reply-To: <788556b70e154103ed1f6131db7ee1f8cd687848.1558605591.git.kshcherbatov@tarantool.org>

Thanks for the patch! See 12 comments below.

> @@ -1387,6 +1377,79 @@ UpdateSchemaVersion::alter(struct alter_space *alter)
>      ++schema_version;
>  }
>  
> +/**
> + * As ck_constraint object depends on space_def we must rebuild
> + * all ck constraints on space alter.
> + *
> + * To perform it transactionally, we create a list of new ck
> + * constraints objects in ::prepare method that is fault-tolerant.
> + * Finally in ::alter or ::rollback methods we only swap thouse

1. 'thouse' word does not exist, it is clearly visible with a
spell checker, which usually highlights unknown words.

> + * lists securely.
> + */
> +class RebuildCkConstraints: public AlterSpaceOp
> +{
> +	void space_swap_ck_constraint(struct space *old_space,
> +				      struct space *new_space);
> +public:
> +	RebuildCkConstraints(struct alter_space *alter) : AlterSpaceOp(alter),
> +		ck_constraint(RLIST_HEAD_INITIALIZER(ck_constraint)) {}
> +	struct rlist ck_constraint;
> +	virtual void prepare(struct alter_space *alter);
> +	virtual void alter(struct alter_space *alter);
> +	virtual void rollback(struct alter_space *alter);
> +	virtual ~RebuildCkConstraints();
> +};
> @@ -4040,6 +4111,176 @@ on_replace_dd_fk_constraint(struct trigger * /* trigger*/, void *event)
> +
> +/** A trigger invoked on replace in the _ck_constraint space. */
> +static void
> +on_replace_dd_ck_constraint(struct trigger * /* trigger*/, void *event)
> +{
> +	struct txn *txn = (struct txn *) event;
> +	txn_check_singlestatement_xc(txn, "Space _ck_constraint");
> +	struct txn_stmt *stmt = txn_current_stmt(txn);
> +	struct tuple *old_tuple = stmt->old_tuple;
> +	struct tuple *new_tuple = stmt->new_tuple;
> +	uint32_t space_id =
> +		tuple_field_u32_xc(old_tuple != NULL ? old_tuple : new_tuple,
> +				   BOX_CK_CONSTRAINT_FIELD_SPACE_ID);
> +	struct space *space = space_cache_find_xc(space_id);
> +	struct trigger *on_rollback =
> +		txn_alter_trigger_new(on_replace_ck_constraint_rollback, NULL);
> +	struct trigger *on_commit =
> +		txn_alter_trigger_new(on_replace_ck_constraint_commit, NULL);
> +
> +	if (new_tuple != NULL) {
> +		bool is_deferred =
> +			tuple_field_bool_xc(new_tuple,
> +					    BOX_CK_CONSTRAINT_FIELD_DEFERRED);
> +		if (is_deferred) {
> +			tnt_raise(ClientError, ER_UNSUPPORTED, "Tarantool",
> +				  "deferred ck constraints");
> +		}
> +		/* Create or replace check constraint. */
> +		struct ck_constraint_def *ck_def =
> +			ck_constraint_def_new_from_tuple(new_tuple);
> +		auto ck_guard = make_scoped_guard([=] { free(ck_def); });

2. Please, implement and use ck_constraint_def_delete. Free() will leak, when
ck_constraint will become more complex.

> +		/*
> +		 * FIXME: Ck constraint creation on non-empty
> +		 * space must be implemented as preparatory
> +		 * step for ALTER SPACE ADD CONSTRAINT feature.
> +		 */
> +		struct index *pk = space_index(space, 0);
> +		if (pk != NULL && index_size(pk) > 0) {
> +			tnt_raise(ClientError, ER_CREATE_CK_CONSTRAINT,
> +				  ck_def->name,
> +				  "referencing space must be empty");
> +		}
> +		struct ck_constraint *new_ck_constraint =
> +			ck_constraint_new(ck_def, space->def);
> +		if (new_ck_constraint == NULL)
> +			diag_raise();
> +		ck_guard.is_active = false;
> +		const char *name = new_ck_constraint->def->name;
> +		struct ck_constraint *old_ck_constraint =
> +			space_ck_constraint_by_name(space, name, strlen(name));
> +		if (old_ck_constraint != NULL)
> +			rlist_del_entry(old_ck_constraint, link);
> +		rlist_add_entry(&space->ck_constraint, new_ck_constraint, link);
> +		on_commit->data = old_tuple == NULL ? new_ck_constraint :
> +						      old_ck_constraint;
> +		on_rollback->data = on_commit->data;
> diff --git a/src/box/ck_constraint.c b/src/box/ck_constraint.c
> new file mode 100644
> index 000000000..c74687b31
> --- /dev/null
> +++ b/src/box/ck_constraint.c
> +
> +void
> +ck_constraint_delete(struct ck_constraint *ck_constraint)
> +{
> +	sql_expr_delete(sql_get(), ck_constraint->expr, false);
> +	free(ck_constraint->def);

3. The same. Use ck_constraint_def_delete.

> +	TRASH(ck_constraint);
> +	free(ck_constraint);
> +}
> diff --git a/src/box/ck_constraint.h b/src/box/ck_constraint.h
> new file mode 100644
> index 000000000..e20203bb5
> --- /dev/null
> +++ b/src/box/ck_constraint.h
> +
> +/**
> + * Calculate check constraint definition memory size and fields
> + * offsets for given arguments.
> + *
> + * Alongside with struct ck_constraint_def itself, we reserve
> + * memory for string containing its name and expression string.
> + *
> + * Memory layout:
> + * +-----------------------------+ <- Allocated memory starts here
> + * |   struct ck_constraint_def  |
> + * |-----------------------------|
> + * |          name + \0          |
> + * |-----------------------------|
> + * |        expr_str + \0        |
> + * +-----------------------------+
> + *
> + * @param name_len The length of the name.
> + * @param expr_str_len The length of the expr_str.
> + * @param[out] name_offset The offset of the name string.
> + * @param[out] expr_str_offset The offset of the expr_str string.
> + * @retval The size of the ck constraint definition object for
> + *         given parameters.

4. I said it probably 2-3 times, but you still ignore. @retval takes
one parameter, @return take 0 parameters. Here you wrote, that
returned value is 'The'.

> + */
> +static inline uint32_t
> +ck_constraint_def_sizeof(uint32_t name_len, uint32_t expr_str_len,
> +			 uint32_t *name_offset, uint32_t *expr_str_offset)
> +{
> +	*name_offset = sizeof(struct ck_constraint_def);
> +	*expr_str_offset = *name_offset + name_len + 1;
> +	return *expr_str_offset + expr_str_len + 1;
> +}
> diff --git a/src/box/schema_def.h b/src/box/schema_def.h
> index dea3fad19..317e6b51f 100644
> --- a/src/box/schema_def.h
> +++ b/src/box/schema_def.h
> @@ -108,6 +108,8 @@ enum {
>  	BOX_SPACE_SEQUENCE_ID = 340,
>  	/** Space id of _fk_constraint. */
>  	BOX_FK_CONSTRAINT_ID = 356,
> +	/** Space id of _ck_contraint. */
> +	BOX_CK_CONSTRAINT_ID = 357,

5. Please, leave a gap after BOX_FK_CONSTRAINT_ID. We keep
gaps to be able in future to add a view space, and to choose
recovery order. Gap is typically 7 unused IDs. The new ID
should be 364.

>  	/** End of the reserved range of system spaces. */
>  	BOX_SYSTEM_ID_MAX = 511,
>  	BOX_ID_NIL = 2147483647
> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> index 91b977de2..a3b11531f 100644
> --- a/src/box/sql/build.c
> +++ b/src/box/sql/build.c
> @@ -638,40 +640,116 @@ primary_key_exit:
>  	return;
>  }
>  
> +/**
> + * Prepare a 0-terminated string in the wptr memory buffer that
> + * does not contain a sequence of more than one whatespace
> + * character. Routine enforces ' ' (space) as whitespace
> + * delimiter. When character ' or " was met, the sting is copied
> + * without any changes until the next (corres) ' or " .

6. What is 'corres'?

> + * The wptr buffer is expected to have str_len + 1 bytes
> + * (this is the expected scenario where no extra whitespace
> + * characters preset in the source string).

7. What is 'characters preset'?

> + * @param wptr The destination memory buffer of size
> + *             @a str_len + 1.
> + * @param str The source string to be copied.
> + * @param str_len The source string @a str length.
> + */
> +static void
> +trim_space_snprintf(char *wptr, const char *str, uint32_t str_len)
> @@ -1416,6 +1529,37 @@ vdbe_emit_fk_constraint_drop(struct Parse *parse_context, char *constraint_name,
>  	sqlReleaseTempRange(parse_context, key_reg, 3);
>  }
>  
> +/**
> + * Generate VDBE program to remove entry from _ck_constraint space.
> + *
> + * @param parser Parsing context.
> + * @param ck_name Name of CK constraint to be dropped.
> + * @param child_id Id of table which constraint belongs to.

8. There is no parameter 'child_id'.

> + */
> +static void
> +vdbe_emit_ck_constraint_drop(struct Parse *parser, const char *ck_name,
> +			     uint32_t space_id)
> diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
> index f241b8d52..e93dfe751 100644
> --- a/src/box/sql/parse.y
> +++ b/src/box/sql/parse.y
> @@ -297,7 +297,7 @@ ccons ::= check_constraint_def .
>  
>  check_constraint_def ::= cconsname(N) CHECK LP expr(X) RP. {
>    create_ck_def_init(&pParse->create_ck_def, &N, &X);
> -  sql_add_check_constraint(pParse);
> +  sql_create_check_contraint(pParse);

9. What was a motivation of this rename? As I understand,
we can add many CHECK constraints in one CREATE TABLE. We
do not 'create' one single CHECK, we add multiple ones. Please,
keep the old name.

>  }
>  
>  ccons ::= cconsname(N) REFERENCES nm(T) eidlist_opt(TA) matcharg(M) refargs(R). {
> diff --git a/test/sql/checks.result b/test/sql/checks.result
> index f7cddec43..5f0098e23 100644
> --- a/test/sql/checks.result
> +++ b/test/sql/checks.result
> @@ -30,89 +32,216 @@ t = {513, 1, 'test', 'memtx', 0, opts, format}
> -s = box.space._space:insert(t)
> +-- Pass integer instead of expression.
> +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 666})
> +---
> +- error: 'Tuple field 5 type does not match one required by operation: expected string'
> +...
> +-- Defered CK constraints are not supported.

10. 'Defered' word does not exist, use 'deferred'.
'Unexistent' word does not exist as well. Non-existent is better.

> +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', true, 'SQL', 'X<5'})
> +---
> +- error: Tarantool does not support deferred ck constraints
> +...
> +-- The only supperted language is SQL.

11. 'Supperted' word does not exist.

> +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'LUA', 'X<5'})
> +---
> +- error: Unsupported language 'LUA' specified for function 'CK_CONSTRAINT_01'
> +...

> ...

> +---
> +...
> +box.execute("CREATE TABLE T2(ID INT PRIMARY KEY, CONSTRAINT CK1 CHECK(ID > 0), CONSTRAINT CK1 CHECK(ID < 0))")
> +---
> +- error: Duplicate key exists in unique index 'primary' in space '_ck_constraint'

12. The error is not ok. It should not expose any system details like
_ck_constraint space. Please, check duplicate names before an insertion.

> +...
> +box.space._ck_constraint:select()
> +---
> +- []
>  ...

  reply	other threads:[~2019-05-26 12:06 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-23 10:19 [tarantool-patches] [PATCH v5 0/6] box: run checks on insertions in LUA spaces Kirill Shcherbatov
2019-05-23 10:19 ` [tarantool-patches] [PATCH v5 1/6] sql: introduce a new method to bind a pointer Kirill Shcherbatov
2019-05-23 10:19 ` [tarantool-patches] [PATCH v5 2/6] sql: refactor OP_Column vdbe instruction Kirill Shcherbatov
2019-05-23 10:19 ` [tarantool-patches] [PATCH v5 3/6] sql: introduce tuple_fetcher class Kirill Shcherbatov
2019-05-26 12:05   ` [tarantool-patches] " Vladislav Shpilevoy
2019-05-31 13:45     ` Kirill Shcherbatov
2019-05-31 19:45       ` Konstantin Osipov
2019-05-31 19:50         ` Kirill Shcherbatov
2019-05-31 22:36         ` Vladislav Shpilevoy
2019-06-01  5:45           ` Konstantin Osipov
2019-06-02 18:50         ` Kirill Shcherbatov
2019-06-03 21:15           ` Vladislav Shpilevoy
2019-06-05  6:47           ` Konstantin Osipov
2019-06-05  6:48             ` Konstantin Osipov
2019-05-23 10:19 ` [tarantool-patches] [PATCH v5 4/6] schema: add new system space for CHECK constraints Kirill Shcherbatov
2019-05-26 12:06   ` Vladislav Shpilevoy [this message]
2019-05-26 13:31     ` [tarantool-patches] " n.pettik
2019-05-26 13:32       ` Vladislav Shpilevoy
2019-05-31 13:45     ` Kirill Shcherbatov
2019-06-03 21:15       ` Vladislav Shpilevoy
2019-05-23 10:19 ` [tarantool-patches] [PATCH v5 5/6] box: run check constraint tests on space alter Kirill Shcherbatov
2019-05-26 12:07   ` [tarantool-patches] " Vladislav Shpilevoy
2019-05-31 13:45     ` Kirill Shcherbatov
2019-06-03 21:15       ` Vladislav Shpilevoy
2019-05-23 10:19 ` [tarantool-patches] [PATCH v5 6/6] box: user-friendly interface to manage ck constraints Kirill Shcherbatov
2019-05-26 12:07   ` [tarantool-patches] " Vladislav Shpilevoy
2019-05-31 13:45     ` Kirill Shcherbatov
2019-06-03 21:15 ` [tarantool-patches] Re: [PATCH v5 0/6] box: run checks on insertions in LUA spaces Vladislav Shpilevoy
2019-06-04  7:21   ` Kirill Shcherbatov
2019-06-04 18:59     ` Vladislav Shpilevoy
2019-06-06 11:58 ` Kirill Yukhin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c48a4885-faa3-77b0-f2e8-69c4e24a43f9@tarantool.org \
    --to=v.shpilevoy@tarantool.org \
    --cc=kshcherbatov@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --subject='[tarantool-patches] Re: [PATCH v5 4/6] schema: add new system space for CHECK constraints' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox