@@ -57,64 +57,99 @@ func keyColumnArrayContainsColumn(keyColumns []*proto.KeyColumn, c string) bool
5757}
5858
5959// keyColumnsToColumnPath returns a list of all the column sets to use in path keys
60- func keyColumnsToColumnPath (keyColumns []* proto.KeyColumn ) (columnPaths [][]string , baseCost Cost ) {
60+ func keyColumnsToColumnPath (keyColumns []* proto.KeyColumn ) ([][]string , Cost ) {
61+ var columnPaths [][]string
62+ var baseCost Cost
63+
6164 if len (keyColumns ) == 0 {
62- return
65+ return columnPaths , baseCost
6366 }
6467
65- // collect required and optional columns - we build a single path for all of them
66- var requiredKeys , optionalKeys []string
67- // an array of paths for any of keys - each path will have a single element (the any-of key)
68- var anyOfKeys [][]string
68+ // collect required and optional and any of keys
69+ var requiredKeys , optionalKeys , anyOfKeys []string
6970 for _ , c := range keyColumns {
7071 if c .Require == plugin .Required {
7172 requiredKeys = append (requiredKeys , c .Name )
7273 } else if c .Require == plugin .Optional {
7374 optionalKeys = append (optionalKeys , c .Name )
7475 } else if c .Require == plugin .AnyOf {
75- anyOfKeys = append (anyOfKeys , [] string { c .Name } )
76+ anyOfKeys = append (anyOfKeys , c .Name )
7677 }
7778 }
7879
79- if len (requiredKeys ) > 0 {
80- // add required keys as a single path
81- columnPaths = append (columnPaths , requiredKeys )
82- }
80+ var requiredColumnPaths [][]string
81+ // if we have any-of keys, for each any-of key we will create a separate path containing that key and all required keys
8382 if len (anyOfKeys ) > 0 {
84- // add a separate path for _each_ any-of key
85- columnPaths = append (columnPaths , anyOfKeys ... )
83+ for _ , a := range anyOfKeys {
84+ columnPath := append ([]string {a }, requiredKeys ... )
85+ requiredColumnPaths = append (requiredColumnPaths , columnPath )
86+ }
87+ } else if len (requiredKeys ) > 0 {
88+ // add required keys as a single path
89+ requiredColumnPaths = append (requiredColumnPaths , requiredKeys )
8690 }
91+
8792 // if we have any column paths (meaning we have aither required or any-of columns),
8893 // we have required keys so make the base cost CHEAP
89- if len (columnPaths ) > 0 {
94+ if len (requiredColumnPaths ) > 0 {
9095 baseCost = requiredKeyColumnBaseCost
9196 } else {
9297 baseCost = optionalKeyColumnBaseCost
9398 }
94- // if there are optional keys, add:
95- // - a path with required keys and each optional key
96- // - a path with each any-of key and each optional key
99+
100+ // create output column paths - init to the required column paths - we will add permutations with optional keys
101+ columnPaths = requiredColumnPaths
102+ // now create additional paths based on the required paths, with each of the optional keys
97103 for _ , optional := range optionalKeys {
104+ col := optional
98105 // NOTE: append onto optional, NOT requiredKeys - otherwise we end up reusing the underlying array
99106 // and mutating values in columnPaths
100107
101108 // if there are any required keys, build path from optional AND required
102- if len (requiredKeys ) > 0 {
103- p := append ([] string { optional }, requiredKeys ... )
104- columnPaths = append (columnPaths , p )
105- }
106- // if there are any anyOf keys, build path from optional AND required
107- for _ , a := range anyOfKeys {
108- p := append ([] string { optional }, a ... )
109- columnPaths = append (columnPaths , p )
109+ if len (requiredColumnPaths ) > 0 {
110+ for _ , requiredPath := range requiredColumnPaths {
111+ p : = append (append ([] string {}, requiredPath ... ), col )
112+ columnPaths = append ( columnPaths , p )
113+ }
114+ } else {
115+ // if there are no required keys or anyof keys, just create a path from the optional
116+ columnPaths = append (columnPaths , [] string { col } )
110117 }
111- // if there are no required keys or anyof keys, just create a path from the optional
112- if baseCost == optionalKeyColumnBaseCost {
113- columnPaths = append (columnPaths , []string {optional })
118+ }
119+
120+ return columnPaths , baseCost
121+ }
122+
123+ func columnPathsToPathKeys (columnPaths [][]string , allColumns []string , baseCost Cost ) []PathKey {
124+
125+ var res []PathKey
126+
127+ // generate path keys each column set
128+ for _ , s := range columnPaths {
129+ // create a path for just the column path
130+ res = append (res , PathKey {
131+ ColumnNames : s ,
132+ // make this cheap so the planner prefers to give us the qual
133+ Rows : baseCost * keyColumnOnlyCostMultiplier ,
134+ })
135+ // also create paths for the columns path WITH each other column
136+ for _ , c := range allColumns {
137+ if ! slices .Contains (s , c ) {
138+ // NOTE: create a new slice rather than appending onto s - to avoid clash between loop iterations
139+ columnNames := append ([]string {c }, s ... )
140+
141+ res = append (res , PathKey {
142+ ColumnNames : columnNames ,
143+ // make this even cheaper - prefer to include all quals which were provided
144+ Rows : baseCost ,
145+ })
146+ }
114147 }
115148 }
116149
117- return
150+ log .Printf ("[TRACE] columnPathsToPathKeys %d column paths %d all columns, %d pathkeys" , len (columnPaths ), len (allColumns ), len (res ))
151+
152+ return res
118153}
119154
120155func LegacyKeyColumnsToPathKeys (requiredColumns , optionalColumns * proto.KeyColumnsSet , allColumns []string ) []PathKey {
@@ -155,34 +190,3 @@ func LegacyKeyColumnsToColumnPaths(k *proto.KeyColumnsSet) [][]string {
155190 }
156191 return res
157192}
158- func columnPathsToPathKeys (columnPaths [][]string , allColumns []string , baseCost Cost ) []PathKey {
159-
160- var res []PathKey
161-
162- // generate path keys each column set
163- for _ , s := range columnPaths {
164- // create a path for just the column path
165- res = append (res , PathKey {
166- ColumnNames : s ,
167- // make this cheap so the planner prefers to give us the qual
168- Rows : baseCost * keyColumnOnlyCostMultiplier ,
169- })
170- // also create paths for the columns path WITH each other column
171- for _ , c := range allColumns {
172- if ! slices .Contains (s , c ) {
173- // NOTE: create a new slice rather than appending onto s - to avoid clash between loop iterations
174- columnNames := append ([]string {c }, s ... )
175-
176- res = append (res , PathKey {
177- ColumnNames : columnNames ,
178- // make this even cheaper - prefer to include all quals which were provided
179- Rows : baseCost ,
180- })
181- }
182- }
183- }
184-
185- log .Printf ("[TRACE] columnPathsToPathKeys %d column paths %d all columns, %d pathkeys" , len (columnPaths ), len (allColumns ), len (res ))
186-
187- return res
188- }
0 commit comments