Tarantool development patches archive
 help / color / mirror / Atom feed
From: Nikita Pettik <korablev@tarantool.org>
To: Roman Khabibov <roman.habibov@tarantool.org>
Cc: tarantool-patches@freelists.org
Subject: [tarantool-patches] Re: [PATCH] sql: add check for <WITH> absence in <CREATE VIEW>
Date: Thu, 29 Aug 2019 20:59:55 +0300	[thread overview]
Message-ID: <20190829175955.GA52650@tarantool.org> (raw)
In-Reply-To: <1B494CAB-704F-4A62-A00D-257388DDB2B8@tarantool.org>

On Wed, Aug 28, 2019 at 03:17:41PM +0300, Roman Khabibov wrote:
> 
> > On Aug 20, 2019, at 22:41, n.pettik <korablev@tarantool.org> wrote:
> > You slightly misunderstood me. I proposed to allow such queries
> > gracefully handling WITH statement and avoiding references
> > counter incrementation for CTEs.
> 
> commit 202677704c455208d6def08d373776cfae82fdbe
> Author: Roman Khabibov <roman.habibov@tarantool.org>
> Date:   Mon Jul 29 18:00:34 2019 +0300
> 
>     sql: allow to create view as <WITH> clause
>     
>     Allow views to use CTEs in <WITH> clauses, which can be in any
>     (nested) select after <AS>.

Please, provide decent commit message which would include problem
explanation, chosen solution, some of implementation details.

