Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expression: handle max_allowed_packet warnings for to_base64 function. #7266

Merged
merged 17 commits into from
Aug 15, 2018

Conversation

supernan1994
Copy link
Contributor

@supernan1994 supernan1994 commented Aug 2, 2018

What have you changed? (mandatory)

Return NULL and a warning when the result of to_base64 exceeds max_allowed_packetbs.
Before this PR:

mysql> show variables like 'max_allowed_packet';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| max_allowed_packet | 3    |
+--------------------+-------+
1 row in set (0.01 sec)

mysql> select to_base64("abc");
+------------------+
| to_base64("abc") |
+------------------+
| YWJj             |
+------------------+
1 row in set (0.00 sec)

After this PR:

mysql> show variables like 'max_allowed_packet';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| max_allowed_packet | 3    |
+--------------------+-------+
1 row in set (0.01 sec)

mysql> select to_base64("abc");
+------------------+
| to_base64("abc") |
+------------------+
| NULL             |
+------------------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+--------------------------------------------------------------------------+
| Level   | Code | Message                                                                  |
+---------+------+--------------------------------------------------------------------------+
| Warning | 1301 | Result of to_base64() was larger than max_allowed_packet (3) - truncated |
+---------+------+--------------------------------------------------------------------------+
1 row in set (0.00 sec)

This PR calculates length of to_base64 result by function base64NeededEncodedLength before executing core of to_base64 logic, and compares length with global variable max_allowed_packet.
unit tests are added for covering three circumstances:

  1. result hasn't line feed
  2. result has line feed, last few characters of result were filled with =
  3. result has many line feed

What is the type of the changes? (mandatory)

  • Bug fix (non-breaking change which fixes an issue)

How has this PR been tested? (mandatory)

  • unit test
  • explain test
  • manual test

Does this PR affect documentation (docs/docs-cn) update? (mandatory)

no

Does this PR affect tidb-ansible update? (mandatory)

no

Does this PR need to be added to the release notes? (mandatory)

Yes
Please note:

Return `NULL` when the result of function `TO_BASE64` is larger than `max_allowed_packet`

Refer to a related PR or issue link (optional)

to #7153

Benchmark result if necessary (optional)

Add a few positive/negative examples (optional)

@sre-bot
Copy link
Contributor

sre-bot commented Aug 2, 2018

Hi contributor, thanks for your PR.

This patch needs to be approved by someone of admins. They should reply with "/ok-to-test" to accept this PR for running test automatically.

@CLAassistant
Copy link

CLAassistant commented Aug 2, 2018

CLA assistant check
All committers have signed the CLA.

@ciscoxll ciscoxll added the contribution This PR is from a community contributor. label Aug 2, 2018
@@ -3044,6 +3055,10 @@ func (b *builtinToBase64Sig) evalString(row chunk.Row) (d string, isNull bool, e
return "", isNull, errors.Trace(err)
}

if b.tp.Flen*mysql.MaxBytesOfCharacter > int(b.maxAllowedPacket) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not correct to use Flen to decide whether the result of ToBase64 exceeds max_allowed_packet, I think we can learn from MySQL:

String *Item_func_to_base64::val_str_ascii(String *str) {
  String *res = args[0]->val_str(str);
  bool too_long = false;
  uint64 length;
  if (!res || res->length() > (uint)base64_encode_max_arg_length() ||
      (too_long =
           ((length = base64_needed_encoded_length((uint64)res->length())) >
            current_thd->variables.max_allowed_packet)) ||
      tmp_value.alloc((uint)length)) {
    null_value = 1;  // NULL input, too long input, or OOM.
    if (too_long) {
      push_warning_printf(
          current_thd, Sql_condition::SL_WARNING,
          ER_WARN_ALLOWED_PACKET_OVERFLOWED,
          ER_THD(current_thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
          current_thd->variables.max_allowed_packet);
    }
    return 0;
  }
  base64_encode(res->ptr(), (int)res->length(), (char *)tmp_value.ptr());
  DBUG_ASSERT(length > 0);
  tmp_value.length((uint)length - 1);  // Without trailing '\0'
  null_value = 0;
  return &tmp_value;
}

The above code is taken from: https://github.com/mysql/mysql-server/blob/5.7/sql/item_strfunc.cc#L690

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, thanks, I will correct it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @supernan1994 any update?

Copy link
Contributor Author

@supernan1994 supernan1994 Aug 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry!!! I had a bussiness trip and was back yesterday, I will take a look at it tonight and tomorrow night @zz-jason

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😄 take your time, it's just a just a friendly Ping

input := chunk.NewChunkWithCapacity(colTypes, 1)
input.AppendString(0, test.args)
res, isNull, err := toBase64.evalString(input.GetRow(0))
if test.getErr {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all the added test.getErr is false, maybe this check can be replaced with: c.Assert(err, IsNil)

c.Assert(res, Equals, test.expect)
}
warnings := s.ctx.GetSessionVars().StmtCtx.GetWarnings()
c.Assert(len(warnings), Equals, warningCount)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warningCount is always zero, seems the test of max_allowed_packets is not working

c.Assert(err, IsNil)
if test.isNil {
c.Assert(isNull, IsTrue)
warningCount += 1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warningCount will add 1 when to_base64 result is nil

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we reset the warning appended to s.ctx.GetSessionVars().StmtCtx and check the exactly warning count and warning content in each test case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@supernan1994
Copy link
Contributor Author

It seems travis ci failed because of temporary network problem

go get github.com/etcd-io/gofail
# cd .; git clone https://github.com/etcd-io/gofail /home/travis/gopath/src/github.com/etcd-io/gofail
Cloning into '/home/travis/gopath/src/github.com/etcd-io/gofail'...
fatal: unable to access 'https://github.com/etcd-io/gofail/': GnuTLS recv error (-9): A TLS packet with unexpected length was received.
package github.com/etcd-io/gofail: exit status 128
make: *** [gotest] Error 1

The command "make dev" exited with 2.

Done. Your build exited with 1.

@zz-jason
Copy link
Member

@supernan1994 re-triggered

Copy link
Member

@zz-jason zz-jason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 1 of 2 files at r2, 1 of 1 files at r4.
Reviewable status: all files reviewed, 4 unresolved discussions (waiting on @supernan1994 and @zz-jason)

@zz-jason zz-jason added the status/LGT1 Indicates that a PR has LGTM 1. label Aug 10, 2018
@zz-jason
Copy link
Member

/run-all-tests

2 similar comments
@supernan1994
Copy link
Contributor Author

/run-all-tests

@supernan1994
Copy link
Contributor Author

/run-all-tests

@supernan1994
Copy link
Contributor Author

/run-all-tests

@zz-jason
Copy link
Member

@XuHuaiyu PTAL

Copy link
Contributor

@crazycs520 crazycs520 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@crazycs520 crazycs520 added status/LGT2 Indicates that a PR has LGTM 2. and removed status/LGT1 Indicates that a PR has LGTM 1. labels Aug 14, 2018
@zz-jason zz-jason merged commit 016006f into pingcap:master Aug 15, 2018
@zz-jason
Copy link
Member

@supernan1994 It would be nice if you can cherry-pick this PR to the release-2.0 branch 😄

@supernan1994
Copy link
Contributor Author

@zz-jason OK!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component/expression contribution This PR is from a community contributor. status/LGT2 Indicates that a PR has LGTM 2. type/compatibility
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants