github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/compile/util.go (about) 1 // Copyright 2023 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package compile 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "time" 22 23 plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" 24 25 "github.com/matrixorigin/matrixone/pkg/catalog" 26 "github.com/matrixorigin/matrixone/pkg/container/types" 27 "github.com/matrixorigin/matrixone/pkg/pb/plan" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine" 29 "github.com/matrixorigin/matrixone/pkg/vm/process" 30 ) 31 32 const ( 33 INDEX_TYPE_PRIMARY = "PRIMARY" 34 INDEX_TYPE_UNIQUE = "UNIQUE" 35 INDEX_TYPE_MULTIPLE = "MULTIPLE" 36 ) 37 38 const ( 39 INDEX_VISIBLE_YES = 1 40 INDEX_VISIBLE_NO = 0 41 ) 42 43 const ( 44 INDEX_HIDDEN_YES = 1 45 INDEX_HIDDEN_NO = 0 46 ) 47 48 const ( 49 NULL_VALUE = "null" 50 EMPTY_STRING = "" 51 ) 52 53 const ( 54 ALLOCID_INDEX_KEY = "index_key" 55 ) 56 57 var ( 58 // see the comment in fuzzyCheck func genCondition for the reason why has to be two SQLs 59 fuzzyNonCompoundCheck = "select %s from `%s`.`%s` where %s in (%s) group by %s having count(*) > 1 limit 1;" 60 fuzzyCompoundCheck = "select serial(%s) from `%s`.`%s` where %s group by serial(%s) having count(*) > 1 limit 1;" 61 ) 62 63 var ( 64 insertIntoSingleIndexTableWithPKeyFormat = "insert into `%s`.`%s` select (%s), %s from `%s`.`%s` where (%s) is not null;" 65 insertIntoUniqueIndexTableWithPKeyFormat = "insert into `%s`.`%s` select serial(%s), %s from `%s`.`%s` where serial(%s) is not null;" 66 insertIntoSecondaryIndexTableWithPKeyFormat = "insert into `%s`.`%s` select serial_full(%s), %s from `%s`.`%s`;" 67 insertIntoSingleIndexTableWithoutPKeyFormat = "insert into `%s`.`%s` select (%s) from `%s`.`%s` where (%s) is not null;" 68 insertIntoIndexTableWithoutPKeyFormat = "insert into `%s`.`%s` select serial(%s) from `%s`.`%s` where serial(%s) is not null;" 69 insertIntoMasterIndexTableFormat = "insert into `%s`.`%s` select serial_full('%s', %s, %s), %s from `%s`.`%s`;" 70 createIndexTableForamt = "create table `%s`.`%s` (%s);" 71 ) 72 73 var ( 74 deleteMoIndexesWithDatabaseIdFormat = `delete from mo_catalog.mo_indexes where database_id = %v;` 75 deleteMoIndexesWithTableIdFormat = `delete from mo_catalog.mo_indexes where table_id = %v;` 76 deleteMoIndexesWithTableIdAndIndexNameFormat = `delete from mo_catalog.mo_indexes where table_id = %v and name = '%s';` 77 updateMoIndexesVisibleFormat = `update mo_catalog.mo_indexes set is_visible = %v where table_id = %v and name = '%s';` 78 updateMoIndexesTruncateTableFormat = `update mo_catalog.mo_indexes set table_id = %v where table_id = %v` 79 updateMoIndexesAlgoParams = `update mo_catalog.mo_indexes set algo_params = '%s' where table_id = %v and name = '%s';` 80 ) 81 82 var ( 83 deleteMoTablePartitionsWithDatabaseIdFormat = `delete from mo_catalog.mo_table_partitions where database_id = %v;` 84 deleteMoTablePartitionsWithTableIdFormat = `delete from mo_catalog.mo_table_partitions where table_id = %v;` 85 //deleteMoTablePartitionsWithTableIdAndIndexNameFormat = `delete from mo_catalog.mo_table_partitions where table_id = %v and name = '%s';` 86 ) 87 88 // genCreateIndexTableSql: Generate ddl statements for creating index table 89 func genCreateIndexTableSql(indexTableDef *plan.TableDef, indexDef *plan.IndexDef, DBName string) string { 90 var sql string 91 planCols := indexTableDef.GetCols() 92 for i, planCol := range planCols { 93 if i >= 1 { 94 sql += "," 95 } 96 sql += planCol.Name + " " 97 typeId := types.T(planCol.Typ.Id) 98 switch typeId { 99 case types.T_bit: 100 sql += fmt.Sprintf("BIT(%d)", planCol.Typ.Width) 101 case types.T_char: 102 sql += fmt.Sprintf("CHAR(%d)", planCol.Typ.Width) 103 case types.T_varchar: 104 sql += fmt.Sprintf("VARCHAR(%d)", planCol.Typ.Width) 105 case types.T_binary: 106 sql += fmt.Sprintf("BINARY(%d)", planCol.Typ.Width) 107 case types.T_varbinary: 108 sql += fmt.Sprintf("VARBINARY(%d)", planCol.Typ.Width) 109 case types.T_decimal64: 110 sql += fmt.Sprintf("DECIMAL(%d,%d)", planCol.Typ.Width, planCol.Typ.Scale) 111 case types.T_decimal128: 112 sql += fmt.Sprintf("DECIMAL(%d,%d)", planCol.Typ.Width, planCol.Typ.Scale) 113 default: 114 sql += typeId.String() 115 } 116 if i == 0 { 117 sql += " primary key" 118 } 119 } 120 return fmt.Sprintf(createIndexTableForamt, DBName, indexDef.IndexTableName, sql) 121 } 122 123 // genCreateIndexTableSqlForIvfIndex: Generate ddl statements for creating ivf index table 124 // NOTE: Here the columns are part of meta, centroids, entries table. 125 // meta -> key varchar(65535), value varchar(65535) 126 // centroids -> version int64, centroid_id int64, centroid vecf32(xx) 127 // entries -> version int64, entry_id int64, pk xx 128 // TODO: later on merge with genCreateIndexTableSql 129 func genCreateIndexTableSqlForIvfIndex(indexTableDef *plan.TableDef, indexDef *plan.IndexDef, DBName string) string { 130 var sql string 131 planCols := indexTableDef.GetCols() 132 for i, planCol := range planCols { 133 if planCol.Name == catalog.CPrimaryKeyColName { 134 continue 135 } 136 if i >= 1 { 137 sql += "," 138 } 139 sql += "`" + planCol.Name + "`" + " " 140 typeId := types.T(planCol.Typ.Id) 141 switch typeId { 142 case types.T_char: 143 sql += fmt.Sprintf("CHAR(%d)", planCol.Typ.Width) 144 case types.T_varchar: 145 sql += fmt.Sprintf("VARCHAR(%d)", planCol.Typ.Width) 146 case types.T_binary: 147 sql += fmt.Sprintf("BINARY(%d)", planCol.Typ.Width) 148 case types.T_varbinary: 149 sql += fmt.Sprintf("VARBINARY(%d)", planCol.Typ.Width) 150 case types.T_decimal64: 151 sql += fmt.Sprintf("DECIMAL(%d,%d)", planCol.Typ.Width, planCol.Typ.Scale) 152 case types.T_decimal128: 153 sql += fmt.Sprintf("DECIMAL(%d,%d)", planCol.Typ.Width, planCol.Typ.Scale) 154 case types.T_array_float32: 155 sql += fmt.Sprintf("VECF32(%d)", planCol.Typ.Width) 156 case types.T_array_float64: 157 sql += fmt.Sprintf("VECF64(%d)", planCol.Typ.Width) 158 default: 159 sql += typeId.String() 160 } 161 162 } 163 164 if indexTableDef.Pkey != nil && indexTableDef.Pkey.Names != nil { 165 pkStr := fmt.Sprintf(", primary key ( %s ) ", partsToColsStr(indexTableDef.Pkey.Names)) 166 sql += pkStr 167 } 168 169 return fmt.Sprintf(createIndexTableForamt, DBName, indexDef.IndexTableName, sql) 170 } 171 172 // genInsertIndexTableSql: Generate an insert statement for inserting data into the index table 173 func genInsertIndexTableSql(originTableDef *plan.TableDef, indexDef *plan.IndexDef, DBName string, isUnique bool) string { 174 // insert data into index table 175 var insertSQL string 176 temp := partsToColsStr(indexDef.Parts) 177 if len(originTableDef.Pkey.PkeyColName) == 0 { 178 if len(indexDef.Parts) == 1 { 179 insertSQL = fmt.Sprintf(insertIntoSingleIndexTableWithoutPKeyFormat, DBName, indexDef.IndexTableName, temp, DBName, originTableDef.Name, temp) 180 } else { 181 insertSQL = fmt.Sprintf(insertIntoIndexTableWithoutPKeyFormat, DBName, indexDef.IndexTableName, temp, DBName, originTableDef.Name, temp) 182 } 183 } else { 184 pkeyName := originTableDef.Pkey.PkeyColName 185 var pKeyMsg string 186 if pkeyName == catalog.CPrimaryKeyColName { 187 pKeyMsg = "serial(" 188 for i, part := range originTableDef.Pkey.Names { 189 if i == 0 { 190 pKeyMsg += part 191 } else { 192 pKeyMsg += "," + part 193 } 194 } 195 pKeyMsg += ")" 196 } else { 197 pKeyMsg = pkeyName 198 } 199 if len(indexDef.Parts) == 1 { 200 insertSQL = fmt.Sprintf(insertIntoSingleIndexTableWithPKeyFormat, DBName, indexDef.IndexTableName, temp, pKeyMsg, DBName, originTableDef.Name, temp) 201 } else { 202 if isUnique { 203 insertSQL = fmt.Sprintf(insertIntoUniqueIndexTableWithPKeyFormat, DBName, indexDef.IndexTableName, temp, pKeyMsg, DBName, originTableDef.Name, temp) 204 } else { 205 insertSQL = fmt.Sprintf(insertIntoSecondaryIndexTableWithPKeyFormat, DBName, indexDef.IndexTableName, temp, pKeyMsg, DBName, originTableDef.Name) 206 } 207 } 208 } 209 return insertSQL 210 } 211 212 // genInsertIndexTableSqlForMasterIndex: Create inserts for master index table 213 func genInsertIndexTableSqlForMasterIndex(originTableDef *plan.TableDef, indexDef *plan.IndexDef, DBName string) []string { 214 // insert data into index table 215 var insertSQLs = make([]string, len(indexDef.Parts)) 216 217 pkeyName := originTableDef.Pkey.PkeyColName 218 var pKeyMsg string 219 if pkeyName == catalog.CPrimaryKeyColName { 220 pKeyMsg = "serial(" 221 for i, part := range originTableDef.Pkey.Names { 222 if i == 0 { 223 pKeyMsg += part 224 } else { 225 pKeyMsg += "," + part 226 } 227 } 228 pKeyMsg += ")" 229 } else { 230 pKeyMsg = pkeyName 231 } 232 233 colSeqNumMap := make(map[string]string) 234 for _, col := range originTableDef.Cols { 235 // NOTE: 236 // ColDef.ColId is not used as "after alter table, different columns may have the same colId" 237 // ColDef.SeqNum is used instead as it is always unique. 238 colSeqNumMap[col.GetName()] = fmt.Sprintf("%d", col.GetSeqnum()) 239 } 240 241 for i, part := range indexDef.Parts { 242 insertSQLs[i] = fmt.Sprintf(insertIntoMasterIndexTableFormat, 243 DBName, indexDef.IndexTableName, 244 colSeqNumMap[part], part, pKeyMsg, pKeyMsg, DBName, originTableDef.Name) 245 } 246 247 return insertSQLs 248 } 249 250 // genInsertMOIndexesSql: Generate an insert statement for insert index metadata into `mo_catalog.mo_indexes` 251 func genInsertMOIndexesSql(eg engine.Engine, proc *process.Process, databaseId string, tableId uint64, ct *engine.ConstraintDef) (string, error) { 252 buffer := bytes.NewBuffer(make([]byte, 0, 1024)) 253 buffer.WriteString("insert into mo_catalog.mo_indexes values") 254 255 isFirst := true 256 for _, constraint := range ct.Cts { 257 switch def := constraint.(type) { 258 case *engine.IndexDef: 259 for _, indexdef := range def.Indexes { 260 ctx, cancelFunc := context.WithTimeout(proc.Ctx, time.Second*30) 261 index_id, err := eg.AllocateIDByKey(ctx, ALLOCID_INDEX_KEY) 262 cancelFunc() 263 if err != nil { 264 return "", err 265 } 266 267 for i, part := range indexdef.Parts { 268 // NOTE: Don't resolve the alias here. 269 // If we resolve it here, it will insert "OriginalPKColumnName" into the "mo_catalog.mo_indexes" table instead of 270 // "AliasPKColumnName". This will result is issues filter "Programmatically added PK" from the output of 271 // "show indexes" and "show create table" command. 272 273 //1. index id 274 if isFirst { 275 fmt.Fprintf(buffer, "(%d, ", index_id) 276 isFirst = false 277 } else { 278 fmt.Fprintf(buffer, ", (%d, ", index_id) 279 } 280 281 //2. table_id 282 fmt.Fprintf(buffer, "%d, ", tableId) 283 284 // 3. databaseId 285 fmt.Fprintf(buffer, "%s, ", databaseId) 286 287 // 4.index.IndexName 288 fmt.Fprintf(buffer, "'%s', ", indexdef.IndexName) 289 290 // 5. index_type 291 var index_type string 292 if indexdef.Unique { 293 index_type = INDEX_TYPE_UNIQUE 294 } else { 295 index_type = INDEX_TYPE_MULTIPLE 296 } 297 fmt.Fprintf(buffer, "'%s', ", index_type) 298 299 //6. algorithm 300 var algorithm = indexdef.IndexAlgo 301 fmt.Fprintf(buffer, "'%s', ", algorithm) 302 303 //7. algorithm_table_type 304 var algorithm_table_type = indexdef.IndexAlgoTableType 305 fmt.Fprintf(buffer, "'%s', ", algorithm_table_type) 306 307 //8. algorithm_params 308 var algorithm_params = indexdef.IndexAlgoParams 309 fmt.Fprintf(buffer, "'%s', ", algorithm_params) 310 311 // 9. index visible 312 fmt.Fprintf(buffer, "%d, ", INDEX_VISIBLE_YES) 313 314 // 10. index vec_hidden 315 fmt.Fprintf(buffer, "%d, ", INDEX_HIDDEN_NO) 316 317 // 11. index vec_comment 318 fmt.Fprintf(buffer, "'%s', ", indexdef.Comment) 319 320 // 12. index vec_column_name 321 fmt.Fprintf(buffer, "'%s', ", part) 322 323 // 13. index vec_ordinal_position 324 fmt.Fprintf(buffer, "%d, ", i+1) 325 326 // 14. index vec_options 327 fmt.Fprintf(buffer, "%s, ", NULL_VALUE) 328 329 // 15. index vec_index_table 330 if indexdef.TableExist { 331 fmt.Fprintf(buffer, "'%s')", indexdef.IndexTableName) 332 } else { 333 fmt.Fprintf(buffer, "%s)", NULL_VALUE) 334 } 335 } 336 } 337 case *engine.PrimaryKeyDef: 338 ctx, cancelFunc := context.WithTimeout(proc.Ctx, time.Second*30) 339 index_id, err := eg.AllocateIDByKey(ctx, ALLOCID_INDEX_KEY) 340 cancelFunc() 341 if err != nil { 342 return "", err 343 } 344 if def.Pkey.PkeyColName != catalog.FakePrimaryKeyColName { 345 for i, colName := range def.Pkey.Names { 346 //1. index id 347 if isFirst { 348 fmt.Fprintf(buffer, "(%d, ", index_id) 349 isFirst = false 350 } else { 351 fmt.Fprintf(buffer, ", (%d, ", index_id) 352 } 353 354 //2. table_id 355 fmt.Fprintf(buffer, "%d, ", tableId) 356 357 // 3. databaseId 358 fmt.Fprintf(buffer, "%s, ", databaseId) 359 360 // 4.index.IndexName 361 fmt.Fprintf(buffer, "'%s', ", "PRIMARY") 362 363 // 5.index_type 364 fmt.Fprintf(buffer, "'%s', ", INDEX_TYPE_PRIMARY) 365 366 //6. algorithm 367 fmt.Fprintf(buffer, "'%s', ", EMPTY_STRING) 368 369 //7. algorithm_table_type 370 fmt.Fprintf(buffer, "'%s', ", EMPTY_STRING) 371 372 //8. algorithm_params 373 fmt.Fprintf(buffer, "'%s', ", EMPTY_STRING) 374 375 //9. index visible 376 fmt.Fprintf(buffer, "%d, ", INDEX_VISIBLE_YES) 377 378 // 10. index vec_hidden 379 fmt.Fprintf(buffer, "%d, ", INDEX_HIDDEN_NO) 380 381 // 11. index vec_comment 382 fmt.Fprintf(buffer, "'%s', ", EMPTY_STRING) 383 384 // 12. index vec_column_name 385 fmt.Fprintf(buffer, "'%s', ", colName) 386 387 // 13. index vec_ordinal_position 388 fmt.Fprintf(buffer, "%d, ", i+1) 389 390 // 14. index vec_options 391 fmt.Fprintf(buffer, "%s, ", NULL_VALUE) 392 393 // 15. index vec_index_table 394 fmt.Fprintf(buffer, "%s)", NULL_VALUE) 395 } 396 } 397 } 398 } 399 buffer.WriteString(";") 400 return buffer.String(), nil 401 } 402 403 // makeInsertSingleIndexSQL: make index metadata information sql for a single index object 404 func makeInsertSingleIndexSQL(eg engine.Engine, proc *process.Process, databaseId string, tableId uint64, idxdef *plan.IndexDef) (string, error) { 405 if idxdef == nil { 406 return "", nil 407 } 408 ct := &engine.ConstraintDef{ 409 Cts: []engine.Constraint{ 410 &engine.IndexDef{ 411 Indexes: []*plan.IndexDef{idxdef}, 412 }, 413 }, 414 } 415 insertMoIndexesSql, err := genInsertMOIndexesSql(eg, proc, databaseId, tableId, ct) 416 if err != nil { 417 return "", err 418 } 419 return insertMoIndexesSql, nil 420 } 421 422 func makeInsertTablePartitionsSQL(ctx context.Context, dbSource engine.Database, relation engine.Relation) (string, error) { 423 if dbSource == nil || relation == nil { 424 return "", nil 425 } 426 databaseId := dbSource.GetDatabaseId(ctx) 427 tableId := relation.GetTableID(ctx) 428 tableDefs, err := relation.TableDefs(ctx) 429 if err != nil { 430 return "", err 431 } 432 433 for _, def := range tableDefs { 434 if partitionDef, ok := def.(*engine.PartitionDef); ok { 435 partitionByDef := &plan2.PartitionByDef{} 436 if err = partitionByDef.UnMarshalPartitionInfo(([]byte)(partitionDef.Partition)); err != nil { 437 return "", nil 438 } 439 440 insertMoTablePartitionSql := genInsertMoTablePartitionsSql(databaseId, tableId, partitionByDef, partitionByDef.Partitions) 441 return insertMoTablePartitionSql, nil 442 } 443 } 444 return "", nil 445 } 446 447 // makeInsertMultiIndexSQL :Synchronize the index metadata information of the table to the index metadata table 448 func makeInsertMultiIndexSQL(eg engine.Engine, ctx context.Context, proc *process.Process, dbSource engine.Database, relation engine.Relation) (string, error) { 449 if dbSource == nil || relation == nil { 450 return "", nil 451 } 452 databaseId := dbSource.GetDatabaseId(ctx) 453 tableId := relation.GetTableID(ctx) 454 455 ct, err := GetConstraintDef(ctx, relation) 456 if err != nil { 457 return "", err 458 } 459 if ct == nil { 460 return "", nil 461 } 462 463 hasIndex := false 464 for _, constraint := range ct.Cts { 465 if idxdef, ok := constraint.(*engine.IndexDef); ok && len(idxdef.Indexes) > 0 { 466 hasIndex = true 467 break 468 } 469 if pkdef, ok := constraint.(*engine.PrimaryKeyDef); ok { 470 if pkdef.Pkey.PkeyColName != catalog.FakePrimaryKeyColName { 471 hasIndex = true 472 break 473 } 474 } 475 } 476 if !hasIndex { 477 return "", nil 478 } 479 480 insertMoIndexesSql, err := genInsertMOIndexesSql(eg, proc, databaseId, tableId, ct) 481 if err != nil { 482 return "", err 483 } 484 return insertMoIndexesSql, nil 485 } 486 487 func partsToColsStr(parts []string) string { 488 var temp string 489 for i, part := range parts { 490 part = catalog.ResolveAlias(part) 491 if i == 0 { 492 temp += part 493 } else { 494 temp += "," + part 495 } 496 } 497 return temp 498 } 499 500 func haveSinkScanInPlan(nodes []*plan.Node, curNodeIdx int32) bool { 501 node := nodes[curNodeIdx] 502 if node.NodeType == plan.Node_SINK_SCAN { 503 return true 504 } 505 for _, newIdx := range node.Children { 506 flag := haveSinkScanInPlan(nodes, newIdx) 507 if flag { 508 return flag 509 } 510 } 511 return false 512 } 513 514 // genInsertMoTablePartitionsSql: Generate an insert statement for insert index metadata into `mo_catalog.mo_table_partitions` 515 func genInsertMoTablePartitionsSql(databaseId string, tableId uint64, partitionByDef *plan2.PartitionByDef, partitions []*plan.PartitionItem) string { 516 buffer := bytes.NewBuffer(make([]byte, 0, 2048)) 517 buffer.WriteString("insert into mo_catalog.mo_table_partitions values") 518 519 isFirst := true 520 for _, partition := range partitions { 521 // 1. tableId 522 if isFirst { 523 fmt.Fprintf(buffer, "(%d, ", tableId) 524 isFirst = false 525 } else { 526 fmt.Fprintf(buffer, ", (%d, ", tableId) 527 } 528 529 // 2. database_id 530 fmt.Fprintf(buffer, "%s, ", databaseId) 531 532 // 3. partition number 533 fmt.Fprintf(buffer, "%d, ", partition.OrdinalPosition) 534 535 // 4. partition name 536 fmt.Fprintf(buffer, "'%s', ", partition.PartitionName) 537 538 // 5. partition type 539 fmt.Fprintf(buffer, "'%s', ", partitionByDef.Type.String()) 540 541 // 6. partition expression 542 fmt.Fprintf(buffer, "'%s', ", partitionByDef.GenPartitionExprString()) 543 544 // 7. description_utf8 545 fmt.Fprintf(buffer, "'%s', ", partition.Description) 546 547 // 8. partition item comment 548 fmt.Fprintf(buffer, "'%s', ", partition.Comment) 549 550 // 9. partition item options 551 fmt.Fprintf(buffer, "%s, ", NULL_VALUE) 552 553 // 10. partition_table_name 554 fmt.Fprintf(buffer, "'%s')", partition.PartitionTableName) 555 } 556 buffer.WriteString(";") 557 return buffer.String() 558 } 559 560 func GetConstraintDef(ctx context.Context, rel engine.Relation) (*engine.ConstraintDef, error) { 561 defs, err := rel.TableDefs(ctx) 562 if err != nil { 563 return nil, err 564 } 565 566 return GetConstraintDefFromTableDefs(defs), nil 567 } 568 569 func GetConstraintDefFromTableDefs(defs []engine.TableDef) *engine.ConstraintDef { 570 var cstrDef *engine.ConstraintDef 571 for _, def := range defs { 572 if ct, ok := def.(*engine.ConstraintDef); ok { 573 cstrDef = ct 574 break 575 } 576 } 577 if cstrDef == nil { 578 cstrDef = &engine.ConstraintDef{} 579 cstrDef.Cts = make([]engine.Constraint, 0) 580 } 581 return cstrDef 582 }