describe.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package engine
  2. import (
  3. "context"
  4. "fmt"
  5. "strings"
  6. "github.com/seaweedfs/seaweedfs/weed/query/sqltypes"
  7. )
  8. // executeDescribeStatement handles DESCRIBE table commands
  9. // Shows table schema in PostgreSQL-compatible format
  10. func (e *SQLEngine) executeDescribeStatement(ctx context.Context, tableName string, database string) (*QueryResult, error) {
  11. if database == "" {
  12. database = e.catalog.GetCurrentDatabase()
  13. if database == "" {
  14. database = "default"
  15. }
  16. }
  17. // Auto-discover and register topic if not already in catalog (same logic as SELECT)
  18. if _, err := e.catalog.GetTableInfo(database, tableName); err != nil {
  19. // Topic not in catalog, try to discover and register it
  20. if regErr := e.discoverAndRegisterTopic(ctx, database, tableName); regErr != nil {
  21. fmt.Printf("Warning: Failed to discover topic %s.%s: %v\n", database, tableName, regErr)
  22. return &QueryResult{Error: fmt.Errorf("topic %s.%s not found and auto-discovery failed: %v", database, tableName, regErr)}, regErr
  23. }
  24. }
  25. // Get topic schema from broker
  26. recordType, err := e.catalog.brokerClient.GetTopicSchema(ctx, database, tableName)
  27. if err != nil {
  28. return &QueryResult{Error: err}, err
  29. }
  30. // System columns to include in DESCRIBE output
  31. systemColumns := []struct {
  32. Name string
  33. Type string
  34. Extra string
  35. }{
  36. {"_ts", "TIMESTAMP", "System column: Message timestamp"},
  37. {"_key", "VARBINARY", "System column: Message key"},
  38. {"_source", "VARCHAR(255)", "System column: Data source (parquet/log)"},
  39. }
  40. // Format schema as DESCRIBE output (regular fields + system columns)
  41. totalRows := len(recordType.Fields) + len(systemColumns)
  42. result := &QueryResult{
  43. Columns: []string{"Field", "Type", "Null", "Key", "Default", "Extra"},
  44. Rows: make([][]sqltypes.Value, totalRows),
  45. }
  46. // Add regular fields
  47. for i, field := range recordType.Fields {
  48. sqlType := e.convertMQTypeToSQL(field.Type)
  49. result.Rows[i] = []sqltypes.Value{
  50. sqltypes.NewVarChar(field.Name), // Field
  51. sqltypes.NewVarChar(sqlType), // Type
  52. sqltypes.NewVarChar("YES"), // Null (assume nullable)
  53. sqltypes.NewVarChar(""), // Key (no keys for now)
  54. sqltypes.NewVarChar("NULL"), // Default
  55. sqltypes.NewVarChar(""), // Extra
  56. }
  57. }
  58. // Add system columns
  59. for i, sysCol := range systemColumns {
  60. rowIndex := len(recordType.Fields) + i
  61. result.Rows[rowIndex] = []sqltypes.Value{
  62. sqltypes.NewVarChar(sysCol.Name), // Field
  63. sqltypes.NewVarChar(sysCol.Type), // Type
  64. sqltypes.NewVarChar("YES"), // Null
  65. sqltypes.NewVarChar(""), // Key
  66. sqltypes.NewVarChar("NULL"), // Default
  67. sqltypes.NewVarChar(sysCol.Extra), // Extra - description
  68. }
  69. }
  70. return result, nil
  71. }
  72. // Enhanced executeShowStatementWithDescribe handles SHOW statements including DESCRIBE
  73. func (e *SQLEngine) executeShowStatementWithDescribe(ctx context.Context, stmt *ShowStatement) (*QueryResult, error) {
  74. switch strings.ToUpper(stmt.Type) {
  75. case "DATABASES":
  76. return e.showDatabases(ctx)
  77. case "TABLES":
  78. // Parse FROM clause for database specification, or use current database context
  79. database := ""
  80. // Check if there's a database specified in SHOW TABLES FROM database
  81. if stmt.Schema != "" {
  82. // Use schema field if set by parser
  83. database = stmt.Schema
  84. } else {
  85. // Try to get from OnTable.Name with proper nil checks
  86. if stmt.OnTable.Name != nil {
  87. if nameStr := stmt.OnTable.Name.String(); nameStr != "" {
  88. database = nameStr
  89. } else {
  90. database = e.catalog.GetCurrentDatabase()
  91. }
  92. } else {
  93. database = e.catalog.GetCurrentDatabase()
  94. }
  95. }
  96. if database == "" {
  97. // Use current database context
  98. database = e.catalog.GetCurrentDatabase()
  99. }
  100. return e.showTables(ctx, database)
  101. case "COLUMNS":
  102. // SHOW COLUMNS FROM table is equivalent to DESCRIBE
  103. var tableName, database string
  104. // Safely extract table name and database with proper nil checks
  105. if stmt.OnTable.Name != nil {
  106. tableName = stmt.OnTable.Name.String()
  107. if stmt.OnTable.Qualifier != nil {
  108. database = stmt.OnTable.Qualifier.String()
  109. }
  110. }
  111. if tableName != "" {
  112. return e.executeDescribeStatement(ctx, tableName, database)
  113. }
  114. fallthrough
  115. default:
  116. err := fmt.Errorf("unsupported SHOW statement: %s", stmt.Type)
  117. return &QueryResult{Error: err}, err
  118. }
  119. }