1use rupg_common::{Error, Result, SqlState};
4use rupg_pgcatalog::builtin;
5use rupg_types::{
6 self as types, Array, DateTimeInput, Record, Recv, RegKind, Value, ZoneAbbrevs, oid, tz,
7};
8
9use crate::{Call, Session, bad_value, not_yet, reg, type_error};
10
11const XID: u32 = 28;
13const CID: u32 = 29;
15const ARRAY_CATEGORY: u8 = b'A';
17
18pub fn base_type(ty: u32) -> u32 {
20 let mut ty = ty;
21 while let Some(row) = builtin::type_by_oid(ty)
22 && row.kind == b'd'
23 {
24 ty = row.base;
25 }
26 ty
27}
28
29pub(crate) fn array_of(ty: u32) -> Option<(u32, u8)> {
31 if ty == oid::INT2VECTOR || ty == oid::OIDVECTOR {
32 return None;
33 }
34 let row = builtin::type_by_oid(ty)?;
35 if (row.category != ARRAY_CATEGORY && ty != oid::RECORD_ARRAY) || row.elem == 0 {
37 return None;
38 }
39 let delim = builtin::type_by_oid(row.elem).map_or(b',', |e| e.delim);
40 Some((row.elem, delim))
41}
42
43pub fn output_supported(ty: u32) -> bool {
45 let ty = base_type(ty);
46 if let Some((elem, _)) = array_of(ty) {
47 return output_supported(elem);
48 }
49 if let Some(sub) = builtin::range_subtype(ty) {
50 return output_supported(sub);
51 }
52 if let Some(range) = builtin::multirange_range(ty) {
53 return output_supported(range);
54 }
55 matches!(
56 ty,
57 oid::BOOL
58 | oid::BYTEA
59 | oid::CHAR
60 | oid::NAME
61 | oid::INT8
62 | oid::INT2
63 | oid::INT4
64 | oid::INT2VECTOR
65 | oid::TEXT
66 | oid::OID
67 | XID
68 | CID
69 | oid::OIDVECTOR
70 | oid::JSON
71 | oid::FLOAT4
72 | oid::FLOAT8
73 | oid::UNKNOWN
74 | oid::BPCHAR
75 | oid::VARCHAR
76 | oid::DATE
77 | oid::TIME
78 | oid::TIMESTAMP
79 | oid::TIMESTAMPTZ
80 | oid::INTERVAL
81 | oid::TIMETZ
82 | oid::NUMERIC
83 | oid::CSTRING
84 | oid::UUID
85 | oid::INET
86 | oid::CIDR
87 | oid::JSONB
88 | oid::PG_NODE_TREE
89 | oid::PG_NDISTINCT
90 | oid::PG_DEPENDENCIES
91 | oid::PG_MCV_LIST
92 | oid::ACLITEM
93 | oid::ANYARRAY
94 | oid::PG_LSN
95 | oid::VOID
96 | oid::TRIGGER
97 | oid::EVENT_TRIGGER
98 | oid::MONEY
99 | oid::TID
100 | oid::XID8
101 | oid::OID8
102 | oid::REFCURSOR
103 | oid::MACADDR
104 | oid::MACADDR8
105 | oid::BIT
106 | oid::VARBIT
107 | oid::POINT
108 | oid::LSEG
109 | oid::PATH
110 | oid::BOX
111 | oid::POLYGON
112 | oid::LINE
113 | oid::CIRCLE
114 | oid::PG_SNAPSHOT
115 | oid::TXID_SNAPSHOT
116 | oid::TSVECTOR
117 | oid::TSQUERY
118 | oid::JSONPATH
119 | oid::XML
120 ) || RegKind::from_oid(ty).is_some()
121 || is_row_type(ty)
122 || is_enum(ty)
123}
124
125pub(crate) fn is_enum(ty: u32) -> bool {
127 builtin::type_by_oid(ty).is_some_and(|row| row.kind == b'e')
128}
129
130fn enum_label(ty: u32, label: u32) -> Result<&'static str> {
132 builtin::enum_labels(ty)
133 .and_then(|labels| labels.iter().find(|(oid, _)| *oid == label))
134 .map(|(_, name)| name.as_str())
135 .ok_or_else(|| {
136 Error::new(
137 SqlState::INVALID_BINARY_REPRESENTATION,
138 format!("invalid internal value for enum: {label}"),
139 )
140 })
141}
142
143fn enum_in(ty: u32, text: &str) -> std::result::Result<u32, Error> {
145 builtin::enum_labels(ty)
146 .and_then(|labels| labels.iter().find(|(_, name)| name == text))
147 .map(|(oid, _)| *oid)
148 .ok_or_else(|| {
149 Error::new(
150 SqlState::INVALID_TEXT_REPRESENTATION,
151 format!("invalid input value for enum {}: \"{text}\"", type_name(ty)),
152 )
153 })
154}
155
156pub(crate) fn check_safe_enum_use(ty: u32, oid: u32, label: &str) -> Result<()> {
158 if !builtin::enum_label_is_uncommitted(ty, oid) {
159 return Ok(());
160 }
161 Err(Error::new(
162 SqlState::UNSAFE_NEW_ENUM_VALUE_USAGE,
163 format!("unsafe use of new value \"{label}\" of enum type {}", type_name(ty)),
164 )
165 .with_hint("New enum values must be committed before they can be used."))
166}
167
168pub fn is_row_type(ty: u32) -> bool {
170 ty == oid::RECORD || builtin::type_by_oid(ty).is_some_and(|row| row.kind == b'c')
171}
172
173pub fn input_supported(ty: u32) -> bool {
175 let ty = base_type(ty);
176 if let Some((elem, _)) = array_of(ty) {
177 return input_supported(elem);
178 }
179 if let Some(sub) = builtin::range_subtype(ty) {
180 return input_supported(sub);
181 }
182 if let Some(range) = builtin::multirange_range(ty) {
183 return input_supported(range);
184 }
185 output_supported(ty) && ty != oid::ANYARRAY && ty != oid::RECORD
186}
187
188pub(crate) fn type_name(ty: u32) -> String {
190 let name = types::format_type(ty);
191 if name != "???" {
192 return name.into_owned();
193 }
194 match builtin::type_by_oid(ty) {
195 Some(row) if row.category == ARRAY_CATEGORY && row.elem != 0 => {
196 format!("{}[]", type_name(row.elem))
197 }
198 Some(row) => row.name.to_owned(),
199 None => name.into_owned(),
200 }
201}
202
203pub(crate) fn datetime_input<'a>(
205 session: &'a dyn Session,
206 zone: &'a dyn types::TimeZone,
207) -> DateTimeInput<'a> {
208 DateTimeInput {
209 order: session.date_format().order,
210 zone,
211 zones: &tz::TzDatabase,
212 abbrevs: ZoneAbbrevs::postgres_default(),
213 now: session.transaction_start(),
214 }
215}
216
217pub fn output(ty: u32, value: &Value, session: &dyn Session, out: &mut Vec<u8>) -> Result<()> {
223 let ty = base_type(ty);
224 if is_enum(ty)
225 && let Value::Oid(label) = value
226 {
227 out.extend_from_slice(enum_label(ty, *label)?.as_bytes());
228 return Ok(());
229 }
230 if let Some((elem, delim)) = array_of(ty) {
231 let Value::Array(array) = value else { return Err(bad_value()) };
232 let mut failed = None;
233 types::array_out(array, delim, out, |item, out| {
234 if failed.is_none()
235 && let Err(error) = output(elem, item, session, out)
236 {
237 failed = Some(error);
238 }
239 });
240 return failed.map_or(Ok(()), Err);
241 }
242 if let (Some(kind), Value::Oid(v)) = (RegKind::from_oid(ty), value) {
243 reg::output(kind, *v, session, out);
244 return Ok(());
245 }
246 if let Value::Range(range) = value {
247 return range_out(ty, range, session, out);
248 }
249 if let Value::Multirange(ranges) = value {
250 return multirange_out(ty, ranges, session, out);
251 }
252 if let Value::Record(record) = value {
253 return record_out(record, session, out);
254 }
255 if let Value::TsVector(lexemes) = value {
256 types::tsvector_deparse(lexemes, out);
257 return Ok(());
258 }
259 if let Value::TsQuery(items) = value {
260 types::tsquery_deparse(items, out);
261 return Ok(());
262 }
263 if let Value::JsonPath(path) = value {
264 types::jsonpath_deparse(path, out);
265 return Ok(());
266 }
267 if let (Some(kind), Value::Bytea(v)) = (types::GeoKind::from_oid(ty), value) {
268 types::geo_out(kind, v, session.extra_float_digits(), out);
269 return Ok(());
270 }
271 match (ty, value) {
272 (oid::MONEY, Value::Int8(v)) => types::cash_out(*v, out),
273 (oid::PG_LSN, Value::Int8(v)) => types::pg_lsn_out(v.cast_unsigned(), out),
274 (oid::PG_SNAPSHOT | oid::TXID_SNAPSHOT, Value::Bytea(v)) => {
275 let snapshot = types::Snapshot::from_bytes(v).ok_or_else(bad_value)?;
276 types::snapshot_out(&snapshot, out);
277 }
278 (oid::MACADDR, Value::Int8(v)) => types::macaddr_out(v.cast_unsigned(), out),
279 (oid::MACADDR8, Value::Int8(v)) => types::macaddr8_out(v.cast_unsigned(), out),
280 (oid::XID8 | oid::OID8, Value::Int8(v)) => types::u64_out(v.cast_unsigned(), out),
281 (oid::TID, Value::Int8(v)) => {
282 let (block, offset) = tid_parts(*v)?;
283 types::tid_out(block, offset, out);
284 }
285 (_, Value::Bool(v)) => types::bool_out(*v, out),
286 (_, Value::Int2(v)) => types::int_out(i64::from(*v), out),
287 (_, Value::Int4(v)) => types::int_out(i64::from(*v), out),
288 (_, Value::Int8(v)) => types::int_out(*v, out),
289 (_, Value::Float4(v)) => types::float4_out(*v, session.extra_float_digits(), out),
290 (_, Value::Float8(v)) => types::float8_out(*v, session.extra_float_digits(), out),
291 (_, Value::Numeric(v)) => types::numeric_out(v, out),
292 (oid::OID | XID | CID, Value::Oid(v)) => types::oid_out(*v, out),
293 (_, Value::Char(v)) => types::char_out(*v, out),
294 (oid::XML, Value::Text(v)) => {
295 if let Some(warning) = types::xml_out(v, out) {
296 session.warn(type_error(warning));
297 }
298 }
299 (_, Value::Text(v)) => out.extend_from_slice(v.as_bytes()),
300 (oid::PG_NDISTINCT, Value::Bytea(v)) => {
301 types::pg_ndistinct_out(v, out).map_err(type_error)?
302 }
303 (oid::PG_DEPENDENCIES, Value::Bytea(v)) => {
304 types::pg_dependencies_out(v, out).map_err(type_error)?;
305 }
306 (_, Value::Bytea(v)) => types::bytea_out(v, session.bytea_output(), out),
307 (_, Value::Uuid(v)) => types::uuid_out(v, out),
308 (_, Value::Inet(v)) => types::inet_out(v, ty == oid::CIDR, out),
309 (_, Value::Date(v)) => types::date_out(*v, session.date_format(), out),
310 (_, Value::Time(v)) => types::time_out(*v, out),
311 (_, Value::TimeTz(time, zone)) => types::timetz_out(*time, *zone, out),
312 (_, Value::Timestamp(v)) => {
313 types::timestamp_out(*v, session.date_format(), out).map_err(type_error)?;
314 }
315 (_, Value::TimestampTz(v)) => {
316 types::timestamptz_out(*v, session.date_format(), &*session.zone()?, out)
317 .map_err(type_error)?;
318 }
319 (_, Value::Interval(v)) => types::interval_out(v, session.interval_style(), out),
320 (oid::INT2VECTOR, Value::Array(array)) => {
321 let values = vector(array, |v| match v {
322 Value::Int2(n) => Some(*n),
323 _ => None,
324 })?;
325 types::int2vector_out(&values, out);
326 }
327 (oid::OIDVECTOR, Value::Array(array)) => {
328 let values = vector(array, Value::as_oid)?;
329 types::oidvector_out(&values, out);
330 }
331 (_, Value::Null) => return Err(Error::internal("the output function got a null value")),
332 _ => return Err(not_yet(format!("output of type {}", type_name(ty)))),
333 }
334 Ok(())
335}
336
337pub(crate) fn tid_value(block: u32, offset: u16) -> Value {
339 Value::Int8(i64::from(block) << 16 | i64::from(offset))
340}
341
342pub(crate) fn tid_parts(value: i64) -> Result<(u32, u16)> {
344 let block = u32::try_from(value >> 16).map_err(|_| bad_value())?;
345 let offset = u16::try_from(value & 0xFFFF).map_err(|_| bad_value())?;
346 Ok((block, offset))
347}
348
349fn range_out(
351 ty: u32,
352 range: &types::Range,
353 session: &dyn Session,
354 out: &mut Vec<u8>,
355) -> Result<()> {
356 let sub = crate::range::subtype(ty);
357 let (mut lower, mut upper) = (Vec::new(), Vec::new());
358 if range.has_lower() {
359 output(sub, &range.lower, session, &mut lower)?;
360 }
361 if range.has_upper() {
362 output(sub, &range.upper, session, &mut upper)?;
363 }
364 types::range_deparse(
365 range.flags,
366 range.has_lower().then_some(&lower[..]),
367 range.has_upper().then_some(&upper[..]),
368 out,
369 );
370 Ok(())
371}
372
373fn range_send(ty: u32, range: &types::Range, out: &mut Vec<u8>) -> Result<()> {
375 let sub = crate::range::subtype(ty);
376 let (mut lower, mut upper) = (Vec::new(), Vec::new());
377 if range.has_lower() {
378 send(sub, &range.lower, &mut lower)?;
379 }
380 if range.has_upper() {
381 send(sub, &range.upper, &mut upper)?;
382 }
383 types::range_send(
384 range.flags,
385 range.has_lower().then_some(&lower[..]),
386 range.has_upper().then_some(&upper[..]),
387 out,
388 );
389 Ok(())
390}
391
392fn multirange_out(
394 ty: u32,
395 ranges: &[types::Range],
396 session: &dyn Session,
397 out: &mut Vec<u8>,
398) -> Result<()> {
399 let range_ty = crate::multirange::range_of(ty);
400 let mut texts = Vec::with_capacity(ranges.len());
401 for range in ranges {
402 let mut text = Vec::new();
403 range_out(range_ty, range, session, &mut text)?;
404 texts.push(text);
405 }
406 types::multirange_deparse(texts.iter().map(Vec::as_slice), out);
407 Ok(())
408}
409
410fn multirange_send(ty: u32, ranges: &[types::Range], out: &mut Vec<u8>) -> Result<()> {
412 let range_ty = crate::multirange::range_of(ty);
413 let mut bytes = Vec::with_capacity(ranges.len());
414 for range in ranges {
415 let mut one = Vec::new();
416 range_send(range_ty, range, &mut one)?;
417 bytes.push(one);
418 }
419 types::multirange_send(&bytes.iter().map(Vec::as_slice).collect::<Vec<_>>(), out);
420 Ok(())
421}
422
423fn record_out(record: &Record, session: &dyn Session, out: &mut Vec<u8>) -> Result<()> {
425 out.push(b'(');
426 let mut field = Vec::new();
427 for (i, (ty, value)) in record.types.iter().zip(&record.values).enumerate() {
428 if i > 0 {
429 out.push(b',');
430 }
431 if value.is_null() {
432 continue;
433 }
434 field.clear();
435 output(*ty, value, session, &mut field)?;
436 let quote = field.is_empty()
437 || field.iter().any(|b| matches!(b, b'"' | b'\\' | b'(' | b')' | b',') || is_space(*b));
438 if !quote {
439 out.extend_from_slice(&field);
440 continue;
441 }
442 out.push(b'"');
443 for &b in &field {
444 if matches!(b, b'"' | b'\\') {
445 out.push(b);
446 }
447 out.push(b);
448 }
449 out.push(b'"');
450 }
451 out.push(b')');
452 Ok(())
453}
454
455fn row_columns(ty: u32, session: &dyn Session) -> Option<Vec<(u32, i32)>> {
457 let relid = builtin::type_by_oid(ty).filter(|row| row.relid != 0)?.relid;
458 if let Some(catalog) = rupg_pgcatalog::catalog_by_oid(relid) {
459 return Some(catalog.columns.iter().map(|c| (c.type_oid, -1)).collect());
460 }
461 let rel = session.catalog()?.relation(relid)?;
462 Some(rel.columns.iter().filter(|c| !c.dropped).map(|c| (c.ty, c.typmod)).collect())
463}
464
465fn record_in(
467 ty: u32,
468 text: &str,
469 session: &dyn Session,
470 noisy: bool,
471) -> std::result::Result<Value, Failed> {
472 if ty == oid::RECORD {
473 return Err(Failed::Hard(Error::new(
474 SqlState::FEATURE_NOT_SUPPORTED,
475 "input of anonymous composite types is not implemented",
476 )));
477 }
478 let columns = row_columns(ty, session).ok_or_else(|| Failed::Hard(no_input(ty)))?;
479 let malformed = |detail: &str| {
480 Failed::Soft(
481 Error::new(
482 SqlState::INVALID_TEXT_REPRESENTATION,
483 format!("malformed record literal: \"{text}\""),
484 )
485 .with_detail(detail),
486 )
487 };
488 let bytes = text.as_bytes();
489 let mut at = bytes.iter().take_while(|&&b| is_space(b)).count();
490 if bytes.get(at) != Some(&b'(') {
491 return Err(malformed("Missing left parenthesis."));
492 }
493 at += 1;
494 let mut types = Vec::with_capacity(columns.len());
495 let mut values = Vec::with_capacity(columns.len());
496 let mut field = Vec::new();
497 for (i, &(column, typmod)) in columns.iter().enumerate() {
498 if i > 0 {
499 if bytes.get(at) != Some(&b',') {
500 return Err(malformed("Too few columns."));
501 }
502 at += 1;
503 }
504 types.push(column);
505 if matches!(bytes.get(at), Some(b',' | b')')) {
506 values.push(Value::Null);
507 continue;
508 }
509 field.clear();
510 let mut quoted = false;
511 while quoted || !matches!(bytes.get(at), Some(b',' | b')')) {
512 let Some(&b) = bytes.get(at) else {
513 return Err(malformed("Unexpected end of input."));
514 };
515 at += 1;
516 match b {
517 b'\\' => {
518 let Some(&next) = bytes.get(at) else {
519 return Err(malformed("Unexpected end of input."));
520 };
521 field.push(next);
522 at += 1;
523 }
524 b'"' if quoted && bytes.get(at) == Some(&b'"') => {
525 field.push(b'"');
526 at += 1;
527 }
528 b'"' => quoted = !quoted,
529 _ => field.push(b),
530 }
531 }
532 let item = String::from_utf8_lossy(&field);
534 values.push(input_value(column, &item, typmod, session, noisy)?);
535 }
536 if bytes.get(at) != Some(&b')') {
537 return Err(malformed("Too many columns."));
538 }
539 at += 1;
540 if bytes[at..].iter().any(|&b| !is_space(b)) {
541 return Err(malformed("Junk after right parenthesis."));
542 }
543 Ok(Value::Record(Box::new(Record::new(types, values))))
544}
545
546fn is_space(b: u8) -> bool {
548 matches!(b, b' ' | b'\t' | b'\n' | b'\r' | 0x0B | 0x0C)
549}
550
551fn record_send(record: &Record, out: &mut Vec<u8>) -> Result<()> {
553 let count = i32::try_from(record.values.len()).map_err(|_| bad_value())?;
554 out.extend_from_slice(&count.to_be_bytes());
555 let mut field = Vec::new();
556 for (ty, value) in record.types.iter().zip(&record.values) {
557 out.extend_from_slice(&ty.to_be_bytes());
558 if value.is_null() {
559 out.extend_from_slice(&(-1i32).to_be_bytes());
560 continue;
561 }
562 field.clear();
563 send(*ty, value, &mut field)?;
564 let len = i32::try_from(field.len()).map_err(|_| bad_value())?;
565 out.extend_from_slice(&len.to_be_bytes());
566 out.extend_from_slice(&field);
567 }
568 Ok(())
569}
570
571fn vector<T>(array: &Array<Value>, get: impl Fn(&Value) -> Option<T>) -> Result<Vec<T>> {
573 array.values.iter().map(|v| v.as_ref().and_then(&get).ok_or_else(bad_value)).collect()
574}
575
576pub fn to_text(ty: u32, value: &Value, session: &dyn Session) -> Result<String> {
582 match (base_type(ty), value) {
583 (oid::BOOL, Value::Bool(v)) => Ok(if *v { "true" } else { "false" }.to_string()),
584 (oid::BPCHAR, Value::Text(v)) => Ok(v.trim_end_matches(' ').to_string()),
585 (_, Value::Text(v)) => Ok(v.clone()),
586 _ => {
587 let mut out = Vec::new();
588 output(ty, value, session, &mut out)?;
589 String::from_utf8(out)
590 .map_err(|_| Error::internal("an output function gave bytes that are not UTF-8"))
591 }
592 }
593}
594
595pub fn input(ty: u32, text: &str, typmod: i32, session: &dyn Session) -> Result<Value> {
601 match input_value(ty, text, typmod, session, true) {
602 Ok(value) => Ok(value),
603 Err(Failed::Soft(error) | Failed::Hard(error)) => Err(error),
604 }
605}
606
607pub fn input_soft(
613 ty: u32,
614 text: &str,
615 typmod: i32,
616 session: &dyn Session,
617) -> Result<Result<Value>> {
618 match input_value(ty, text, typmod, session, false) {
619 Ok(value) => Ok(Ok(value)),
620 Err(Failed::Soft(error)) => Ok(Err(error)),
621 Err(Failed::Hard(error)) => Err(error),
622 }
623}
624
625enum Failed {
627 Soft(Error),
629 Hard(Error),
631}
632
633impl From<types::TypeError> for Failed {
634 fn from(error: types::TypeError) -> Failed {
635 Failed::Soft(type_error(error))
636 }
637}
638
639impl From<Error> for Failed {
640 fn from(error: Error) -> Failed {
641 Failed::Hard(error)
642 }
643}
644
645fn tsquery_in(
647 text: &str,
648 session: &dyn Session,
649 noisy: bool,
650) -> std::result::Result<Vec<types::QueryItem>, Failed> {
651 let items = types::tsquery_parse(text).map_err(|error| {
652 if error.sqlstate == SqlState::INTERNAL_ERROR
653 || error.sqlstate == SqlState::STATEMENT_TOO_COMPLEX
654 {
655 Failed::Hard(type_error(error))
656 } else {
657 Failed::from(error)
658 }
659 })?;
660 if noisy && items.is_empty() {
661 session.warn(crate::tsquery::no_lexemes(text));
662 }
663 Ok(items)
664}
665
666fn xml_in(text: &[u8], session: &dyn Session) -> std::result::Result<(), types::TypeError> {
668 let document = session.setting("xmloption").is_some_and(|v| v.eq_ignore_ascii_case("document"));
669 types::xml_in(text, document, &mut |warning| {
670 session.warn(Error::new(SqlState::WARNING, warning))
671 })
672}
673
674fn xml_recv<'a>(
676 recv: &mut Recv<'a>,
677 session: &dyn Session,
678) -> std::result::Result<&'a str, Received> {
679 let bytes = recv.rest();
680 if let Some(name) = types::xml_encoding(bytes) {
681 match crate::encoding::encoding(&name) {
682 Some("UTF8" | "SQL_ASCII") => {}
683 Some(other) => {
684 return Err(Received::Engine(not_yet(format!(
685 "binary input of type xml in the encoding {other}"
686 ))));
687 }
688 None => {
689 return Err(Received::Engine(Error::new(
690 SqlState::INVALID_PARAMETER_VALUE,
691 format!("invalid encoding name \"{name}\""),
692 )));
693 }
694 }
695 }
696 xml_in(bytes, session)?;
697 Ok(Recv::new(bytes).text()?)
698}
699
700fn jsonpath_in(text: &str, noisy: bool) -> std::result::Result<types::JsonPath, Failed> {
702 types::jsonpath_parse(text, !noisy, &crate::regex::validate).map_err(|error| {
703 if error.sqlstate == SqlState::NUMERIC_VALUE_OUT_OF_RANGE
704 || error.sqlstate == SqlState::STATEMENT_TOO_COMPLEX
705 {
706 Failed::Hard(type_error(error))
707 } else {
708 Failed::from(error)
709 }
710 })
711}
712
713fn input_value(
715 ty: u32,
716 text: &str,
717 typmod: i32,
718 session: &dyn Session,
719 noisy: bool,
720) -> std::result::Result<Value, Failed> {
721 let typmod = match builtin::type_by_oid(ty) {
723 Some(row) if row.kind == b'd' => row.typmod,
724 _ => typmod,
725 };
726 let ty = base_type(ty);
727 if let Some((elem, delim)) = array_of(ty) {
728 let mut hard = None;
730 let array = types::array_in(text, delim, session.array_nulls(), |item| {
731 match input_value(elem, item, typmod, session, noisy) {
732 Ok(value) => Ok(value),
733 Err(Failed::Soft(e)) => Err(types_error(&e)),
734 Err(Failed::Hard(e)) => {
735 let error = types_error(&e);
736 hard = Some(e);
737 Err(error)
738 }
739 }
740 });
741 return match (array, hard) {
742 (_, Some(error)) => Err(Failed::Hard(error)),
743 (array, None) => Ok(Value::Array(Box::new(array?))),
744 };
745 }
746 if let Some(sub) = builtin::range_subtype(ty) {
747 return range_in(ty, sub, text, session, noisy);
748 }
749 if let Some(range) = builtin::multirange_range(ty) {
750 return multirange_in(range, text, session, noisy);
751 }
752 if is_row_type(ty) {
753 return record_in(ty, text, session, noisy);
754 }
755 if is_enum(ty) {
756 let oid = enum_in(ty, text).map_err(Failed::Soft)?;
757 check_safe_enum_use(ty, oid, text).map_err(Failed::Hard)?;
758 return Ok(Value::Oid(oid));
759 }
760 if let Some(kind) = RegKind::from_oid(ty) {
761 return match reg::input(kind, text, session)? {
762 Ok(oid) => Ok(Value::Oid(oid)),
763 Err(error) => Err(Failed::Soft(error)),
764 };
765 }
766 if let Some(kind) = types::GeoKind::from_oid(ty) {
767 return Ok(Value::Bytea(types::geo_in(kind, text)?));
768 }
769 let value = match ty {
770 oid::BOOL => Value::Bool(types::bool_in(text)?),
771 oid::BYTEA => Value::Bytea(types::bytea_in(text)?),
772 oid::CHAR => Value::Char(types::char_in(text)),
773 oid::NAME => Value::text(types::name_in(text)),
774 oid::INT2 => Value::Int2(types::int2_in(text)?),
775 oid::INT4 => Value::Int4(types::int4_in(text)?),
776 oid::TSVECTOR => Value::TsVector(types::tsvector_parse(text)?),
777 oid::TSQUERY => Value::TsQuery(tsquery_in(text, session, noisy)?),
778 oid::JSONPATH => Value::JsonPath(Box::new(jsonpath_in(text, noisy)?)),
779 oid::XML => {
780 xml_in(text.as_bytes(), session)?;
781 Value::text(text)
782 }
783 oid::INT8 => Value::Int8(types::int8_in(text)?),
784 oid::OID => Value::Oid(types::oid_in(text)?),
785 oid::MONEY => Value::Int8(types::cash_in(text)?),
786 oid::MACADDR => Value::Int8(types::macaddr_in(text)?.cast_signed()),
787 oid::MACADDR8 => Value::Int8(types::macaddr8_in(text)?.cast_signed()),
788 oid::BIT => Value::Text(types::bit_in(text, typmod, false)?),
789 oid::VARBIT => Value::Text(types::bit_in(text, typmod, true)?),
790 oid::XID8 => Value::Int8(types::uint64_in(text, "xid8")?.cast_signed()),
791 oid::OID8 => Value::Int8(types::uint64_in(text, "oid8")?.cast_signed()),
792 oid::PG_LSN => Value::Int8(types::pg_lsn_in(text)?.cast_signed()),
793 oid::PG_SNAPSHOT | oid::TXID_SNAPSHOT => Value::Bytea(types::snapshot_in(text)?.to_bytes()),
794 oid::TID => {
795 let (block, offset) = types::tid_in(text)?;
796 tid_value(block, offset)
797 }
798 XID => Value::Oid(types::uint32_in(text, "xid")?),
799 CID => Value::Oid(types::uint32_in(text, "cid")?),
800 oid::ACLITEM => Value::Text(crate::acl::aclitem_in(text, session).map_err(Failed::Soft)?),
801 oid::TEXT | oid::UNKNOWN | oid::CSTRING | oid::REFCURSOR => Value::text(text),
802 oid::VOID => Value::Text(String::new()),
804 oid::VARCHAR => Value::text(types::varchar_in(text, typmod)?),
805 oid::BPCHAR => Value::text(types::bpchar_in(text, typmod)?),
806 oid::JSON => Value::text(types::json_in(text)?),
807 oid::JSONB => Value::Text(types::jsonb_in(text)?),
808 oid::FLOAT4 => Value::Float4(types::float4_in(text)?),
809 oid::FLOAT8 => Value::Float8(types::float8_in(text)?),
810 oid::NUMERIC => Value::Numeric(types::numeric_in(text, typmod)?),
811 oid::UUID => Value::Uuid(types::uuid_in(text)?),
812 oid::INET | oid::CIDR => Value::Inet(types::inet_in(text, ty == oid::CIDR)?),
813 oid::INT2VECTOR => {
814 let values = types::int2vector_in(text)?;
815 Value::Array(Box::new(Array::vector(
816 values.into_iter().map(|v| Some(Value::Int2(v))).collect(),
817 )))
818 }
819 oid::OIDVECTOR => {
820 let values = types::oidvector_in(text)?;
821 Value::Array(Box::new(Array::vector(
822 values.into_iter().map(|v| Some(Value::Oid(v))).collect(),
823 )))
824 }
825 oid::DATE | oid::TIME | oid::TIMETZ | oid::TIMESTAMP | oid::TIMESTAMPTZ => {
826 let zone = session.zone()?;
827 let cx = datetime_input(session, &*zone);
828 match ty {
829 oid::DATE => Value::Date(types::date_in(text, &cx)?),
830 oid::TIME => Value::Time(types::time_in(text, typmod, &cx)?),
831 oid::TIMETZ => {
832 let (time, zone) = types::timetz_in(text, typmod, &cx)?;
833 Value::TimeTz(time, zone)
834 }
835 oid::TIMESTAMP => Value::Timestamp(types::timestamp_in(text, typmod, &cx)?),
836 _ => Value::TimestampTz(types::timestamptz_in(text, typmod, &cx)?),
837 }
838 }
839 oid::INTERVAL => {
840 Value::Interval(types::interval_in(text, typmod, session.interval_style())?)
841 }
842 oid::PG_NODE_TREE => return Err(Failed::Hard(no_input(ty))),
844 oid::PG_NDISTINCT => Value::Bytea(types::pg_ndistinct_in(text)?),
845 oid::PG_DEPENDENCIES => Value::Bytea(types::pg_dependencies_in(text)?),
846 oid::PG_MCV_LIST => return Err(Failed::Hard(no_input(ty))),
848 oid::GTSVECTOR | oid::PG_BRIN_BLOOM_SUMMARY => return Err(Failed::Hard(no_input(ty))),
850 oid::PG_BRIN_MINMAX_MULTI_SUMMARY => {
852 return Err(Failed::Hard(Error::new(
853 SqlState::FEATURE_NOT_SUPPORTED,
854 "cannot accept a value of type brin_minmax_multi_summary".to_string(),
855 )));
856 }
857 _ if builtin::type_by_oid(ty).is_some_and(|row| row.kind == b'p')
859 && !matches!(ty, oid::VOID | oid::RECORD) =>
860 {
861 return Err(Failed::Hard(no_input(ty)));
862 }
863 _ => return Err(Failed::Hard(not_yet(format!("input of type {}", type_name(ty))))),
864 };
865 Ok(value)
866}
867
868fn range_in(
870 ty: u32,
871 sub: u32,
872 text: &str,
873 session: &dyn Session,
874 noisy: bool,
875) -> std::result::Result<Value, Failed> {
876 let parsed = types::range_parse(text)?;
877 let bound = |text: Option<&String>| match text {
878 Some(text) => input_value(sub, text, -1, session, noisy),
879 None => Ok(Value::Null),
880 };
881 let lower = bound(parsed.lower.as_ref())?;
882 let upper = bound(parsed.upper.as_ref())?;
883 let range = crate::range::make_range(ty, parsed.flags, lower, upper).map_err(Failed::Soft)?;
884 Ok(Value::Range(Box::new(range)))
885}
886
887fn multirange_in(
889 range_ty: u32,
890 text: &str,
891 session: &dyn Session,
892 noisy: bool,
893) -> std::result::Result<Value, Failed> {
894 let mut ranges = Vec::new();
895 types::multirange_parse(text, |text| match input_value(range_ty, text, -1, session, noisy)? {
896 Value::Range(range) => {
897 if !range.is_empty() {
898 ranges.push(*range);
899 }
900 Ok(())
901 }
902 _ => Err(Failed::Hard(bad_value())),
903 })?;
904 let ranges = crate::multirange::make_multirange(range_ty, ranges).map_err(Failed::Soft)?;
905 Ok(Value::Multirange(ranges))
906}
907
908fn range_recv(
910 ty: u32,
911 sub: u32,
912 recv: &mut Recv<'_>,
913 session: &dyn Session,
914) -> std::result::Result<Value, Received> {
915 let (flags, lower, upper) = types::range_recv(recv)?;
916 let bound = |bytes: Option<&[u8]>| match bytes {
917 Some(bytes) => receive_from(sub, &mut Recv::new(bytes), -1, session),
918 None => Ok(Value::Null),
919 };
920 let lower = bound(lower)?;
921 let upper = bound(upper)?;
922 let range = crate::range::make_range(ty, flags, lower, upper).map_err(Received::Engine)?;
923 Ok(Value::Range(Box::new(range)))
924}
925
926fn multirange_recv(
928 range_ty: u32,
929 recv: &mut Recv<'_>,
930 session: &dyn Session,
931) -> std::result::Result<Value, Received> {
932 let mut ranges = Vec::new();
933 types::multirange_recv(recv, |bytes| {
934 match receive_from(range_ty, &mut Recv::new(bytes), -1, session)? {
935 Value::Range(range) => {
936 ranges.push(*range);
937 Ok(())
938 }
939 _ => Err(Received::Engine(bad_value())),
940 }
941 })?;
942 let ranges = crate::multirange::make_multirange(range_ty, ranges).map_err(Received::Engine)?;
943 Ok(Value::Multirange(ranges))
944}
945
946fn no_input(ty: u32) -> Error {
948 Error::new(
949 SqlState::FEATURE_NOT_SUPPORTED,
950 format!("cannot accept a value of type {}", type_name(ty)),
951 )
952}
953
954fn no_binary(ty: u32, what: &str) -> Error {
956 Error::new(
957 SqlState::UNDEFINED_FUNCTION,
958 format!("no binary {what} function available for type {}", type_name(ty)),
959 )
960}
961
962fn types_error(error: &Error) -> types::TypeError {
964 types::TypeError {
965 sqlstate: error.state(),
966 message: error.message().to_string(),
967 detail: error.detail().map(str::to_string),
968 hint: error.hint().map(str::to_string),
969 context: None,
970 }
971}
972
973pub fn receive(
979 ty: u32,
980 data: &[u8],
981 typmod: i32,
982 number: usize,
983 session: &dyn Session,
984) -> Result<Value> {
985 let mut recv = Recv::new(data);
986 let value = receive_from(ty, &mut recv, typmod, session).map_err(|e| match e {
987 Received::Type(e) => type_error(e),
988 Received::Engine(e) => e,
989 })?;
990 recv.finish(number).map_err(type_error)?;
991 Ok(value)
992}
993
994enum Received {
996 Type(types::TypeError),
997 Engine(Error),
998}
999
1000impl From<types::TypeError> for Received {
1001 fn from(error: types::TypeError) -> Received {
1002 Received::Type(error)
1003 }
1004}
1005
1006fn receive_from(
1008 ty: u32,
1009 recv: &mut Recv<'_>,
1010 typmod: i32,
1011 session: &dyn Session,
1012) -> std::result::Result<Value, Received> {
1013 let ty = base_type(ty);
1014 if let Some((elem, _)) = array_of(ty) {
1015 let mut failed = None;
1016 let array =
1017 types::array_recv(recv, elem, |item| match receive_from(elem, item, typmod, session) {
1018 Ok(value) => Ok(value),
1019 Err(Received::Type(e)) => Err(e),
1020 Err(Received::Engine(e)) => {
1021 let text = types_error(&e);
1022 failed = Some(e);
1023 Err(text)
1024 }
1025 });
1026 if let Some(error) = failed {
1027 return Err(Received::Engine(error));
1028 }
1029 return Ok(Value::Array(Box::new(array?)));
1030 }
1031 if let Some(sub) = builtin::range_subtype(ty) {
1032 return range_recv(ty, sub, recv, session);
1033 }
1034 if let Some(range) = builtin::multirange_range(ty) {
1035 return multirange_recv(range, recv, session);
1036 }
1037 if let Some(kind) = types::GeoKind::from_oid(ty) {
1038 return Ok(Value::Bytea(types::geo_recv(kind, recv)?));
1039 }
1040 if is_enum(ty) {
1041 let text = recv.text()?;
1042 let oid = enum_in(ty, text).map_err(Received::Engine)?;
1043 check_safe_enum_use(ty, oid, text).map_err(Received::Engine)?;
1044 return Ok(Value::Oid(oid));
1045 }
1046 let value = match ty {
1047 oid::BOOL => Value::Bool(recv.bool()?),
1048 oid::BYTEA => Value::Bytea(recv.rest().to_vec()),
1049 oid::CHAR => Value::Char(recv.byte()?),
1050 oid::NAME => Value::text(types::name_recv(recv.text()?)?),
1051 oid::INT2 => Value::Int2(recv.i16()?),
1052 oid::INT4 => Value::Int4(recv.i32()?),
1053 oid::INT8 | oid::MONEY | oid::XID8 | oid::OID8 | oid::PG_LSN => Value::Int8(recv.i64()?),
1054 oid::VOID => Value::Text(String::new()),
1056 XID | CID => Value::Oid(recv.u32()?),
1057 oid::PG_SNAPSHOT | oid::TXID_SNAPSHOT => {
1058 Value::Bytea(types::snapshot_recv(recv)?.to_bytes())
1059 }
1060 oid::MACADDR => Value::Int8(types::macaddr_recv(recv)?.cast_signed()),
1061 oid::MACADDR8 => Value::Int8(types::macaddr8_recv(recv)?.cast_signed()),
1062 oid::BIT => Value::Text(types::bit_recv(recv, typmod, false)?),
1063 oid::VARBIT => Value::Text(types::bit_recv(recv, typmod, true)?),
1064 oid::TID => {
1065 let block = recv.u32()?;
1066 tid_value(block, recv.i16()?.cast_unsigned())
1067 }
1068 oid::TEXT | oid::UNKNOWN | oid::CSTRING | oid::REFCURSOR => Value::text(recv.text()?),
1069 oid::VARCHAR => Value::text(types::varchar_in(recv.text()?, typmod)?),
1070 oid::BPCHAR => Value::text(types::bpchar_in(recv.text()?, typmod)?),
1071 oid::OID => Value::Oid(recv.u32()?),
1072 oid::TSVECTOR => Value::TsVector(types::tsvector_recv(recv)?),
1073 oid::TSQUERY => Value::TsQuery(types::tsquery_recv(recv)?),
1074 oid::JSONPATH => {
1075 Value::JsonPath(Box::new(types::jsonpath_recv(recv, &crate::regex::validate)?))
1076 }
1077 ty if RegKind::from_oid(ty).is_some() => Value::Oid(recv.u32()?),
1078 oid::JSON => Value::text(types::json_in(recv.text()?)?),
1079 oid::XML => Value::text(xml_recv(recv, session)?),
1080 oid::JSONB => Value::Text(types::jsonb_recv(recv.rest())?),
1081 oid::FLOAT4 => Value::Float4(recv.f32()?),
1082 oid::FLOAT8 => Value::Float8(recv.f64()?),
1083 oid::NUMERIC => Value::Numeric(types::numeric_recv(recv, typmod)?),
1084 oid::UUID => Value::Uuid(recv.uuid()?),
1085 oid::INET | oid::CIDR => Value::Inet(types::inet_recv(recv, ty == oid::CIDR)?),
1086 oid::DATE => Value::Date(types::date_recv(recv)?),
1087 oid::TIME => Value::Time(types::time_recv(recv, typmod)?),
1088 oid::TIMETZ => {
1089 let (time, zone) = types::timetz_recv(recv, typmod)?;
1090 Value::TimeTz(time, zone)
1091 }
1092 oid::TIMESTAMP => Value::Timestamp(types::timestamp_recv(recv, typmod)?),
1093 oid::TIMESTAMPTZ => Value::TimestampTz(types::timestamp_recv(recv, typmod)?),
1094 oid::INTERVAL => Value::Interval(types::interval_recv(recv, typmod)?),
1095 oid::INT2VECTOR => {
1096 let values = types::int2vector_recv(recv)?;
1097 Value::Array(Box::new(Array::vector(
1098 values.into_iter().map(|v| Some(Value::Int2(v))).collect(),
1099 )))
1100 }
1101 oid::OIDVECTOR => {
1102 let values = types::oidvector_recv(recv)?;
1103 Value::Array(Box::new(Array::vector(
1104 values.into_iter().map(|v| Some(Value::Oid(v))).collect(),
1105 )))
1106 }
1107 oid::PG_NDISTINCT | oid::PG_DEPENDENCIES | oid::PG_MCV_LIST => {
1108 return Err(Received::Engine(no_input(ty)));
1109 }
1110 oid::ACLITEM => return Err(Received::Engine(no_binary(ty, "input"))),
1111 _ => {
1112 return Err(Received::Engine(not_yet(format!(
1113 "binary input of type {}",
1114 type_name(ty)
1115 ))));
1116 }
1117 };
1118 Ok(value)
1119}
1120
1121pub(crate) fn input_kernel(call: &Call<'_>, args: &[Value]) -> Result<Value> {
1123 let text = args.first().and_then(Value::as_str).ok_or_else(bad_value)?;
1124 let typmod = match args.get(2) {
1125 Some(Value::Int4(typmod)) => *typmod,
1126 _ => -1,
1127 };
1128 input(call.ret, text, typmod, call.session)
1129}
1130
1131pub(crate) fn output_kernel(call: &Call<'_>, args: &[Value]) -> Result<Value> {
1133 let ([ty], [value]) = (call.args, args) else { return Err(bad_value()) };
1134 let mut out = Vec::new();
1135 output(*ty, value, call.session, &mut out)?;
1136 Ok(Value::text(String::from_utf8(out).map_err(|_| bad_value())?))
1137}
1138
1139pub(crate) fn send_kernel(call: &Call<'_>, args: &[Value]) -> Result<Value> {
1141 let ([ty], [value]) = (call.args, args) else { return Err(bad_value()) };
1142 let mut out = Vec::new();
1143 send(*ty, value, &mut out)?;
1144 Ok(Value::Bytea(out))
1145}
1146
1147pub fn send(ty: u32, value: &Value, out: &mut Vec<u8>) -> Result<()> {
1153 let ty = base_type(ty);
1154 if let Some((elem, _)) = array_of(ty) {
1155 let Value::Array(array) = value else { return Err(bad_value()) };
1156 let mut failed = None;
1157 types::array_send(array, elem, out, |item, out| {
1158 if failed.is_none()
1159 && let Err(error) = send(elem, item, out)
1160 {
1161 failed = Some(error);
1162 }
1163 });
1164 return failed.map_or(Ok(()), Err);
1165 }
1166 if is_enum(ty)
1167 && let Value::Oid(label) = value
1168 {
1169 out.extend_from_slice(enum_label(ty, *label)?.as_bytes());
1170 return Ok(());
1171 }
1172 match (ty, value) {
1173 (oid::ACLITEM, _) => return Err(no_binary(ty, "output")),
1174 (oid::ANYARRAY, _) => {
1175 return Err(not_yet(format!("binary output of type {}", type_name(ty))));
1176 }
1177 (oid::MACADDR, Value::Int8(v)) => out.extend_from_slice(&v.to_be_bytes()[2..]),
1178 (oid::TID, Value::Int8(v)) => {
1179 let (block, offset) = tid_parts(*v)?;
1180 out.extend_from_slice(&block.to_be_bytes());
1181 out.extend_from_slice(&offset.to_be_bytes());
1182 }
1183 (_, Value::Bool(v)) => out.push(u8::from(*v)),
1184 (_, Value::Int2(v)) => out.extend_from_slice(&v.to_be_bytes()),
1185 (_, Value::Int4(v) | Value::Date(v)) => out.extend_from_slice(&v.to_be_bytes()),
1186 (_, Value::Int8(v) | Value::Time(v) | Value::Timestamp(v) | Value::TimestampTz(v)) => {
1187 out.extend_from_slice(&v.to_be_bytes());
1188 }
1189 (_, Value::Float4(v)) => out.extend_from_slice(&v.to_be_bytes()),
1190 (_, Value::Float8(v)) => out.extend_from_slice(&v.to_be_bytes()),
1191 (_, Value::Numeric(v)) => types::numeric_send(v, out),
1192 (_, Value::Oid(v)) => out.extend_from_slice(&v.to_be_bytes()),
1193 (_, Value::Char(v)) => out.push(*v),
1194 (oid::JSONB, Value::Text(v)) => types::jsonb_send(v, out),
1195 (oid::BIT | oid::VARBIT, Value::Text(v)) => types::bit_send(v, out),
1196 (oid::XML, Value::Text(v)) => {
1198 let _ = types::xml_out(v, out);
1199 }
1200 (_, Value::Text(v)) => out.extend_from_slice(v.as_bytes()),
1201 (_, Value::Bytea(v)) => out.extend_from_slice(v),
1202 (_, Value::Uuid(v)) => out.extend_from_slice(v),
1203 (_, Value::Inet(v)) => types::inet_send(v, ty == oid::CIDR, out),
1204 (_, Value::TimeTz(time, zone)) => {
1205 out.extend_from_slice(&time.to_be_bytes());
1206 out.extend_from_slice(&zone.to_be_bytes());
1207 }
1208 (_, Value::Interval(v)) => types::interval_send(v, out),
1209 (oid::INT2VECTOR, Value::Array(array)) => {
1210 let values = vector(array, |v| match v {
1211 Value::Int2(n) => Some(*n),
1212 _ => None,
1213 })?;
1214 types::int2vector_send(&values, out);
1215 }
1216 (oid::OIDVECTOR, Value::Array(array)) => {
1217 let values = vector(array, Value::as_oid)?;
1218 types::oidvector_send(&values, out);
1219 }
1220 (_, Value::Record(record)) => record_send(record, out)?,
1221 (_, Value::Range(range)) => range_send(ty, range, out)?,
1222 (_, Value::Multirange(ranges)) => multirange_send(ty, ranges, out)?,
1223 (_, Value::TsVector(lexemes)) => types::tsvector_send(lexemes, out),
1224 (_, Value::TsQuery(items)) => types::tsquery_send(items, out),
1225 (_, Value::JsonPath(path)) => types::jsonpath_send(path, out),
1226 (_, Value::Null) => return Err(Error::internal("the send function got a null value")),
1227 _ => return Err(not_yet(format!("binary output of type {}", type_name(ty)))),
1228 }
1229 Ok(())
1230}