1use rupg_common::SqlState;
8
9use crate::binary::Recv;
10use crate::error::TypeError;
11use crate::number::{int_out, is_space, uint32_in_subr};
12use crate::oid;
13use crate::types::{Oid, format_type};
14
15pub const MAXDIM: usize = 6;
17
18pub const MAX_ARRAY_SIZE: usize = 134_217_727;
20
21const FIRST_GENBKI_OBJECT_ID: Oid = 10_000;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub struct ArrayDim {
27 pub len: i32,
28 pub lower: i32,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct Array<T> {
34 pub dims: Vec<ArrayDim>,
35 pub values: Vec<Option<T>>,
36}
37
38impl<T> Array<T> {
39 pub fn empty() -> Array<T> {
40 Array { dims: Vec::new(), values: Vec::new() }
41 }
42
43 pub fn one(values: Vec<Option<T>>) -> Array<T> {
45 if values.is_empty() {
46 return Array::empty();
47 }
48 let len = i32::try_from(values.len()).unwrap_or(i32::MAX);
49 Array { dims: vec![ArrayDim { len, lower: 1 }], values }
50 }
51
52 pub fn vector(values: Vec<Option<T>>) -> Array<T> {
54 if values.is_empty() {
55 return Array::empty();
56 }
57 let len = i32::try_from(values.len()).unwrap_or(i32::MAX);
58 Array { dims: vec![ArrayDim { len, lower: 0 }], values }
59 }
60}
61
62fn malformed(input: &str, detail: &str) -> TypeError {
63 let mut error = TypeError::new(
64 SqlState::INVALID_TEXT_REPRESENTATION,
65 format!("malformed array literal: \"{input}\""),
66 );
67 error.detail = Some(detail.to_string());
68 error
69}
70
71fn limit(message: String) -> TypeError {
72 TypeError::new(SqlState::PROGRAM_LIMIT_EXCEEDED, message)
73}
74
75fn too_large() -> TypeError {
76 limit(format!("array size exceeds the maximum allowed ({MAX_ARRAY_SIZE})"))
77}
78
79fn too_many_dimensions() -> TypeError {
80 limit(format!("number of array dimensions exceeds the maximum allowed ({MAXDIM})"))
81}
82
83fn binary(message: String) -> TypeError {
84 TypeError::new(SqlState::INVALID_BINARY_REPRESENTATION, message)
85}
86
87pub(crate) fn item_count(dims: &[ArrayDim]) -> Result<usize, TypeError> {
89 let mut count = 1i32;
90 for dim in dims {
91 if dim.len < 0 {
93 return Err(too_large());
94 }
95 count = count.checked_mul(dim.len).ok_or_else(too_large)?;
96 }
97 let count = if dims.is_empty() { 0 } else { count as usize };
98 if count > MAX_ARRAY_SIZE {
99 return Err(too_large());
100 }
101 Ok(count)
102}
103
104fn dimension_int(b: &[u8], start: usize) -> Result<(i32, usize), TypeError> {
106 let at = |i: usize| b.get(i).copied().unwrap_or(0);
107 let mut i = start;
108 let neg = at(i) == b'-';
109 if neg || at(i) == b'+' {
110 i += 1;
111 }
112 let first = i;
113 let mut value = 0i64;
114 while at(i).is_ascii_digit() {
115 value = value.saturating_mul(10).saturating_add(i64::from(at(i) - b'0'));
116 i += 1;
117 }
118 if i == first {
119 return Ok((0, start));
120 }
121 let value = if neg { -value } else { value };
122 let value = i32::try_from(value)
123 .map_err(|_| limit("array bound is out of integer range".to_string()))?;
124 Ok((value, i))
125}
126
127enum Token {
129 Start,
130 End,
131 Delim,
132 Element,
133 Null,
134}
135
136struct Reader<'a> {
138 input: &'a str,
139 b: &'a [u8],
140 at: usize,
141 delim: u8,
142 array_nulls: bool,
143 buf: Vec<u8>,
144}
145
146impl Reader<'_> {
147 fn byte(&self, i: usize) -> u8 {
148 self.b.get(i).copied().unwrap_or(0)
149 }
150
151 fn malformed(&self, detail: &str) -> TypeError {
152 malformed(self.input, detail)
153 }
154
155 fn unexpected(&self, c: u8) -> TypeError {
156 self.malformed(&format!("Unexpected \"{}\" character.", char::from(c)))
157 }
158
159 fn end(&self) -> TypeError {
160 self.malformed("Unexpected end of input.")
161 }
162
163 fn token(&mut self) -> Result<Token, TypeError> {
165 self.buf.clear();
166 let mut p = self.at;
167 loop {
168 match self.byte(p) {
169 0 => return Err(self.end()),
170 b'{' => {
171 self.at = p + 1;
172 return Ok(Token::Start);
173 }
174 b'}' => {
175 self.at = p + 1;
176 return Ok(Token::End);
177 }
178 b'"' => return self.quoted(p + 1),
179 c if c == self.delim => {
180 self.at = p + 1;
181 return Ok(Token::Delim);
182 }
183 c if is_space(c) => p += 1,
184 _ => return self.unquoted(p),
185 }
186 }
187 }
188
189 fn quoted(&mut self, mut p: usize) -> Result<Token, TypeError> {
190 loop {
191 match self.byte(p) {
192 0 => return Err(self.end()),
193 b'\\' => {
194 p += 1;
195 match self.byte(p) {
196 0 => return Err(self.end()),
197 c => self.buf.push(c),
198 }
199 p += 1;
200 }
201 b'"' => loop {
202 p += 1;
204 match self.byte(p) {
205 0 => return Err(self.end()),
206 c if c == self.delim || c == b'}' || c == b'{' => {
207 self.at = p;
208 return Ok(Token::Element);
209 }
210 c if !is_space(c) => {
211 return Err(self.malformed("Incorrectly quoted array element."));
212 }
213 _ => {}
214 }
215 },
216 c => {
217 self.buf.push(c);
218 p += 1;
219 }
220 }
221 }
222 }
223
224 fn unquoted(&mut self, mut p: usize) -> Result<Token, TypeError> {
225 let mut keep = 0;
227 let mut escapes = false;
228 loop {
229 match self.byte(p) {
230 0 => return Err(self.end()),
231 b'{' => return Err(self.unexpected(b'{')),
232 b'"' => return Err(self.malformed("Incorrectly quoted array element.")),
233 b'\\' => {
234 p += 1;
235 match self.byte(p) {
236 0 => return Err(self.end()),
237 c => self.buf.push(c),
238 }
239 p += 1;
240 keep = self.buf.len();
241 escapes = true;
242 }
243 c if c == self.delim || c == b'}' => {
244 self.buf.truncate(keep);
245 self.at = p;
246 if self.array_nulls && !escapes && self.buf.eq_ignore_ascii_case(b"NULL") {
247 return Ok(Token::Null);
248 }
249 return Ok(Token::Element);
250 }
251 c => {
252 self.buf.push(c);
253 if !is_space(c) {
254 keep = self.buf.len();
255 }
256 p += 1;
257 }
258 }
259 }
260 }
261
262 fn element(&self) -> &str {
264 std::str::from_utf8(&self.buf).unwrap_or_default()
265 }
266}
267
268pub fn array_in<T>(
270 s: &str,
271 delim: u8,
272 array_nulls: bool,
273 mut element: impl FnMut(&str) -> Result<T, TypeError>,
274) -> Result<Array<T>, TypeError> {
275 let b = s.as_bytes();
276 let at = |i: usize| b.get(i).copied().unwrap_or(0);
277 let mut p = 0;
278
279 let mut dims: Vec<ArrayDim> = Vec::new();
281 loop {
282 while is_space(at(p)) {
283 p += 1;
284 }
285 if at(p) != b'[' {
286 break;
287 }
288 p += 1;
289 if dims.len() >= MAXDIM {
290 return Err(too_many_dimensions());
291 }
292 let (first, end) = dimension_int(b, p)?;
293 if end == p {
294 return Err(malformed(
295 s,
296 "\"[\" must introduce explicitly-specified array dimensions.",
297 ));
298 }
299 p = end;
300 let (lower, upper) = if at(p) == b':' {
301 p += 1;
302 let (upper, end) = dimension_int(b, p)?;
303 if end == p {
304 return Err(malformed(s, "Missing array dimension value."));
305 }
306 p = end;
307 (first, upper)
308 } else {
309 (1, first)
310 };
311 if at(p) != b']' {
312 return Err(malformed(s, "Missing \"]\" after array dimensions."));
313 }
314 p += 1;
315 if upper < lower {
316 return Err(TypeError::new(
317 SqlState::ARRAY_SUBSCRIPT_ERROR,
318 "upper bound cannot be less than lower bound".to_string(),
319 ));
320 }
321 if upper == i32::MAX {
322 return Err(limit(format!("array upper bound is too large: {upper}")));
323 }
324 let len = upper.checked_sub(lower).and_then(|n| n.checked_add(1)).ok_or_else(too_large)?;
325 dims.push(ArrayDim { len, lower });
326 }
327 if dims.is_empty() {
328 if at(p) != b'{' {
329 return Err(malformed(
330 s,
331 "Array value must start with \"{\" or dimension information.",
332 ));
333 }
334 } else {
335 if at(p) != b'=' {
336 return Err(malformed(s, "Missing \"=\" after array dimensions."));
337 }
338 p += 1;
339 while is_space(at(p)) {
340 p += 1;
341 }
342 if at(p) != b'{' {
343 return Err(malformed(s, "Array contents must start with \"{\"."));
344 }
345 }
346
347 let specified = !dims.is_empty();
349 let mut ndim = dims.len();
350 let mut lens = [-1i32; MAXDIM];
351 for (len, dim) in lens.iter_mut().zip(&dims) {
352 *len = dim.len;
353 }
354 let mut counts = [0i32; MAXDIM];
355 let mut values = Vec::new();
356 let mut level = 0;
357 let mut frozen = specified;
358 let mut expect_delim = false;
359 let mut reader = Reader { input: s, b, at: p, delim, array_nulls, buf: Vec::new() };
360 let dimension_error = || match specified {
361 true => malformed(s, "Specified array dimensions do not match array contents."),
362 false => {
363 malformed(s, "Multidimensional arrays must have sub-arrays with matching dimensions.")
364 }
365 };
366 loop {
367 match reader.token()? {
368 Token::Start => {
369 if expect_delim {
370 return Err(reader.unexpected(b'{'));
371 }
372 if level >= MAXDIM {
373 return Err(too_many_dimensions());
374 }
375 counts[level] = 0;
376 level += 1;
377 if level > ndim {
378 if frozen {
379 return Err(dimension_error());
380 }
381 ndim = level;
382 }
383 }
384 Token::End => {
385 if counts[level - 1] > 0 && !expect_delim {
387 return Err(reader.unexpected(b'}'));
388 }
389 level -= 1;
390 if level > 0 {
391 counts[level - 1] += 1;
392 }
393 if lens[level] < 0 {
394 lens[level] = counts[level];
395 } else if counts[level] != lens[level] {
396 return Err(dimension_error());
397 }
398 expect_delim = true;
399 }
400 Token::Delim => {
401 if !expect_delim {
402 return Err(reader.unexpected(delim));
403 }
404 expect_delim = false;
405 }
406 token @ (Token::Element | Token::Null) => {
407 if expect_delim {
408 return Err(reader.malformed("Unexpected array element."));
409 }
410 if values.len() >= MAX_ARRAY_SIZE {
411 return Err(too_large());
412 }
413 values.push(match token {
414 Token::Null => None,
415 _ => Some(element(reader.element())?),
416 });
417 frozen = true;
419 if level != ndim {
420 return Err(dimension_error());
421 }
422 counts[level - 1] += 1;
423 expect_delim = true;
424 }
425 }
426 if level == 0 {
427 break;
428 }
429 }
430 if b[reader.at..].iter().any(|&c| !is_space(c)) {
431 return Err(malformed(s, "Junk after closing right brace."));
432 }
433 if values.is_empty() {
434 return Ok(Array::empty());
435 }
436 let lowers = dims.iter().map(|dim| dim.lower).chain(std::iter::repeat(1));
437 let dims = lens[..ndim].iter().zip(lowers).map(|(&len, lower)| ArrayDim { len, lower });
438 Ok(Array { dims: dims.collect(), values })
439}
440
441pub fn array_out<T>(
443 array: &Array<T>,
444 delim: u8,
445 out: &mut Vec<u8>,
446 mut element: impl FnMut(&T, &mut Vec<u8>),
447) {
448 let ndim = array.dims.len();
449 if array.values.is_empty() || ndim == 0 {
450 out.extend_from_slice(b"{}");
451 return;
452 }
453 if array.dims.iter().any(|dim| dim.lower != 1) {
454 for dim in &array.dims {
455 out.push(b'[');
456 int_out(dim.lower.into(), out);
457 out.push(b':');
458 int_out(i64::from(dim.lower) + i64::from(dim.len) - 1, out);
459 out.push(b']');
460 }
461 out.push(b'=');
462 }
463 out.push(b'{');
464 let mut index = [0i32; MAXDIM];
465 let mut open = 0;
466 for value in &array.values {
467 out.extend(std::iter::repeat_n(b'{', ndim - 1 - open));
468 match value {
469 None => out.extend_from_slice(b"NULL"),
470 Some(value) => {
471 let start = out.len();
473 element(value, out);
474 let text = &out[start..];
475 let quote = text.is_empty()
476 || text.eq_ignore_ascii_case(b"NULL")
477 || text.iter().any(|&c| {
478 matches!(c, b'"' | b'\\' | b'{' | b'}') || c == delim || is_space(c)
479 });
480 if quote {
481 let text = out.split_off(start);
482 out.push(b'"');
483 for c in text {
484 if c == b'"' || c == b'\\' {
485 out.push(b'\\');
486 }
487 out.push(c);
488 }
489 out.push(b'"');
490 }
491 }
492 }
493 open = ndim;
495 for i in (0..ndim).rev() {
496 index[i] += 1;
497 if index[i] < array.dims[i].len {
498 out.push(delim);
499 open = i;
500 break;
501 }
502 index[i] = 0;
503 out.push(b'}');
504 }
505 if open == ndim {
506 break;
507 }
508 }
509}
510
511pub fn array_recv<'a, T>(
513 recv: &mut Recv<'a>,
514 elem: Oid,
515 mut element: impl FnMut(&mut Recv<'a>) -> Result<T, TypeError>,
516) -> Result<Array<T>, TypeError> {
517 let ndim = recv.i32()?;
518 if ndim < 0 {
519 return Err(binary(format!("invalid number of dimensions: {ndim}")));
520 }
521 if ndim as usize > MAXDIM {
522 return Err(limit(format!(
523 "number of array dimensions ({ndim}) exceeds the maximum allowed ({MAXDIM})"
524 )));
525 }
526 let flags = recv.i32()?;
527 if flags != 0 && flags != 1 {
528 return Err(binary("invalid array flags".to_string()));
529 }
530 let got = recv.u32()?;
532 if got != elem && got < FIRST_GENBKI_OBJECT_ID && elem < FIRST_GENBKI_OBJECT_ID {
533 return Err(TypeError::new(
534 SqlState::DATATYPE_MISMATCH,
535 format!(
536 "binary data has array element type {got} ({}) instead of expected {elem} ({})",
537 format_type(got),
538 format_type(elem)
539 ),
540 ));
541 }
542 let mut dims = Vec::with_capacity(ndim as usize);
543 for _ in 0..ndim {
544 let len = recv.i32()?;
545 let lower = recv.i32()?;
546 dims.push(ArrayDim { len, lower });
547 }
548 let count = item_count(&dims)?;
549 for dim in &dims {
550 if dim.len.checked_add(dim.lower).is_none() {
551 return Err(limit(format!("array lower bound is too large: {}", dim.lower)));
552 }
553 }
554 if count == 0 {
555 return Ok(Array::empty());
556 }
557 let mut values = Vec::with_capacity(count.min(recv.remaining() / 4));
558 for number in 1..=count {
559 let len = recv.i32()?;
560 if len < -1 || len > i32::try_from(recv.remaining()).unwrap_or(i32::MAX) {
561 return Err(binary("insufficient data left in message".to_string()));
562 }
563 if len == -1 {
564 values.push(None);
565 continue;
566 }
567 let mut item = Recv::new(recv.bytes(len as usize)?);
568 values.push(Some(element(&mut item)?));
569 if item.remaining() != 0 {
570 return Err(binary(format!("improper binary format in array element {number}")));
571 }
572 }
573 Ok(Array { dims, values })
574}
575
576pub fn array_send<T>(
578 array: &Array<T>,
579 elem: Oid,
580 out: &mut Vec<u8>,
581 mut element: impl FnMut(&T, &mut Vec<u8>),
582) {
583 let ndim = i32::try_from(array.dims.len()).unwrap_or(i32::MAX);
584 out.extend_from_slice(&ndim.to_be_bytes());
585 let nulls = array.values.iter().any(Option::is_none);
586 out.extend_from_slice(&i32::from(nulls).to_be_bytes());
587 out.extend_from_slice(&elem.to_be_bytes());
588 for dim in &array.dims {
589 out.extend_from_slice(&dim.len.to_be_bytes());
590 out.extend_from_slice(&dim.lower.to_be_bytes());
591 }
592 for value in &array.values {
593 let Some(value) = value else {
594 out.extend_from_slice(&(-1i32).to_be_bytes());
595 continue;
596 };
597 let at = out.len();
598 out.extend_from_slice(&[0; 4]);
599 element(value, out);
600 let len = i32::try_from(out.len() - at - 4).unwrap_or(i32::MAX);
601 out[at..at + 4].copy_from_slice(&len.to_be_bytes());
602 }
603}
604
605pub fn int2vector_in(s: &str) -> Result<Vec<i16>, TypeError> {
607 let b = s.as_bytes();
608 let at = |i: usize| b.get(i).copied().unwrap_or(0);
609 let mut values = Vec::new();
610 let mut p = 0;
611 loop {
612 while is_space(at(p)) {
613 p += 1;
614 }
615 if p == b.len() {
616 return Ok(values);
617 }
618 let rest = &s[p..];
619 let mut i = p;
620 let neg = at(i) == b'-';
621 if neg || at(i) == b'+' {
622 i += 1;
623 }
624 let first = i;
625 let mut value = 0i64;
626 let mut overflow = false;
627 while at(i).is_ascii_digit() {
628 let digit = i64::from(at(i) - b'0');
629 match value.checked_mul(10).and_then(|v| v.checked_add(digit)) {
630 Some(v) => value = v,
631 None => overflow = true,
632 }
633 i += 1;
634 }
635 if i == first {
636 return Err(TypeError::syntax("smallint", rest));
637 }
638 let value = match i16::try_from(if neg { -value } else { value }) {
639 Ok(value) if !overflow => value,
640 _ => return Err(TypeError::range(rest, "smallint")),
641 };
642 if i < b.len() && at(i) != b' ' {
643 return Err(TypeError::syntax("smallint", rest));
644 }
645 values.push(value);
646 p = i;
647 }
648}
649
650pub fn int2vector_out(values: &[i16], out: &mut Vec<u8>) {
652 for (i, &value) in values.iter().enumerate() {
653 if i > 0 {
654 out.push(b' ');
655 }
656 int_out(value.into(), out);
657 }
658}
659
660pub fn int2vector_recv(recv: &mut Recv<'_>) -> Result<Vec<i16>, TypeError> {
662 vector_recv(recv, oid::INT2, Recv::i16, "int2vector")
663}
664
665pub fn int2vector_send(values: &[i16], out: &mut Vec<u8>) {
667 vector_send(values, oid::INT2, out, |v, out| out.extend_from_slice(&v.to_be_bytes()));
668}
669
670pub fn oidvector_in(s: &str) -> Result<Vec<u32>, TypeError> {
672 let b = s.as_bytes();
673 let mut values = Vec::new();
674 let mut p = 0;
675 loop {
676 while p < b.len() && is_space(b[p]) {
677 p += 1;
678 }
679 if p == b.len() {
680 return Ok(values);
681 }
682 let (value, len) = uint32_in_subr(&s[p..], "oid")?;
683 values.push(value);
684 p += len;
685 }
686}
687
688pub fn oidvector_out(values: &[u32], out: &mut Vec<u8>) {
690 for (i, &value) in values.iter().enumerate() {
691 if i > 0 {
692 out.push(b' ');
693 }
694 int_out(value.into(), out);
695 }
696}
697
698pub fn oidvector_recv(recv: &mut Recv<'_>) -> Result<Vec<u32>, TypeError> {
700 vector_recv(recv, oid::OID, Recv::u32, "oidvector")
701}
702
703pub fn oidvector_send(values: &[u32], out: &mut Vec<u8>) {
705 vector_send(values, oid::OID, out, |v, out| out.extend_from_slice(&v.to_be_bytes()));
706}
707
708fn vector_recv<'a, T>(
709 recv: &mut Recv<'a>,
710 elem: Oid,
711 element: impl FnMut(&mut Recv<'a>) -> Result<T, TypeError>,
712 type_name: &str,
713) -> Result<Vec<T>, TypeError> {
714 let array = array_recv(recv, elem, element)?;
715 let valid = matches!(array.dims[..], [ArrayDim { lower: 0, .. }]);
716 if !valid || array.values.iter().any(Option::is_none) {
717 return Err(binary(format!("invalid {type_name} data")));
718 }
719 Ok(array.values.into_iter().flatten().collect())
720}
721
722fn vector_send<T: Copy>(
723 values: &[T],
724 elem: Oid,
725 out: &mut Vec<u8>,
726 mut element: impl FnMut(T, &mut Vec<u8>),
727) {
728 let len = i32::try_from(values.len()).unwrap_or(i32::MAX);
730 for word in [1, 0, elem as i32, len, 0] {
731 out.extend_from_slice(&word.to_be_bytes());
732 }
733 for &value in values {
734 let at = out.len();
735 out.extend_from_slice(&[0; 4]);
736 element(value, out);
737 let len = i32::try_from(out.len() - at - 4).unwrap_or(i32::MAX);
738 out[at..at + 4].copy_from_slice(&len.to_be_bytes());
739 }
740}
741
742#[cfg(test)]
743mod tests {
744 use super::*;
745
746 fn int4s(s: &str) -> Result<Array<i32>, TypeError> {
747 array_in(s, b',', true, crate::int4_in)
748 }
749
750 fn text(array: &Array<String>) -> String {
751 let mut out = Vec::new();
752 array_out(array, b',', &mut out, |v, out| out.extend_from_slice(v.as_bytes()));
753 String::from_utf8(out).unwrap()
754 }
755
756 fn texts(s: &str) -> Array<String> {
757 array_in(s, b',', true, |v| Ok(v.to_string())).unwrap()
758 }
759
760 #[test]
761 fn the_text_form_reads_the_dimensions_from_the_braces() {
762 let array = int4s(" {{1,2},{3,NULL}} ").unwrap();
763 let dims = [ArrayDim { len: 2, lower: 1 }, ArrayDim { len: 2, lower: 1 }];
764 assert_eq!(array.dims, dims);
765 assert_eq!(array.values, [Some(1), Some(2), Some(3), None]);
766 assert_eq!(int4s("{}"), Ok(Array::empty()));
767 assert_eq!(int4s("{{},{}}"), Ok(Array::empty()));
768 let array = int4s("[0:1]={7,8}").unwrap();
769 assert_eq!(array.dims, [ArrayDim { len: 2, lower: 0 }]);
770
771 let detail = |s: &str| int4s(s).unwrap_err().detail.unwrap();
772 assert_eq!(
773 detail("{1,{2}}"),
774 "Multidimensional arrays must have sub-arrays with matching dimensions."
775 );
776 assert_eq!(detail("{1,}"), "Unexpected \"}\" character.");
777 assert_eq!(detail("{1,,2}"), "Unexpected \",\" character.");
778 assert_eq!(detail("{{1}{2}}"), "Unexpected \"{\" character.");
779 assert_eq!(
780 detail("{{1},2}"),
781 "Multidimensional arrays must have sub-arrays with matching dimensions."
782 );
783 assert_eq!(
784 detail("{{1},{2,3}}"),
785 "Multidimensional arrays must have sub-arrays with matching dimensions."
786 );
787 assert_eq!(detail("[1:2]={1}"), "Specified array dimensions do not match array contents.");
788 assert_eq!(detail("{1"), "Unexpected end of input.");
789 assert_eq!(detail("{1} x"), "Junk after closing right brace.");
790 assert_eq!(detail("{\"1\"x}"), "Incorrectly quoted array element.");
791 assert_eq!(detail("{\"1\" \"2\"}"), "Incorrectly quoted array element.");
792 assert_eq!(detail("{1\"2\"}"), "Incorrectly quoted array element.");
793 assert_eq!(detail("[1:2"), "Missing \"]\" after array dimensions.");
794 assert_eq!(detail("[1:]={1}"), "Missing array dimension value.");
795 assert_eq!(
796 detail("[x]={1}"),
797 "\"[\" must introduce explicitly-specified array dimensions."
798 );
799 assert_eq!(detail("[1]{1}"), "Missing \"=\" after array dimensions.");
800 assert_eq!(detail("[1]= 1"), "Array contents must start with \"{\".");
801 assert_eq!(detail("1"), "Array value must start with \"{\" or dimension information.");
802 assert_eq!(
803 int4s("{1 2}").unwrap_err().message,
804 "invalid input syntax for type integer: \"1 2\""
805 );
806 assert_eq!(int4s("[2:1]={}").unwrap_err().sqlstate.as_str(), "2202E");
807 assert_eq!(
808 int4s("[1:2147483647]={}").unwrap_err().message,
809 "array upper bound is too large: 2147483647"
810 );
811 assert_eq!(
812 int4s("[1:99999999999]={}").unwrap_err().message,
813 "array bound is out of integer range"
814 );
815 assert_eq!(
817 int4s("{x,}").unwrap_err().message,
818 "invalid input syntax for type integer: \"x\""
819 );
820 let deep = format!("{}1{}", "{".repeat(7), "}".repeat(7));
821 assert_eq!(int4s(&deep).unwrap_err().sqlstate.as_str(), "54000");
822 }
823
824 #[test]
825 fn the_output_quotes_only_what_the_input_needs() {
826 let array = texts(r#"{"", "NULL", a b, "x\"y", plain, NULL}"#);
827 assert_eq!(text(&array), r#"{"","NULL","a b","x\"y",plain,NULL}"#);
828 assert_eq!(texts(&text(&array)), array);
829 assert_eq!(text(&texts("[-1:0][2:2]={{a},{b}}")), "[-1:0][2:2]={{a},{b}}");
830 assert_eq!(text(&texts("{{a,b},{c,d}}")), "{{a,b},{c,d}}");
831 let off = array_in("{NULL}", b',', false, |v| Ok(v.to_string())).unwrap();
832 assert_eq!(off.values, [Some("NULL".to_string())]);
833 }
834
835 #[test]
836 fn the_binary_form_goes_back_to_the_same_array() {
837 let array = int4s("[0:2]={1,NULL,3}").unwrap();
838 let mut bytes = Vec::new();
839 array_send(&array, oid::INT4, &mut bytes, |v, out| out.extend_from_slice(&v.to_be_bytes()));
840 let back = array_recv(&mut Recv::new(&bytes), oid::INT4, Recv::i32).unwrap();
841 assert_eq!(back, array);
842
843 let error = array_recv(&mut Recv::new(&bytes), oid::INT2, Recv::i16).unwrap_err();
844 assert_eq!(
845 error.message,
846 "binary data has array element type 23 (integer) instead of expected 21 (smallint)"
847 );
848 let error = array_recv(&mut Recv::new(&bytes), oid::INT8, Recv::i64).unwrap_err();
849 assert_eq!(error.sqlstate.as_str(), "42804");
850 let mut words = bytes.clone();
852 words[8..12].copy_from_slice(&oid::INT2.to_be_bytes());
853 let error = array_recv(&mut Recv::new(&words), oid::INT2, Recv::i16).unwrap_err();
854 assert_eq!(error.message, "improper binary format in array element 1");
855
856 let header =
857 |words: &[i32]| -> Vec<u8> { words.iter().flat_map(|w| w.to_be_bytes()).collect() };
858 let message = |bytes: Vec<u8>| {
859 array_recv(&mut Recv::new(&bytes), oid::INT4, Recv::i32).unwrap_err().message
860 };
861 assert_eq!(message(header(&[-1])), "invalid number of dimensions: -1");
862 assert_eq!(
863 message(header(&[7])),
864 "number of array dimensions (7) exceeds the maximum allowed (6)"
865 );
866 assert_eq!(message(header(&[1, 2])), "invalid array flags");
867 assert_eq!(
868 message(header(&[1, 0, 23, -1, 1])),
869 "array size exceeds the maximum allowed (134217727)"
870 );
871 assert_eq!(
872 message(header(&[1, 0, 23, 1, i32::MAX])),
873 "array lower bound is too large: 2147483647"
874 );
875 assert_eq!(message(header(&[1, 0, 23, 1, 1, 5, 0])), "insufficient data left in message");
876 let empty = header(&[1, 0, 23, 0, 1]);
877 assert_eq!(array_recv(&mut Recv::new(&empty), oid::INT4, Recv::i32), Ok(Array::empty()));
878 }
879
880 #[test]
881 fn a_vector_is_a_zero_based_array_with_spaces_in_the_text() {
882 assert_eq!(int2vector_in(" 1 -2 3 "), Ok(vec![1, -2, 3]));
883 assert_eq!(int2vector_in(""), Ok(vec![]));
884 assert_eq!(
885 int2vector_in("1 x").unwrap_err().message,
886 "invalid input syntax for type smallint: \"x\""
887 );
888 assert_eq!(
889 int2vector_in("1,2").unwrap_err().message,
890 "invalid input syntax for type smallint: \"1,2\""
891 );
892 assert_eq!(
893 int2vector_in("40000 1").unwrap_err().message,
894 "value \"40000 1\" is out of range for type smallint"
895 );
896 assert_eq!(oidvector_in("1-2 0x10"), Ok(vec![1, u32::MAX - 1, 16]));
897 assert_eq!(
898 oidvector_in("1 x").unwrap_err().message,
899 "invalid input syntax for type oid: \"x\""
900 );
901
902 let mut bytes = Vec::new();
903 int2vector_send(&[5, 6], &mut bytes);
904 assert_eq!(int2vector_recv(&mut Recv::new(&bytes)), Ok(vec![5, 6]));
905 let mut out = Vec::new();
906 int2vector_out(&[5, -6], &mut out);
907 assert_eq!(out, b"5 -6");
908
909 let mut empty = Vec::new();
910 oidvector_send(&[], &mut empty);
911 let error = oidvector_recv(&mut Recv::new(&empty)).unwrap_err();
912 assert_eq!(
913 (error.sqlstate.as_str(), error.message.as_str()),
914 ("22P03", "invalid oidvector data")
915 );
916 }
917}