> diff --git a/src/box/alter.cc b/src/box/alter.cc
> index 92f1d5b22..d3d6770cf 100644
> --- a/src/box/alter.cc
> +++ b/src/box/alter.cc
> @@ -1721,6 +1721,8 @@ update_view_references(struct Select *select, int update_value,
>  		const char *space_name = sql_src_list_entry_name(list, i);
>  		if (space_name == NULL)
>  			continue;
> +		if (is_cte(select, space_name) == true)
> +			continue;

If function returns boolean value, you don't need to use comparison
to check it:

'if (returns_boolean()) ...' or 'if (! returns_boolean()) ...'

Also, put comment explaining why do you skip reference counter
increment in case of SELECT containts CTE.

> diff --git a/src/box/sql.h b/src/box/sql.h
> index 9ccecf28c..c180e40e1 100644
> --- a/src/box/sql.h
> +++ b/src/box/sql.h
> @@ -323,6 +323,17 @@ sql_select_delete(struct sql *db, struct Select *select);
>  struct SrcList *
>  sql_select_expand_from_tables(struct Select *select);
>  
> +/**
> + * Check if @a name matches with at least one of CTE names typed
> + * in <WITH> clauses within @a select.
> + *
> + * @param select Select to be checked.

-> Select which may contain CTE.

> + * @retval true Has CTE with @a name.
> + * @retval false Hasn't CTE with @a name.
> +*/
> +bool
> +is_cte(struct Select *select, const char *name);
> +
>  /**
>   * Temporary getter in order to avoid including sqlInt.h
>   * in alter.cc.
> diff --git a/src/box/sql/select.c b/src/box/sql/select.c
> index c312f61f1..0ee840b89 100644
> --- a/src/box/sql/select.c
> +++ b/src/box/sql/select.c
> @@ -332,6 +332,25 @@ sql_select_expand_from_tables(struct Select *select)
>  	return walker.u.pSrcList;
>  }
>  
> +bool
> +is_cte(struct Select *select, const char *name)

Such a bad name. Please, get in touch with our naming policy
and come up with better one.

> +{
> +	assert(select != NULL && name != NULL);
> +	struct With *with = select->pWith;
> +	if (with != NULL) {
> +		if (memcmp(name, with->a->zName, strlen(name)) == 0)
> +			return true;
> +	}
> +	struct SrcList *list = select->pSrc;
> +	int item_count = sql_src_list_entry_count(list);
> +	for (int i = 0; i < item_count; ++i) {
> +		if (list->a[i].pSelect != NULL)
> +			if (is_cte(list->a[i].pSelect, name) == true)
> +				return true;
> +	}

It's wrong way of CTE traversal. See sqlTreeViewWith() for correct
implementation. With your approach this example still fails:

create view v as WITH RECURSIVE
  xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+0.05 FROM xaxis WHERE x<1.2),
  yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+0.1 FROM yaxis WHERE y<1.0),
  m(iter, cx, cy, x, y) AS (
    SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis
    UNION ALL
    SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m 
     WHERE (x*x + y*y) < 4.0 AND iter<28
  ),
  m2(iter, cx, cy) AS (
    SELECT max(iter), cx, cy FROM m GROUP BY cx, cy
  ),
  a(t) AS (
    SELECT group_concat( substr(' .+*#', 1+least(iter/7,4), 1), '') 
    FROM m2 GROUP BY cy
  )
SELECT group_concat(trim(t),x'0a') FROM a;

> diff --git a/test/sql-tap/view.test.lua b/test/sql-tap/view.test.lua
> index 101f4c3e7..4b695fa6a 100755
> --- a/test/sql-tap/view.test.lua
> +++ b/test/sql-tap/view.test.lua
> @@ -1233,4 +1233,99 @@ test:do_catchsql_test(
>          -- </view-23.8>
>      })
>  
> +-- gh-4149: Check error message for view creation with (nested)
> +-- select with <WITH> clause.

-> gh-4149: make sure that VIEW can be created as CTE.

> +test:do_execsql_test(
> +    "view-24.1",
> +    [[
> +        CREATE TABLE ts (s1 INT PRIMARY KEY);
> +        INSERT INTO ts VALUES (1);
> +    ]], {
> +        -- <view-24.1>
> +        -- </view-24.1>
> +    })
> +
> +test:do_execsql_test(
> +    "view-24.2",
> +    [[
> +        CREATE VIEW v AS WITH w(id) AS (
> +            SELECT 1)
> +          SELECT * FROM ts;
> +    ]], {

Please test not only the fact that view can be created, but also that
it is queryable (i.e. SELECT * FROM v is processed without accidents).

> +        -- <view-24.2>
> +        -- </view-24.2>
> +    })
> 

All examples below are almost identical since nCte for them equals to 1.

> +test:do_execsql_test(
> +    "view-24.3",
> +    [[
> +        DROP VIEW v;
> +        CREATE VIEW v AS WITH RECURSIVE w AS (
> +            SELECT s1 FROM ts
> +            UNION ALL
> +            SELECT s1+1 FROM w WHERE s1 < 4)
> +          SELECT * FROM w;
> +    ]], {
> +        -- <view-24.3>
> +        -- </view-24.3>
> +    })
> +
> +test:do_execsql_test(
> +    "view-24.4",
> +    [[
> +        DROP VIEW v;
> +        CREATE VIEW v AS SELECT * FROM (
> +            WITH RECURSIVE w AS (
> +                SELECT s1 FROM ts
> +                UNION ALL
> +                SELECT s1+1 FROM w WHERE s1 < 4)
> +              SELECT * FROM w);
> +    ]], {
> +        -- <view-24.4>
> +        -- </view-24.4>
> +    })
> +
> +test:do_execsql_test(
> +    "view-24.5",
> +    [[
> +        DROP VIEW v;
> +        CREATE VIEW v AS SELECT * FROM (
> +            SELECT * FROM (
> +                WITH RECURSIVE w AS (
> +                    SELECT s1 FROM ts
> +                    UNION ALL
> +                    SELECT s1+1 FROM w WHERE s1 < 4)
> +                  SELECT * FROM w));
> +    ]], {
> +        -- <view-24.5>
> +        -- </view-24.5>
> +    })
> +
> +test:do_execsql_test(
> +    "view-24.6",
> +    [[
> +        DROP VIEW v;
> +        CREATE VIEW v AS SELECT * FROM
> +            (SELECT 1),
> +            (SELECT 2) JOIN
> +            (WITH RECURSIVE w AS (
> +                SELECT s1 FROM ts
> +                UNION ALL
> +                SELECT s1+1 FROM w WHERE s1 < 4)
> +                SELECT * FROM w);
> +    ]], {
> +        -- <view-24.6>
> +        -- </view-24.6>
> +    })
> +
> +test:do_execsql_test(
> +    "view-24.7",
> +    [[
> +        DROP VIEW v;
> +        DROP TABLE ts;

You don't have to provide clean-up in SQL-tap suite.

  reply	other threads:[~2019-08-29 17:59 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-02 12:52 [tarantool-patches] " Roman Khabibov
2019-08-09 15:15 ` [tarantool-patches] " n.pettik
2019-08-13 12:42   ` Roman Khabibov
2019-08-13 22:10     ` n.pettik
2019-08-16 19:09       ` Roman Khabibov
2019-08-19 15:39         ` Roman Khabibov
2019-08-20 19:41         ` n.pettik
2019-08-28 12:17           ` Roman Khabibov
2019-08-29 17:59             ` Nikita Pettik [this message]
2019-09-04 14:14               ` Roman Khabibov
2019-09-11 13:32                 ` Nikita Pettik
2019-09-13 14:57                   ` Roman Khabibov

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=20190829175955.GA52650@tarantool.org \
    --to=korablev@tarantool.org \
    --cc=roman.habibov@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --subject='[tarantool-patches] Re: [PATCH] sql: add check for <WITH> absence in <CREATE VIEW>' \
    /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