vitess.io/vitess@v0.16.2/go/vt/vtgate/vindexes/lookup.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package vindexes 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 24 "vitess.io/vitess/go/sqltypes" 25 "vitess.io/vitess/go/vt/key" 26 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 27 vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" 28 ) 29 30 var ( 31 _ SingleColumn = (*LookupUnique)(nil) 32 _ Lookup = (*LookupUnique)(nil) 33 _ LookupPlanable = (*LookupUnique)(nil) 34 _ SingleColumn = (*LookupNonUnique)(nil) 35 _ Lookup = (*LookupNonUnique)(nil) 36 _ LookupPlanable = (*LookupNonUnique)(nil) 37 ) 38 39 func init() { 40 Register("lookup", NewLookup) 41 Register("lookup_unique", NewLookupUnique) 42 } 43 44 // LookupNonUnique defines a vindex that uses a lookup table and create a mapping between from ids and KeyspaceId. 45 // It's NonUnique and a Lookup. 46 type LookupNonUnique struct { 47 name string 48 writeOnly bool 49 noVerify bool 50 lkp lookupInternal 51 } 52 53 func (ln *LookupNonUnique) GetCommitOrder() vtgatepb.CommitOrder { 54 return vtgatepb.CommitOrder_NORMAL 55 } 56 57 func (ln *LookupNonUnique) AllowBatch() bool { 58 return ln.lkp.BatchLookup 59 } 60 61 func (ln *LookupNonUnique) AutoCommitEnabled() bool { 62 return ln.lkp.Autocommit 63 } 64 65 // String returns the name of the vindex. 66 func (ln *LookupNonUnique) String() string { 67 return ln.name 68 } 69 70 // Cost returns the cost of this vindex as 20. 71 func (ln *LookupNonUnique) Cost() int { 72 return 20 73 } 74 75 // IsUnique returns false since the Vindex is non unique. 76 func (ln *LookupNonUnique) IsUnique() bool { 77 return false 78 } 79 80 // NeedsVCursor satisfies the Vindex interface. 81 func (ln *LookupNonUnique) NeedsVCursor() bool { 82 return true 83 } 84 85 // Map can map ids to key.Destination objects. 86 func (ln *LookupNonUnique) Map(ctx context.Context, vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) { 87 out := make([]key.Destination, 0, len(ids)) 88 if ln.writeOnly { 89 for range ids { 90 out = append(out, key.DestinationKeyRange{KeyRange: &topodatapb.KeyRange{}}) 91 } 92 return out, nil 93 } 94 95 // if ignore_nulls is set and the query is about single null value, then fallback to all shards 96 if len(ids) == 1 && ids[0].IsNull() && ln.lkp.IgnoreNulls { 97 for range ids { 98 out = append(out, key.DestinationKeyRange{KeyRange: &topodatapb.KeyRange{}}) 99 } 100 return out, nil 101 } 102 103 results, err := ln.lkp.Lookup(ctx, vcursor, ids, vtgatepb.CommitOrder_NORMAL) 104 if err != nil { 105 return nil, err 106 } 107 108 return ln.MapResult(ids, results) 109 } 110 111 // MapResult implements the LookupPlanable interface 112 func (ln *LookupNonUnique) MapResult(ids []sqltypes.Value, results []*sqltypes.Result) ([]key.Destination, error) { 113 out := make([]key.Destination, 0, len(ids)) 114 if ln.writeOnly { 115 for range ids { 116 out = append(out, key.DestinationKeyRange{KeyRange: &topodatapb.KeyRange{}}) 117 } 118 return out, nil 119 } 120 for _, result := range results { 121 if len(result.Rows) == 0 { 122 out = append(out, key.DestinationNone{}) 123 continue 124 } 125 ksids := make([][]byte, 0, len(result.Rows)) 126 for _, row := range result.Rows { 127 rowBytes, err := row[0].ToBytes() 128 if err != nil { 129 return nil, err 130 } 131 ksids = append(ksids, rowBytes) 132 } 133 out = append(out, key.DestinationKeyspaceIDs(ksids)) 134 } 135 return out, nil 136 } 137 138 // Verify returns true if ids maps to ksids. 139 func (ln *LookupNonUnique) Verify(ctx context.Context, vcursor VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) { 140 if ln.writeOnly || ln.noVerify { 141 out := make([]bool, len(ids)) 142 for i := range ids { 143 out[i] = true 144 } 145 return out, nil 146 } 147 return ln.lkp.Verify(ctx, vcursor, ids, ksidsToValues(ksids)) 148 } 149 150 // Create reserves the id by inserting it into the vindex table. 151 func (ln *LookupNonUnique) Create(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value, ksids [][]byte, ignoreMode bool) error { 152 return ln.lkp.Create(ctx, vcursor, rowsColValues, ksidsToValues(ksids), ignoreMode) 153 } 154 155 // Delete deletes the entry from the vindex table. 156 func (ln *LookupNonUnique) Delete(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value, ksid []byte) error { 157 return ln.lkp.Delete(ctx, vcursor, rowsColValues, sqltypes.MakeTrusted(sqltypes.VarBinary, ksid), vtgatepb.CommitOrder_NORMAL) 158 } 159 160 // Update updates the entry in the vindex table. 161 func (ln *LookupNonUnique) Update(ctx context.Context, vcursor VCursor, oldValues []sqltypes.Value, ksid []byte, newValues []sqltypes.Value) error { 162 return ln.lkp.Update(ctx, vcursor, oldValues, ksid, sqltypes.MakeTrusted(sqltypes.VarBinary, ksid), newValues) 163 } 164 165 // MarshalJSON returns a JSON representation of LookupHash. 166 func (ln *LookupNonUnique) MarshalJSON() ([]byte, error) { 167 return json.Marshal(ln.lkp) 168 } 169 170 // Query implements the LookupPlanable interface 171 func (ln *LookupNonUnique) Query() (selQuery string, arguments []string) { 172 return ln.lkp.query() 173 } 174 175 // NewLookup creates a LookupNonUnique vindex. 176 // The supplied map has the following required fields: 177 // 178 // table: name of the backing table. It can be qualified by the keyspace. 179 // from: list of columns in the table that have the 'from' values of the lookup vindex. 180 // to: The 'to' column name of the table. 181 // 182 // The following fields are optional: 183 // 184 // autocommit: setting this to "true" will cause inserts to upsert and deletes to be ignored. 185 // write_only: in this mode, Map functions return the full keyrange causing a full scatter. 186 // no_verify: in this mode, Verify will always succeed. 187 func NewLookup(name string, m map[string]string) (Vindex, error) { 188 lookup := &LookupNonUnique{name: name} 189 190 cc, err := parseCommonConfig(m) 191 if err != nil { 192 return nil, err 193 } 194 lookup.writeOnly, err = boolFromMap(m, "write_only") 195 if err != nil { 196 return nil, err 197 } 198 199 lookup.noVerify, err = boolFromMap(m, "no_verify") 200 if err != nil { 201 return nil, err 202 } 203 204 // if autocommit is on for non-unique lookup, upsert should also be on. 205 upsert := cc.autocommit || cc.multiShardAutocommit 206 if err := lookup.lkp.Init(m, cc.autocommit, upsert, cc.multiShardAutocommit); err != nil { 207 return nil, err 208 } 209 return lookup, nil 210 } 211 212 func ksidsToValues(ksids [][]byte) []sqltypes.Value { 213 values := make([]sqltypes.Value, 0, len(ksids)) 214 for _, ksid := range ksids { 215 values = append(values, sqltypes.MakeTrusted(sqltypes.VarBinary, ksid)) 216 } 217 return values 218 } 219 220 //==================================================================== 221 222 // LookupUnique defines a vindex that uses a lookup table. 223 // The table is expected to define the id column as unique. It's 224 // Unique and a Lookup. 225 type LookupUnique struct { 226 name string 227 writeOnly bool 228 noVerify bool 229 lkp lookupInternal 230 } 231 232 func (lu *LookupUnique) GetCommitOrder() vtgatepb.CommitOrder { 233 return vtgatepb.CommitOrder_NORMAL 234 } 235 236 func (lu *LookupUnique) AllowBatch() bool { 237 return lu.lkp.BatchLookup 238 } 239 240 func (lu *LookupUnique) AutoCommitEnabled() bool { 241 return lu.lkp.Autocommit 242 } 243 244 // NewLookupUnique creates a LookupUnique vindex. 245 // The supplied map has the following required fields: 246 // 247 // table: name of the backing table. It can be qualified by the keyspace. 248 // from: list of columns in the table that have the 'from' values of the lookup vindex. 249 // to: The 'to' column name of the table. 250 // 251 // The following fields are optional: 252 // 253 // autocommit: setting this to "true" will cause deletes to be ignored. 254 // write_only: in this mode, Map functions return the full keyrange causing a full scatter. 255 func NewLookupUnique(name string, m map[string]string) (Vindex, error) { 256 lu := &LookupUnique{name: name} 257 258 cc, err := parseCommonConfig(m) 259 if err != nil { 260 return nil, err 261 } 262 lu.writeOnly, err = boolFromMap(m, "write_only") 263 if err != nil { 264 return nil, err 265 } 266 267 lu.noVerify, err = boolFromMap(m, "no_verify") 268 if err != nil { 269 return nil, err 270 } 271 272 // Don't allow upserts for unique vindexes. 273 if err := lu.lkp.Init(m, cc.autocommit, false /* upsert */, cc.multiShardAutocommit); err != nil { 274 return nil, err 275 } 276 return lu, nil 277 } 278 279 // String returns the name of the vindex. 280 func (lu *LookupUnique) String() string { 281 return lu.name 282 } 283 284 // Cost returns the cost of this vindex as 10. 285 func (lu *LookupUnique) Cost() int { 286 return 10 287 } 288 289 // IsUnique returns true since the Vindex is unique. 290 func (lu *LookupUnique) IsUnique() bool { 291 return true 292 } 293 294 // NeedsVCursor satisfies the Vindex interface. 295 func (lu *LookupUnique) NeedsVCursor() bool { 296 return true 297 } 298 299 // Map can map ids to key.Destination objects. 300 func (lu *LookupUnique) Map(ctx context.Context, vcursor VCursor, ids []sqltypes.Value) ([]key.Destination, error) { 301 if lu.writeOnly { 302 out := make([]key.Destination, 0, len(ids)) 303 for range ids { 304 out = append(out, key.DestinationKeyRange{KeyRange: &topodatapb.KeyRange{}}) 305 } 306 return out, nil 307 } 308 results, err := lu.lkp.Lookup(ctx, vcursor, ids, vtgatepb.CommitOrder_NORMAL) 309 if err != nil { 310 return nil, err 311 } 312 return lu.MapResult(ids, results) 313 } 314 315 func (lu *LookupUnique) MapResult(ids []sqltypes.Value, results []*sqltypes.Result) ([]key.Destination, error) { 316 out := make([]key.Destination, 0, len(ids)) 317 for i, result := range results { 318 switch len(result.Rows) { 319 case 0: 320 out = append(out, key.DestinationNone{}) 321 case 1: 322 rowBytes, err := result.Rows[0][0].ToBytes() 323 if err != nil { 324 return nil, err 325 } 326 out = append(out, key.DestinationKeyspaceID(rowBytes)) 327 default: 328 return nil, fmt.Errorf("Lookup.Map: unexpected multiple results from vindex %s: %v", lu.lkp.Table, ids[i]) 329 } 330 } 331 return out, nil 332 } 333 334 // Verify returns true if ids maps to ksids. 335 func (lu *LookupUnique) Verify(ctx context.Context, vcursor VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) { 336 if lu.writeOnly || lu.noVerify { 337 out := make([]bool, len(ids)) 338 for i := range ids { 339 out[i] = true 340 } 341 return out, nil 342 } 343 return lu.lkp.Verify(ctx, vcursor, ids, ksidsToValues(ksids)) 344 } 345 346 // Create reserves the id by inserting it into the vindex table. 347 func (lu *LookupUnique) Create(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value, ksids [][]byte, ignoreMode bool) error { 348 return lu.lkp.Create(ctx, vcursor, rowsColValues, ksidsToValues(ksids), ignoreMode) 349 } 350 351 // Update updates the entry in the vindex table. 352 func (lu *LookupUnique) Update(ctx context.Context, vcursor VCursor, oldValues []sqltypes.Value, ksid []byte, newValues []sqltypes.Value) error { 353 return lu.lkp.Update(ctx, vcursor, oldValues, ksid, sqltypes.MakeTrusted(sqltypes.VarBinary, ksid), newValues) 354 } 355 356 // Delete deletes the entry from the vindex table. 357 func (lu *LookupUnique) Delete(ctx context.Context, vcursor VCursor, rowsColValues [][]sqltypes.Value, ksid []byte) error { 358 return lu.lkp.Delete(ctx, vcursor, rowsColValues, sqltypes.MakeTrusted(sqltypes.VarBinary, ksid), vtgatepb.CommitOrder_NORMAL) 359 } 360 361 // MarshalJSON returns a JSON representation of LookupUnique. 362 func (lu *LookupUnique) MarshalJSON() ([]byte, error) { 363 return json.Marshal(lu.lkp) 364 } 365 366 // IsBackfilling implements the LookupBackfill interface 367 func (lu *LookupUnique) IsBackfilling() bool { 368 return lu.writeOnly 369 } 370 371 func (lu *LookupUnique) LookupQuery() (string, error) { 372 return lu.lkp.sel, nil 373 } 374 375 func (lu *LookupUnique) Query() (string, []string) { 376 return lu.lkp.query() 377 }