github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/distsql_plan_join_test.go (about)

     1  // Copyright 2017 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package sql
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  	"reflect"
    17  	"strconv"
    18  	"strings"
    19  	"testing"
    20  
    21  	"github.com/cockroachdb/cockroach/pkg/base"
    22  	"github.com/cockroachdb/cockroach/pkg/keys"
    23  	"github.com/cockroachdb/cockroach/pkg/kv"
    24  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    26  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    27  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    28  	"github.com/cockroachdb/cockroach/pkg/util/encoding"
    29  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    30  	"github.com/cockroachdb/errors"
    31  )
    32  
    33  func setTestEqColForSide(colName string, side *scanNode, equalityIndices *[]int) error {
    34  	colFound := false
    35  
    36  	for i, leftCol := range side.cols {
    37  		if colName == leftCol.Name {
    38  			*equalityIndices = append(*equalityIndices, i)
    39  			colFound = true
    40  			break
    41  		}
    42  	}
    43  	if !colFound {
    44  		return errors.Errorf("column %s not found in %s", colName, side.desc.Name)
    45  	}
    46  	return nil
    47  }
    48  
    49  func setTestEqCols(n *joinNode, colNames []string) error {
    50  	left := n.left.plan.(*scanNode)
    51  	right := n.right.plan.(*scanNode)
    52  
    53  	n.pred = &joinPredicate{}
    54  	n.mergeJoinOrdering = nil
    55  
    56  	for _, colName := range colNames {
    57  		if colName == "" {
    58  			continue
    59  		}
    60  
    61  		if err := setTestEqColForSide(colName, left, &n.pred.leftEqualityIndices); err != nil {
    62  			return err
    63  		}
    64  		if err := setTestEqColForSide(colName, right, &n.pred.rightEqualityIndices); err != nil {
    65  			return err
    66  		}
    67  	}
    68  
    69  	n.mergeJoinOrdering = computeMergeJoinOrdering(
    70  		left.reqOrdering,
    71  		right.reqOrdering,
    72  		n.pred.leftEqualityIndices,
    73  		n.pred.rightEqualityIndices,
    74  	)
    75  
    76  	return nil
    77  }
    78  
    79  func genPermutations(slice []string) [][]string {
    80  	if len(slice) == 0 {
    81  		return [][]string{{}}
    82  	}
    83  
    84  	var out [][]string
    85  	for i, str := range slice {
    86  		recurse := append([]string{}, slice[:i]...)
    87  		recurse = append(recurse, slice[i+1:]...)
    88  		for _, subperms := range genPermutations(recurse) {
    89  			out = append(out, append([]string{str}, subperms...))
    90  		}
    91  	}
    92  
    93  	return out
    94  }
    95  
    96  var tableNames = map[string]bool{
    97  	"parent1":     true,
    98  	"child1":      true,
    99  	"grandchild1": true,
   100  	"child2":      true,
   101  	"parent2":     true,
   102  }
   103  
   104  // Format for any key:
   105  //   <table-name>/<index-id>/<index-col1>/.../#/<table-name>/<index-id>/....
   106  func encodeTestKey(kvDB *kv.DB, keyStr string) (roachpb.Key, error) {
   107  	key := keys.SystemSQLCodec.TenantPrefix()
   108  	tokens := strings.Split(keyStr, "/")
   109  
   110  	for _, tok := range tokens {
   111  		// Encode the table ID if the token is a table name.
   112  		if tableNames[tok] {
   113  			desc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, sqlutils.TestDB, tok)
   114  			key = encoding.EncodeUvarintAscending(key, uint64(desc.ID))
   115  			continue
   116  		}
   117  
   118  		// Interleaved sentinel.
   119  		if tok == "#" {
   120  			key = encoding.EncodeNotNullDescending(key)
   121  			continue
   122  		}
   123  
   124  		// Assume any other value is an unsigned integer.
   125  		tokInt, err := strconv.ParseUint(tok, 10, 64)
   126  		if err != nil {
   127  			return nil, err
   128  		}
   129  		key = encoding.EncodeUvarintAscending(key, tokInt)
   130  	}
   131  
   132  	return key, nil
   133  }
   134  
   135  func decodeTestKey(kvDB *kv.DB, key roachpb.Key) (string, error) {
   136  	var out []byte
   137  
   138  	keyStr := roachpb.PrettyPrintKey(nil /* valDirs */, key)
   139  	tokens := strings.Split(keyStr, "/")[1:]
   140  
   141  	for i := 0; i < len(tokens); i++ {
   142  		tok := tokens[i]
   143  		// We know for certain the next token is the table ID. Need
   144  		// to convert into a table name.
   145  		if tok == "Table" || tok == "#" {
   146  			if tok == "#" {
   147  				out = append(out, []byte("#/")...)
   148  			}
   149  
   150  			descID, err := strconv.ParseUint(tokens[i+1], 10, 64)
   151  			if err != nil {
   152  				return "", err
   153  			}
   154  
   155  			if err := kvDB.Txn(context.Background(), func(ctx context.Context, txn *kv.Txn) error {
   156  				desc, err := sqlbase.GetTableDescFromID(context.Background(), txn, keys.SystemSQLCodec, sqlbase.ID(descID))
   157  				if err != nil {
   158  					return err
   159  				}
   160  
   161  				out = append(out, []byte(desc.Name)...)
   162  				return nil
   163  			}); err != nil {
   164  				return "", err
   165  			}
   166  
   167  			// We read an extra token for the table ID.
   168  			i++
   169  		} else {
   170  			// Encode anything else as is.
   171  			out = append(out, []byte(tok)...)
   172  		}
   173  
   174  		out = append(out, '/')
   175  	}
   176  
   177  	// Omit the last '/'.
   178  	return string(out[:len(out)-1]), nil
   179  }
   180  
   181  // See CreateTestInterleavedHierarchy for the longest chain used for the short
   182  // format.
   183  var shortFormTables = [3]string{"parent1", "child1", "grandchild1"}
   184  
   185  // shortToLongKey converts the short key format preferred in test cases
   186  //    /1/#/3/4
   187  // to its long form required by parseTestkey
   188  //    parent1/1/1/#/child1/1/3/4
   189  func shortToLongKey(short string) string {
   190  	tableOrder := shortFormTables
   191  	curTableIdx := 0
   192  
   193  	var long []byte
   194  	tokens := strings.Split(short, "/")
   195  	// Verify short format starts with '/'.
   196  	if tokens[0] != "" {
   197  		panic("missing '/' token at the beginning of short format")
   198  	}
   199  	// Skip the first element since short format has starting '/'.
   200  	tokens = tokens[1:]
   201  
   202  	// Always append parent1.
   203  	long = append(long, []byte(fmt.Sprintf("%s/1/", tableOrder[curTableIdx]))...)
   204  	curTableIdx++
   205  
   206  	for _, tok := range tokens {
   207  		// New interleaved table and primary keys follow.
   208  		if tok == "#" {
   209  			if curTableIdx >= len(tableOrder) {
   210  				panic("too many '#' tokens specified in short format (max 2 for child1 and grandchild1)")
   211  			}
   212  
   213  			long = append(long, []byte(fmt.Sprintf("#/%s/1/", tableOrder[curTableIdx]))...)
   214  			curTableIdx++
   215  
   216  			continue
   217  		}
   218  
   219  		long = append(long, []byte(fmt.Sprintf("%s/", tok))...)
   220  	}
   221  
   222  	// Remove the last '/'.
   223  	return string(long[:len(long)-1])
   224  }
   225  
   226  func TestUseInterleavedJoin(t *testing.T) {
   227  	defer leaktest.AfterTest(t)()
   228  
   229  	s, sqlDB, kvDB := serverutils.StartServer(t, base.TestServerArgs{})
   230  	defer s.Stopper().Stop(context.Background())
   231  
   232  	sqlutils.CreateTestInterleavedHierarchy(t, sqlDB)
   233  
   234  	// Only test cases on the full interleave prefix between the two
   235  	// tables should return true.
   236  	for _, tc := range []struct {
   237  		table1   string
   238  		table2   string
   239  		eqCols   string
   240  		expected bool
   241  	}{
   242  		// Refer to comment above CreateTestInterleavedHierarchy for
   243  		// table schemas.
   244  
   245  		// Simple parent-child case.
   246  		// parent1-child1 share interleave prefix (pid1).
   247  		{"parent1", "child1", "pid1", true},
   248  		{"parent1", "child1", "pid1,v", false},
   249  		{"parent1", "child1", "", false},
   250  		{"parent1", "child1", "v", false},
   251  		// Parent-grandchild case.
   252  		// parent1-grandchild1 share interleave prefix (pid1).
   253  		{"parent1", "grandchild1", "pid1", true},
   254  		{"parent1", "grandchild1", "pid1,v", false},
   255  		{"parent1", "grandchild1", "", false},
   256  		{"parent1", "grandchild1", "v", false},
   257  		// Multiple-column interleave prefix.
   258  		// child1-grandchild1 share interleave prefix (pid1, cid1,
   259  		// cid2).
   260  		{"child1", "grandchild1", "pid1,cid1,cid2", true},
   261  		{"child1", "grandchild1", "pid1,cid1,cid2,v", false},
   262  		{"child1", "grandchild1", "", false},
   263  		{"child1", "grandchild1", "v", false},
   264  		// TODO(richardwu): update these once prefix/subset of
   265  		// interleave prefixes are permitted.
   266  		{"child1", "grandchild1", "cid1", false},
   267  		{"child1", "grandchild1", "cid2", false},
   268  		{"child1", "grandchild1", "cid1,v", false},
   269  		{"child1", "grandchild1", "cid2,v", false},
   270  		{"child1", "grandchild1", "cid1,cid2", false},
   271  		{"child1", "grandchild1", "cid1,cid2,v", false},
   272  		{"child1", "grandchild1", "pid1,cid1", false},
   273  		{"child1", "grandchild1", "pid1,cid2", false},
   274  		{"child1", "grandchild1", "pid1,cid1,v", false},
   275  		{"child1", "grandchild1", "pid1,cid2,v", false},
   276  		// Common ancestor example.
   277  		{"child1", "child2", "", false},
   278  		// TODO(richardwu): update this when common ancestor
   279  		// interleaved joins are possible.
   280  		{"child1", "child2", "pid1", false},
   281  	} {
   282  		// Run the subtests with the tables in both positions (left and
   283  		// right).
   284  		for i := 0; i < 2; i++ {
   285  			// Run every permutation of the equality columns (just
   286  			// to ensure mergeJoinOrdering is invariant since we
   287  			// rely on it to correspond with the primary index of
   288  			// the ancestor).
   289  			eqCols := strings.Split(tc.eqCols, ",")
   290  			for _, colNames := range genPermutations(eqCols) {
   291  				testName := fmt.Sprintf("%s-%s-%s", tc.table1, tc.table2, strings.Join(colNames, ","))
   292  				t.Run(testName, func(t *testing.T) {
   293  					join, err := newTestJoinNode(kvDB, tc.table1, tc.table2)
   294  					if err != nil {
   295  						t.Fatal(err)
   296  					}
   297  					join.joinType = sqlbase.InnerJoin
   298  
   299  					if err := setTestEqCols(join, colNames); err != nil {
   300  						t.Fatal(err)
   301  					}
   302  					join.mergeJoinOrdering = computeMergeJoinOrdering(
   303  						planReqOrdering(join.left.plan),
   304  						planReqOrdering(join.right.plan),
   305  						join.pred.leftEqualityIndices,
   306  						join.pred.rightEqualityIndices,
   307  					)
   308  
   309  					actual := useInterleavedJoin(join)
   310  
   311  					if tc.expected != actual {
   312  						t.Errorf("expected useInterleaveJoin to return %t, actual %t", tc.expected, actual)
   313  					}
   314  				})
   315  			}
   316  			// Rerun the same subtests but flip the tables
   317  			tc.table1, tc.table2 = tc.table2, tc.table1
   318  		}
   319  	}
   320  
   321  	// Test that a join from an interleaved column to a non-interleaved column
   322  	// doesn't get planned as an interleaved table join, even if the
   323  	// non-interleaved column is constant and is given a merge join ordering.
   324  	t.Run("MismatchedJoin", func(t *testing.T) {
   325  		join, err := newTestJoinNode(kvDB, "parent1", "child1")
   326  		if err != nil {
   327  			t.Fatal(err)
   328  		}
   329  		join.joinType = sqlbase.InnerJoin
   330  
   331  		join.pred = &joinPredicate{}
   332  		join.mergeJoinOrdering = nil
   333  		if err := setTestEqColForSide("pid1", join.left.plan.(*scanNode), &join.pred.leftEqualityIndices); err != nil {
   334  			t.Fatal(err)
   335  		}
   336  		if err := setTestEqColForSide("v", join.right.plan.(*scanNode), &join.pred.rightEqualityIndices); err != nil {
   337  			t.Fatal(err)
   338  		}
   339  		// Set the merge join ordering to idx 0 - this says that the column `pid1`
   340  		// and `v` have the same ordering. This can be true if `v` has been
   341  		// constrained to a constant value. We shouldn't plan an interleaved table
   342  		// join in this case, even though the left equality columns are a prefix
   343  		// of the interleaved columns, because the right equality columns are not
   344  		// part of the interleaved columns.
   345  		// See issue #25838 for a case where this could happen.
   346  		join.mergeJoinOrdering = sqlbase.ColumnOrdering{
   347  			sqlbase.ColumnOrderInfo{
   348  				ColIdx:    0,
   349  				Direction: encoding.Ascending,
   350  			},
   351  		}
   352  
   353  		actual := useInterleavedJoin(join)
   354  
   355  		if actual {
   356  			t.Errorf("expected useInterleaveJoin to return %t, actual %t", false, actual)
   357  		}
   358  	})
   359  }
   360  
   361  func TestMaximalJoinPrefix(t *testing.T) {
   362  	defer leaktest.AfterTest(t)()
   363  
   364  	s, sqlDB, kvDB := serverutils.StartServer(t, base.TestServerArgs{})
   365  	defer s.Stopper().Stop(context.Background())
   366  
   367  	sqlutils.CreateTestInterleavedHierarchy(t, sqlDB)
   368  
   369  	testCases := []struct {
   370  		table1    string
   371  		table2    string
   372  		input     string
   373  		expected  string
   374  		truncated bool
   375  	}{
   376  		// Key is already an ancestor prefix.
   377  		{"parent1", "child1", "/2", "/2", false},
   378  
   379  		// Key of descendant child1.
   380  		{"parent1", "child1", "/2/#/3/4", "/2", true},
   381  
   382  		// Partial key of descendant child1 (only cid1, missing cid2).
   383  		{"parent1", "child1", "/2/#/1/3", "/2", true},
   384  
   385  		// Key of descendant grandchild1.
   386  		{"parent1", "grandchild1", "/2/#/3/4/#/5", "/2", true},
   387  
   388  		// Key of some descendant child1 is still a descendant key
   389  		// of parent1.
   390  		{"parent1", "grandchild1", "/2/#/3/4", "/2", true},
   391  
   392  		// Key is already an ancestor prefix of child1.
   393  		{"child1", "grandchild1", "/2/#/3/4", "/2/#/3/4", false},
   394  
   395  		// Key of descendant grandchild1 with ancestor child1:
   396  		// prefix of parent1 retained.
   397  		{"child1", "grandchild1", "/2/#/3/4/#/5", "/2/#/3/4", true},
   398  
   399  		// TODO(richardwu): prefix/subset joins and sibiling joins.
   400  	}
   401  
   402  	for testIdx, tc := range testCases {
   403  		t.Run(strconv.Itoa(testIdx), func(t *testing.T) {
   404  			join, err := newTestJoinNode(kvDB, tc.table1, tc.table2)
   405  			if err != nil {
   406  				t.Fatal(err)
   407  			}
   408  
   409  			input, err := encodeTestKey(kvDB, shortToLongKey(tc.input))
   410  			if err != nil {
   411  				t.Fatal(err)
   412  			}
   413  
   414  			ancestor, descendant := join.interleavedNodes()
   415  
   416  			// Compute maximal join prefix.
   417  			actualKey, truncated, err := maximalJoinPrefix(ancestor, descendant, input)
   418  			if err != nil {
   419  				t.Fatal(err)
   420  			}
   421  
   422  			actual, err := decodeTestKey(kvDB, actualKey)
   423  			if err != nil {
   424  				t.Fatal(err)
   425  			}
   426  
   427  			expected := shortToLongKey(tc.expected)
   428  
   429  			if expected != actual {
   430  				t.Errorf("unexpected maximal join prefix.\nexpected:\t%s\nactual:\t%s", expected, actual)
   431  			}
   432  
   433  			if tc.truncated != truncated {
   434  				t.Errorf("expected maximalJoinPrefix to return %t for truncated, got %t", tc.truncated, truncated)
   435  			}
   436  		})
   437  	}
   438  }
   439  
   440  type testPartition struct {
   441  	node  roachpb.NodeID
   442  	spans [][2]string
   443  }
   444  
   445  func makeSpanPartitions(kvDB *kv.DB, testParts []testPartition) ([]SpanPartition, error) {
   446  	spanParts := make([]SpanPartition, len(testParts))
   447  
   448  	for i, testPart := range testParts {
   449  		spanParts[i].Node = testPart.node
   450  		for _, span := range testPart.spans {
   451  			start, err := encodeTestKey(kvDB, shortToLongKey(span[0]))
   452  			if err != nil {
   453  				return nil, err
   454  			}
   455  
   456  			end, err := encodeTestKey(kvDB, shortToLongKey(span[1]))
   457  			if err != nil {
   458  				return nil, err
   459  			}
   460  
   461  			spanParts[i].Spans = append(
   462  				spanParts[i].Spans,
   463  				roachpb.Span{Key: start, EndKey: end},
   464  			)
   465  		}
   466  	}
   467  
   468  	return spanParts, nil
   469  }
   470  
   471  func TestAlignInterleavedSpans(t *testing.T) {
   472  	defer leaktest.AfterTest(t)()
   473  
   474  	s, sqlDB, kvDB := serverutils.StartServer(t, base.TestServerArgs{})
   475  	defer s.Stopper().Stop(context.Background())
   476  
   477  	sqlutils.CreateTestInterleavedHierarchy(t, sqlDB)
   478  
   479  	testCases := []struct {
   480  		table1 string
   481  		table2 string
   482  
   483  		ancsParts []testPartition
   484  		descParts []testPartition
   485  		expected  []testPartition
   486  	}{
   487  		// Test that child1 spans get mapped to their corresponding
   488  		// parent1 spans and the descendant span is recursively split
   489  		// to satisfaction.
   490  		{
   491  			table1: "parent1", table2: "child1",
   492  
   493  			ancsParts: []testPartition{
   494  				// Test that the next parent row after the
   495  				// last is computed properly if the end key
   496  				// is not a parent1 key.
   497  				{1, [][2]string{{"/1", "/2/#/5"}}},
   498  				// End key is a parent1 key.
   499  				{2, [][2]string{{"/3", "/4"}}},
   500  				{3, [][2]string{{"/4", "/5"}}},
   501  			},
   502  
   503  			descParts: []testPartition{
   504  				{4, [][2]string{{"/1/#/7", "/4/#/8"}}},
   505  			},
   506  
   507  			expected: []testPartition{
   508  				{1, [][2]string{{"/1/#/7", "/3"}}},
   509  				{2, [][2]string{{"/3", "/4"}}},
   510  				{3, [][2]string{{"/4", "/4/#/8"}}},
   511  			},
   512  		},
   513  
   514  		// Test that child spans do not get remapped if they're already
   515  		// on the correct node.
   516  		{
   517  			table1: "parent1", table2: "child1",
   518  
   519  			ancsParts: []testPartition{
   520  				{1, [][2]string{{"/1", "/3"}}},
   521  			},
   522  
   523  			descParts: []testPartition{
   524  				{1, [][2]string{{"/1/#/7", "/2/#/8"}}},
   525  			},
   526  
   527  			expected: []testPartition{
   528  				{1, [][2]string{{"/1/#/7", "/2/#/8"}}},
   529  			},
   530  		},
   531  
   532  		// Test that even if the parent1 span does not entirely contain
   533  		// the child1 span, it gets mapped to the relevant parent row
   534  		// correctly.
   535  		{
   536  			table1: "parent1", table2: "child1",
   537  
   538  			ancsParts: []testPartition{
   539  				{1, [][2]string{{"/1", "/1/#/5"}}},
   540  			},
   541  
   542  			descParts: []testPartition{
   543  				{2, [][2]string{{"/1/#/7", "/1/#/8"}}},
   544  			},
   545  
   546  			expected: []testPartition{
   547  				{1, [][2]string{{"/1/#/7", "/1/#/8"}}},
   548  			},
   549  		},
   550  
   551  		// Test that multiple child spans mapped to the same nodes
   552  		// are merged and properly ordered.
   553  		{
   554  			table1: "parent1", table2: "child1",
   555  
   556  			ancsParts: []testPartition{
   557  				// Multiple spans within each partition.
   558  				{1, [][2]string{
   559  					{"/1", "/1/#/1"},
   560  					{"/1/#/1", "/2"},
   561  				}},
   562  				{2, [][2]string{
   563  					{"/2", "/2/#/1/1/#/8"},
   564  					{"/2/#/1/1/#/8", "/2/#/3/5"},
   565  					{"/2/#/3/5", "/3"},
   566  				}},
   567  			},
   568  
   569  			descParts: []testPartition{
   570  				{1, [][2]string{
   571  					// pid1=1 rows should map to node 1.
   572  					{"/1/#/1", "/1/#/2"},
   573  					{"/1/#/7", "/1/#/9"},
   574  					// pid1=2 rows should map to node 2.
   575  					{"/2/#/1", "/2/#/2"},
   576  					{"/2/#/5", "/2/#/8"},
   577  				}},
   578  				{2, [][2]string{
   579  					// pid1=1 rows should map to node 1.
   580  					{"/1/#/2", "/1/#/7"},
   581  					// pid1=2 rows should map to node 2.
   582  					// Overlaps with previous spans in node
   583  					// 1.
   584  					{"/2/#/2", "/2/#/6"},
   585  				}},
   586  				{3, [][2]string{
   587  					// pid1=1 rows should map to node 1.
   588  					{"/1/#/11", "/1/#/13"},
   589  					// pid1=2 rows should map to node 2.
   590  					{"/2/#/11", "/2/#/15"},
   591  				}},
   592  				// pid1=1 and pid=2 rows in a span.
   593  				{4, [][2]string{{"/1/#/15", "/2/#/0/7/#/1"}}},
   594  			},
   595  
   596  			expected: []testPartition{
   597  				{1, [][2]string{
   598  					{"/1/#/1", "/1/#/9"},
   599  					{"/1/#/11", "/1/#/13"},
   600  					{"/1/#/15", "/2"},
   601  				}},
   602  				{2, [][2]string{
   603  					{"/2", "/2/#/0/7/#/1"},
   604  					{"/2/#/1", "/2/#/8"},
   605  					{"/2/#/11", "/2/#/15"},
   606  				}},
   607  			},
   608  		},
   609  
   610  		// Test with child1 spans having parent1 keys split points.
   611  		{
   612  			table1: "parent1", table2: "child1",
   613  
   614  			ancsParts: []testPartition{
   615  				{1, [][2]string{{"/1", "/2"}}},
   616  				{2, [][2]string{{"/2", "/3"}}},
   617  				{3, [][2]string{{"/3", "/4"}}},
   618  			},
   619  
   620  			descParts: []testPartition{
   621  				{1, [][2]string{{"/2", "/3"}}},
   622  				// Technically not possible for two partitions
   623  				// to have the same span.
   624  				{3, [][2]string{{"/1", "/2"}}},
   625  				{6, [][2]string{{"/1", "/2"}}},
   626  			},
   627  
   628  			expected: []testPartition{
   629  				{1, [][2]string{{"/1", "/2"}}},
   630  				{2, [][2]string{{"/2", "/3"}}},
   631  			},
   632  		},
   633  
   634  		// Test child1 span that do not need to be remapped are still
   635  		// split by the next parent1 row after the last.
   636  		{
   637  			table1: "parent1", table2: "child1",
   638  
   639  			ancsParts: []testPartition{
   640  				{1, [][2]string{{"/1", "/2"}}},
   641  				{2, [][2]string{{"/2", "/3"}}},
   642  			},
   643  
   644  			descParts: []testPartition{
   645  				{1, [][2]string{{"/1", "/3"}}},
   646  			},
   647  
   648  			expected: []testPartition{
   649  				{1, [][2]string{{"/1", "/2"}}},
   650  				{2, [][2]string{{"/2", "/3"}}},
   651  			},
   652  		},
   653  
   654  		// Test that child1 spans that have no corresponding parent1
   655  		// span are not remapped.
   656  		{
   657  			table1: "parent1", table2: "child1",
   658  
   659  			ancsParts: []testPartition{
   660  				{1, [][2]string{{"/1", "/2"}}},
   661  				{2, [][2]string{{"/2", "/3"}}},
   662  			},
   663  
   664  			descParts: []testPartition{
   665  				// No corresponding parent span: not remapped.
   666  				{1, [][2]string{{"/4", "/5"}}},
   667  				// Partially no corresponding parent span.
   668  				{2, [][2]string{{"/2", "/4"}}},
   669  			},
   670  
   671  			expected: []testPartition{
   672  				{1, [][2]string{{"/4", "/5"}}},
   673  				{2, [][2]string{{"/2", "/4"}}},
   674  			},
   675  		},
   676  
   677  		// Test parent-grandchild example.
   678  		{
   679  			table1: "parent1", table2: "grandchild1",
   680  
   681  			ancsParts: []testPartition{
   682  				{1, [][2]string{{"/1", "/2/#/1/1/#/5"}}},
   683  				{2, [][2]string{{"/3", "/4"}}},
   684  				{3, [][2]string{{"/4", "/5"}}},
   685  			},
   686  
   687  			descParts: []testPartition{
   688  				{4, [][2]string{{"/1/#/42/37/#/5", "/2/#/1/1/#/5"}}},
   689  				// Partial child1 key (instead of grandchild1).
   690  				{5, [][2]string{{"/3/#/1", "/4/#/1/1/#/5"}}},
   691  			},
   692  
   693  			expected: []testPartition{
   694  				{1, [][2]string{{"/1/#/42/37/#/5", "/2/#/1/1/#/5"}}},
   695  				{2, [][2]string{{"/3/#/1", "/4"}}},
   696  				{3, [][2]string{{"/4", "/4/#/1/1/#/5"}}},
   697  			},
   698  		},
   699  
   700  		// Test child-grandchild example.
   701  		{
   702  			table1: "child1", table2: "grandchild1",
   703  
   704  			ancsParts: []testPartition{
   705  				{1, [][2]string{{"/1/#/2/3", "/2"}}},
   706  				{2, [][2]string{{"/2/#/2/3", "/2/#/5/2"}}},
   707  				{3, [][2]string{{"/4", "/5"}}},
   708  				{4, [][2]string{{"/2/#/5/2", "/2/#/6"}}},
   709  			},
   710  
   711  			descParts: []testPartition{
   712  				// Starts before any of the child1 spans.
   713  				{5, [][2]string{{"/1", "/1/#/5/6"}}},
   714  				// Starts in between the first and second
   715  				// child1 spans.
   716  				{6, [][2]string{{"/2/#/1/2", "/2/#/5/2/#/7"}}},
   717  			},
   718  
   719  			expected: []testPartition{
   720  				{1, [][2]string{{"/1/#/2/3", "/1/#/5/6"}}},
   721  				{2, [][2]string{{"/2/#/2/3", "/2/#/5/2"}}},
   722  				{4, [][2]string{{"/2/#/5/2", "/2/#/5/2/#/7"}}},
   723  				{5, [][2]string{{"/1", "/1/#/2/3"}}},
   724  				{6, [][2]string{{"/2/#/1/2", "/2/#/2/3"}}},
   725  			},
   726  		},
   727  	}
   728  
   729  	for testIdx, tc := range testCases {
   730  		t.Run(strconv.Itoa(testIdx), func(t *testing.T) {
   731  			join, err := newTestJoinNode(kvDB, tc.table1, tc.table2)
   732  			if err != nil {
   733  				t.Fatal(err)
   734  			}
   735  
   736  			ancsParts, err := makeSpanPartitions(kvDB, tc.ancsParts)
   737  			if err != nil {
   738  				t.Fatal(err)
   739  			}
   740  
   741  			descParts, err := makeSpanPartitions(kvDB, tc.descParts)
   742  			if err != nil {
   743  				t.Fatal(err)
   744  			}
   745  
   746  			actual, err := alignInterleavedSpans(join, ancsParts, descParts)
   747  			if err != nil {
   748  				t.Fatal(err)
   749  			}
   750  
   751  			expected, err := makeSpanPartitions(kvDB, tc.expected)
   752  			if err != nil {
   753  				t.Fatal(err)
   754  			}
   755  
   756  			if !reflect.DeepEqual(expected, actual) {
   757  				t.Errorf("unexpected partition results after aligning.\nexpected:\t%v\nactual:\t%v", expected, actual)
   758  			}
   759  		})
   760  	}
   761  }
   762  
   763  // computeMergeJoinOrdering determines if merge-join can be used to perform a join.
   764  //
   765  // It takes the orderings of the two data sources that are to be joined on a set
   766  // of equality columns (the join condition is that the value for the column
   767  // colA[i] equals the value for column colB[i]).
   768  //
   769  // If merge-join can be used, the function returns a ColumnOrdering that refers
   770  // to the equality columns by their index in colA/colB. Specifically column i in
   771  // the returned ordering refers to column colA[i] for A and colB[i] for B. This
   772  // is the ordering that must be used by the merge-join.
   773  //
   774  // The returned ordering can be partial, i.e. only contains a subset of the
   775  // equality columns.
   776  func computeMergeJoinOrdering(
   777  	a, b sqlbase.ColumnOrdering, colA, colB []int,
   778  ) sqlbase.ColumnOrdering {
   779  	if len(colA) != len(colB) {
   780  		panic(fmt.Sprintf("invalid column lists %v; %v", colA, colB))
   781  	}
   782  	var result sqlbase.ColumnOrdering
   783  	for i := 0; i < len(a) && i < len(b); i++ {
   784  		found := false
   785  		if a[i].Direction != b[i].Direction {
   786  			break
   787  		}
   788  		for j := range colA {
   789  			if colA[j] == a[i].ColIdx && colB[j] == b[i].ColIdx {
   790  				result = append(result, sqlbase.ColumnOrderInfo{
   791  					ColIdx:    j,
   792  					Direction: a[i].Direction,
   793  				})
   794  				found = true
   795  				break
   796  			}
   797  		}
   798  		if !found {
   799  			break
   800  		}
   801  	}
   802  	return result
   803  }
   804  
   805  func TestInterleavedNodes(t *testing.T) {
   806  	defer leaktest.AfterTest(t)()
   807  
   808  	s, sqlDB, kvDB := serverutils.StartServer(t, base.TestServerArgs{})
   809  	defer s.Stopper().Stop(context.Background())
   810  
   811  	sqlutils.CreateTestInterleavedHierarchy(t, sqlDB)
   812  
   813  	for _, tc := range []struct {
   814  		table1     string
   815  		table2     string
   816  		ancestor   string
   817  		descendant string
   818  	}{
   819  		// Refer to comment above CreateTestInterleavedHierarchy for
   820  		// table schemas.
   821  
   822  		{"parent1", "child1", "parent1", "child1"},
   823  		{"parent1", "child2", "parent1", "child2"},
   824  		{"parent1", "grandchild1", "parent1", "grandchild1"},
   825  		{"child1", "child2", "", ""},
   826  		{"child1", "grandchild1", "child1", "grandchild1"},
   827  		{"child2", "grandchild1", "", ""},
   828  		{"parent1", "parent2", "", ""},
   829  		{"parent2", "child1", "", ""},
   830  		{"parent2", "grandchild1", "", ""},
   831  		{"parent2", "child2", "", ""},
   832  	} {
   833  		// Run the subtests with the tables in both positions (left
   834  		// and right).
   835  		for i := 0; i < 2; i++ {
   836  			testName := fmt.Sprintf("%s-%s", tc.table1, tc.table2)
   837  			t.Run(testName, func(t *testing.T) {
   838  				join, err := newTestJoinNode(kvDB, tc.table1, tc.table2)
   839  				if err != nil {
   840  					t.Fatal(err)
   841  				}
   842  
   843  				ancestor, descendant := join.interleavedNodes()
   844  
   845  				if tc.ancestor == tc.descendant && tc.ancestor == "" {
   846  					if ancestor != nil || descendant != nil {
   847  						t.Errorf("expected ancestor and descendant to both be nil")
   848  					}
   849  					return
   850  				}
   851  
   852  				if ancestor == nil || descendant == nil {
   853  					t.Fatalf("expected ancestor and descendant to not be nil")
   854  				}
   855  
   856  				if tc.ancestor != ancestor.desc.Name || tc.descendant != descendant.desc.Name {
   857  					t.Errorf(
   858  						"unexpected ancestor and descendant nodes.\nexpected: %s (ancestor), %s (descendant)\nactual: %s (ancestor), %s (descendant)",
   859  						tc.ancestor, tc.descendant,
   860  						ancestor.desc.Name, descendant.desc.Name,
   861  					)
   862  				}
   863  			})
   864  			// Rerun the same subtests but flip the tables
   865  			tc.table1, tc.table2 = tc.table2, tc.table1
   866  		}
   867  	}
   868  }