cockroach_parser.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. package engine
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/cockroachdb/cockroachdb-parser/pkg/sql/parser"
  6. "github.com/cockroachdb/cockroachdb-parser/pkg/sql/sem/tree"
  7. )
  8. // CockroachSQLParser wraps CockroachDB's PostgreSQL-compatible SQL parser for use in SeaweedFS
  9. type CockroachSQLParser struct{}
  10. // NewCockroachSQLParser creates a new instance of the CockroachDB SQL parser wrapper
  11. func NewCockroachSQLParser() *CockroachSQLParser {
  12. return &CockroachSQLParser{}
  13. }
  14. // ParseSQL parses a SQL statement using CockroachDB's parser
  15. func (p *CockroachSQLParser) ParseSQL(sql string) (Statement, error) {
  16. // Parse using CockroachDB's parser
  17. stmts, err := parser.Parse(sql)
  18. if err != nil {
  19. return nil, fmt.Errorf("CockroachDB parser error: %v", err)
  20. }
  21. if len(stmts) != 1 {
  22. return nil, fmt.Errorf("expected exactly one statement, got %d", len(stmts))
  23. }
  24. stmt := stmts[0].AST
  25. // Convert CockroachDB AST to SeaweedFS AST format
  26. switch s := stmt.(type) {
  27. case *tree.Select:
  28. return p.convertSelectStatement(s)
  29. default:
  30. return nil, fmt.Errorf("unsupported statement type: %T", s)
  31. }
  32. }
  33. // convertSelectStatement converts CockroachDB's Select AST to SeaweedFS format
  34. func (p *CockroachSQLParser) convertSelectStatement(crdbSelect *tree.Select) (*SelectStatement, error) {
  35. selectClause, ok := crdbSelect.Select.(*tree.SelectClause)
  36. if !ok {
  37. return nil, fmt.Errorf("expected SelectClause, got %T", crdbSelect.Select)
  38. }
  39. seaweedSelect := &SelectStatement{
  40. SelectExprs: make([]SelectExpr, 0, len(selectClause.Exprs)),
  41. From: []TableExpr{},
  42. }
  43. // Convert SELECT expressions
  44. for _, expr := range selectClause.Exprs {
  45. seaweedExpr, err := p.convertSelectExpr(expr)
  46. if err != nil {
  47. return nil, fmt.Errorf("failed to convert select expression: %v", err)
  48. }
  49. seaweedSelect.SelectExprs = append(seaweedSelect.SelectExprs, seaweedExpr)
  50. }
  51. // Convert FROM clause
  52. if len(selectClause.From.Tables) > 0 {
  53. for _, fromExpr := range selectClause.From.Tables {
  54. seaweedTableExpr, err := p.convertFromExpr(fromExpr)
  55. if err != nil {
  56. return nil, fmt.Errorf("failed to convert FROM clause: %v", err)
  57. }
  58. seaweedSelect.From = append(seaweedSelect.From, seaweedTableExpr)
  59. }
  60. }
  61. // Convert WHERE clause if present
  62. if selectClause.Where != nil {
  63. whereExpr, err := p.convertExpr(selectClause.Where.Expr)
  64. if err != nil {
  65. return nil, fmt.Errorf("failed to convert WHERE clause: %v", err)
  66. }
  67. seaweedSelect.Where = &WhereClause{
  68. Expr: whereExpr,
  69. }
  70. }
  71. // Convert LIMIT and OFFSET clauses if present
  72. if crdbSelect.Limit != nil {
  73. limitClause := &LimitClause{}
  74. // Convert LIMIT (Count)
  75. if crdbSelect.Limit.Count != nil {
  76. countExpr, err := p.convertExpr(crdbSelect.Limit.Count)
  77. if err != nil {
  78. return nil, fmt.Errorf("failed to convert LIMIT clause: %v", err)
  79. }
  80. limitClause.Rowcount = countExpr
  81. }
  82. // Convert OFFSET
  83. if crdbSelect.Limit.Offset != nil {
  84. offsetExpr, err := p.convertExpr(crdbSelect.Limit.Offset)
  85. if err != nil {
  86. return nil, fmt.Errorf("failed to convert OFFSET clause: %v", err)
  87. }
  88. limitClause.Offset = offsetExpr
  89. }
  90. seaweedSelect.Limit = limitClause
  91. }
  92. return seaweedSelect, nil
  93. }
  94. // convertSelectExpr converts CockroachDB SelectExpr to SeaweedFS format
  95. func (p *CockroachSQLParser) convertSelectExpr(expr tree.SelectExpr) (SelectExpr, error) {
  96. // Handle star expressions (SELECT *)
  97. if _, isStar := expr.Expr.(tree.UnqualifiedStar); isStar {
  98. return &StarExpr{}, nil
  99. }
  100. // CockroachDB's SelectExpr is a struct, not an interface, so handle it directly
  101. seaweedExpr := &AliasedExpr{}
  102. // Convert the main expression
  103. convertedExpr, err := p.convertExpr(expr.Expr)
  104. if err != nil {
  105. return nil, fmt.Errorf("failed to convert expression: %v", err)
  106. }
  107. seaweedExpr.Expr = convertedExpr
  108. // Convert alias if present
  109. if expr.As != "" {
  110. seaweedExpr.As = aliasValue(expr.As)
  111. }
  112. return seaweedExpr, nil
  113. }
  114. // convertExpr converts CockroachDB expressions to SeaweedFS format
  115. func (p *CockroachSQLParser) convertExpr(expr tree.Expr) (ExprNode, error) {
  116. switch e := expr.(type) {
  117. case *tree.FuncExpr:
  118. // Function call
  119. seaweedFunc := &FuncExpr{
  120. Name: stringValue(strings.ToUpper(e.Func.String())), // Convert to uppercase for consistency
  121. Exprs: make([]SelectExpr, 0, len(e.Exprs)),
  122. }
  123. // Convert function arguments
  124. for _, arg := range e.Exprs {
  125. // Special case: Handle star expressions in function calls like COUNT(*)
  126. if _, isStar := arg.(tree.UnqualifiedStar); isStar {
  127. seaweedFunc.Exprs = append(seaweedFunc.Exprs, &StarExpr{})
  128. } else {
  129. convertedArg, err := p.convertExpr(arg)
  130. if err != nil {
  131. return nil, fmt.Errorf("failed to convert function argument: %v", err)
  132. }
  133. seaweedFunc.Exprs = append(seaweedFunc.Exprs, &AliasedExpr{Expr: convertedArg})
  134. }
  135. }
  136. return seaweedFunc, nil
  137. case *tree.BinaryExpr:
  138. // Arithmetic/binary operations (including string concatenation ||)
  139. seaweedArith := &ArithmeticExpr{
  140. Operator: e.Operator.String(),
  141. }
  142. // Convert left operand
  143. left, err := p.convertExpr(e.Left)
  144. if err != nil {
  145. return nil, fmt.Errorf("failed to convert left operand: %v", err)
  146. }
  147. seaweedArith.Left = left
  148. // Convert right operand
  149. right, err := p.convertExpr(e.Right)
  150. if err != nil {
  151. return nil, fmt.Errorf("failed to convert right operand: %v", err)
  152. }
  153. seaweedArith.Right = right
  154. return seaweedArith, nil
  155. case *tree.ComparisonExpr:
  156. // Comparison operations (=, >, <, >=, <=, !=, etc.) used in WHERE clauses
  157. seaweedComp := &ComparisonExpr{
  158. Operator: e.Operator.String(),
  159. }
  160. // Convert left operand
  161. left, err := p.convertExpr(e.Left)
  162. if err != nil {
  163. return nil, fmt.Errorf("failed to convert comparison left operand: %v", err)
  164. }
  165. seaweedComp.Left = left
  166. // Convert right operand
  167. right, err := p.convertExpr(e.Right)
  168. if err != nil {
  169. return nil, fmt.Errorf("failed to convert comparison right operand: %v", err)
  170. }
  171. seaweedComp.Right = right
  172. return seaweedComp, nil
  173. case *tree.StrVal:
  174. // String literal
  175. return &SQLVal{
  176. Type: StrVal,
  177. Val: []byte(string(e.RawString())),
  178. }, nil
  179. case *tree.NumVal:
  180. // Numeric literal
  181. valStr := e.String()
  182. if strings.Contains(valStr, ".") {
  183. return &SQLVal{
  184. Type: FloatVal,
  185. Val: []byte(valStr),
  186. }, nil
  187. } else {
  188. return &SQLVal{
  189. Type: IntVal,
  190. Val: []byte(valStr),
  191. }, nil
  192. }
  193. case *tree.UnresolvedName:
  194. // Column name
  195. return &ColName{
  196. Name: stringValue(e.String()),
  197. }, nil
  198. case *tree.AndExpr:
  199. // AND expression
  200. left, err := p.convertExpr(e.Left)
  201. if err != nil {
  202. return nil, fmt.Errorf("failed to convert AND left operand: %v", err)
  203. }
  204. right, err := p.convertExpr(e.Right)
  205. if err != nil {
  206. return nil, fmt.Errorf("failed to convert AND right operand: %v", err)
  207. }
  208. return &AndExpr{
  209. Left: left,
  210. Right: right,
  211. }, nil
  212. case *tree.OrExpr:
  213. // OR expression
  214. left, err := p.convertExpr(e.Left)
  215. if err != nil {
  216. return nil, fmt.Errorf("failed to convert OR left operand: %v", err)
  217. }
  218. right, err := p.convertExpr(e.Right)
  219. if err != nil {
  220. return nil, fmt.Errorf("failed to convert OR right operand: %v", err)
  221. }
  222. return &OrExpr{
  223. Left: left,
  224. Right: right,
  225. }, nil
  226. case *tree.Tuple:
  227. // Tuple expression for IN clauses: (value1, value2, value3)
  228. tupleValues := make(ValTuple, 0, len(e.Exprs))
  229. for _, tupleExpr := range e.Exprs {
  230. convertedExpr, err := p.convertExpr(tupleExpr)
  231. if err != nil {
  232. return nil, fmt.Errorf("failed to convert tuple element: %v", err)
  233. }
  234. tupleValues = append(tupleValues, convertedExpr)
  235. }
  236. return tupleValues, nil
  237. case *tree.CastExpr:
  238. // Handle INTERVAL expressions: INTERVAL '1 hour'
  239. // CockroachDB represents these as cast expressions
  240. if p.isIntervalCast(e) {
  241. // Extract the string value being cast to interval
  242. if strVal, ok := e.Expr.(*tree.StrVal); ok {
  243. return &IntervalExpr{
  244. Value: string(strVal.RawString()),
  245. }, nil
  246. }
  247. return nil, fmt.Errorf("invalid INTERVAL expression: expected string literal")
  248. }
  249. // For non-interval casts, just convert the inner expression
  250. return p.convertExpr(e.Expr)
  251. case *tree.RangeCond:
  252. // Handle BETWEEN expressions: column BETWEEN value1 AND value2
  253. seaweedBetween := &BetweenExpr{
  254. Not: e.Not, // Handle NOT BETWEEN
  255. }
  256. // Convert the left operand (the expression being tested)
  257. left, err := p.convertExpr(e.Left)
  258. if err != nil {
  259. return nil, fmt.Errorf("failed to convert BETWEEN left operand: %v", err)
  260. }
  261. seaweedBetween.Left = left
  262. // Convert the FROM operand (lower bound)
  263. from, err := p.convertExpr(e.From)
  264. if err != nil {
  265. return nil, fmt.Errorf("failed to convert BETWEEN from operand: %v", err)
  266. }
  267. seaweedBetween.From = from
  268. // Convert the TO operand (upper bound)
  269. to, err := p.convertExpr(e.To)
  270. if err != nil {
  271. return nil, fmt.Errorf("failed to convert BETWEEN to operand: %v", err)
  272. }
  273. seaweedBetween.To = to
  274. return seaweedBetween, nil
  275. case *tree.IsNullExpr:
  276. // Handle IS NULL expressions: column IS NULL
  277. expr, err := p.convertExpr(e.Expr)
  278. if err != nil {
  279. return nil, fmt.Errorf("failed to convert IS NULL expression: %v", err)
  280. }
  281. return &IsNullExpr{
  282. Expr: expr,
  283. }, nil
  284. case *tree.IsNotNullExpr:
  285. // Handle IS NOT NULL expressions: column IS NOT NULL
  286. expr, err := p.convertExpr(e.Expr)
  287. if err != nil {
  288. return nil, fmt.Errorf("failed to convert IS NOT NULL expression: %v", err)
  289. }
  290. return &IsNotNullExpr{
  291. Expr: expr,
  292. }, nil
  293. default:
  294. return nil, fmt.Errorf("unsupported expression type: %T", e)
  295. }
  296. }
  297. // convertFromExpr converts CockroachDB FROM expressions to SeaweedFS format
  298. func (p *CockroachSQLParser) convertFromExpr(expr tree.TableExpr) (TableExpr, error) {
  299. switch e := expr.(type) {
  300. case *tree.TableName:
  301. // Simple table name
  302. tableName := TableName{
  303. Name: stringValue(e.Table()),
  304. }
  305. // Extract database qualifier if present
  306. if e.Schema() != "" {
  307. tableName.Qualifier = stringValue(e.Schema())
  308. }
  309. return &AliasedTableExpr{
  310. Expr: tableName,
  311. }, nil
  312. case *tree.AliasedTableExpr:
  313. // Handle aliased table expressions (which is what CockroachDB uses for qualified names)
  314. if tableName, ok := e.Expr.(*tree.TableName); ok {
  315. seaweedTableName := TableName{
  316. Name: stringValue(tableName.Table()),
  317. }
  318. // Extract database qualifier if present
  319. if tableName.Schema() != "" {
  320. seaweedTableName.Qualifier = stringValue(tableName.Schema())
  321. }
  322. return &AliasedTableExpr{
  323. Expr: seaweedTableName,
  324. }, nil
  325. }
  326. return nil, fmt.Errorf("unsupported expression in AliasedTableExpr: %T", e.Expr)
  327. default:
  328. return nil, fmt.Errorf("unsupported table expression type: %T", e)
  329. }
  330. }
  331. // isIntervalCast checks if a CastExpr is casting to an INTERVAL type
  332. func (p *CockroachSQLParser) isIntervalCast(castExpr *tree.CastExpr) bool {
  333. // Check if the target type is an interval type
  334. // CockroachDB represents interval types in the Type field
  335. // We need to check if it's an interval type by examining the type structure
  336. if castExpr.Type != nil {
  337. // Try to detect interval type by examining the AST structure
  338. // Since we can't easily access the type string, we'll be more conservative
  339. // and assume any cast expression on a string literal could be an interval
  340. if _, ok := castExpr.Expr.(*tree.StrVal); ok {
  341. // This is likely an INTERVAL expression since CockroachDB
  342. // represents INTERVAL '1 hour' as casting a string to interval type
  343. return true
  344. }
  345. }
  346. return false
  347. }