indexexpr.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. // Native JSONB scalar functions.
  207. "TO_JSONB": true, "JSONB_TYPEOF": true, "JSONB_ARRAY_LENGTH": true,
  208. "JSONB_STRIP_NULLS": true, "JSONB_PRETTY": true, "JSONB_BUILD_OBJECT": true,
  209. "JSONB_BUILD_ARRAY": true,
  210. }
  211. func isDeterministicFunction(name string) bool {
  212. return deterministicFunctions[strings.ToUpper(name)]
  213. }
  214. // ValidateIndexColumns checks that every column referenced by a stored
  215. // expression exists on the table (or is a hidden rowid alias). It is applied to
  216. // expression indexes and generated columns at creation time.
  217. func ValidateIndexColumns(expr parser.Expr, schema *storage.Schema) error {
  218. switch e := expr.(type) {
  219. case nil:
  220. return nil
  221. case *parser.ColumnRef:
  222. if e.Column == "*" {
  223. return fmt.Errorf("wildcards are not allowed in index expressions")
  224. }
  225. if storage.IsRowIDColumn(e.Column) {
  226. return nil
  227. }
  228. if _, ok := schema.GetColumn(e.Column); !ok {
  229. return fmt.Errorf("column not found in index expression: %s", e.Column)
  230. }
  231. return nil
  232. case *parser.ParenExpr:
  233. return ValidateIndexColumns(e.Expr, schema)
  234. case *parser.UnaryExpr:
  235. return ValidateIndexColumns(e.Operand, schema)
  236. case *parser.BinaryExpr:
  237. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  238. return err
  239. }
  240. return ValidateIndexColumns(e.Right, schema)
  241. case *parser.IsNullExpr:
  242. return ValidateIndexColumns(e.Left, schema)
  243. case *parser.IsDistinctExpr:
  244. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  245. return err
  246. }
  247. return ValidateIndexColumns(e.Right, schema)
  248. case *parser.BetweenExpr:
  249. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  250. return err
  251. }
  252. if err := ValidateIndexColumns(e.Low, schema); err != nil {
  253. return err
  254. }
  255. return ValidateIndexColumns(e.High, schema)
  256. case *parser.LikeExpr:
  257. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  258. return err
  259. }
  260. if err := ValidateIndexColumns(e.Pattern, schema); err != nil {
  261. return err
  262. }
  263. return ValidateIndexColumns(e.Escape, schema)
  264. case *parser.CaseExpr:
  265. if err := ValidateIndexColumns(e.Operand, schema); err != nil {
  266. return err
  267. }
  268. for _, w := range e.Whens {
  269. if err := ValidateIndexColumns(w.Condition, schema); err != nil {
  270. return err
  271. }
  272. if err := ValidateIndexColumns(w.Result, schema); err != nil {
  273. return err
  274. }
  275. }
  276. return ValidateIndexColumns(e.Else, schema)
  277. case *parser.CastExpr:
  278. return ValidateIndexColumns(e.Expr, schema)
  279. case *parser.ArrayExpr:
  280. for _, element := range e.Elements {
  281. if err := ValidateIndexColumns(element, schema); err != nil {
  282. return err
  283. }
  284. }
  285. return nil
  286. case *parser.SubscriptExpr:
  287. if err := ValidateIndexColumns(e.Expr, schema); err != nil {
  288. return err
  289. }
  290. return ValidateIndexColumns(e.Index, schema)
  291. case *parser.AnyAllExpr:
  292. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  293. return err
  294. }
  295. return ValidateIndexColumns(e.Array, schema)
  296. case *parser.InExpr:
  297. if err := ValidateIndexColumns(e.Left, schema); err != nil {
  298. return err
  299. }
  300. for _, v := range e.Values {
  301. if err := ValidateIndexColumns(v, schema); err != nil {
  302. return err
  303. }
  304. }
  305. return nil
  306. case *parser.FunctionCall:
  307. for _, a := range e.Args {
  308. if err := ValidateIndexColumns(a, schema); err != nil {
  309. return err
  310. }
  311. }
  312. return nil
  313. default:
  314. return nil
  315. }
  316. }