{"id":1315,"date":"2009-09-17T07:42:53","date_gmt":"2009-09-17T05:42:53","guid":{"rendered":"http:\/\/code.openark.org\/blog\/?p=1315"},"modified":"2009-09-17T07:42:53","modified_gmt":"2009-09-17T05:42:53","slug":"on-user-variables-evaluation-order","status":"publish","type":"post","link":"https:\/\/code.openark.org\/blog\/mysql\/on-user-variables-evaluation-order","title":{"rendered":"On user variables evaluation order"},"content":{"rendered":"<p>There is something very unclear about what is defined and is undefined with regard to the order by which user variables are evaluated, even within the <a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.0\/en\/user-variables.html\">MySQL documentation<\/a> itself.<\/p>\n<p>I wish to present some examples and draw a conclusion. Since I will following state there&#8217;s missing information, I would greatly appreciate any educated comments.<\/p>\n<h4>The trivial &#8220;reordering problem&#8221; case<\/h4>\n<p>Let&#8217;s look at the following query:<!--more--><\/p>\n<blockquote>\n<pre>mysql&gt; SET @a := 0;\r\nQuery OK, 0 rows affected (0.00 sec)\r\n\r\nmysql&gt; SET @b := 0;\r\nQuery OK, 0 rows affected (0.00 sec)\r\n\r\nmysql&gt; SELECT @a:=@b+1, @b:=@a FROM mysql.user;\r\n+----------+--------+\r\n| @a:=@b+1 | @b:=@a |\r\n+----------+--------+\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 1 |\u00a0\u00a0\u00a0\u00a0\u00a0 1 |\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2 |\u00a0\u00a0\u00a0\u00a0\u00a0 2 |\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 3 |\u00a0\u00a0\u00a0\u00a0\u00a0 3 |\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4 |\u00a0\u00a0\u00a0\u00a0\u00a0 4 |\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 5 |\u00a0\u00a0\u00a0\u00a0\u00a0 5 |\r\n+----------+--------+\r\n5 rows in set (0.04 sec)<\/pre>\n<\/blockquote>\n<p>According to the docs, I can&#8217;t rely on the fact that the <strong>@b:=@a<\/strong> part reads the value of <strong>@a<\/strong> after is has incremented, So I may eventually end up with:<\/p>\n<blockquote>\n<pre>+----------+--------+\r\n| @a:=@b+1 | @b:=@a |\r\n+----------+--------+\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 1 |\u00a0\u00a0\u00a0\u00a0\u00a0 0 |\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2 |\u00a0\u00a0\u00a0\u00a0\u00a0 1 |\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 3 |\u00a0\u00a0\u00a0\u00a0\u00a0 2 |\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4 |\u00a0\u00a0\u00a0\u00a0\u00a0 3 |\r\n|\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 5 |\u00a0\u00a0\u00a0\u00a0\u00a0 4 |\r\n+----------+--------+<\/pre>\n<\/blockquote>\n<p>I wish to follow the documentation and see about other cases.<\/p>\n<h4>The trivial &#8220;trivial&#8221; case<\/h4>\n<p>Quoting the MySQL documentation (<a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.0\/en\/user-variables.html\">8.4. User-Defined Variables<\/a>):<\/p>\n<blockquote><p>&#8230;The general rule is never to assign a value to a user variable in       one part of a statement <span><em>and<\/em><\/span> use the same       variable in some <strong>other part<\/strong> of the same statement. &#8230;<\/p><\/blockquote>\n<p>How does the above quote (focus on <strong>bold<\/strong> text) from the manual apply to the trivial:<\/p>\n<blockquote>\n<pre>SET @a := 0;\r\nSELECT *, @a := @a+1 FROM mysql.user;<\/pre>\n<\/blockquote>\n<p>We&#8217;ve just used\/read the value of <strong>@a<\/strong>, and have assigned it a new value <strong>(@a+1)<\/strong> at the same statement. What&#8217;s an <strong>other part<\/strong>? Is this considered to be the <strong>same part<\/strong> just because it&#8217;s the same column in the result set?<\/p>\n<p>Let&#8217;s complicate this further:<\/p>\n<h4>A complicated case<\/h4>\n<p>Quoting the manual again, we see:<\/p>\n<blockquote>\n<pre>mysql&gt; <strong><code>SET @t1=0, @t2=0, @t3=0;<\/code><\/strong>\r\nmysql&gt; <strong><code>SELECT @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3;<\/code><\/strong>\r\n+----------------------+------+------+------+\r\n| @t1:=(@t2:=1)+@t3:=4 | @t1  | @t2  | @t3  |\r\n+----------------------+------+------+------+\r\n|                    5 |    5 |    1 |    4 |\r\n+----------------------+------+------+------+<\/pre>\n<\/blockquote>\n<p>What&#8217;s going on here? Haven&#8217;t we been told not to assign and use the same variable in the same statement? <strong>@t1<\/strong> has been assigned in the first part, then has been used in the second (according to the documentation itself, we could have got <em>&#8216;0&#8217;<\/em> for <strong>@t1<\/strong>, second column). But I&#8217;m not keen on ranting, look further:<\/p>\n<p>Looking at the first part of the statement: <strong>@t1:=(@t2:=1)+@t3:=4<\/strong>, what promises do I get here?<\/p>\n<ul>\n<li>Does the use of brackets <em>ensure<\/em> that <strong>@t2<\/strong> is evaluated before <strong>@t1<\/strong>?<\/li>\n<li>Does the use of brackets <em>ensure<\/em> that <strong>@t3<\/strong> is evaluated before <strong>@t1<\/strong>?<\/li>\n<li>Does the order of expression tokens <em>ensure<\/em> that <strong>@t2<\/strong> is evaluated before <strong>@t3<\/strong> is assigned?<\/li>\n<\/ul>\n<p>I think the answer to the above is &#8216;yes&#8217; to all. But I can&#8217;t verify this using the text. The reasons I think all answer &#8216;yes&#8217; are:<\/p>\n<ul>\n<li>This all happens in only one part of the statement (ignoring the use of <strong>@t1<\/strong>, <strong>@t2<\/strong>, <strong>@t3<\/strong> later on).<\/li>\n<li>Experience verifies it is so.<\/li>\n<li>I don&#8217;t see how <strong>ORDER BY<\/strong>, <strong>GROUP BY<\/strong>, <strong>HAVING<\/strong> (choosing examples from the docs) will change this: my understanding is that it all relates to column computation, and here this is a single column.<\/li>\n<\/ul>\n<h4>Drawing a conclusion<\/h4>\n<p>If the above is correct, and within the same part of the statement the use of brackets can dictate ordering of assignments, then we can workaround many problems arising from the danger of assigning and reading variables in the same statement.<\/p>\n<p>If, in addition, the ordering of the tokens in the expression guarantees execution order within that part of statement, then the workaround does not need to be too ugly.<\/p>\n<p>Using such expressions as <strong>COALESCE(@a := 1, @b := @a+1, &#8230;)<\/strong> or otherwise using <strong>IF<\/strong>\/<strong>CASE<\/strong>\/other tricks, we can perform as many assignments as we wish within the <strong>same part<\/strong> of the statement.<\/p>\n<p>Looking back at <a title=\"Link to SQL: Ranking without self join\" rel=\"bookmark\" href=\"http:\/\/code.openark.org\/blog\/mysql\/sql-ranking-without-self-join\">SQL: Ranking without self join<\/a>, the solution can be fixed, if the answers to the above are correct.<\/p>\n<p>The use of user variables is not a child&#8217;s play; it can help solving problems with great speed, and small memory footprint. I think this issue is a little too obscurred. I call for clarifications.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There is something very unclear about what is defined and is undefined with regard to the order by which user variables are evaluated, even within the MySQL documentation itself. I wish to present some examples and draw a conclusion. Since I will following state there&#8217;s missing information, I would greatly appreciate any educated comments. The [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"enabled":false},"version":2}},"categories":[5],"tags":[],"class_list":["post-1315","post","type-post","status-publish","format-standard","hentry","category-mysql"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2bZZp-ld","_links":{"self":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/1315","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/comments?post=1315"}],"version-history":[{"count":12,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/1315\/revisions"}],"predecessor-version":[{"id":1327,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/1315\/revisions\/1327"}],"wp:attachment":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/media?parent=1315"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/categories?post=1315"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/tags?post=1315"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}