arrays.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. package executor
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. "github.com/danfragoso/pizzasql-next/pkg/lexer"
  7. "github.com/danfragoso/pizzasql-next/pkg/parser"
  8. "github.com/danfragoso/pizzasql-next/pkg/pgerror"
  9. "github.com/danfragoso/pizzasql-next/pkg/storage"
  10. )
  11. // Array values are carried as their canonical PostgreSQL array-literal text.
  12. // Storing the text keeps the row codec unchanged (a string is a string), makes
  13. // NULL and the empty array distinguishable (nil vs "{}"), and gives reloads a
  14. // stable encoding: every write path canonicalizes before storage, so equal
  15. // arrays always encode to identical bytes.
  16. //
  17. // The canonical form uses unquoted elements when the element text is unambiguous
  18. // and double-quoted (backslash-escaped) elements otherwise. Element text is
  19. // canonicalized per declared element type: integers to decimal, reals to Go's
  20. // shortest round-trip form, booleans to t/f.
  21. // arrayElementKind classifies an array element type for canonicalization.
  22. type arrayElementKind int
  23. const (
  24. arrayElementText arrayElementKind = iota
  25. arrayElementInteger
  26. arrayElementReal
  27. arrayElementNumeric
  28. arrayElementBoolean
  29. )
  30. // arrayElementType reports the base element type of an array type name such as
  31. // "INTEGER[]". It reports false for non-array type names.
  32. func arrayElementType(typeName string) (string, bool) {
  33. upper := strings.ToUpper(strings.TrimSpace(typeName))
  34. if !strings.HasSuffix(upper, "[]") {
  35. return "", false
  36. }
  37. return strings.TrimSpace(strings.TrimSuffix(upper, "[]")), true
  38. }
  39. // arrayElementKindOf reports the canonicalization kind for an array type name.
  40. func arrayElementKindOf(typeName string) (arrayElementKind, error) {
  41. element, ok := arrayElementType(typeName)
  42. if !ok {
  43. return arrayElementText, fmt.Errorf("%s is not an array type", typeName)
  44. }
  45. return arrayElementKindForName(element)
  46. }
  47. // arrayElementKindForName classifies a scalar element type name.
  48. func arrayElementKindForName(name string) (arrayElementKind, error) {
  49. switch strings.ToUpper(strings.TrimSpace(name)) {
  50. case "TEXT", "VARCHAR", "CHAR", "CHARACTER", "CLOB", "NCHAR", "NVARCHAR", "UUID":
  51. return arrayElementText, nil
  52. case "INTEGER", "INT", "TINYINT", "SMALLINT", "MEDIUMINT", "BIGINT":
  53. return arrayElementInteger, nil
  54. case "REAL", "FLOAT", "DOUBLE":
  55. return arrayElementReal, nil
  56. case "NUMERIC", "DECIMAL":
  57. // NUMERIC elements keep their exact text: the engine's float64 carrier
  58. // would lose digits above 2^53 and trailing zeros.
  59. return arrayElementNumeric, nil
  60. case "BOOLEAN", "BOOL":
  61. return arrayElementBoolean, nil
  62. default:
  63. return arrayElementText, pgerror.Unsupported("arrays of %s are not supported; supported element types are TEXT, VARCHAR, INTEGER, BIGINT, SMALLINT, BOOLEAN, REAL, DOUBLE PRECISION, and NUMERIC", strings.ToUpper(name))
  64. }
  65. }
  66. // parseArrayLiteral splits PostgreSQL array-literal text into element strings.
  67. // A nil element is SQL NULL. Nested braces (multidimensional arrays) are
  68. // rejected, as is malformed quoting.
  69. func parseArrayLiteral(text string) ([]*string, error) {
  70. s := strings.TrimSpace(text)
  71. if len(s) < 2 || s[0] != '{' || s[len(s)-1] != '}' {
  72. return nil, invalidArrayInput(text, "array text must be enclosed in {}")
  73. }
  74. inner := s[1 : len(s)-1]
  75. if strings.TrimSpace(inner) == "" {
  76. return nil, nil
  77. }
  78. var elements []*string
  79. i := 0
  80. for {
  81. for i < len(inner) && isArraySpace(inner[i]) {
  82. i++
  83. }
  84. if i >= len(inner) {
  85. return nil, invalidArrayInput(text, "missing } after comma")
  86. }
  87. var value *string
  88. if inner[i] == '"' {
  89. i++
  90. var b strings.Builder
  91. closed := false
  92. for i < len(inner) {
  93. c := inner[i]
  94. if c == '\\' {
  95. if i+1 >= len(inner) {
  96. return nil, invalidArrayInput(text, "trailing backslash in quoted element")
  97. }
  98. b.WriteByte(inner[i+1])
  99. i += 2
  100. continue
  101. }
  102. if c == '"' {
  103. i++
  104. closed = true
  105. break
  106. }
  107. b.WriteByte(c)
  108. i++
  109. }
  110. if !closed {
  111. return nil, invalidArrayInput(text, "unterminated quoted element")
  112. }
  113. quoted := b.String()
  114. value = &quoted
  115. for i < len(inner) && isArraySpace(inner[i]) {
  116. i++
  117. }
  118. } else {
  119. if inner[i] == '{' {
  120. return nil, pgerror.Unsupported("multidimensional arrays are not supported; array text must be one-dimensional")
  121. }
  122. start := i
  123. for i < len(inner) && inner[i] != ',' {
  124. if inner[i] == '{' || inner[i] == '}' || inner[i] == '"' {
  125. return nil, invalidArrayInput(text, "malformed array element")
  126. }
  127. i++
  128. }
  129. raw := strings.TrimSpace(inner[start:i])
  130. if raw == "" {
  131. return nil, invalidArrayInput(text, "empty array element")
  132. }
  133. if !strings.EqualFold(raw, "NULL") {
  134. value = &raw
  135. }
  136. }
  137. elements = append(elements, value)
  138. if i >= len(inner) {
  139. return elements, nil
  140. }
  141. if inner[i] != ',' {
  142. return nil, invalidArrayInput(text, "expected , between elements")
  143. }
  144. i++
  145. if i >= len(inner) {
  146. return nil, invalidArrayInput(text, "trailing comma")
  147. }
  148. }
  149. }
  150. func isArraySpace(c byte) bool {
  151. return c == ' ' || c == '\t' || c == '\n' || c == '\r'
  152. }
  153. // invalidArrayInput reports malformed array text as a client input error.
  154. func invalidArrayInput(text, reason string) error {
  155. return pgerror.InvalidText("invalid array input %q: %s", text, reason)
  156. }
  157. // formatArrayLiteral renders elements in canonical array text.
  158. func formatArrayLiteral(elements []*string) string {
  159. var b strings.Builder
  160. b.WriteByte('{')
  161. for i, element := range elements {
  162. if i > 0 {
  163. b.WriteByte(',')
  164. }
  165. if element == nil {
  166. b.WriteString("NULL")
  167. continue
  168. }
  169. b.WriteString(formatArrayElementText(*element))
  170. }
  171. b.WriteByte('}')
  172. return b.String()
  173. }
  174. // formatArrayElementText quotes an element when leaving it bare would change its
  175. // meaning: empty text, the NULL keyword, or characters that delimit elements.
  176. func formatArrayElementText(text string) string {
  177. needsQuote := text == "" || strings.EqualFold(text, "NULL")
  178. for i := 0; i < len(text) && !needsQuote; i++ {
  179. switch text[i] {
  180. case '{', '}', ',', '"', '\\', ' ', '\t', '\n', '\r':
  181. needsQuote = true
  182. }
  183. }
  184. if !needsQuote {
  185. return text
  186. }
  187. var b strings.Builder
  188. b.WriteByte('"')
  189. for i := 0; i < len(text); i++ {
  190. if text[i] == '"' || text[i] == '\\' {
  191. b.WriteByte('\\')
  192. }
  193. b.WriteByte(text[i])
  194. }
  195. b.WriteByte('"')
  196. return b.String()
  197. }
  198. // CanonicalizeArrayText validates PostgreSQL array text for an array type and
  199. // returns its canonical encoding. The protocol layer uses it to reject a
  200. // malformed bound array parameter at Bind time instead of waiting for a row to
  201. // evaluate the predicate.
  202. func CanonicalizeArrayText(text, typeName string) (string, error) {
  203. return canonicalArrayText(text, typeName)
  204. }
  205. // canonicalArrayText parses array text and re-encodes it for the given array
  206. // type, converting each element to its canonical spelling.
  207. func canonicalArrayText(text, typeName string) (string, error) {
  208. kind, err := arrayElementKindOf(typeName)
  209. if err != nil {
  210. return "", err
  211. }
  212. elements, err := parseArrayLiteral(text)
  213. if err != nil {
  214. return "", err
  215. }
  216. canonical := make([]*string, len(elements))
  217. for i, element := range elements {
  218. value, elementErr := canonicalArrayElement(element, kind, typeName)
  219. if elementErr != nil {
  220. return "", elementErr
  221. }
  222. canonical[i] = value
  223. }
  224. return formatArrayLiteral(canonical), nil
  225. }
  226. // canonicalArrayElement converts one element to its canonical text. Element
  227. // types the engine does not carry exactly (integer widths, floating point) are
  228. // parsed and re-formatted so equivalent inputs encode identically.
  229. func canonicalArrayElement(element *string, kind arrayElementKind, typeName string) (*string, error) {
  230. if element == nil {
  231. return nil, nil
  232. }
  233. raw := *element
  234. switch kind {
  235. case arrayElementInteger:
  236. n, err := strconv.ParseInt(strings.TrimSpace(raw), 10, 64)
  237. if err != nil {
  238. return nil, pgerror.InvalidText("invalid input syntax for type %s: %q", typeName, raw)
  239. }
  240. canonical := strconv.FormatInt(n, 10)
  241. return &canonical, nil
  242. case arrayElementReal:
  243. f, err := strconv.ParseFloat(strings.TrimSpace(raw), 64)
  244. if err != nil {
  245. return nil, pgerror.InvalidText("invalid input syntax for type %s: %q", typeName, raw)
  246. }
  247. canonical := strconv.FormatFloat(f, 'g', -1, 64)
  248. return &canonical, nil
  249. case arrayElementNumeric:
  250. if !isNumericArrayElement(raw) {
  251. return nil, pgerror.InvalidText("invalid input syntax for type %s: %q", typeName, raw)
  252. }
  253. canonical := raw
  254. return &canonical, nil
  255. case arrayElementBoolean:
  256. value, ok := parseArrayBoolean(raw)
  257. if !ok {
  258. return nil, pgerror.InvalidText("invalid input syntax for type %s: %q", typeName, raw)
  259. }
  260. canonical := "f"
  261. if value {
  262. canonical = "t"
  263. }
  264. return &canonical, nil
  265. default:
  266. canonical := raw
  267. return &canonical, nil
  268. }
  269. }
  270. // parseArrayBoolean accepts the boolean spellings PostgreSQL accepts in a text
  271. // array element and reports the value.
  272. func parseArrayBoolean(raw string) (bool, bool) {
  273. switch strings.ToLower(strings.TrimSpace(raw)) {
  274. case "t", "true", "1", "y", "yes", "on":
  275. return true, true
  276. case "f", "false", "0", "n", "no", "off":
  277. return false, true
  278. default:
  279. return false, false
  280. }
  281. }
  282. // arrayElementValue converts canonical element text to the Go value the engine
  283. // uses for that element type. Text elements stay strings.
  284. func arrayElementValue(element *string, elementType string) (interface{}, error) {
  285. if element == nil {
  286. return nil, nil
  287. }
  288. kind, err := arrayElementKindForName(elementType)
  289. if err != nil {
  290. return nil, err
  291. }
  292. raw := *element
  293. switch kind {
  294. case arrayElementInteger:
  295. n, err := strconv.ParseInt(raw, 10, 64)
  296. if err != nil {
  297. return nil, pgerror.InvalidText("invalid input syntax for type integer: %q", raw)
  298. }
  299. return n, nil
  300. case arrayElementReal:
  301. f, err := strconv.ParseFloat(raw, 64)
  302. if err != nil {
  303. return nil, pgerror.InvalidText("invalid input syntax for type double precision: %q", raw)
  304. }
  305. return f, nil
  306. case arrayElementNumeric:
  307. if !isNumericArrayElement(raw) {
  308. return nil, pgerror.InvalidText("invalid input syntax for type numeric: %q", raw)
  309. }
  310. // Return the text so a value above 2^53 keeps every digit.
  311. return raw, nil
  312. case arrayElementBoolean:
  313. value, ok := parseArrayBoolean(raw)
  314. if !ok {
  315. return nil, pgerror.InvalidText("invalid input syntax for type boolean: %q", raw)
  316. }
  317. return value, nil
  318. default:
  319. return raw, nil
  320. }
  321. }
  322. // isNumericArrayElement reports whether text is a valid SQL numeric spelling.
  323. // NUMERIC elements are not rewritten, so this is validation only.
  324. func isNumericArrayElement(raw string) bool {
  325. text := strings.TrimSpace(raw)
  326. if text == "" {
  327. return false
  328. }
  329. _, err := strconv.ParseFloat(text, 64)
  330. return err == nil
  331. }
  332. // arrayValueElement renders one evaluated expression value as a canonical array
  333. // element. Array nesting and non-scalar values are rejected.
  334. func arrayValueElement(value interface{}) (*string, error) {
  335. switch v := value.(type) {
  336. case nil:
  337. return nil, nil
  338. case bool:
  339. text := "f"
  340. if v {
  341. text = "t"
  342. }
  343. return &text, nil
  344. case int64:
  345. text := strconv.FormatInt(v, 10)
  346. return &text, nil
  347. case int:
  348. text := strconv.FormatInt(int64(v), 10)
  349. return &text, nil
  350. case float64:
  351. text := strconv.FormatFloat(v, 'g', -1, 64)
  352. return &text, nil
  353. case string:
  354. return &v, nil
  355. case []byte:
  356. return nil, pgerror.Unsupported("arrays of BLOB are not supported")
  357. default:
  358. return nil, pgerror.Unsupported("ARRAY[...] element type %T is not supported", value)
  359. }
  360. }
  361. // evalArrayExpr evaluates the ARRAY[...] constructor into canonical array text.
  362. func (e *Executor) evalArrayExpr(expr *parser.ArrayExpr, row storage.Row) (interface{}, error) {
  363. elements := make([]*string, len(expr.Elements))
  364. for i, element := range expr.Elements {
  365. value, err := e.evalExpr(element, row)
  366. if err != nil {
  367. return nil, err
  368. }
  369. text, err := arrayValueElement(value)
  370. if err != nil {
  371. return nil, fmt.Errorf("ARRAY element %d: %w", i+1, err)
  372. }
  373. elements[i] = text
  374. }
  375. return formatArrayLiteral(elements), nil
  376. }
  377. // arrayExpressionIsConstant reports whether evaluating an array expression once
  378. // per statement is safe: it references no columns and no volatile function.
  379. func arrayExpressionIsConstant(expr parser.Expr) bool {
  380. if expr == nil || len(collectColumnRefs(expr)) != 0 {
  381. return false
  382. }
  383. return ValidateDeterministicExpr(expr) == nil
  384. }
  385. // arrayOperand evaluates an array-valued expression through the per-statement
  386. // value cache. A constant operand is evaluated once for the whole scan instead
  387. // of once per row; a column-dependent operand is re-evaluated every time.
  388. func (e *Executor) arrayOperand(expr parser.Expr, evaluate func() (interface{}, error)) (interface{}, error) {
  389. if e.arrayValueCache != nil && expr != nil {
  390. if value, ok := e.arrayValueCache[expr]; ok {
  391. return value, nil
  392. }
  393. }
  394. value, err := evaluate()
  395. if err != nil {
  396. return nil, err
  397. }
  398. if e.arrayValueCache != nil && expr != nil && arrayExpressionIsConstant(expr) {
  399. e.arrayValueCache[expr] = value
  400. }
  401. return value, nil
  402. }
  403. // arrayParseEntry memoizes the parsed elements of one array expression for the
  404. // current statement. The evaluated text is compared before a hit is used, so a
  405. // value that changes between rows or between executions is re-parsed.
  406. type arrayParseEntry struct {
  407. text string
  408. elements []*string
  409. err error
  410. }
  411. // parsedArray parses an evaluated array value for one expression. The
  412. // per-statement cache keyed by AST node keeps `= ANY($1)` to one parse for the
  413. // whole scan instead of one parse per row.
  414. func (e *Executor) parsedArray(expr parser.Expr, value interface{}) ([]*string, error) {
  415. text := toString(value)
  416. if e.arrayCache != nil && expr != nil {
  417. if entry, ok := e.arrayCache[expr]; ok && entry.text == text {
  418. return entry.elements, entry.err
  419. }
  420. }
  421. elements, err := parseArrayLiteral(text)
  422. if e.arrayCache != nil && expr != nil {
  423. e.arrayCache[expr] = &arrayParseEntry{text: text, elements: elements, err: err}
  424. }
  425. return elements, err
  426. }
  427. // arrayElementTypeOf reports the element type of an expression whose value is an
  428. // array, resolved against the declared column types of the query currently
  429. // executing. An unknown type (a derived table, a bare literal) reports false so
  430. // the caller keeps the element text.
  431. func (e *Executor) arrayElementTypeOf(expr parser.Expr) (string, bool) {
  432. if expr == nil {
  433. return "", false
  434. }
  435. return arrayElementType(inferExprType(expr, e.resolveColumnType))
  436. }
  437. // arrayIndexValue validates an array subscript or array_length dimension.
  438. // PostgreSQL's signatures take integers; floats, booleans, and text are a
  439. // datatype mismatch, not an implicit truncation.
  440. func arrayIndexValue(value interface{}, what string) (int64, error) {
  441. switch v := value.(type) {
  442. case int64:
  443. return v, nil
  444. case int:
  445. return int64(v), nil
  446. case int32:
  447. return int64(v), nil
  448. case int16:
  449. return int64(v), nil
  450. case int8:
  451. return int64(v), nil
  452. default:
  453. return 0, pgerror.DatatypeMismatch("%s must be an integer, got %T", what, value)
  454. }
  455. }
  456. // evalSubscriptExpr evaluates arr[index] with PostgreSQL's 1-based indexing. An
  457. // out-of-range subscript yields NULL, and a NULL array, index, or element yields
  458. // NULL. The element is decoded to the array's declared element type so a
  459. // boolean subscript is a Go bool rather than the canonical t/f text.
  460. func (e *Executor) evalSubscriptExpr(expr *parser.SubscriptExpr, row storage.Row) (interface{}, error) {
  461. value, err := e.arrayOperand(expr.Expr, func() (interface{}, error) {
  462. return e.evalExpr(expr.Expr, row)
  463. })
  464. if err != nil {
  465. return nil, err
  466. }
  467. index, err := e.evalExpr(expr.Index, row)
  468. if err != nil {
  469. return nil, err
  470. }
  471. return e.subscriptArrayValue(expr.Expr, value, index)
  472. }
  473. // subscriptArrayValue applies a 1-based subscript to an evaluated array value.
  474. func (e *Executor) subscriptArrayValue(arrayExpr parser.Expr, value, index interface{}) (interface{}, error) {
  475. if value == nil || index == nil {
  476. return nil, nil
  477. }
  478. position, err := arrayIndexValue(index, "array subscript")
  479. if err != nil {
  480. return nil, err
  481. }
  482. elements, err := e.parsedArray(arrayExpr, value)
  483. if err != nil {
  484. return nil, fmt.Errorf("array subscript requires an array value: %w", err)
  485. }
  486. if position < 1 || position > int64(len(elements)) {
  487. return nil, nil
  488. }
  489. element := elements[position-1]
  490. if element == nil {
  491. return nil, nil
  492. }
  493. elementType, ok := e.arrayElementTypeOf(arrayExpr)
  494. if !ok {
  495. return *element, nil
  496. }
  497. return arrayElementValue(element, elementType)
  498. }
  499. // evalAnyAllExpr evaluates `left op ANY(array)` / `left op ALL(array)` with SQL
  500. // three-valued logic. ANY is true when any comparison is true, false when none
  501. // is true and no comparison is NULL, and NULL otherwise; ALL is its dual.
  502. func (e *Executor) evalAnyAllExpr(expr *parser.AnyAllExpr, row storage.Row) (interface{}, error) {
  503. left, err := e.evalExpr(expr.Left, row)
  504. if err != nil {
  505. return nil, err
  506. }
  507. arrayValue, err := e.arrayOperand(expr.Array, func() (interface{}, error) {
  508. return e.evalExpr(expr.Array, row)
  509. })
  510. if err != nil {
  511. return nil, err
  512. }
  513. if arrayValue == nil {
  514. return nil, nil
  515. }
  516. elements, err := e.parsedArray(expr.Array, arrayValue)
  517. if err != nil {
  518. return nil, fmt.Errorf("ANY/ALL requires an array operand: %w", err)
  519. }
  520. return evalQuantifiedComparison(expr.Op, expr.All, left, elements)
  521. }
  522. // evalQuantifiedComparison applies a comparison to each array element. The
  523. // empty array is decided before the left operand: ANY over no elements is
  524. // false and ALL over no elements is true, even when the left operand is NULL.
  525. func evalQuantifiedComparison(op lexer.TokenType, all bool, left interface{}, elements []*string) (interface{}, error) {
  526. if len(elements) == 0 {
  527. return all, nil
  528. }
  529. if left == nil {
  530. return nil, nil
  531. }
  532. sawNull := false
  533. for _, element := range elements {
  534. if element == nil {
  535. sawNull = true
  536. continue
  537. }
  538. matched, err := compareArrayElement(op, left, *element)
  539. if err != nil {
  540. return nil, err
  541. }
  542. if all && !matched {
  543. return false, nil
  544. }
  545. if !all && matched {
  546. return true, nil
  547. }
  548. }
  549. if sawNull {
  550. return nil, nil
  551. }
  552. return all, nil
  553. }
  554. // compareArrayElement applies a comparison operator between a scalar left value
  555. // and one array element's text. Booleans are decoded so `true = ANY('{t,f}')`
  556. // compares as booleans; every other type compares through the engine's numeric
  557. // or textual comparison rules.
  558. func compareArrayElement(op lexer.TokenType, left interface{}, element string) (bool, error) {
  559. var right interface{} = element
  560. if _, isBool := left.(bool); isBool {
  561. value, ok := parseArrayBoolean(element)
  562. if !ok {
  563. return false, pgerror.InvalidText("invalid input syntax for type boolean: %q", element)
  564. }
  565. right = value
  566. }
  567. cmp := compare(left, right)
  568. switch op {
  569. case lexer.TokenEq:
  570. return cmp == 0, nil
  571. case lexer.TokenNeq:
  572. return cmp != 0, nil
  573. case lexer.TokenLt:
  574. return cmp < 0, nil
  575. case lexer.TokenLte:
  576. return cmp <= 0, nil
  577. case lexer.TokenGt:
  578. return cmp > 0, nil
  579. case lexer.TokenGte:
  580. return cmp >= 0, nil
  581. default:
  582. return false, fmt.Errorf("unsupported ANY/ALL comparison operator: %v", op)
  583. }
  584. }
  585. // evalArrayLength implements array_length(array, dimension). Only dimension 1 is
  586. // meaningful for a one-dimensional array; any other dimension yields NULL, as
  587. // PostgreSQL does for an out-of-range dimension of a non-nested array.
  588. func (e *Executor) evalArrayLength(arrayExpr parser.Expr, args []interface{}) (interface{}, error) {
  589. if len(args) != 2 {
  590. return nil, fmt.Errorf("array_length requires two arguments")
  591. }
  592. if args[0] == nil || args[1] == nil {
  593. return nil, nil
  594. }
  595. dimension, err := arrayIndexValue(args[1], "array dimension")
  596. if err != nil {
  597. return nil, err
  598. }
  599. if dimension != 1 {
  600. return nil, nil
  601. }
  602. elements, err := e.parsedArray(arrayExpr, args[0])
  603. if err != nil {
  604. return nil, fmt.Errorf("array_length requires an array value: %w", err)
  605. }
  606. if len(elements) == 0 {
  607. // PostgreSQL reports NULL for the length of an empty array.
  608. return nil, nil
  609. }
  610. return int64(len(elements)), nil
  611. }
  612. // arrayTypeOf reports the declared array type of an expression, if any.
  613. func (e *Executor) arrayTypeOf(expr parser.Expr) (string, bool) {
  614. if expr == nil {
  615. return "", false
  616. }
  617. typeName := inferExprType(expr, e.resolveColumnType)
  618. if _, ok := arrayElementType(typeName); !ok {
  619. return "", false
  620. }
  621. return typeName, true
  622. }
  623. // canonicalArrayValue canonicalizes a value against the array type of expr. It
  624. // is a no-op for non-array expressions, NULL, and non-string values.
  625. func (e *Executor) canonicalArrayValue(arrayExpr parser.Expr, value interface{}) (interface{}, error) {
  626. typeName, ok := e.arrayTypeOf(arrayExpr)
  627. if !ok || value == nil {
  628. return value, nil
  629. }
  630. text, isText := value.(string)
  631. if !isText {
  632. return value, nil
  633. }
  634. return canonicalArrayText(text, typeName)
  635. }
  636. // canonicalizeArrayComparison canonicalizes the string operand of a comparison
  637. // when the other operand is array-typed, so a text literal such as '{a, b}' or
  638. // '{"a","b"}' compares equal to the canonical stored '{a,b}'.
  639. func (e *Executor) canonicalizeArrayComparison(leftExpr, rightExpr parser.Expr, left, right interface{}) (interface{}, interface{}, error) {
  640. if _, ok := e.arrayTypeOf(leftExpr); ok {
  641. canonical, err := e.canonicalArrayValue(leftExpr, right)
  642. if err != nil {
  643. return nil, nil, err
  644. }
  645. right = canonical
  646. }
  647. if _, ok := e.arrayTypeOf(rightExpr); ok {
  648. canonical, err := e.canonicalArrayValue(rightExpr, left)
  649. if err != nil {
  650. return nil, nil, err
  651. }
  652. left = canonical
  653. }
  654. return left, right, nil
  655. }
  656. // evalArrayCast converts a value to an array type. The input must already be
  657. // array text (a literal, a parameter, or another array value); every element is
  658. // validated and re-encoded canonically for the target element type.
  659. func evalArrayCast(target parser.DataType, value interface{}) (interface{}, error) {
  660. if value == nil {
  661. return nil, nil
  662. }
  663. text, ok := value.(string)
  664. if !ok {
  665. return nil, pgerror.InvalidText("cannot cast %T to %s", value, target.SQLTypeName())
  666. }
  667. return canonicalArrayText(text, target.SQLTypeName())
  668. }
  669. // canonicalArrayDefault canonicalizes a constant DEFAULT for an array column so
  670. // the catalog and any ALTER TABLE backfill store the same bytes an INSERT would.
  671. func canonicalArrayDefault(typeName string, value interface{}, exprText string) (interface{}, string, error) {
  672. if _, isArray := arrayElementType(typeName); !isArray || exprText != "" || value == nil {
  673. return value, exprText, nil
  674. }
  675. text, ok := value.(string)
  676. if !ok {
  677. return nil, "", pgerror.InvalidText("DEFAULT for %s must be array text, got %T", typeName, value)
  678. }
  679. canonical, err := canonicalArrayText(text, typeName)
  680. if err != nil {
  681. return nil, "", err
  682. }
  683. return canonical, "", nil
  684. }
  685. // normalizeArrayRow canonicalizes every array-typed column value in a row before
  686. // it is written. A string value is parsed as array text; an already-canonical
  687. // value is re-encoded identically, so the encoding is stable across reloads and
  688. // every write path shares one representation.
  689. func (e *Executor) normalizeArrayRow(schema *storage.Schema, row storage.Row) error {
  690. if schema == nil {
  691. return nil
  692. }
  693. for _, column := range schema.Columns {
  694. if _, isArray := arrayElementType(column.Type); !isArray {
  695. continue
  696. }
  697. value, ok := lookupRowValue(row, column.Name)
  698. if !ok || value == nil {
  699. continue
  700. }
  701. text, isText := value.(string)
  702. if !isText {
  703. return pgerror.InvalidText("column %q is %s and accepts array text, got %T", column.Name, column.Type, value)
  704. }
  705. canonical, err := canonicalArrayText(text, column.Type)
  706. if err != nil {
  707. return fmt.Errorf("column %q: %w", column.Name, err)
  708. }
  709. row[column.Name] = canonical
  710. }
  711. return nil
  712. }