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

     1  // Copyright 2018 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 sqlbase
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  	"fmt"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    21  )
    22  
    23  // ProcessTargetColumns returns the column descriptors identified by the
    24  // given name list. It also checks that a given column name is only
    25  // listed once. If no column names are given (special case for INSERT)
    26  // and ensureColumns is set, the descriptors for all visible columns
    27  // are returned. If allowMutations is set, even columns undergoing
    28  // mutations are added.
    29  func ProcessTargetColumns(
    30  	tableDesc *ImmutableTableDescriptor, nameList tree.NameList, ensureColumns, allowMutations bool,
    31  ) ([]ColumnDescriptor, error) {
    32  	if len(nameList) == 0 {
    33  		if ensureColumns {
    34  			// VisibleColumns is used here to prevent INSERT INTO <table> VALUES (...)
    35  			// (as opposed to INSERT INTO <table> (...) VALUES (...)) from writing
    36  			// hidden columns. At present, the only hidden column is the implicit rowid
    37  			// primary key column.
    38  			return tableDesc.VisibleColumns(), nil
    39  		}
    40  		return nil, nil
    41  	}
    42  
    43  	cols := make([]ColumnDescriptor, len(nameList))
    44  	colIDSet := make(map[ColumnID]struct{}, len(nameList))
    45  	for i, colName := range nameList {
    46  		var col *ColumnDescriptor
    47  		var err error
    48  		if allowMutations {
    49  			col, _, err = tableDesc.FindColumnByName(colName)
    50  		} else {
    51  			col, err = tableDesc.FindActiveColumnByName(string(colName))
    52  		}
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  
    57  		if _, ok := colIDSet[col.ID]; ok {
    58  			return nil, pgerror.Newf(pgcode.Syntax,
    59  				"multiple assignments to the same column %q", &nameList[i])
    60  		}
    61  		colIDSet[col.ID] = struct{}{}
    62  		cols[i] = *col
    63  	}
    64  
    65  	return cols, nil
    66  }
    67  
    68  // sourceNameMatches checks whether a request for table name toFind
    69  // can be satisfied by the FROM source name srcName.
    70  //
    71  // For example:
    72  // - a request for "kv" is matched by a source named "db1.public.kv"
    73  // - a request for "public.kv" is not matched by a source named just "kv"
    74  func sourceNameMatches(srcName *tree.TableName, toFind tree.TableName) bool {
    75  	if srcName.ObjectName != toFind.ObjectName {
    76  		return false
    77  	}
    78  	if toFind.ExplicitSchema {
    79  		if !srcName.ExplicitSchema || srcName.SchemaName != toFind.SchemaName {
    80  			return false
    81  		}
    82  		if toFind.ExplicitCatalog {
    83  			if !srcName.ExplicitCatalog || srcName.CatalogName != toFind.CatalogName {
    84  				return false
    85  			}
    86  		}
    87  	}
    88  	return true
    89  }
    90  
    91  // ColumnResolver is a utility struct to be used when resolving column
    92  // names to point to one of the data sources and one of the column IDs
    93  // in that data source.
    94  type ColumnResolver struct {
    95  	Source *DataSourceInfo
    96  
    97  	// ResolverState is modified in-place by the implementation of the
    98  	// tree.ColumnItemResolver interface in resolver.go.
    99  	ResolverState struct {
   100  		ColIdx int
   101  	}
   102  }
   103  
   104  // FindSourceMatchingName is part of the tree.ColumnItemResolver interface.
   105  func (r *ColumnResolver) FindSourceMatchingName(
   106  	ctx context.Context, tn tree.TableName,
   107  ) (
   108  	res tree.NumResolutionResults,
   109  	prefix *tree.TableName,
   110  	srcMeta tree.ColumnSourceMeta,
   111  	err error,
   112  ) {
   113  	if !sourceNameMatches(&r.Source.SourceAlias, tn) {
   114  		return tree.NoResults, nil, nil, nil
   115  	}
   116  	prefix = &r.Source.SourceAlias
   117  	return tree.ExactlyOne, prefix, nil, nil
   118  }
   119  
   120  const invalidColIdx = -1
   121  
   122  // FindSourceProvidingColumn is part of the tree.ColumnItemResolver interface.
   123  func (r *ColumnResolver) FindSourceProvidingColumn(
   124  	ctx context.Context, col tree.Name,
   125  ) (prefix *tree.TableName, srcMeta tree.ColumnSourceMeta, colHint int, err error) {
   126  	colIdx := invalidColIdx
   127  	colName := string(col)
   128  
   129  	for idx := range r.Source.SourceColumns {
   130  		colIdx, err = r.findColHelper(colName, colIdx, idx)
   131  		if err != nil {
   132  			return nil, nil, -1, err
   133  		}
   134  		if colIdx != invalidColIdx {
   135  			prefix = &r.Source.SourceAlias
   136  			break
   137  		}
   138  	}
   139  	if colIdx == invalidColIdx {
   140  		colAlloc := col
   141  		return nil, nil, -1, NewUndefinedColumnError(tree.ErrString(&colAlloc))
   142  	}
   143  	r.ResolverState.ColIdx = colIdx
   144  	return prefix, nil, colIdx, nil
   145  }
   146  
   147  // Resolve is part of the tree.ColumnItemResolver interface.
   148  func (r *ColumnResolver) Resolve(
   149  	ctx context.Context,
   150  	prefix *tree.TableName,
   151  	srcMeta tree.ColumnSourceMeta,
   152  	colHint int,
   153  	col tree.Name,
   154  ) (tree.ColumnResolutionResult, error) {
   155  	if colHint != -1 {
   156  		// (*ColumnItem).Resolve() is telling us that we found the source
   157  		// via FindSourceProvidingColumn(). So we can count on
   158  		// r.ResolverState.ColIdx being set already. There's nothing remaining
   159  		// to do!
   160  		return nil, nil
   161  	}
   162  
   163  	// If we're here, we just know that some source alias was found that
   164  	// matches the column prefix, but we haven't found the column
   165  	// yet. Do this now.
   166  	// FindSourceMatchingName() was careful to set r.ResolverState.SrcIdx
   167  	// and r.ResolverState.ColSetIdx for us.
   168  	colIdx := invalidColIdx
   169  	colName := string(col)
   170  	for idx := range r.Source.SourceColumns {
   171  		var err error
   172  		colIdx, err = r.findColHelper(colName, colIdx, idx)
   173  		if err != nil {
   174  			return nil, err
   175  		}
   176  	}
   177  
   178  	if colIdx == invalidColIdx {
   179  		r.ResolverState.ColIdx = invalidColIdx
   180  		return nil, NewUndefinedColumnError(
   181  			tree.ErrString(tree.NewColumnItem(&r.Source.SourceAlias, tree.Name(colName))))
   182  	}
   183  	r.ResolverState.ColIdx = colIdx
   184  	return nil, nil
   185  }
   186  
   187  // findColHelper is used by FindSourceProvidingColumn and Resolve above.
   188  // It checks whether a column name is available in a given data source.
   189  func (r *ColumnResolver) findColHelper(colName string, colIdx, idx int) (int, error) {
   190  	col := r.Source.SourceColumns[idx]
   191  	if col.Name == colName {
   192  		if colIdx != invalidColIdx {
   193  			colString := tree.ErrString(r.Source.NodeFormatter(idx))
   194  			var msgBuf bytes.Buffer
   195  			name := tree.ErrString(&r.Source.SourceAlias)
   196  			if len(name) == 0 {
   197  				name = "<anonymous>"
   198  			}
   199  			fmt.Fprintf(&msgBuf, "%s.%s", name, colString)
   200  			return invalidColIdx, pgerror.Newf(pgcode.AmbiguousColumn,
   201  				"column reference %q is ambiguous (candidates: %s)", colString, msgBuf.String())
   202  		}
   203  		colIdx = idx
   204  	}
   205  	return colIdx, nil
   206  }
   207  
   208  // NameResolutionResult implements the tree.NameResolutionResult interface.
   209  func (*TableDescriptor) NameResolutionResult() {}
   210  
   211  // SchemaMeta implements the tree.SchemaMeta interface.
   212  func (*DatabaseDescriptor) SchemaMeta() {}
   213  
   214  // SchemaMeta implements the tree.SchemaMeta interface.
   215  func (Descriptor) SchemaMeta() {}
   216  
   217  // NameResolutionResult implements the tree.NameResolutionResult interface.
   218  func (Descriptor) NameResolutionResult() {}