Repository: vitessio/vitess
Pull request #11659 (2022-11-08 06:58:25)

build(deps): Bump loader-utils from 1.4.0 to 1.4.1 in /web/vtadmin
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/webpack/loader-utils/releases">loader-utils's releases</a>.</em></p>
<blockquote>
<h2>v1.4.1</h2>
<h3><a href="https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.1">1.4.1</a> (2022-11-07)</h3>
<h3>Bug Fixes</h3>
<ul>
<li>security problem (<a href="https://github-redirect.dependabot.com/webpack/loader-utils/issues/220">#220</a>) (<a href="https://github.com/webpack/loader-utils/commit/4504e34c4796a5836ef70458327351675aed48a5">4504e34</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/webpack/loader-utils/blob/v1.4.1/CHANGELOG.md">loader-utils's changelog</a>.</em></p>
<blockquote>
<h3><a href="https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.1">1.4.1</a> (2022-11-07)</h3>
<h3>Bug Fixes</h3>
<ul>
<li>security problem (<a href="https://github-redirect.dependabot.com/webpack/loader-utils/issues/220">#220</a>) (<a href="https://github.com/webpack/loader-utils/commit/4504e34c4796a5836ef70458327351675aed48a5">4504e34</a>)</li>
</ul>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/webpack/loader-utils/commit/8f082b39f6903929f30fe29dab34f4d9c7ef070a"><code>8f082b3</code></a> chore(release): 1.4.1</li>
<li><a href="https://github.com/webpack/loader-utils/commit/4504e34c4796a5836ef70458327351675aed48a5"><code>4504e34</code></a> fix: security problem (<a href="https://github-redirect.dependabot.com/webpack/loader-utils/issues/220">#220</a>)</li>
<li>See full diff in <a href="https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.1">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=loader-utils&package-manager=npm_and_yarn&previous-version=1.4.0&new-version=1.4.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/vitessio/vitess/network/alerts).

</details>

vitess-bot[bot]: ### Review Checklist
            
Hello reviewers! :wave: Please follow this checklist when reviewing this Pull Request.

#### General
- [ ] Ensure that the Pull Request has a descriptive title.
- [ ] If this is a change that users need to know about, please apply the `release notes (needs details)` label so that merging is blocked unless the summary release notes document is included.

#### If a new flag is being introduced:
- [ ] Is it really necessary to add this flag?
- [ ] Flag names should be clear and intuitive (as far as possible)
- [ ] Help text should be descriptive.
- [ ] Flag names should use dashes (`-`) as word separators rather than underscores (`_`).

#### If a workflow is added or modified:
- [ ] Each item in `Jobs` should be named in order to mark it as `required`.
- [ ] If the workflow should be required, the maintainer team should be notified.

#### Bug fixes
- [ ] There should be at least one unit or end-to-end test.
- [ ] The Pull Request description should include a link to an issue that describes the bug.

#### Non-trivial changes
- [ ] There should be some code comments as to why things are implemented the way they are.

#### New/Existing features
- [ ] Should be documented, either by modifying the existing documentation or creating new documentation.
- [ ] New features should have a link to a feature request issue or an RFC that documents the use cases, corner cases and test cases.

#### Backward compatibility            
- [ ] Protobuf changes should be wire-compatible.
- [ ] Changes to `_vt` tables and RPCs need to be backward compatible.
- [ ] `vtctl` command output order should be stable and `awk`-able.
- [ ] RPC changes should be compatible with vitess-operator
- [ ] If a flag is removed, then it should also be removed from VTop, if used there.


Patch:
diff --git a/doc/releasenotes/14_0_0_release_notes.md b/doc/releasenotes/14_0_0_release_notes.md
index 50d02232ae..a7b4bcf4ef 100644
--- a/doc/releasenotes/14_0_0_release_notes.md
+++ b/doc/releasenotes/14_0_0_release_notes.md
@@ -18,6 +18,7 @@
 ## Known Issues
 
 - [VTOrc doesn't discover the tablets](https://github.com/vitessio/vitess/issues/10650) of a keyspace if the durability policy doesn't exist in the topo server when it comes up. This can be resolved by restarting VTOrc.
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
 
 ## Major Changes
 
diff --git a/doc/releasenotes/14_0_0_summary.md b/doc/releasenotes/14_0_0_summary.md
index e02c9d9a28..6047ec7ec1 100644
--- a/doc/releasenotes/14_0_0_summary.md
+++ b/doc/releasenotes/14_0_0_summary.md
@@ -17,6 +17,7 @@
 ## Known Issues
 
 - [VTOrc doesn't discover the tablets](https://github.com/vitessio/vitess/issues/10650) of a keyspace if the durability policy doesn't exist in the topo server when it comes up. This can be resolved by restarting VTOrc.
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
 
 ## Major Changes
 
diff --git a/doc/releasenotes/14_0_1_release_notes.md b/doc/releasenotes/14_0_1_release_notes.md
index 7215301939..57d68be31c 100644
--- a/doc/releasenotes/14_0_1_release_notes.md
+++ b/doc/releasenotes/14_0_1_release_notes.md
@@ -1,4 +1,8 @@
 # Release of Vitess v14.0.1
+## Known Issues
+
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
+
 ## Major Changes
 
 ### Upgrade to `go1.18.4`
diff --git a/doc/releasenotes/14_0_1_summary.md b/doc/releasenotes/14_0_1_summary.md
index 1f2f985bab..5a176b6af1 100644
--- a/doc/releasenotes/14_0_1_summary.md
+++ b/doc/releasenotes/14_0_1_summary.md
@@ -1,3 +1,7 @@
+## Known Issues
+
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
+
 ## Major Changes
 
 ### Upgrade to `go1.18.4`
diff --git a/doc/releasenotes/14_0_2_release_notes.md b/doc/releasenotes/14_0_2_release_notes.md
index 956ca21ef6..d83b940f45 100644
--- a/doc/releasenotes/14_0_2_release_notes.md
+++ b/doc/releasenotes/14_0_2_release_notes.md
@@ -1,4 +1,8 @@
 # Release of Vitess v14.0.2
+## Known Issues
+
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
+
 ## Major Changes
 
 ### Upgrade to `go1.18.5`
diff --git a/doc/releasenotes/14_0_2_summary.md b/doc/releasenotes/14_0_2_summary.md
index 05a1aac5d6..8b26887dd0 100644
--- a/doc/releasenotes/14_0_2_summary.md
+++ b/doc/releasenotes/14_0_2_summary.md
@@ -1,3 +1,7 @@
+## Known Issues
+
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
+
 ## Major Changes
 
 ### Upgrade to `go1.18.5`
diff --git a/doc/releasenotes/14_0_3_release_notes.md b/doc/releasenotes/14_0_3_release_notes.md
index d9cd4ac7a6..721c47640e 100644
--- a/doc/releasenotes/14_0_3_release_notes.md
+++ b/doc/releasenotes/14_0_3_release_notes.md
@@ -1,4 +1,8 @@
 # Release of Vitess v14.0.3
+## Known Issues
+
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
+
 ## Major Changes
 
 ### Fix VTOrc Discovery
diff --git a/doc/releasenotes/14_0_3_summary.md b/doc/releasenotes/14_0_3_summary.md
index 9d9364f67b..121d9054a1 100644
--- a/doc/releasenotes/14_0_3_summary.md
+++ b/doc/releasenotes/14_0_3_summary.md
@@ -1,3 +1,7 @@
+## Known Issues
+
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
+
 ## Major Changes
 
 ### Fix VTOrc Discovery
diff --git a/doc/releasenotes/15_0_0_release_notes.md b/doc/releasenotes/15_0_0_release_notes.md
index a67dbb9881..430100fa8f 100644
--- a/doc/releasenotes/15_0_0_release_notes.md
+++ b/doc/releasenotes/15_0_0_release_notes.md
@@ -1,6 +1,7 @@
 # Release of Vitess v15.0.0
 ## Summary
 
+- **[Known Issues](#known-issues)**
 - **[Breaking Changes](#breaking-changes)**
   - [Flags](#flags)
   - [VTTablet Flag Deletions](#vttablet-flag-deletions)
@@ -44,6 +45,10 @@
 - **[Flags Restructure](#flags-restructure)**
   - [Flags Diff](#flags-diff)
 
+## <a id="known-issues"/>Known Issues
+
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
+
 ## Major Changes
 
 ### <a id="breaking-changes"/>Breaking Changes
diff --git a/doc/releasenotes/15_0_0_summary.md b/doc/releasenotes/15_0_0_summary.md
index 069f2c217b..56b784b55d 100644
--- a/doc/releasenotes/15_0_0_summary.md
+++ b/doc/releasenotes/15_0_0_summary.md
@@ -1,5 +1,6 @@
 ## Summary
 
+- **[Known Issues](#known-issues)**
 - **[Breaking Changes](#breaking-changes)**
   - [Flags](#flags)
   - [VTTablet Flag Deletions](#vttablet-flag-deletions)
@@ -43,6 +44,10 @@
 - **[Flags Restructure](#flags-restructure)**
   - [Flags Diff](#flags-diff)
 
+## <a id="known-issues"/>Known Issues
+
+- [Corrupted results for non-full-group-by queries with JOINs](https://github.com/vitessio/vitess/issues/11625). This can be resolved by using full-group-by queries.
+
 ## Major Changes
 
 ### <a id="breaking-changes"/>Breaking Changes
diff --git a/doc/releasenotes/16_0_0_summary.md b/doc/releasenotes/16_0_0_summary.md
index 8347d75b8c..41050fea6f 100644
--- a/doc/releasenotes/16_0_0_summary.md
+++ b/doc/releasenotes/16_0_0_summary.md
@@ -34,6 +34,13 @@ Other aspects of the VReplication copy-phase logic are preserved:
 
  Other phases, catchup, fast-forward, and replicating/"running", are unchanged.
 
+### Important bug fixes
+
+#### Corrupted results for non-full-group-by queries with JOINs
+
+An issue in versions `<= v14.0.3` and `<= v15.0.0` that generated corrupted results for non-full-group-by queries with a JOIN
+is now fixed. The full issue can be found [here](https://github.com/vitessio/vitess/issues/11625), and its fix [here](https://github.com/vitessio/vitess/pull/11633).
+
 ### Deprecations
 
 The V3 planner is deprecated as of the V16 release, and will be removed in the V17 release of Vitess.
diff --git a/go/ioutil2/ioutil.go b/go/ioutil2/ioutil.go
deleted file mode 100644
index 0b2ae7a645..0000000000
--- a/go/ioutil2/ioutil.go
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-Copyright 2019 The Vitess Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Package ioutil2 provides extra functionality along similar lines to io/ioutil.
-package ioutil2
-
-import (
-	"os"
-	"path"
-)
-
-// WriteFileAtomic writes the data to a temp file and atomically move if everything else succeeds.
-func WriteFileAtomic(filename string, data []byte, perm os.FileMode) error {
-	dir, name := path.Split(filename)
-	f, err := os.CreateTemp(dir, name)
-	if err != nil {
-		return err
-	}
-	_, err = f.Write(data)
-	if err == nil {
-		err = f.Sync()
-	}
-	if closeErr := f.Close(); err == nil {
-		err = closeErr
-	}
-	if permErr := os.Chmod(f.Name(), perm); err == nil {
-		err = permErr
-	}
-	if err == nil {
-		err = os.Rename(f.Name(), filename)
-	}
-	// Any err should result in full cleanup.
-	if err != nil {
-		os.Remove(f.Name())
-	}
-	return err
-}
diff --git a/go/sqltypes/value.go b/go/sqltypes/value.go
index 20b8843b4b..cdb1ce9ccb 100644
--- a/go/sqltypes/value.go
+++ b/go/sqltypes/value.go
@@ -73,12 +73,12 @@ type (
 func NewValue(typ querypb.Type, val []byte) (v Value, err error) {
 	switch {
 	case IsSigned(typ):
-		if _, err := strconv.ParseInt(string(val), 0, 64); err != nil {
+		if _, err := strconv.ParseInt(string(val), 10, 64); err != nil {
 			return NULL, err
 		}
 		return MakeTrusted(typ, val), nil
 	case IsUnsigned(typ):
-		if _, err := strconv.ParseUint(string(val), 0, 64); err != nil {
+		if _, err := strconv.ParseUint(string(val), 10, 64); err != nil {
 			return NULL, err
 		}
 		return MakeTrusted(typ, val), nil
diff --git a/go/vt/vtgate/planbuilder/aggregation_pushing.go b/go/vt/vtgate/planbuilder/aggregation_pushing.go
index e677be660b..f6d72d2943 100644
--- a/go/vt/vtgate/planbuilder/aggregation_pushing.go
+++ b/go/vt/vtgate/planbuilder/aggregation_pushing.go
@@ -429,6 +429,10 @@ func isMinOrMax(in engine.AggregateOpcode) bool {
 	}
 }
 
+func isRandom(in engine.AggregateOpcode) bool {
+	return in == engine.AggregateRandom
+}
+
 func splitAggregationsToLeftAndRight(
 	ctx *plancontext.PlanningContext,
 	aggregations []operators.Aggr,
@@ -443,8 +447,8 @@ func splitAggregationsToLeftAndRight(
 		} else {
 			deps := ctx.SemTable.RecursiveDeps(aggr.Original.Expr)
 			var other *operators.Aggr
-			// if we are sending down min/max, we don't have to multiply the results with anything
-			if !isMinOrMax(aggr.OpCode) {
+			// if we are sending down min/max/random, we don't have to multiply the results with anything
+			if !isMinOrMax(aggr.OpCode) && !isRandom(aggr.OpCode) {
 				other = countStarAggr()
 			}
 			switch {
diff --git a/go/vt/vttablet/onlineddl/executor.go b/go/vt/vttablet/onlineddl/executor.go
index 49df47d985..a2ebdb540d 100644
--- a/go/vt/vttablet/onlineddl/executor.go
+++ b/go/vt/vttablet/onlineddl/executor.go
@@ -943,6 +943,53 @@ func (e *Executor) initMigrationSQLMode(ctx context.Context, onlineDDL *schema.O
 	return deferFunc, nil
 }
 
+// newConstraintName generates a new, unique name for a constraint. Our problem is that a MySQL
+// constraint's name is unique in the schema (!). And so as we duplicate the original table, we must
+// create completely new names for all constraints.
+// Moreover, we really want this name to be consistent across all shards. We therefore use a deterministic
+// UUIDv5 (SHA) function over the migration UUID, table name, and constraint's _contents_.
+// We _also_ include the original constraint name as prefix, as room allows
+// for example, if the original constraint name is "check_1",
+// we might generate "check_1_cps1okb4uafunfqusi2lp22u3".
+// If we then again migrate a table whose constraint name is "check_1_cps1okb4uafunfqusi2lp22u3	" we
+// get for example "check_1_19l09s37kbhj4axnzmi10e18k" (hash changes, and we still try to preserve original name)
+//
+// Furthermore, per bug report https://bugs.mysql.com/bug.php?id=107772, if the user doesn't provide a name for
+// their CHECK constraint, then MySQL picks a name in this format <tablename>_chk_<number>.
+// Example: sometable_chk_1
+// Next, when MySQL is asked to RENAME TABLE and sees a constraint with this format, it attempts to rename
+// the constraint with the new table's name. This is problematic for Vitess, because we often rename tables to
+// very long names, such as _vt_HOLD_394f9e6dfc3d11eca0390a43f95f28a3_20220706091048.
+// As we rename the constraint to e.g. `sometable_chk_1_cps1okb4uafunfqusi2lp22u3`, this makes MySQL want to
+// call the new constraint something like _vt_HOLD_394f9e6dfc3d11eca0390a43f95f28a3_20220706091048_chk_1_cps1okb4uafunfqusi2lp22u3,
+// which exceeds the 64 character limit for table names. Long story short, we also trim down <tablename> if the constraint seems
+// to be auto-generated.
+func (e *Executor) newConstraintName(onlineDDL *schema.OnlineDDL, hashExists map[string]bool, seed string, oldName string) string {
+	oldName = schemadiff.ExtractConstraintOriginalName(oldName)
+	autoGeneratedName := fmt.Sprintf("%s_chk_", onlineDDL.Table)
+	if strings.HasPrefix(oldName, autoGeneratedName) {
+		// strip out table name
+		oldName = "chk_" + oldName[len(autoGeneratedName):]
+	}
+
+	hash := textutil.UUIDv5Base36(onlineDDL.UUID, onlineDDL.Table, seed)
+	for i := 1; hashExists[hash]; i++ {
+		hash = textutil.UUIDv5Base36(onlineDDL.UUID, onlineDDL.Table, seed, fmt.Sprintf("%d", i))
+	}
+	hashExists[hash] = true
+	suffix := "_" + hash
+	maxAllowedNameLength := maxConstraintNameLength - len(suffix)
+	newName := oldName
+	if newName == "" {
+		newName = "chk" // start with something that looks consistent with MySQL's naming
+	}
+	if len(newName) > maxAllowedNameLength {
+		newName = newName[0:maxAllowedNameLength]
+	}
+	newName = newName + suffix
+	return newName
+}
+
 // validateAndEditCreateTableStatement inspects the CreateTable AST and does the following:
 // - extra validation (no FKs for now...)
 // - generate new and unique names for all constraints (CHECK and FK; yes, why not handle FK names; even as we don't support FKs today, we may in the future)
@@ -950,56 +997,13 @@ func (e *Executor) validateAndEditCreateTableStatement(ctx context.Context, onli
 	constraintMap = map[string]string{}
 	hashExists := map[string]bool{}
 
-	// newConstraintName generates a new, unique name for a constraint. Our problem is that a MySQL
-	// constraint's name is unique in the schema (!). And so as we duplicate the original table, we must
-	// create completely new names for all constraints.
-	// Moreover, we really want this name to be consistent across all shards. We therefore use a deterministic
-	// UUIDv5 (SHA) function over the migration UUID, table name, and constraint's _contents_.
-	// We _also_ include the original constraint name as prefix, as room allows
-	// for example, if the original constraint name is "check_1",
-	// we might generate "check_1_cps1okb4uafunfqusi2lp22u3".
-	// If we then again migrate a table whose constraint name is "check_1_cps1okb4uafunfqusi2lp22u3	" we
-	// get for example "check_1_19l09s37kbhj4axnzmi10e18k" (hash changes, and we still try to preserve original name)
-	//
-	// Furthermore, per bug report https://bugs.mysql.com/bug.php?id=107772, if the user doesn' tprovide a name for
-	// their CHECK constraint, then MySQL picks a name in this format <tablename>_chk_<number>.
-	// Example: sometable_chk_1
-	// Next, when MySQL is asked to RENAME TABLE and sees a constraint with this format, it attempts to rename
-	// the constraint with the new table's name. This is problematic for Vitess, because we often rename tables to
-	// very long names, such as _vt_HOLD_394f9e6dfc3d11eca0390a43f95f28a3_20220706091048.
-	// As we rename the constraint to e.g. `sometable_chk_1_cps1okb4uafunfqusi2lp22u3`, this makes MySQL want to
-	// call the new constraint something like _vt_HOLD_394f9e6dfc3d11eca0390a43f95f28a3_20220706091048_chk_1_cps1okb4uafunfqusi2lp22u3,
-	// which exceeds the 64 character limit for table names. Long story short, we also trim down <tablename> if the constraint seems
-	// to be auto-generated.
-	newConstraintName := func(seed string, oldName string) string {
-		oldName = schemadiff.ExtractConstraintOriginalName(oldName)
-		autoGeneratedName := fmt.Sprintf("%s_chk_", onlineDDL.Table)
-		if strings.HasPrefix(oldName, autoGeneratedName) {
-			// strip out table name
-			oldName = "chk_" + oldName[len(autoGeneratedName):]
-		}
-
-		hash := textutil.UUIDv5Base36(onlineDDL.UUID, onlineDDL.Table, seed)
-		for i := 1; hashExists[hash]; i++ {
-			hash = textutil.UUIDv5Base36(onlineDDL.UUID, onlineDDL.Table, seed, fmt.Sprintf("%d", i))
-		}
-		hashExists[hash] = true
-		suffix := "_" + hash
-		maxAllowedNameLength := maxConstraintNameLength - len(suffix)
-		newName := oldName
-		if len(newName) > maxAllowedNameLength {
-			newName = newName[0:maxAllowedNameLength]
-		}
-		newName = newName + suffix
-		return newName
-	}
 	validateWalk := func(node sqlparser.SQLNode) (kontinue bool, err error) {
 		switch node := node.(type) {
 		case *sqlparser.ForeignKeyDefinition:
 			return false, schema.ErrForeignKeyFound
 		case *sqlparser.ConstraintDefinition:
 			oldName := node.Name.String()
-			newName := newConstraintName(sqlparser.CanonicalString(node.Details), oldName)
+			newName := e.newConstraintName(onlineDDL, hashExists, sqlparser.CanonicalString(node.Details), oldName)
 			node.Name = sqlparser.NewIdentifierCI(newName)
 			constraintMap[oldName] = newName
 		}
@@ -1014,7 +1018,8 @@ func (e *Executor) validateAndEditCreateTableStatement(ctx context.Context, onli
 // validateAndEditAlterTableStatement inspects the AlterTable statement and:
 // - modifies any CONSTRAINT name according to given name mapping
 // - explode ADD FULLTEXT KEY into multiple statements
-func (e *Executor) validateAndEditAlterTableStatement(ctx context.Context, alterTable *sqlparser.AlterTable, constraintMap map[string]string) (alters []*sqlparser.AlterTable, err error) {
+func (e *Executor) validateAndEditAlterTableStatement(ctx context.Context, onlineDDL *schema.OnlineDDL, alterTable *sqlparser.AlterTable, constraintMap map[string]string) (alters []*sqlparser.AlterTable, err error) {
+	hashExists := map[string]bool{}
 	validateWalk := func(node sqlparser.SQLNode) (kontinue bool, err error) {
 		switch node := node.(type) {
 		case *sqlparser.DropKey:
@@ -1026,6 +1031,11 @@ func (e *Executor) validateAndEditAlterTableStatement(ctx context.Context, alter
 				}
 				node.Name = sqlparser.NewIdentifierCI(mappedName)
 			}
+		case *sqlparser.AddConstraintDefinition:
+			oldName := node.ConstraintDefinition.Name.String()
+			newName := e.newConstraintName(onlineDDL, hashExists, sqlparser.CanonicalString(node.ConstraintDefinition.Details), oldName)
+			node.ConstraintDefinition.Name = sqlparser.NewIdentifierCI(newName)
+			constraintMap[oldName] = newName
 		}
 		return true, nil
 	}
@@ -1125,7 +1135,7 @@ func (e *Executor) initVreplicationOriginalMigration(ctx context.Context, online
 		// ALTER TABLE should apply to the vrepl table
 		alterTable.SetTable(alterTable.GetTable().Qualifier.CompliantName(), vreplTableName)
 		// Also, change any constraint names:
-		alters, err := e.validateAndEditAlterTableStatement(ctx, alterTable, constraintMap)
+		alters, err := e.validateAndEditAlterTableStatement(ctx, onlineDDL, alterTable, constraintMap)
 		if err != nil {
 			return v, err
 		}
diff --git a/web/vtadmin/package-lock.json b/web/vtadmin/package-lock.json
index a91a0ae0e1..433d25c170 100644
--- a/web/vtadmin/package-lock.json
+++ b/web/vtadmin/package-lock.json
@@ -5817,9 +5817,9 @@
       }
     },
     "node_modules/babel-loader/node_modules/loader-utils": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
-      "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.1.tgz",
+      "integrity": "sha512-1Qo97Y2oKaU+Ro2xnDMR26g1BwMT29jNbem1EvcujW2jqt+j5COXyscjM7bLQkM9HaxI7pkWeW7gnI072yMI9Q==",
       "dependencies": {
         "big.js": "^5.2.2",
         "emojis-list": "^3.0.0",
@@ -14747,9 +14747,9 @@
       }
     },
     "node_modules/loader-utils": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
-      "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
+      "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
       "dependencies": {
         "big.js": "^5.2.2",
         "emojis-list": "^3.0.0",
@@ -25605,9 +25605,9 @@
           }
         },
         "loader-utils": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
-          "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
+          "version": "1.4.1",
+          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.1.tgz",
+          "integrity": "sha512-1Qo97Y2oKaU+Ro2xnDMR26g1BwMT29jNbem1EvcujW2jqt+j5COXyscjM7bLQkM9HaxI7pkWeW7gnI072yMI9Q==",
           "requires": {
             "big.js": "^5.2.2",
             "emojis-list": "^3.0.0",
@@ -32099,9 +32099,9 @@
       "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw=="
     },
     "loader-utils": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
-      "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
+      "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
       "requires": {
         "big.js": "^5.2.2",
         "emojis-list": "^3.0.0",


Test patch:
diff --git a/go/ioutil2/ioutil_test.go b/go/ioutil2/ioutil_test.go
deleted file mode 100644
index 916b1fe207..0000000000
--- a/go/ioutil2/ioutil_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-Copyright 2019 The Vitess Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreedto in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package ioutil2
-
-import (
-	"bytes"
-	"fmt"
-	"os"
-	"testing"
-	"time"
-)
-
-func TestWrite(t *testing.T) {
-	data := []byte("test string\n")
-	fname := fmt.Sprintf("/tmp/atomic-file-test-%v.txt", time.Now().UnixNano())
-	err := WriteFileAtomic(fname, data, 0664)
-	if err != nil {
-		t.Fatal(err)
-	}
-	rData, err := os.ReadFile(fname)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !bytes.Equal(data, rData) {
-		t.Fatalf("data mismatch: %v != %v", data, rData)
-	}
-	if err := os.Remove(fname); err != nil {
-		t.Fatal(err)
-	}
-}
diff --git a/go/sqltypes/value_test.go b/go/sqltypes/value_test.go
index a6d91c814d..1e6c597bd9 100644
--- a/go/sqltypes/value_test.go
+++ b/go/sqltypes/value_test.go
@@ -86,6 +86,14 @@ func TestNewValue(t *testing.T) {
 		inType: Uint64,
 		inVal:  "1",
 		outVal: TestValue(Uint64, "1"),
+	}, {
+		inType: Uint64,
+		inVal:  "01",
+		outVal: TestValue(Uint64, "01"),
+	}, {
+		inType: Int64,
+		inVal:  "01",
+		outVal: TestValue(Int64, "01"),
 	}, {
 		inType: Float32,
 		inVal:  "1.00",
diff --git a/go/test/endtoend/vtgate/queries/aggregation/aggregation_test.go b/go/test/endtoend/vtgate/queries/aggregation/aggregation_test.go
index 820e6ad36e..ba9bbd8b19 100644
--- a/go/test/endtoend/vtgate/queries/aggregation/aggregation_test.go
+++ b/go/test/endtoend/vtgate/queries/aggregation/aggregation_test.go
@@ -374,3 +374,13 @@ func TestOrderByCount(t *testing.T) {
 
 	mcmp.AssertMatches("SELECT /*vt+ PLANNER=gen4 */ t9.id2 FROM t9 GROUP BY t9.id2 ORDER BY COUNT(t9.id2) DESC", `[[VARCHAR("3")] [VARCHAR("2")] [VARCHAR("1")]]`)
 }
+
+func TestAggregateRandom(t *testing.T) {
+	mcmp, closer := start(t)
+	defer closer()
+
+	mcmp.Exec("insert into t1(t1_id, name, value, shardKey) values (1, 'name 1', 'value 1', 1), (2, 'name 2', 'value 2', 2)")
+	mcmp.Exec("insert into t2(id, shardKey) values (1, 10), (2, 20)")
+
+	mcmp.AssertMatches("SELECT /*vt+ PLANNER=gen4 */ t1.shardKey, t1.name, count(t2.id) FROM t1 JOIN t2 ON t1.value != t2.shardKey GROUP BY t1.t1_id", `[[INT64(1) VARCHAR("name 1") INT64(2)] [INT64(2) VARCHAR("name 2") INT64(2)]]`)
+}
diff --git a/go/vt/sqlparser/normalizer_test.go b/go/vt/sqlparser/normalizer_test.go
index f8f72ceff2..3fbb7687d6 100644
--- a/go/vt/sqlparser/normalizer_test.go
+++ b/go/vt/sqlparser/normalizer_test.go
@@ -311,6 +311,13 @@ func TestNormalize(t *testing.T) {
 			"bv1":                   sqltypes.Int64BindVariable(1),
 			"comms_by_companies_id": sqltypes.StringBindVariable("rjve634shXzaavKHbAH16ql6OrxJ"),
 		},
+	}, {
+		// Int leading with zero should also be normalized
+		in:      `select * from t where zipcode = 01001900`,
+		outstmt: `select * from t where zipcode = :zipcode`,
+		outbv: map[string]*querypb.BindVariable{
+			"zipcode": sqltypes.ValueBindVariable(sqltypes.MakeTrusted(sqltypes.Int64, []byte("01001900"))),
+		},
 	}}
 	for _, tc := range testcases {
 		t.Run(tc.in, func(t *testing.T) {
diff --git a/go/vt/vtgate/planbuilder/testdata/aggr_cases.json b/go/vt/vtgate/planbuilder/testdata/aggr_cases.json
index 45a6cb7238..760a136eca 100644
--- a/go/vt/vtgate/planbuilder/testdata/aggr_cases.json
+++ b/go/vt/vtgate/planbuilder/testdata/aggr_cases.json
@@ -4324,7 +4324,7 @@
           {
             "OperatorType": "Projection",
             "Expressions": [
-              "[COLUMN 2] * [COLUMN 3] as col",
+              "[COLUMN 2] as col",
               "[COLUMN 1]",
               "[COLUMN 0] as id"
             ],
@@ -4332,7 +4332,7 @@
               {
                 "OperatorType": "Join",
                 "Variant": "Join",
-                "JoinColumnIndexes": "L:1,L:2,L:0,R:1",
+                "JoinColumnIndexes": "L:1,L:2,L:0",
                 "JoinVars": {
                   "user_col": 0
                 },
@@ -4357,8 +4357,8 @@
                       "Name": "user",
                       "Sharded": true
                     },
-                    "FieldQuery": "select 1, count(*) from user_extra where 1 != 1 group by 1",
-                    "Query": "select 1, count(*) from user_extra where user_extra.col = :user_col group by 1",
+                    "FieldQuery": "select 1 from user_extra where 1 != 1 group by 1",
+                    "Query": "select 1 from user_extra where user_extra.col = :user_col group by 1",
                     "Table": "user_extra"
                   }
                 ]
@@ -4473,7 +4473,7 @@
           {
             "OperatorType": "Projection",
             "Expressions": [
-              "[COLUMN 2] * [COLUMN 3] as id",
+              "[COLUMN 2] as id",
               "[COLUMN 1]",
               "[COLUMN 0] as id"
             ],
@@ -4481,7 +4481,7 @@
               {
                 "OperatorType": "Join",
                 "Variant": "Join",
-                "JoinColumnIndexes": "L:0,L:1,L:0,R:1",
+                "JoinColumnIndexes": "L:0,L:1,L:0",
                 "TableName": "`user`_user_extra",
                 "Inputs": [
                   {
@@ -4503,8 +4503,8 @@
                       "Name": "user",
                       "Sharded": true
                     },
-                    "FieldQuery": "select 1, count(*) from user_extra where 1 != 1 group by 1",
-                    "Query": "select 1, count(*) from user_extra group by 1",
+                    "FieldQuery": "select 1 from user_extra where 1 != 1 group by 1",
+                    "Query": "select 1 from user_extra group by 1",
                     "Table": "user_extra"
                   }
                 ]
@@ -4819,5 +4819,82 @@
         "user.user"
       ]
     }
+  },
+  {
+    "comment": "AggregateRandom in non full group by query",
+    "query": "select u.id, u.name, count(m.predef1) from user.user as u join user.user_extra as m on u.id = m.order group by u.id",
+    "v3-plan": "unsupported: cross-shard query with aggregates",
+    "gen4-plan": {
+      "QueryType": "SELECT",
+      "Original": "select u.id, u.name, count(m.predef1) from user.user as u join user.user_extra as m on u.id = m.order group by u.id",
+      "Instructions": {
+        "OperatorType": "Aggregate",
+        "Variant": "Ordered",
+        "Aggregates": "random(1) AS name, sum_count(2) AS count(m.predef1)",
+        "GroupBy": "(0|3)",
+        "ResultColumns": 3,
+        "Inputs": [
+          {
+            "OperatorType": "Projection",
+            "Expressions": [
+              "[COLUMN 0] as id",
+              "[COLUMN 2] as name",
+              "[COLUMN 3] * [COLUMN 4] as count(m.predef1)",
+              "[COLUMN 1]"
+            ],
+            "Inputs": [
+              {
+                "OperatorType": "Sort",
+                "Variant": "Memory",
+                "OrderBy": "(0|1) ASC",
+                "Inputs": [
+                  {
+                    "OperatorType": "Join",
+                    "Variant": "Join",
+                    "JoinColumnIndexes": "R:2,R:3,R:0,L:1,R:1",
+                    "JoinVars": {
+                      "m_order": 0
+                    },
+                    "TableName": "user_extra_`user`",
+                    "Inputs": [
+                      {
+                        "OperatorType": "Route",
+                        "Variant": "Scatter",
+                        "Keyspace": {
+                          "Name": "user",
+                          "Sharded": true
+                        },
+                        "FieldQuery": "select m.`order`, count(m.predef1), weight_string(m.`order`) from user_extra as m where 1 != 1 group by m.`order`, weight_string(m.`order`)",
+                        "Query": "select m.`order`, count(m.predef1), weight_string(m.`order`) from user_extra as m group by m.`order`, weight_string(m.`order`)",
+                        "Table": "user_extra"
+                      },
+                      {
+                        "OperatorType": "Route",
+                        "Variant": "EqualUnique",
+                        "Keyspace": {
+                          "Name": "user",
+                          "Sharded": true
+                        },
+                        "FieldQuery": "select u.`name`, count(*), u.id, weight_string(u.id) from `user` as u where 1 != 1 group by u.id, weight_string(u.id)",
+                        "Query": "select u.`name`, count(*), u.id, weight_string(u.id) from `user` as u where u.id = :m_order group by u.id, weight_string(u.id)",
+                        "Table": "`user`",
+                        "Values": [
+                          ":m_order"
+                        ],
+                        "Vindex": "user_index"
+                      }
+                    ]
+                  }
+                ]
+              }
+            ]
+          }
+        ]
+      },
+      "TablesUsed": [
+        "user.user",
+        "user.user_extra"
+      ]
+    }
   }
 ]
\ No newline at end of file
diff --git a/go/vt/vttablet/onlineddl/executor_test.go b/go/vt/vttablet/onlineddl/executor_test.go
index c41f3b24f3..2d9be7630f 100644
--- a/go/vt/vttablet/onlineddl/executor_test.go
+++ b/go/vt/vttablet/onlineddl/executor_test.go
@@ -93,7 +93,7 @@ func TestValidateAndEditCreateTableStatement(t *testing.T) {
 			}, createTable)
 			assert.NoError(t, err)
 			assert.Equal(t, tc.countConstraints, len(uniqueConstraintNames))
-			assert.Equal(t, tc.countConstraints, len(constraintMap))
+			assert.Equalf(t, tc.countConstraints, len(constraintMap), "got contraints: %v", constraintMap)
 		})
 	}
 }
@@ -120,6 +120,18 @@ func TestValidateAndEditAlterTableStatement(t *testing.T) {
 			alter:  "alter table t add fulltext key name0_ft (name0), add column i int, add fulltext key name1_ft (name1), add fulltext key name2_ft (name2)",
 			expect: []string{"alter table t add fulltext key name0_ft (name0), add column i int", "alter table t add fulltext key name1_ft (name1)", "alter table t add fulltext key name2_ft (name2)"},
 		},
+		{
+			alter:  "alter table t add constraint check (id != 1)",
+			expect: []string{"alter table t add constraint chk_aulpn7bjeortljhguy86phdn9 check (id != 1)"},
+		},
+		{
+			alter:  "alter table t add constraint t_chk_1 check (id != 1)",
+			expect: []string{"alter table t add constraint chk_1_aulpn7bjeortljhguy86phdn9 check (id != 1)"},
+		},
+		{
+			alter:  "alter table t add constraint some_check check (id != 1)",
+			expect: []string{"alter table t add constraint some_check_aulpn7bjeortljhguy86phdn9 check (id != 1)"},
+		},
 	}
 	for _, tc := range tt {
 		t.Run(tc.alter, func(t *testing.T) {
@@ -129,7 +141,8 @@ func TestValidateAndEditAlterTableStatement(t *testing.T) {
 			require.True(t, ok)
 
 			m := map[string]string{}
-			alters, err := e.validateAndEditAlterTableStatement(context.Background(), alterTable, m)
+			onlineDDL := &schema.OnlineDDL{UUID: "a5a563da_dc1a_11ec_a416_0a43f95f28a3", Table: "t"}
+			alters, err := e.validateAndEditAlterTableStatement(context.Background(), onlineDDL, alterTable, m)
 			assert.NoError(t, err)
 			altersStrings := []string{}
 			for _, alter := range alters {