indexexpr.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. package executor
  2. import (
  3. "fmt"
  4. "strings"
  5. "sync"
  6. "github.com/danfragoso/pizzasql-next/pkg/parser"
  7. "github.com/danfragoso/pizzasql-next/pkg/storage"
  8. )
  9. // statelessEval is a shared, immutable Executor used only to evaluate validated,
  10. // side-effect-free expressions (expression indexes and generated columns) from
  11. // the storage layer. It holds no session, catalog, or per-connection state, so
  12. // concurrent evaluations from different connections share no mutable data. The
  13. // expression validators below guarantee that only subquery-free, deterministic
  14. // expressions reach it.
  15. var statelessEval = &Executor{}
  16. // storedExprCache memoizes parsed stored expressions across all connections. A
  17. // stored expression is immutable text, so the cache is safe to share.
  18. var storedExprCache sync.Map // string -> parser.Expr
  19. // parseStoredExpr parses (once) an expression persisted in the durable schema
  20. // (generated column or expression index) and rejects anything that is not
  21. // deterministic, subquery-free SQL. The same text always parses to the same
  22. // expression, so the result is cached.
  23. func parseStoredExpr(text string) (parser.Expr, error) {
  24. if cached, ok := storedExprCache.Load(text); ok {
  25. return cached.(parser.Expr), nil
  26. }
  27. expr, err := parser.ParseExpr(text)
  28. if err != nil {
  29. return nil, fmt.Errorf("invalid stored expression %q: %w", text, err)
  30. }
  31. if err := ValidateDeterministicExpr(expr); err != nil {
  32. return nil, fmt.Errorf("invalid stored expression %q: %w", text, err)
  33. }
  34. storedExprCache.Store(text, expr)
  35. return expr, nil
  36. }
  37. // EvalStoredExpression evaluates a persisted, validated expression against a
  38. // row. It is the storage layer's expression-index evaluator and is stateless and
  39. // concurrency-safe.
  40. func EvalStoredExpression(text string, row storage.Row) (interface{}, error) {
  41. expr, err := parseStoredExpr(text)
  42. if err != nil {
  43. return nil, err
  44. }
  45. return statelessEval.evalExpr(expr, row)
  46. }
  47. // storedExpressionReferencesColumn reports whether a persisted index expression
  48. // names column. The engine stores expression SQL text verbatim, so a column
  49. // rename cannot rewrite the reference.
  50. func storedExpressionReferencesColumn(text, column string) (bool, error) {
  51. expr, err := parseStoredExpr(text)
  52. if err != nil {
  53. return false, err
  54. }
  55. for _, ref := range collectColumnRefs(expr) {
  56. if strings.EqualFold(ref, column) {
  57. return true, nil
  58. }
  59. }
  60. return false, nil
  61. }
  62. // ValidateDeterministicExpr rejects an expression that SQLite would not allow in
  63. // an index or generated column: subqueries, window functions, aggregates, and
  64. // non-deterministic or unknown functions.
  65. func ValidateDeterministicExpr(expr parser.Expr) error {
  66. switch e := expr.(type) {
  67. case nil:
  68. return nil
  69. case *parser.LiteralExpr:
  70. return nil
  71. case *parser.ColumnRef:
  72. return nil
  73. case *parser.ParenExpr:
  74. return ValidateDeterministicExpr(e.Expr)
  75. case *parser.UnaryExpr:
  76. return ValidateDeterministicExpr(e.Operand)
  77. case *parser.BinaryExpr:
  78. if err := ValidateDeterministicExpr(e.Left); err != nil {
  79. return err
  80. }
  81. return ValidateDeterministicExpr(e.Right)
  82. case *parser.IsNullExpr:
  83. return ValidateDeterministicExpr(e.Left)
  84. case *parser.IsDistinctExpr:
  85. if err := ValidateDeterministicExpr(e.Left); err != nil {
  86. return err
  87. }
  88. return ValidateDeterministicExpr(e.Right)
  89. case *parser.BetweenExpr:
  90. if err := ValidateDeterministicExpr(e.Left); err != nil {
  91. return err
  92. }
  93. if err := ValidateDeterministicExpr(e.Low); err != nil {
  94. return err
  95. }
  96. return ValidateDeterministicExpr(e.High)
  97. case *parser.LikeExpr:
  98. if err := ValidateDeterministicExpr(e.Left); err != nil {
  99. return err
  100. }
  101. if err := ValidateDeterministicExpr(e.Pattern); err != nil {
  102. return err
  103. }
  104. return ValidateDeterministicExpr(e.Escape)
  105. case *parser.CaseExpr:
  106. if err := ValidateDeterministicExpr(e.Operand); err != nil {
  107. return err
  108. }
  109. for _, w := range e.Whens {
  110. if err := ValidateDeterministicExpr(w.Condition); err != nil {
  111. return err
  112. }
  113. if err := ValidateDeterministicExpr(w.Result); err != nil {
  114. return err
  115. }
  116. }
  117. return ValidateDeterministicExpr(e.Else)
  118. case *parser.CastExpr:
  119. return ValidateDeterministicExpr(e.Expr)
  120. case *parser.ArrayExpr:
  121. for _, element := range e.Elements {
  122. if err := ValidateDeterministicExpr(element); err != nil {
  123. return err
  124. }
  125. }
  126. return nil
  127. case *parser.SubscriptExpr:
  128. if err := ValidateDeterministicExpr(e.Expr); err != nil {
  129. return err
  130. }
  131. return ValidateDeterministicExpr(e.Index)
  132. case *parser.AnyAllExpr:
  133. if err := ValidateDeterministicExpr(e.Left); err != nil {
  134. return err
  135. }
  136. return ValidateDeterministicExpr(e.Array)
  137. case *parser.InExpr:
  138. if e.Subquery != nil {
  139. return fmt.Errorf("subqueries are not allowed in index expressions")
  140. }
  141. if err := ValidateDeterministicExpr(e.Left); err != nil {
  142. return err
  143. }
  144. for _, v := range e.Values {
  145. if err := ValidateDeterministicExpr(v); err != nil {
  146. return err
  147. }
  148. }
  149. return nil
  150. case *parser.FunctionCall:
  151. if e.Star {
  152. return fmt.Errorf("function %s(*) is not allowed in index expressions", e.Name)
  153. }
  154. if isAggregateFunctionName(e.Name, len(e.Args)) {
  155. return fmt.Errorf("aggregate function %s() is not allowed in index expressions", e.Name)
  156. }
  157. if !isDeterministicFunction(e.Name) {
  158. return fmt.Errorf("non-deterministic or unsupported function %s() is not allowed in index expressions", e.Name)
  159. }
  160. for _, a := range e.Args {
  161. if err := ValidateDeterministicExpr(a); err != nil {
  162. return err
  163. }
  164. }
  165. return nil
  166. case *parser.SubqueryExpr:
  167. return fmt.Errorf("subqueries are not allowed in index expressions")
  168. case *parser.ExistsExpr:
  169. return fmt.Errorf("subqueries are not allowed in index expressions")
  170. case *parser.WindowExpr:
  171. return fmt.Errorf("window functions are not allowed in index expressions")
  172. default:
  173. return fmt.Errorf("unsupported expression in index definition: %T", expr)
  174. }
  175. }
  176. // isAggregateFunctionName reports whether a function name is an aggregate in the
  177. // given call shape. MIN/MAX are scalar with two or more arguments.
  178. func isAggregateFunctionName(name string, argCount int) bool {
  179. switch strings.ToUpper(name) {
  180. case "COUNT", "SUM", "AVG", "TOTAL", "GROUP_CONCAT",
  181. "JSON_GROUP_ARRAY", "JSONB_GROUP_ARRAY", "JSON_GROUP_OBJECT", "JSONB_GROUP_OBJECT":
  182. return true
  183. case "MIN", "MAX":
  184. return argCount < 2
  185. }
  186. return false
  187. }
  188. // deterministicFunctions is the allowlist of scalar functions that may appear in
  189. // a persisted expression. It intentionally excludes date/time functions (which
  190. // are non-deterministic when using "now") and every random/session function.
  191. var deterministicFunctions = map[string]bool{
  192. "LOWER": true, "UPPER": true, "LENGTH": true, "ABS": true,
  193. "COALESCE": true, "NULLIF": true, "IFNULL": true, "NVL": true,
  194. "TYPEOF": true, "SUBSTR": true, "SUBSTRING": true, "TRIM": true,
  195. "REPLACE": true, "PRINTF": true, "HEX": true, "UNHEX": true,
  196. "ZEROBLOB": true, "INSTR": true, "GLOB": true, "ROUND": true,
  197. "MAX": true, "MIN": true, "CONCAT": true, "PERCENT_DIFF": true,
  198. "ARRAY_LENGTH": true,
  199. // JSON1 scalar functions.
  200. "JSON": true, "JSONB": true, "JSON_VALID": true, "JSONB_VALID": true,
  201. "JSON_TYPE": true, "JSON_EXTRACT": true, "JSONB_EXTRACT": true,
  202. "JSON_SET": true, "JSONB_SET": true, "JSON_INSERT": true, "JSONB_INSERT": true,
  203. "JSON_REPLACE": true, "JSONB_REPLACE": true, "JSON_REMOVE": true, "JSONB_REMOVE": true,
  204. "JSON_ARRAY": true, "JSONB_ARRAY": true, "JSON_OBJECT": true, "JSONB_OBJECT": true,
  205. "JSON_QUOTE": true, "JSONB_QUOTE": true,
  206. }
  207. func isDeterministicFunction(name string) bool {
  208. return deterministicFunctions[strings.ToUpper(name)]
  209. }
  210. // ValidateIndexColumns checks that every column referenced by a stored
  211. // expression exists on the table (or is a hidden rowid alias). It is applied to
  212. // expression indexes and generated columns at creation time.
  213. func ValidateIndexColumns(expr parser.Expr, schema *storage.Schema) error {
  214. switch e := expr.(type) {
  215. case nil:
  216. return nil
  217. case *parser.ColumnRef:
  218. if e.Column == "*" {
  219. return fmt.Errorf("wildcards are not allowed in index expressions")
  220. }
  221. if storage.IsRowIDColumn(e.Column) {
  222. return nil
  223. }
  224. if _, ok := schema.GetColumn(e.Column); !ok {
  225. return fmt.Errorf("column not found in index expression: %s", e.Column)
  226. }
  227. return nil
  228. case *parser.ParenExpr:
  229. return ValidateIndexColumns(e.Expr, schema)
  230. case *parser.UnaryExpr:
  231. return ValidateIndexColumns(e.Operand, schema)
  232. case *parser.BinaryExpr:
  233. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  234. return err
  235. }
  236. return ValidateIndexColumns(e.Right, schema)
  237. case *parser.IsNullExpr:
  238. return ValidateIndexColumns(e.Left, schema)
  239. case *parser.IsDistinctExpr:
  240. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  241. return err
  242. }
  243. return ValidateIndexColumns(e.Right, schema)
  244. case *parser.BetweenExpr:
  245. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  246. return err
  247. }
  248. if err := ValidateIndexColumns(e.Low, schema); err != nil {
  249. return err
  250. }
  251. return ValidateIndexColumns(e.High, schema)
  252. case *parser.LikeExpr:
  253. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  254. return err
  255. }
  256. if err := ValidateIndexColumns(e.Pattern, schema); err != nil {
  257. return err
  258. }
  259. return ValidateIndexColumns(e.Escape, schema)
  260. case *parser.CaseExpr:
  261. if err := ValidateIndexColumns(e.Operand, schema); err != nil {
  262. return err
  263. }
  264. for _, w := range e.Whens {
  265. if err := ValidateIndexColumns(w.Condition, schema); err != nil {
  266. return err
  267. }
  268. if err := ValidateIndexColumns(w.Result, schema); err != nil {
  269. return err
  270. }
  271. }
  272. return ValidateIndexColumns(e.Else, schema)
  273. case *parser.CastExpr:
  274. return ValidateIndexColumns(e.Expr, schema)
  275. case *parser.ArrayExpr:
  276. for _, element := range e.Elements {
  277. if err := ValidateIndexColumns(element, schema); err != nil {
  278. return err
  279. }
  280. }
  281. return nil
  282. case *parser.SubscriptExpr:
  283. if err := ValidateIndexColumns(e.Expr, schema); err != nil {
  284. return err
  285. }
  286. return ValidateIndexColumns(e.Index, schema)
  287. case *parser.AnyAllExpr:
  288. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  289. return err
  290. }
  291. return ValidateIndexColumns(e.Array, schema)
  292. case *parser.InExpr:
  293. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  294. return err
  295. }
  296. for _, v := range e.Values {
  297. if err := ValidateIndexColumns(v, schema); err != nil {
  298. return err
  299. }
  300. }
  301. return nil
  302. case *parser.FunctionCall:
  303. for _, a := range e.Args {
  304. if err := ValidateIndexColumns(a, schema); err != nil {
  305. return err
  306. }
  307. }
  308. return nil
  309. default:
  310. return nil
  311. }
  312. }