From 747ffa50d67edea23b8ba4fdbd9ee62c10508058 Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Wed, 2 Aug 2023 09:27:27 +0100 Subject: [PATCH] recursive type queries --- proxy/src/http/sql_over_http.rs | 154 ++- proxy/src/pg_client/connection.rs | 191 +--- proxy/src/pg_client/mod.rs | 3 +- proxy/src/pg_client/pg_type.rs | 1524 ----------------------------- proxy/src/pg_client/prepare.rs | 443 +++++---- 5 files changed, 346 insertions(+), 1969 deletions(-) delete mode 100644 proxy/src/pg_client/pg_type.rs diff --git a/proxy/src/http/sql_over_http.rs b/proxy/src/http/sql_over_http.rs index edeeaf1d27..5caa889e8d 100644 --- a/proxy/src/http/sql_over_http.rs +++ b/proxy/src/http/sql_over_http.rs @@ -30,6 +30,7 @@ use crate::pg_client; use crate::pg_client::codec::FrontendMessage; use crate::pg_client::connection; use crate::pg_client::connection::RequestMessages; +use crate::pg_client::prepare::TypeinfoPreparedQueries; use super::conn_pool::ConnInfo; use super::conn_pool::GlobalConnPool; @@ -370,60 +371,59 @@ async fn query_raw_txt_as_json<'a, St, T>( params: Vec>, raw_output: bool, array_mode: bool, -) -> Result +) -> anyhow::Result where - St: AsyncRead + AsyncWrite + Unpin, - T: AsyncRead + AsyncWrite + Unpin, + St: AsyncRead + AsyncWrite + Unpin + Send, + T: AsyncRead + AsyncWrite + Unpin + Send, { let params = params.into_iter(); - conn.prepare_and_execute("", "", query.as_str(), params)?; - conn.sync().await?; + let stmt_name = conn.statement_name(); + let row_description = conn.prepare(&stmt_name, &query).await?; let mut fields = vec![]; + let mut columns = vec![]; + let mut it = row_description.fields(); + while let Some(field) = it.next().map_err(pg_client::error::Error::parse)? { + fields.push(json!({ + "name": Value::String(field.name().to_owned()), + "dataTypeID": Value::Number(field.type_oid().into()), + "tableID": field.table_oid(), + "columnID": field.column_id(), + "dataTypeSize": field.type_size(), + "dataTypeModifier": field.type_modifier(), + "format": "text", + })); + + let type_ = match Type::from_oid(field.type_oid()) { + Some(t) => t, + None => TypeinfoPreparedQueries::get_type(conn, field.type_oid()).await?, + }; + + columns.push(Column { + name: field.name().to_string(), + type_, + }); + } + + conn.execute("", &stmt_name, params)?; + conn.sync().await?; + let mut rows = vec![]; - let command_tag = match conn.stream_query_results().await? { - connection::QueryResult::NoRows(tag) => tag, - connection::QueryResult::Rows { - row_description, - mut row_stream, - } => { - let mut columns = vec![]; - let mut it = row_description.fields(); - while let Some(field) = it.next().map_err(pg_client::error::Error::parse)? { - fields.push(json!({ - "name": Value::String(field.name().to_owned()), - "dataTypeID": Value::Number(field.type_oid().into()), - "tableID": field.table_oid(), - "columnID": field.column_id(), - "dataTypeSize": field.type_size(), - "dataTypeModifier": field.type_modifier(), - "format": "text", - })); - let type_ = Type::from_oid(field.type_oid()); - // let column = Column::new(field.name().to_string(), type_, field); - columns.push(Column { - name: field.name().to_string(), - type_, - }); - } + let mut row_stream = conn.stream_query_results().await?; - let mut curret_size = 0; - while let Some(row) = row_stream.next().await.transpose()? { - curret_size += row.buffer().len(); - if curret_size > MAX_RESPONSE_SIZE { - todo!() - // return Err(anyhow::anyhow!("response too large")); - } - - rows.push(pg_text_row_to_json2(&row, &columns, raw_output, array_mode).unwrap()); - } - - row_stream.tag() + let mut curret_size = 0; + while let Some(row) = row_stream.next().await.transpose()? { + curret_size += row.buffer().len(); + if curret_size > MAX_RESPONSE_SIZE { + return Err(anyhow::anyhow!("response too large")); } - }; + rows.push(pg_text_row_to_json2(&row, &columns, raw_output, array_mode).unwrap()); + } + + let command_tag = row_stream.tag(); let command_tag = command_tag.tag()?; let mut command_tag_split = command_tag.split(' '); let command_tag_name = command_tag_split.next().unwrap_or_default(); @@ -448,7 +448,7 @@ where struct Column { name: String, - type_: Option, + type_: Type, } // @@ -468,7 +468,7 @@ pub fn pg_text_row_to_json( None => Value::Null, } } else { - pg_text_to_json(pg_value, Some(column.type_()))? + pg_text_to_json(pg_value, column.type_())? }; Ok((name, json_value)) }); @@ -514,7 +514,7 @@ fn pg_text_row_to_json2( None => Value::Null, } } else { - pg_text_to_json(pg_value, column.type_.as_ref())? + pg_text_to_json(pg_value, &column.type_)? }; Ok((name, json_value)) }); @@ -536,22 +536,19 @@ fn pg_text_row_to_json2( // // Convert postgres text-encoded value to JSON value // -pub fn pg_text_to_json( - pg_value: Option<&str>, - pg_type: Option<&Type>, -) -> Result { +pub fn pg_text_to_json(pg_value: Option<&str>, pg_type: &Type) -> Result { if let Some(val) = pg_value { - if let Some(Kind::Array(elem_type)) = pg_type.map(|t| t.kind()) { - return pg_array_parse(val, Some(elem_type)); + if let Kind::Array(elem_type) = pg_type.kind() { + return pg_array_parse(val, &elem_type); } match pg_type { - Some(&Type::BOOL) => Ok(Value::Bool(val == "t")), - Some(&Type::INT2 | &Type::INT4) => { + &Type::BOOL => Ok(Value::Bool(val == "t")), + &Type::INT2 | &Type::INT4 => { let val = val.parse::()?; Ok(Value::Number(serde_json::Number::from(val))) } - Some(&Type::FLOAT4 | &Type::FLOAT8) => { + &Type::FLOAT4 | &Type::FLOAT8 => { let fval = val.parse::()?; let num = serde_json::Number::from_f64(fval); if let Some(num) = num { @@ -563,7 +560,7 @@ pub fn pg_text_to_json( Ok(Value::String(val.to_string())) } } - Some(&Type::JSON | &Type::JSONB) => Ok(serde_json::from_str(val)?), + &Type::JSON | &Type::JSONB => Ok(serde_json::from_str(val)?), _ => Ok(Value::String(val.to_string())), } } else { @@ -578,13 +575,13 @@ pub fn pg_text_to_json( // values. Unlike postgres we don't check that all nested arrays have the same // dimensions, we just return them as is. // -fn pg_array_parse(pg_array: &str, elem_type: Option<&Type>) -> Result { +fn pg_array_parse(pg_array: &str, elem_type: &Type) -> Result { _pg_array_parse(pg_array, elem_type, false).map(|(v, _)| v) } fn _pg_array_parse( pg_array: &str, - elem_type: Option<&Type>, + elem_type: &Type, nested: bool, ) -> Result<(Value, usize), anyhow::Error> { let mut pg_array_chr = pg_array.char_indices(); @@ -605,7 +602,7 @@ fn _pg_array_parse( fn push_checked( entry: &mut String, entries: &mut Vec, - elem_type: Option<&Type>, + elem_type: &Type, ) -> Result<(), anyhow::Error> { if !entry.is_empty() { // While in usual postgres response we get nulls as None and everything else @@ -731,43 +728,34 @@ mod tests { #[test] fn test_atomic_types_parse() { assert_eq!( - pg_text_to_json(Some("foo"), Some(&Type::TEXT)).unwrap(), + pg_text_to_json(Some("foo"), &Type::TEXT).unwrap(), json!("foo") ); + assert_eq!(pg_text_to_json(None, &Type::TEXT).unwrap(), json!(null)); + assert_eq!(pg_text_to_json(Some("42"), &Type::INT4).unwrap(), json!(42)); + assert_eq!(pg_text_to_json(Some("42"), &Type::INT2).unwrap(), json!(42)); assert_eq!( - pg_text_to_json(None, Some(&Type::TEXT)).unwrap(), - json!(null) - ); - assert_eq!( - pg_text_to_json(Some("42"), Some(&Type::INT4)).unwrap(), - json!(42) - ); - assert_eq!( - pg_text_to_json(Some("42"), Some(&Type::INT2)).unwrap(), - json!(42) - ); - assert_eq!( - pg_text_to_json(Some("42"), Some(&Type::INT8)).unwrap(), + pg_text_to_json(Some("42"), &Type::INT8).unwrap(), json!("42") ); assert_eq!( - pg_text_to_json(Some("42.42"), Some(&Type::FLOAT8)).unwrap(), + pg_text_to_json(Some("42.42"), &Type::FLOAT8).unwrap(), json!(42.42) ); assert_eq!( - pg_text_to_json(Some("42.42"), Some(&Type::FLOAT4)).unwrap(), + pg_text_to_json(Some("42.42"), &Type::FLOAT4).unwrap(), json!(42.42) ); assert_eq!( - pg_text_to_json(Some("NaN"), Some(&Type::FLOAT4)).unwrap(), + pg_text_to_json(Some("NaN"), &Type::FLOAT4).unwrap(), json!("NaN") ); assert_eq!( - pg_text_to_json(Some("Infinity"), Some(&Type::FLOAT4)).unwrap(), + pg_text_to_json(Some("Infinity"), &Type::FLOAT4).unwrap(), json!("Infinity") ); assert_eq!( - pg_text_to_json(Some("-Infinity"), Some(&Type::FLOAT4)).unwrap(), + pg_text_to_json(Some("-Infinity"), &Type::FLOAT4).unwrap(), json!("-Infinity") ); @@ -777,7 +765,7 @@ mod tests { assert_eq!( pg_text_to_json( Some(r#"{"s":"str","n":42,"f":4.2,"a":[null,3,"a"]}"#), - Some(&Type::JSONB) + &Type::JSONB ) .unwrap(), json @@ -787,7 +775,7 @@ mod tests { #[test] fn test_pg_array_parse_text() { fn pt(pg_arr: &str) -> Value { - pg_array_parse(pg_arr, Some(&Type::TEXT)).unwrap() + pg_array_parse(pg_arr, &Type::TEXT).unwrap() } assert_eq!( pt(r#"{"aa\"\\\,a",cha,"bbbb"}"#), @@ -810,7 +798,7 @@ mod tests { #[test] fn test_pg_array_parse_bool() { fn pb(pg_arr: &str) -> Value { - pg_array_parse(pg_arr, Some(&Type::BOOL)).unwrap() + pg_array_parse(pg_arr, &Type::BOOL).unwrap() } assert_eq!(pb(r#"{t,f,t}"#), json!([true, false, true])); assert_eq!(pb(r#"{{t,f,t}}"#), json!([[true, false, true]])); @@ -827,7 +815,7 @@ mod tests { #[test] fn test_pg_array_parse_numbers() { fn pn(pg_arr: &str, ty: &Type) -> Value { - pg_array_parse(pg_arr, Some(ty)).unwrap() + pg_array_parse(pg_arr, ty).unwrap() } assert_eq!(pn(r#"{1,2,3}"#, &Type::INT4), json!([1, 2, 3])); assert_eq!(pn(r#"{1,2,3}"#, &Type::INT2), json!([1, 2, 3])); @@ -855,7 +843,7 @@ mod tests { #[test] fn test_pg_array_with_decoration() { fn p(pg_arr: &str) -> Value { - pg_array_parse(pg_arr, Some(&Type::INT2)).unwrap() + pg_array_parse(pg_arr, &Type::INT2).unwrap() } assert_eq!( p(r#"[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}"#), diff --git a/proxy/src/pg_client/connection.rs b/proxy/src/pg_client/connection.rs index 1e21faec7f..f9c05f6d8a 100644 --- a/proxy/src/pg_client/connection.rs +++ b/proxy/src/pg_client/connection.rs @@ -1,23 +1,23 @@ use super::codec::{BackendMessages, FrontendMessage, PostgresCodec}; use super::error::Error; +use super::prepare::TypeinfoPreparedQueries; use bytes::{BufMut, BytesMut}; -use fallible_iterator::FallibleIterator; use futures::channel::mpsc; use futures::{Sink, StreamExt}; use futures::{SinkExt, Stream}; -use postgres_protocol::authentication; +use hashbrown::HashMap; +use postgres_protocol::Oid; use postgres_protocol::message::backend::{ BackendKeyDataBody, CommandCompleteBody, DataRowBody, Message, ReadyForQueryBody, RowDescriptionBody, }; use postgres_protocol::message::frontend; -use std::collections::{HashMap, VecDeque}; +use tokio_postgres::types::Type; +use std::collections::VecDeque; use std::future::poll_fn; use std::pin::Pin; use std::task::{ready, Context, Poll}; -use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use tokio::net::TcpStream; -use tokio_native_tls::{native_tls, TlsConnector, TlsStream}; +use tokio::io::{AsyncRead, AsyncWrite}; use tokio_postgres::maybe_tls_stream::MaybeTlsStream; use tokio_util::codec::Framed; @@ -41,105 +41,7 @@ pub struct RawConnection { pub buf: BytesMut, } -// enum MaybeTlsStream { -// NoTls(TcpStream), -// Tls(TlsStream), -// } - -// impl Unpin for MaybeTlsStream {} - -// impl AsyncRead for MaybeTlsStream { -// fn poll_read( -// self: Pin<&mut Self>, -// cx: &mut Context<'_>, -// buf: &mut tokio::io::ReadBuf<'_>, -// ) -> Poll> { -// match self.get_mut() { -// MaybeTlsStream::NoTls(no_tls) => Pin::new(no_tls).poll_read(cx, buf), -// MaybeTlsStream::Tls(tls) => Pin::new(tls).poll_read(cx, buf), -// } -// } -// } -// impl AsyncWrite for MaybeTlsStream { -// fn poll_write( -// self: Pin<&mut Self>, -// cx: &mut Context<'_>, -// buf: &[u8], -// ) -> Poll> { -// match self.get_mut() { -// MaybeTlsStream::NoTls(no_tls) => Pin::new(no_tls).poll_write(cx, buf), -// MaybeTlsStream::Tls(tls) => Pin::new(tls).poll_write(cx, buf), -// } -// } - -// fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { -// match self.get_mut() { -// MaybeTlsStream::NoTls(no_tls) => Pin::new(no_tls).poll_flush(cx), -// MaybeTlsStream::Tls(tls) => Pin::new(tls).poll_flush(cx), -// } -// } - -// fn poll_shutdown( -// self: Pin<&mut Self>, -// cx: &mut Context<'_>, -// ) -> Poll> { -// match self.get_mut() { -// MaybeTlsStream::NoTls(no_tls) => Pin::new(no_tls).poll_shutdown(cx), -// MaybeTlsStream::Tls(tls) => Pin::new(tls).poll_shutdown(cx), -// } -// } - -// fn poll_write_vectored( -// self: Pin<&mut Self>, -// cx: &mut Context<'_>, -// bufs: &[std::io::IoSlice<'_>], -// ) -> Poll> { -// match self.get_mut() { -// MaybeTlsStream::NoTls(no_tls) => Pin::new(no_tls).poll_write_vectored(cx, bufs), -// MaybeTlsStream::Tls(tls) => Pin::new(tls).poll_write_vectored(cx, bufs), -// } -// } - -// fn is_write_vectored(&self) -> bool { -// match self { -// MaybeTlsStream::NoTls(no_tls) => no_tls.is_write_vectored(), -// MaybeTlsStream::Tls(tls) => tls.is_write_vectored(), -// } -// } -// } - impl RawConnection { - // pub(crate) async fn connect( - // mut stream: TcpStream, - // tls_domain: Option<&str>, - // ) -> Result, Error> { - // let mut buf = BytesMut::new(); - - // let stream = if let Some(tls_domain) = tls_domain { - // frontend::ssl_request(&mut buf); - // stream - // .write_all_buf(&mut buf.split().freeze()) - // .await - // .unwrap(); - // let bit = stream.read_u8().await.map_err(Error::io)?; - // if bit != b'S' { - // return Err(Error::closed()); - // } - - // let tls = native_tls::TlsConnector::new().map_err(Error::tls)?; - // let tls = TlsConnector::from(tls) - // .connect(tls_domain, stream) - // .await - // .map_err(Error::tls)?; - - // MaybeTlsStream::Tls(tls) - // } else { - // MaybeTlsStream::Raw(stream) - // }; - - // Ok(RawConnection::new(Framed::new(stream, PostgresCodec), buf)) - // } - pub fn new( stream: Framed, PostgresCodec>, buf: BytesMut, @@ -193,8 +95,11 @@ impl RawCo } pub struct Connection { - raw: RawConnection, - key: BackendKeyDataBody, + stmt_counter: usize, + pub typeinfo: Option, + pub typecache: HashMap, + pub raw: RawConnection, + // key: BackendKeyDataBody, } impl Connection { @@ -263,19 +168,27 @@ impl Conne // Ok(Self { raw, key }) // } - pub fn prepare_and_execute( - &mut self, - portal: &str, - name: &str, - query: &str, - params: impl IntoIterator>>, - ) -> std::io::Result<()> { - self.prepare(name, query)?; - self.execute(portal, name, params) + // pub fn prepare_and_execute( + // &mut self, + // portal: &str, + // name: &str, + // query: &str, + // params: impl IntoIterator>>, + // ) -> std::io::Result<()> { + // self.prepare(name, query)?; + // self.execute(portal, name, params) + // } + + pub fn statement_name(&mut self) -> String { + self.stmt_counter += 1; + format!("s{}", self.stmt_counter) } - pub fn prepare(&mut self, name: &str, query: &str) -> std::io::Result<()> { - frontend::parse(name, query, std::iter::empty(), &mut self.raw.buf) + pub async fn prepare(&mut self, name: &str, query: &str) -> Result { + frontend::parse(name, query, std::iter::empty(), &mut self.raw.buf)?; + frontend::describe(b'S', name, &mut self.raw.buf)?; + self.sync().await?; + self.wait_for_prepare().await } pub fn execute( @@ -303,7 +216,6 @@ impl Conne frontend::BindError::Conversion(e) => std::io::Error::new(std::io::ErrorKind::Other, e), frontend::BindError::Serialization(io) => io, })?; - frontend::describe(b'P', portal, &mut self.raw.buf)?; frontend::execute(portal, 0, &mut self.raw.buf) } @@ -312,35 +224,20 @@ impl Conne self.raw.send().await } - pub async fn wait_for_prepare(&mut self) -> Result, Error> { + pub async fn wait_for_prepare(&mut self) -> Result { let Message::ParseComplete = self.raw.next_message().await? else { return Err(Error::expecting("parse")) }; - let Message::BindComplete = self.raw.next_message().await? else { return Err(Error::expecting("bind")) }; - match self.raw.next_message().await? { - Message::RowDescription(desc) => Ok(QueryResult::Rows { - row_stream: RowStream::Stream(&mut self.raw), - row_description: desc, - }), - Message::NoData => { - let Message::CommandComplete(tag) = self.raw.next_message().await? else { return Err(Error::expecting("command completion")) }; - Ok(QueryResult::NoRows(tag)) - } - _ => Err(Error::expecting("query results")), - } + let Message::ParameterDescription(_) = self.raw.next_message().await? else { return Err(Error::expecting("param description")) }; + let Message::RowDescription(desc) = self.raw.next_message().await? else { return Err(Error::expecting("row description")) }; + + self.wait_for_ready().await?; + + Ok(desc) } + pub async fn stream_query_results(&mut self) -> Result, Error> { - let Message::ParseComplete = self.raw.next_message().await? else { return Err(Error::expecting("parse")) }; + // let Message::ParseComplete = self.raw.next_message().await? else { return Err(Error::expecting("parse")) }; let Message::BindComplete = self.raw.next_message().await? else { return Err(Error::expecting("bind")) }; - match self.raw.next_message().await? { - Message::RowDescription(desc) => Ok(QueryResult::Rows { - row_stream: RowStream::Stream(&mut self.raw), - row_description: desc, - }), - Message::NoData => { - let Message::CommandComplete(tag) = self.raw.next_message().await? else { return Err(Error::expecting("command completion")) }; - Ok(QueryResult::NoRows(tag)) - } - _ => Err(Error::expecting("query results")), - } + Ok(RowStream::Stream(&mut self.raw)) } pub async fn wait_for_ready(&mut self) -> Result { @@ -353,14 +250,6 @@ impl Conne } } -// pub enum QueryResult<'a, S, T> { -// NoRows(CommandCompleteBody), -// Rows { -// row_description: RowDescriptionBody, -// row_stream: RowStream<'a, S, T>, -// }, -// } - pub enum RowStream<'a, S, T> { Stream(&'a mut RawConnection), Complete(CommandCompleteBody), diff --git a/proxy/src/pg_client/mod.rs b/proxy/src/pg_client/mod.rs index c0d3c33a4a..e42f843214 100644 --- a/proxy/src/pg_client/mod.rs +++ b/proxy/src/pg_client/mod.rs @@ -2,5 +2,4 @@ pub mod codec; pub mod connection; pub mod error; -// mod prepare; -// mod pg_type; +pub mod prepare; diff --git a/proxy/src/pg_client/pg_type.rs b/proxy/src/pg_client/pg_type.rs deleted file mode 100644 index a1bc3f85c0..0000000000 --- a/proxy/src/pg_client/pg_type.rs +++ /dev/null @@ -1,1524 +0,0 @@ -// Autogenerated file - DO NOT EDIT -use std::sync::Arc; - -use crate::{Kind, Oid, Type}; - -#[derive(PartialEq, Eq, Debug, Hash)] -pub struct Other { - pub name: String, - pub oid: Oid, - pub kind: Kind, - pub schema: String, -} - -#[derive(PartialEq, Eq, Clone, Debug, Hash)] -pub enum Inner { - Bool, - Bytea, - Char, - Name, - Int8, - Int2, - Int2Vector, - Int4, - Regproc, - Text, - Oid, - Tid, - Xid, - Cid, - OidVector, - PgDdlCommand, - Json, - Xml, - XmlArray, - PgNodeTree, - JsonArray, - TableAmHandler, - Xid8Array, - IndexAmHandler, - Point, - Lseg, - Path, - Box, - Polygon, - Line, - LineArray, - Cidr, - CidrArray, - Float4, - Float8, - Unknown, - Circle, - CircleArray, - Macaddr8, - Macaddr8Array, - Money, - MoneyArray, - Macaddr, - Inet, - BoolArray, - ByteaArray, - CharArray, - NameArray, - Int2Array, - Int2VectorArray, - Int4Array, - RegprocArray, - TextArray, - TidArray, - XidArray, - CidArray, - OidVectorArray, - BpcharArray, - VarcharArray, - Int8Array, - PointArray, - LsegArray, - PathArray, - BoxArray, - Float4Array, - Float8Array, - PolygonArray, - OidArray, - Aclitem, - AclitemArray, - MacaddrArray, - InetArray, - Bpchar, - Varchar, - Date, - Time, - Timestamp, - TimestampArray, - DateArray, - TimeArray, - Timestamptz, - TimestamptzArray, - Interval, - IntervalArray, - NumericArray, - CstringArray, - Timetz, - TimetzArray, - Bit, - BitArray, - Varbit, - VarbitArray, - Numeric, - Refcursor, - RefcursorArray, - Regprocedure, - Regoper, - Regoperator, - Regclass, - Regtype, - RegprocedureArray, - RegoperArray, - RegoperatorArray, - RegclassArray, - RegtypeArray, - Record, - Cstring, - Any, - Anyarray, - Void, - Trigger, - LanguageHandler, - Internal, - Anyelement, - RecordArray, - Anynonarray, - TxidSnapshotArray, - Uuid, - UuidArray, - TxidSnapshot, - FdwHandler, - PgLsn, - PgLsnArray, - TsmHandler, - PgNdistinct, - PgDependencies, - Anyenum, - TsVector, - Tsquery, - GtsVector, - TsVectorArray, - GtsVectorArray, - TsqueryArray, - Regconfig, - RegconfigArray, - Regdictionary, - RegdictionaryArray, - Jsonb, - JsonbArray, - AnyRange, - EventTrigger, - Int4Range, - Int4RangeArray, - NumRange, - NumRangeArray, - TsRange, - TsRangeArray, - TstzRange, - TstzRangeArray, - DateRange, - DateRangeArray, - Int8Range, - Int8RangeArray, - Jsonpath, - JsonpathArray, - Regnamespace, - RegnamespaceArray, - Regrole, - RegroleArray, - Regcollation, - RegcollationArray, - Int4multiRange, - NummultiRange, - TsmultiRange, - TstzmultiRange, - DatemultiRange, - Int8multiRange, - AnymultiRange, - AnycompatiblemultiRange, - PgBrinBloomSummary, - PgBrinMinmaxMultiSummary, - PgMcvList, - PgSnapshot, - PgSnapshotArray, - Xid8, - Anycompatible, - Anycompatiblearray, - Anycompatiblenonarray, - AnycompatibleRange, - Int4multiRangeArray, - NummultiRangeArray, - TsmultiRangeArray, - TstzmultiRangeArray, - DatemultiRangeArray, - Int8multiRangeArray, - Other(Arc), -} - -impl Inner { - pub fn from_oid(oid: Oid) -> Option { - match oid { - 16 => Some(Inner::Bool), - 17 => Some(Inner::Bytea), - 18 => Some(Inner::Char), - 19 => Some(Inner::Name), - 20 => Some(Inner::Int8), - 21 => Some(Inner::Int2), - 22 => Some(Inner::Int2Vector), - 23 => Some(Inner::Int4), - 24 => Some(Inner::Regproc), - 25 => Some(Inner::Text), - 26 => Some(Inner::Oid), - 27 => Some(Inner::Tid), - 28 => Some(Inner::Xid), - 29 => Some(Inner::Cid), - 30 => Some(Inner::OidVector), - 32 => Some(Inner::PgDdlCommand), - 114 => Some(Inner::Json), - 142 => Some(Inner::Xml), - 143 => Some(Inner::XmlArray), - 194 => Some(Inner::PgNodeTree), - 199 => Some(Inner::JsonArray), - 269 => Some(Inner::TableAmHandler), - 271 => Some(Inner::Xid8Array), - 325 => Some(Inner::IndexAmHandler), - 600 => Some(Inner::Point), - 601 => Some(Inner::Lseg), - 602 => Some(Inner::Path), - 603 => Some(Inner::Box), - 604 => Some(Inner::Polygon), - 628 => Some(Inner::Line), - 629 => Some(Inner::LineArray), - 650 => Some(Inner::Cidr), - 651 => Some(Inner::CidrArray), - 700 => Some(Inner::Float4), - 701 => Some(Inner::Float8), - 705 => Some(Inner::Unknown), - 718 => Some(Inner::Circle), - 719 => Some(Inner::CircleArray), - 774 => Some(Inner::Macaddr8), - 775 => Some(Inner::Macaddr8Array), - 790 => Some(Inner::Money), - 791 => Some(Inner::MoneyArray), - 829 => Some(Inner::Macaddr), - 869 => Some(Inner::Inet), - 1000 => Some(Inner::BoolArray), - 1001 => Some(Inner::ByteaArray), - 1002 => Some(Inner::CharArray), - 1003 => Some(Inner::NameArray), - 1005 => Some(Inner::Int2Array), - 1006 => Some(Inner::Int2VectorArray), - 1007 => Some(Inner::Int4Array), - 1008 => Some(Inner::RegprocArray), - 1009 => Some(Inner::TextArray), - 1010 => Some(Inner::TidArray), - 1011 => Some(Inner::XidArray), - 1012 => Some(Inner::CidArray), - 1013 => Some(Inner::OidVectorArray), - 1014 => Some(Inner::BpcharArray), - 1015 => Some(Inner::VarcharArray), - 1016 => Some(Inner::Int8Array), - 1017 => Some(Inner::PointArray), - 1018 => Some(Inner::LsegArray), - 1019 => Some(Inner::PathArray), - 1020 => Some(Inner::BoxArray), - 1021 => Some(Inner::Float4Array), - 1022 => Some(Inner::Float8Array), - 1027 => Some(Inner::PolygonArray), - 1028 => Some(Inner::OidArray), - 1033 => Some(Inner::Aclitem), - 1034 => Some(Inner::AclitemArray), - 1040 => Some(Inner::MacaddrArray), - 1041 => Some(Inner::InetArray), - 1042 => Some(Inner::Bpchar), - 1043 => Some(Inner::Varchar), - 1082 => Some(Inner::Date), - 1083 => Some(Inner::Time), - 1114 => Some(Inner::Timestamp), - 1115 => Some(Inner::TimestampArray), - 1182 => Some(Inner::DateArray), - 1183 => Some(Inner::TimeArray), - 1184 => Some(Inner::Timestamptz), - 1185 => Some(Inner::TimestamptzArray), - 1186 => Some(Inner::Interval), - 1187 => Some(Inner::IntervalArray), - 1231 => Some(Inner::NumericArray), - 1263 => Some(Inner::CstringArray), - 1266 => Some(Inner::Timetz), - 1270 => Some(Inner::TimetzArray), - 1560 => Some(Inner::Bit), - 1561 => Some(Inner::BitArray), - 1562 => Some(Inner::Varbit), - 1563 => Some(Inner::VarbitArray), - 1700 => Some(Inner::Numeric), - 1790 => Some(Inner::Refcursor), - 2201 => Some(Inner::RefcursorArray), - 2202 => Some(Inner::Regprocedure), - 2203 => Some(Inner::Regoper), - 2204 => Some(Inner::Regoperator), - 2205 => Some(Inner::Regclass), - 2206 => Some(Inner::Regtype), - 2207 => Some(Inner::RegprocedureArray), - 2208 => Some(Inner::RegoperArray), - 2209 => Some(Inner::RegoperatorArray), - 2210 => Some(Inner::RegclassArray), - 2211 => Some(Inner::RegtypeArray), - 2249 => Some(Inner::Record), - 2275 => Some(Inner::Cstring), - 2276 => Some(Inner::Any), - 2277 => Some(Inner::Anyarray), - 2278 => Some(Inner::Void), - 2279 => Some(Inner::Trigger), - 2280 => Some(Inner::LanguageHandler), - 2281 => Some(Inner::Internal), - 2283 => Some(Inner::Anyelement), - 2287 => Some(Inner::RecordArray), - 2776 => Some(Inner::Anynonarray), - 2949 => Some(Inner::TxidSnapshotArray), - 2950 => Some(Inner::Uuid), - 2951 => Some(Inner::UuidArray), - 2970 => Some(Inner::TxidSnapshot), - 3115 => Some(Inner::FdwHandler), - 3220 => Some(Inner::PgLsn), - 3221 => Some(Inner::PgLsnArray), - 3310 => Some(Inner::TsmHandler), - 3361 => Some(Inner::PgNdistinct), - 3402 => Some(Inner::PgDependencies), - 3500 => Some(Inner::Anyenum), - 3614 => Some(Inner::TsVector), - 3615 => Some(Inner::Tsquery), - 3642 => Some(Inner::GtsVector), - 3643 => Some(Inner::TsVectorArray), - 3644 => Some(Inner::GtsVectorArray), - 3645 => Some(Inner::TsqueryArray), - 3734 => Some(Inner::Regconfig), - 3735 => Some(Inner::RegconfigArray), - 3769 => Some(Inner::Regdictionary), - 3770 => Some(Inner::RegdictionaryArray), - 3802 => Some(Inner::Jsonb), - 3807 => Some(Inner::JsonbArray), - 3831 => Some(Inner::AnyRange), - 3838 => Some(Inner::EventTrigger), - 3904 => Some(Inner::Int4Range), - 3905 => Some(Inner::Int4RangeArray), - 3906 => Some(Inner::NumRange), - 3907 => Some(Inner::NumRangeArray), - 3908 => Some(Inner::TsRange), - 3909 => Some(Inner::TsRangeArray), - 3910 => Some(Inner::TstzRange), - 3911 => Some(Inner::TstzRangeArray), - 3912 => Some(Inner::DateRange), - 3913 => Some(Inner::DateRangeArray), - 3926 => Some(Inner::Int8Range), - 3927 => Some(Inner::Int8RangeArray), - 4072 => Some(Inner::Jsonpath), - 4073 => Some(Inner::JsonpathArray), - 4089 => Some(Inner::Regnamespace), - 4090 => Some(Inner::RegnamespaceArray), - 4096 => Some(Inner::Regrole), - 4097 => Some(Inner::RegroleArray), - 4191 => Some(Inner::Regcollation), - 4192 => Some(Inner::RegcollationArray), - 4451 => Some(Inner::Int4multiRange), - 4532 => Some(Inner::NummultiRange), - 4533 => Some(Inner::TsmultiRange), - 4534 => Some(Inner::TstzmultiRange), - 4535 => Some(Inner::DatemultiRange), - 4536 => Some(Inner::Int8multiRange), - 4537 => Some(Inner::AnymultiRange), - 4538 => Some(Inner::AnycompatiblemultiRange), - 4600 => Some(Inner::PgBrinBloomSummary), - 4601 => Some(Inner::PgBrinMinmaxMultiSummary), - 5017 => Some(Inner::PgMcvList), - 5038 => Some(Inner::PgSnapshot), - 5039 => Some(Inner::PgSnapshotArray), - 5069 => Some(Inner::Xid8), - 5077 => Some(Inner::Anycompatible), - 5078 => Some(Inner::Anycompatiblearray), - 5079 => Some(Inner::Anycompatiblenonarray), - 5080 => Some(Inner::AnycompatibleRange), - 6150 => Some(Inner::Int4multiRangeArray), - 6151 => Some(Inner::NummultiRangeArray), - 6152 => Some(Inner::TsmultiRangeArray), - 6153 => Some(Inner::TstzmultiRangeArray), - 6155 => Some(Inner::DatemultiRangeArray), - 6157 => Some(Inner::Int8multiRangeArray), - _ => None, - } - } - - pub fn oid(&self) -> Oid { - match *self { - Inner::Bool => 16, - Inner::Bytea => 17, - Inner::Char => 18, - Inner::Name => 19, - Inner::Int8 => 20, - Inner::Int2 => 21, - Inner::Int2Vector => 22, - Inner::Int4 => 23, - Inner::Regproc => 24, - Inner::Text => 25, - Inner::Oid => 26, - Inner::Tid => 27, - Inner::Xid => 28, - Inner::Cid => 29, - Inner::OidVector => 30, - Inner::PgDdlCommand => 32, - Inner::Json => 114, - Inner::Xml => 142, - Inner::XmlArray => 143, - Inner::PgNodeTree => 194, - Inner::JsonArray => 199, - Inner::TableAmHandler => 269, - Inner::Xid8Array => 271, - Inner::IndexAmHandler => 325, - Inner::Point => 600, - Inner::Lseg => 601, - Inner::Path => 602, - Inner::Box => 603, - Inner::Polygon => 604, - Inner::Line => 628, - Inner::LineArray => 629, - Inner::Cidr => 650, - Inner::CidrArray => 651, - Inner::Float4 => 700, - Inner::Float8 => 701, - Inner::Unknown => 705, - Inner::Circle => 718, - Inner::CircleArray => 719, - Inner::Macaddr8 => 774, - Inner::Macaddr8Array => 775, - Inner::Money => 790, - Inner::MoneyArray => 791, - Inner::Macaddr => 829, - Inner::Inet => 869, - Inner::BoolArray => 1000, - Inner::ByteaArray => 1001, - Inner::CharArray => 1002, - Inner::NameArray => 1003, - Inner::Int2Array => 1005, - Inner::Int2VectorArray => 1006, - Inner::Int4Array => 1007, - Inner::RegprocArray => 1008, - Inner::TextArray => 1009, - Inner::TidArray => 1010, - Inner::XidArray => 1011, - Inner::CidArray => 1012, - Inner::OidVectorArray => 1013, - Inner::BpcharArray => 1014, - Inner::VarcharArray => 1015, - Inner::Int8Array => 1016, - Inner::PointArray => 1017, - Inner::LsegArray => 1018, - Inner::PathArray => 1019, - Inner::BoxArray => 1020, - Inner::Float4Array => 1021, - Inner::Float8Array => 1022, - Inner::PolygonArray => 1027, - Inner::OidArray => 1028, - Inner::Aclitem => 1033, - Inner::AclitemArray => 1034, - Inner::MacaddrArray => 1040, - Inner::InetArray => 1041, - Inner::Bpchar => 1042, - Inner::Varchar => 1043, - Inner::Date => 1082, - Inner::Time => 1083, - Inner::Timestamp => 1114, - Inner::TimestampArray => 1115, - Inner::DateArray => 1182, - Inner::TimeArray => 1183, - Inner::Timestamptz => 1184, - Inner::TimestamptzArray => 1185, - Inner::Interval => 1186, - Inner::IntervalArray => 1187, - Inner::NumericArray => 1231, - Inner::CstringArray => 1263, - Inner::Timetz => 1266, - Inner::TimetzArray => 1270, - Inner::Bit => 1560, - Inner::BitArray => 1561, - Inner::Varbit => 1562, - Inner::VarbitArray => 1563, - Inner::Numeric => 1700, - Inner::Refcursor => 1790, - Inner::RefcursorArray => 2201, - Inner::Regprocedure => 2202, - Inner::Regoper => 2203, - Inner::Regoperator => 2204, - Inner::Regclass => 2205, - Inner::Regtype => 2206, - Inner::RegprocedureArray => 2207, - Inner::RegoperArray => 2208, - Inner::RegoperatorArray => 2209, - Inner::RegclassArray => 2210, - Inner::RegtypeArray => 2211, - Inner::Record => 2249, - Inner::Cstring => 2275, - Inner::Any => 2276, - Inner::Anyarray => 2277, - Inner::Void => 2278, - Inner::Trigger => 2279, - Inner::LanguageHandler => 2280, - Inner::Internal => 2281, - Inner::Anyelement => 2283, - Inner::RecordArray => 2287, - Inner::Anynonarray => 2776, - Inner::TxidSnapshotArray => 2949, - Inner::Uuid => 2950, - Inner::UuidArray => 2951, - Inner::TxidSnapshot => 2970, - Inner::FdwHandler => 3115, - Inner::PgLsn => 3220, - Inner::PgLsnArray => 3221, - Inner::TsmHandler => 3310, - Inner::PgNdistinct => 3361, - Inner::PgDependencies => 3402, - Inner::Anyenum => 3500, - Inner::TsVector => 3614, - Inner::Tsquery => 3615, - Inner::GtsVector => 3642, - Inner::TsVectorArray => 3643, - Inner::GtsVectorArray => 3644, - Inner::TsqueryArray => 3645, - Inner::Regconfig => 3734, - Inner::RegconfigArray => 3735, - Inner::Regdictionary => 3769, - Inner::RegdictionaryArray => 3770, - Inner::Jsonb => 3802, - Inner::JsonbArray => 3807, - Inner::AnyRange => 3831, - Inner::EventTrigger => 3838, - Inner::Int4Range => 3904, - Inner::Int4RangeArray => 3905, - Inner::NumRange => 3906, - Inner::NumRangeArray => 3907, - Inner::TsRange => 3908, - Inner::TsRangeArray => 3909, - Inner::TstzRange => 3910, - Inner::TstzRangeArray => 3911, - Inner::DateRange => 3912, - Inner::DateRangeArray => 3913, - Inner::Int8Range => 3926, - Inner::Int8RangeArray => 3927, - Inner::Jsonpath => 4072, - Inner::JsonpathArray => 4073, - Inner::Regnamespace => 4089, - Inner::RegnamespaceArray => 4090, - Inner::Regrole => 4096, - Inner::RegroleArray => 4097, - Inner::Regcollation => 4191, - Inner::RegcollationArray => 4192, - Inner::Int4multiRange => 4451, - Inner::NummultiRange => 4532, - Inner::TsmultiRange => 4533, - Inner::TstzmultiRange => 4534, - Inner::DatemultiRange => 4535, - Inner::Int8multiRange => 4536, - Inner::AnymultiRange => 4537, - Inner::AnycompatiblemultiRange => 4538, - Inner::PgBrinBloomSummary => 4600, - Inner::PgBrinMinmaxMultiSummary => 4601, - Inner::PgMcvList => 5017, - Inner::PgSnapshot => 5038, - Inner::PgSnapshotArray => 5039, - Inner::Xid8 => 5069, - Inner::Anycompatible => 5077, - Inner::Anycompatiblearray => 5078, - Inner::Anycompatiblenonarray => 5079, - Inner::AnycompatibleRange => 5080, - Inner::Int4multiRangeArray => 6150, - Inner::NummultiRangeArray => 6151, - Inner::TsmultiRangeArray => 6152, - Inner::TstzmultiRangeArray => 6153, - Inner::DatemultiRangeArray => 6155, - Inner::Int8multiRangeArray => 6157, - Inner::Other(ref u) => u.oid, - } - } - - pub fn kind(&self) -> &Kind { - match *self { - Inner::Bool => &Kind::Simple, - Inner::Bytea => &Kind::Simple, - Inner::Char => &Kind::Simple, - Inner::Name => &Kind::Simple, - Inner::Int8 => &Kind::Simple, - Inner::Int2 => &Kind::Simple, - Inner::Int2Vector => &Kind::Array(Type(Inner::Int2)), - Inner::Int4 => &Kind::Simple, - Inner::Regproc => &Kind::Simple, - Inner::Text => &Kind::Simple, - Inner::Oid => &Kind::Simple, - Inner::Tid => &Kind::Simple, - Inner::Xid => &Kind::Simple, - Inner::Cid => &Kind::Simple, - Inner::OidVector => &Kind::Array(Type(Inner::Oid)), - Inner::PgDdlCommand => &Kind::Pseudo, - Inner::Json => &Kind::Simple, - Inner::Xml => &Kind::Simple, - Inner::XmlArray => &Kind::Array(Type(Inner::Xml)), - Inner::PgNodeTree => &Kind::Simple, - Inner::JsonArray => &Kind::Array(Type(Inner::Json)), - Inner::TableAmHandler => &Kind::Pseudo, - Inner::Xid8Array => &Kind::Array(Type(Inner::Xid8)), - Inner::IndexAmHandler => &Kind::Pseudo, - Inner::Point => &Kind::Simple, - Inner::Lseg => &Kind::Simple, - Inner::Path => &Kind::Simple, - Inner::Box => &Kind::Simple, - Inner::Polygon => &Kind::Simple, - Inner::Line => &Kind::Simple, - Inner::LineArray => &Kind::Array(Type(Inner::Line)), - Inner::Cidr => &Kind::Simple, - Inner::CidrArray => &Kind::Array(Type(Inner::Cidr)), - Inner::Float4 => &Kind::Simple, - Inner::Float8 => &Kind::Simple, - Inner::Unknown => &Kind::Simple, - Inner::Circle => &Kind::Simple, - Inner::CircleArray => &Kind::Array(Type(Inner::Circle)), - Inner::Macaddr8 => &Kind::Simple, - Inner::Macaddr8Array => &Kind::Array(Type(Inner::Macaddr8)), - Inner::Money => &Kind::Simple, - Inner::MoneyArray => &Kind::Array(Type(Inner::Money)), - Inner::Macaddr => &Kind::Simple, - Inner::Inet => &Kind::Simple, - Inner::BoolArray => &Kind::Array(Type(Inner::Bool)), - Inner::ByteaArray => &Kind::Array(Type(Inner::Bytea)), - Inner::CharArray => &Kind::Array(Type(Inner::Char)), - Inner::NameArray => &Kind::Array(Type(Inner::Name)), - Inner::Int2Array => &Kind::Array(Type(Inner::Int2)), - Inner::Int2VectorArray => &Kind::Array(Type(Inner::Int2Vector)), - Inner::Int4Array => &Kind::Array(Type(Inner::Int4)), - Inner::RegprocArray => &Kind::Array(Type(Inner::Regproc)), - Inner::TextArray => &Kind::Array(Type(Inner::Text)), - Inner::TidArray => &Kind::Array(Type(Inner::Tid)), - Inner::XidArray => &Kind::Array(Type(Inner::Xid)), - Inner::CidArray => &Kind::Array(Type(Inner::Cid)), - Inner::OidVectorArray => &Kind::Array(Type(Inner::OidVector)), - Inner::BpcharArray => &Kind::Array(Type(Inner::Bpchar)), - Inner::VarcharArray => &Kind::Array(Type(Inner::Varchar)), - Inner::Int8Array => &Kind::Array(Type(Inner::Int8)), - Inner::PointArray => &Kind::Array(Type(Inner::Point)), - Inner::LsegArray => &Kind::Array(Type(Inner::Lseg)), - Inner::PathArray => &Kind::Array(Type(Inner::Path)), - Inner::BoxArray => &Kind::Array(Type(Inner::Box)), - Inner::Float4Array => &Kind::Array(Type(Inner::Float4)), - Inner::Float8Array => &Kind::Array(Type(Inner::Float8)), - Inner::PolygonArray => &Kind::Array(Type(Inner::Polygon)), - Inner::OidArray => &Kind::Array(Type(Inner::Oid)), - Inner::Aclitem => &Kind::Simple, - Inner::AclitemArray => &Kind::Array(Type(Inner::Aclitem)), - Inner::MacaddrArray => &Kind::Array(Type(Inner::Macaddr)), - Inner::InetArray => &Kind::Array(Type(Inner::Inet)), - Inner::Bpchar => &Kind::Simple, - Inner::Varchar => &Kind::Simple, - Inner::Date => &Kind::Simple, - Inner::Time => &Kind::Simple, - Inner::Timestamp => &Kind::Simple, - Inner::TimestampArray => &Kind::Array(Type(Inner::Timestamp)), - Inner::DateArray => &Kind::Array(Type(Inner::Date)), - Inner::TimeArray => &Kind::Array(Type(Inner::Time)), - Inner::Timestamptz => &Kind::Simple, - Inner::TimestamptzArray => &Kind::Array(Type(Inner::Timestamptz)), - Inner::Interval => &Kind::Simple, - Inner::IntervalArray => &Kind::Array(Type(Inner::Interval)), - Inner::NumericArray => &Kind::Array(Type(Inner::Numeric)), - Inner::CstringArray => &Kind::Array(Type(Inner::Cstring)), - Inner::Timetz => &Kind::Simple, - Inner::TimetzArray => &Kind::Array(Type(Inner::Timetz)), - Inner::Bit => &Kind::Simple, - Inner::BitArray => &Kind::Array(Type(Inner::Bit)), - Inner::Varbit => &Kind::Simple, - Inner::VarbitArray => &Kind::Array(Type(Inner::Varbit)), - Inner::Numeric => &Kind::Simple, - Inner::Refcursor => &Kind::Simple, - Inner::RefcursorArray => &Kind::Array(Type(Inner::Refcursor)), - Inner::Regprocedure => &Kind::Simple, - Inner::Regoper => &Kind::Simple, - Inner::Regoperator => &Kind::Simple, - Inner::Regclass => &Kind::Simple, - Inner::Regtype => &Kind::Simple, - Inner::RegprocedureArray => &Kind::Array(Type(Inner::Regprocedure)), - Inner::RegoperArray => &Kind::Array(Type(Inner::Regoper)), - Inner::RegoperatorArray => &Kind::Array(Type(Inner::Regoperator)), - Inner::RegclassArray => &Kind::Array(Type(Inner::Regclass)), - Inner::RegtypeArray => &Kind::Array(Type(Inner::Regtype)), - Inner::Record => &Kind::Pseudo, - Inner::Cstring => &Kind::Pseudo, - Inner::Any => &Kind::Pseudo, - Inner::Anyarray => &Kind::Pseudo, - Inner::Void => &Kind::Pseudo, - Inner::Trigger => &Kind::Pseudo, - Inner::LanguageHandler => &Kind::Pseudo, - Inner::Internal => &Kind::Pseudo, - Inner::Anyelement => &Kind::Pseudo, - Inner::RecordArray => &Kind::Pseudo, - Inner::Anynonarray => &Kind::Pseudo, - Inner::TxidSnapshotArray => &Kind::Array(Type(Inner::TxidSnapshot)), - Inner::Uuid => &Kind::Simple, - Inner::UuidArray => &Kind::Array(Type(Inner::Uuid)), - Inner::TxidSnapshot => &Kind::Simple, - Inner::FdwHandler => &Kind::Pseudo, - Inner::PgLsn => &Kind::Simple, - Inner::PgLsnArray => &Kind::Array(Type(Inner::PgLsn)), - Inner::TsmHandler => &Kind::Pseudo, - Inner::PgNdistinct => &Kind::Simple, - Inner::PgDependencies => &Kind::Simple, - Inner::Anyenum => &Kind::Pseudo, - Inner::TsVector => &Kind::Simple, - Inner::Tsquery => &Kind::Simple, - Inner::GtsVector => &Kind::Simple, - Inner::TsVectorArray => &Kind::Array(Type(Inner::TsVector)), - Inner::GtsVectorArray => &Kind::Array(Type(Inner::GtsVector)), - Inner::TsqueryArray => &Kind::Array(Type(Inner::Tsquery)), - Inner::Regconfig => &Kind::Simple, - Inner::RegconfigArray => &Kind::Array(Type(Inner::Regconfig)), - Inner::Regdictionary => &Kind::Simple, - Inner::RegdictionaryArray => &Kind::Array(Type(Inner::Regdictionary)), - Inner::Jsonb => &Kind::Simple, - Inner::JsonbArray => &Kind::Array(Type(Inner::Jsonb)), - Inner::AnyRange => &Kind::Pseudo, - Inner::EventTrigger => &Kind::Pseudo, - Inner::Int4Range => &Kind::Range(Type(Inner::Int4)), - Inner::Int4RangeArray => &Kind::Array(Type(Inner::Int4Range)), - Inner::NumRange => &Kind::Range(Type(Inner::Numeric)), - Inner::NumRangeArray => &Kind::Array(Type(Inner::NumRange)), - Inner::TsRange => &Kind::Range(Type(Inner::Timestamp)), - Inner::TsRangeArray => &Kind::Array(Type(Inner::TsRange)), - Inner::TstzRange => &Kind::Range(Type(Inner::Timestamptz)), - Inner::TstzRangeArray => &Kind::Array(Type(Inner::TstzRange)), - Inner::DateRange => &Kind::Range(Type(Inner::Date)), - Inner::DateRangeArray => &Kind::Array(Type(Inner::DateRange)), - Inner::Int8Range => &Kind::Range(Type(Inner::Int8)), - Inner::Int8RangeArray => &Kind::Array(Type(Inner::Int8Range)), - Inner::Jsonpath => &Kind::Simple, - Inner::JsonpathArray => &Kind::Array(Type(Inner::Jsonpath)), - Inner::Regnamespace => &Kind::Simple, - Inner::RegnamespaceArray => &Kind::Array(Type(Inner::Regnamespace)), - Inner::Regrole => &Kind::Simple, - Inner::RegroleArray => &Kind::Array(Type(Inner::Regrole)), - Inner::Regcollation => &Kind::Simple, - Inner::RegcollationArray => &Kind::Array(Type(Inner::Regcollation)), - Inner::Int4multiRange => &Kind::Multirange(Type(Inner::Int4)), - Inner::NummultiRange => &Kind::Multirange(Type(Inner::Numeric)), - Inner::TsmultiRange => &Kind::Multirange(Type(Inner::Timestamp)), - Inner::TstzmultiRange => &Kind::Multirange(Type(Inner::Timestamptz)), - Inner::DatemultiRange => &Kind::Multirange(Type(Inner::Date)), - Inner::Int8multiRange => &Kind::Multirange(Type(Inner::Int8)), - Inner::AnymultiRange => &Kind::Pseudo, - Inner::AnycompatiblemultiRange => &Kind::Pseudo, - Inner::PgBrinBloomSummary => &Kind::Simple, - Inner::PgBrinMinmaxMultiSummary => &Kind::Simple, - Inner::PgMcvList => &Kind::Simple, - Inner::PgSnapshot => &Kind::Simple, - Inner::PgSnapshotArray => &Kind::Array(Type(Inner::PgSnapshot)), - Inner::Xid8 => &Kind::Simple, - Inner::Anycompatible => &Kind::Pseudo, - Inner::Anycompatiblearray => &Kind::Pseudo, - Inner::Anycompatiblenonarray => &Kind::Pseudo, - Inner::AnycompatibleRange => &Kind::Pseudo, - Inner::Int4multiRangeArray => &Kind::Array(Type(Inner::Int4multiRange)), - Inner::NummultiRangeArray => &Kind::Array(Type(Inner::NummultiRange)), - Inner::TsmultiRangeArray => &Kind::Array(Type(Inner::TsmultiRange)), - Inner::TstzmultiRangeArray => &Kind::Array(Type(Inner::TstzmultiRange)), - Inner::DatemultiRangeArray => &Kind::Array(Type(Inner::DatemultiRange)), - Inner::Int8multiRangeArray => &Kind::Array(Type(Inner::Int8multiRange)), - Inner::Other(ref u) => &u.kind, - } - } - - pub fn name(&self) -> &str { - match *self { - Inner::Bool => "bool", - Inner::Bytea => "bytea", - Inner::Char => "char", - Inner::Name => "name", - Inner::Int8 => "int8", - Inner::Int2 => "int2", - Inner::Int2Vector => "int2vector", - Inner::Int4 => "int4", - Inner::Regproc => "regproc", - Inner::Text => "text", - Inner::Oid => "oid", - Inner::Tid => "tid", - Inner::Xid => "xid", - Inner::Cid => "cid", - Inner::OidVector => "oidvector", - Inner::PgDdlCommand => "pg_ddl_command", - Inner::Json => "json", - Inner::Xml => "xml", - Inner::XmlArray => "_xml", - Inner::PgNodeTree => "pg_node_tree", - Inner::JsonArray => "_json", - Inner::TableAmHandler => "table_am_handler", - Inner::Xid8Array => "_xid8", - Inner::IndexAmHandler => "index_am_handler", - Inner::Point => "point", - Inner::Lseg => "lseg", - Inner::Path => "path", - Inner::Box => "box", - Inner::Polygon => "polygon", - Inner::Line => "line", - Inner::LineArray => "_line", - Inner::Cidr => "cidr", - Inner::CidrArray => "_cidr", - Inner::Float4 => "float4", - Inner::Float8 => "float8", - Inner::Unknown => "unknown", - Inner::Circle => "circle", - Inner::CircleArray => "_circle", - Inner::Macaddr8 => "macaddr8", - Inner::Macaddr8Array => "_macaddr8", - Inner::Money => "money", - Inner::MoneyArray => "_money", - Inner::Macaddr => "macaddr", - Inner::Inet => "inet", - Inner::BoolArray => "_bool", - Inner::ByteaArray => "_bytea", - Inner::CharArray => "_char", - Inner::NameArray => "_name", - Inner::Int2Array => "_int2", - Inner::Int2VectorArray => "_int2vector", - Inner::Int4Array => "_int4", - Inner::RegprocArray => "_regproc", - Inner::TextArray => "_text", - Inner::TidArray => "_tid", - Inner::XidArray => "_xid", - Inner::CidArray => "_cid", - Inner::OidVectorArray => "_oidvector", - Inner::BpcharArray => "_bpchar", - Inner::VarcharArray => "_varchar", - Inner::Int8Array => "_int8", - Inner::PointArray => "_point", - Inner::LsegArray => "_lseg", - Inner::PathArray => "_path", - Inner::BoxArray => "_box", - Inner::Float4Array => "_float4", - Inner::Float8Array => "_float8", - Inner::PolygonArray => "_polygon", - Inner::OidArray => "_oid", - Inner::Aclitem => "aclitem", - Inner::AclitemArray => "_aclitem", - Inner::MacaddrArray => "_macaddr", - Inner::InetArray => "_inet", - Inner::Bpchar => "bpchar", - Inner::Varchar => "varchar", - Inner::Date => "date", - Inner::Time => "time", - Inner::Timestamp => "timestamp", - Inner::TimestampArray => "_timestamp", - Inner::DateArray => "_date", - Inner::TimeArray => "_time", - Inner::Timestamptz => "timestamptz", - Inner::TimestamptzArray => "_timestamptz", - Inner::Interval => "interval", - Inner::IntervalArray => "_interval", - Inner::NumericArray => "_numeric", - Inner::CstringArray => "_cstring", - Inner::Timetz => "timetz", - Inner::TimetzArray => "_timetz", - Inner::Bit => "bit", - Inner::BitArray => "_bit", - Inner::Varbit => "varbit", - Inner::VarbitArray => "_varbit", - Inner::Numeric => "numeric", - Inner::Refcursor => "refcursor", - Inner::RefcursorArray => "_refcursor", - Inner::Regprocedure => "regprocedure", - Inner::Regoper => "regoper", - Inner::Regoperator => "regoperator", - Inner::Regclass => "regclass", - Inner::Regtype => "regtype", - Inner::RegprocedureArray => "_regprocedure", - Inner::RegoperArray => "_regoper", - Inner::RegoperatorArray => "_regoperator", - Inner::RegclassArray => "_regclass", - Inner::RegtypeArray => "_regtype", - Inner::Record => "record", - Inner::Cstring => "cstring", - Inner::Any => "any", - Inner::Anyarray => "anyarray", - Inner::Void => "void", - Inner::Trigger => "trigger", - Inner::LanguageHandler => "language_handler", - Inner::Internal => "internal", - Inner::Anyelement => "anyelement", - Inner::RecordArray => "_record", - Inner::Anynonarray => "anynonarray", - Inner::TxidSnapshotArray => "_txid_snapshot", - Inner::Uuid => "uuid", - Inner::UuidArray => "_uuid", - Inner::TxidSnapshot => "txid_snapshot", - Inner::FdwHandler => "fdw_handler", - Inner::PgLsn => "pg_lsn", - Inner::PgLsnArray => "_pg_lsn", - Inner::TsmHandler => "tsm_handler", - Inner::PgNdistinct => "pg_ndistinct", - Inner::PgDependencies => "pg_dependencies", - Inner::Anyenum => "anyenum", - Inner::TsVector => "tsvector", - Inner::Tsquery => "tsquery", - Inner::GtsVector => "gtsvector", - Inner::TsVectorArray => "_tsvector", - Inner::GtsVectorArray => "_gtsvector", - Inner::TsqueryArray => "_tsquery", - Inner::Regconfig => "regconfig", - Inner::RegconfigArray => "_regconfig", - Inner::Regdictionary => "regdictionary", - Inner::RegdictionaryArray => "_regdictionary", - Inner::Jsonb => "jsonb", - Inner::JsonbArray => "_jsonb", - Inner::AnyRange => "anyrange", - Inner::EventTrigger => "event_trigger", - Inner::Int4Range => "int4range", - Inner::Int4RangeArray => "_int4range", - Inner::NumRange => "numrange", - Inner::NumRangeArray => "_numrange", - Inner::TsRange => "tsrange", - Inner::TsRangeArray => "_tsrange", - Inner::TstzRange => "tstzrange", - Inner::TstzRangeArray => "_tstzrange", - Inner::DateRange => "daterange", - Inner::DateRangeArray => "_daterange", - Inner::Int8Range => "int8range", - Inner::Int8RangeArray => "_int8range", - Inner::Jsonpath => "jsonpath", - Inner::JsonpathArray => "_jsonpath", - Inner::Regnamespace => "regnamespace", - Inner::RegnamespaceArray => "_regnamespace", - Inner::Regrole => "regrole", - Inner::RegroleArray => "_regrole", - Inner::Regcollation => "regcollation", - Inner::RegcollationArray => "_regcollation", - Inner::Int4multiRange => "int4multirange", - Inner::NummultiRange => "nummultirange", - Inner::TsmultiRange => "tsmultirange", - Inner::TstzmultiRange => "tstzmultirange", - Inner::DatemultiRange => "datemultirange", - Inner::Int8multiRange => "int8multirange", - Inner::AnymultiRange => "anymultirange", - Inner::AnycompatiblemultiRange => "anycompatiblemultirange", - Inner::PgBrinBloomSummary => "pg_brin_bloom_summary", - Inner::PgBrinMinmaxMultiSummary => "pg_brin_minmax_multi_summary", - Inner::PgMcvList => "pg_mcv_list", - Inner::PgSnapshot => "pg_snapshot", - Inner::PgSnapshotArray => "_pg_snapshot", - Inner::Xid8 => "xid8", - Inner::Anycompatible => "anycompatible", - Inner::Anycompatiblearray => "anycompatiblearray", - Inner::Anycompatiblenonarray => "anycompatiblenonarray", - Inner::AnycompatibleRange => "anycompatiblerange", - Inner::Int4multiRangeArray => "_int4multirange", - Inner::NummultiRangeArray => "_nummultirange", - Inner::TsmultiRangeArray => "_tsmultirange", - Inner::TstzmultiRangeArray => "_tstzmultirange", - Inner::DatemultiRangeArray => "_datemultirange", - Inner::Int8multiRangeArray => "_int8multirange", - Inner::Other(ref u) => &u.name, - } - } -} -impl Type { - /// BOOL - boolean, 'true'/'false' - pub const BOOL: Type = Type(Inner::Bool); - - /// BYTEA - variable-length string, binary values escaped - pub const BYTEA: Type = Type(Inner::Bytea); - - /// CHAR - single character - pub const CHAR: Type = Type(Inner::Char); - - /// NAME - 63-byte type for storing system identifiers - pub const NAME: Type = Type(Inner::Name); - - /// INT8 - ~18 digit integer, 8-byte storage - pub const INT8: Type = Type(Inner::Int8); - - /// INT2 - -32 thousand to 32 thousand, 2-byte storage - pub const INT2: Type = Type(Inner::Int2); - - /// INT2VECTOR - array of int2, used in system tables - pub const INT2_VECTOR: Type = Type(Inner::Int2Vector); - - /// INT4 - -2 billion to 2 billion integer, 4-byte storage - pub const INT4: Type = Type(Inner::Int4); - - /// REGPROC - registered procedure - pub const REGPROC: Type = Type(Inner::Regproc); - - /// TEXT - variable-length string, no limit specified - pub const TEXT: Type = Type(Inner::Text); - - /// OID - object identifier(oid), maximum 4 billion - pub const OID: Type = Type(Inner::Oid); - - /// TID - (block, offset), physical location of tuple - pub const TID: Type = Type(Inner::Tid); - - /// XID - transaction id - pub const XID: Type = Type(Inner::Xid); - - /// CID - command identifier type, sequence in transaction id - pub const CID: Type = Type(Inner::Cid); - - /// OIDVECTOR - array of oids, used in system tables - pub const OID_VECTOR: Type = Type(Inner::OidVector); - - /// PG_DDL_COMMAND - internal type for passing CollectedCommand - pub const PG_DDL_COMMAND: Type = Type(Inner::PgDdlCommand); - - /// JSON - JSON stored as text - pub const JSON: Type = Type(Inner::Json); - - /// XML - XML content - pub const XML: Type = Type(Inner::Xml); - - /// XML[] - pub const XML_ARRAY: Type = Type(Inner::XmlArray); - - /// PG_NODE_TREE - string representing an internal node tree - pub const PG_NODE_TREE: Type = Type(Inner::PgNodeTree); - - /// JSON[] - pub const JSON_ARRAY: Type = Type(Inner::JsonArray); - - /// TABLE_AM_HANDLER - pub const TABLE_AM_HANDLER: Type = Type(Inner::TableAmHandler); - - /// XID8[] - pub const XID8_ARRAY: Type = Type(Inner::Xid8Array); - - /// INDEX_AM_HANDLER - pseudo-type for the result of an index AM handler function - pub const INDEX_AM_HANDLER: Type = Type(Inner::IndexAmHandler); - - /// POINT - geometric point '(x, y)' - pub const POINT: Type = Type(Inner::Point); - - /// LSEG - geometric line segment '(pt1,pt2)' - pub const LSEG: Type = Type(Inner::Lseg); - - /// PATH - geometric path '(pt1,...)' - pub const PATH: Type = Type(Inner::Path); - - /// BOX - geometric box '(lower left,upper right)' - pub const BOX: Type = Type(Inner::Box); - - /// POLYGON - geometric polygon '(pt1,...)' - pub const POLYGON: Type = Type(Inner::Polygon); - - /// LINE - geometric line - pub const LINE: Type = Type(Inner::Line); - - /// LINE[] - pub const LINE_ARRAY: Type = Type(Inner::LineArray); - - /// CIDR - network IP address/netmask, network address - pub const CIDR: Type = Type(Inner::Cidr); - - /// CIDR[] - pub const CIDR_ARRAY: Type = Type(Inner::CidrArray); - - /// FLOAT4 - single-precision floating point number, 4-byte storage - pub const FLOAT4: Type = Type(Inner::Float4); - - /// FLOAT8 - double-precision floating point number, 8-byte storage - pub const FLOAT8: Type = Type(Inner::Float8); - - /// UNKNOWN - pseudo-type representing an undetermined type - pub const UNKNOWN: Type = Type(Inner::Unknown); - - /// CIRCLE - geometric circle '(center,radius)' - pub const CIRCLE: Type = Type(Inner::Circle); - - /// CIRCLE[] - pub const CIRCLE_ARRAY: Type = Type(Inner::CircleArray); - - /// MACADDR8 - XX:XX:XX:XX:XX:XX:XX:XX, MAC address - pub const MACADDR8: Type = Type(Inner::Macaddr8); - - /// MACADDR8[] - pub const MACADDR8_ARRAY: Type = Type(Inner::Macaddr8Array); - - /// MONEY - monetary amounts, $d,ddd.cc - pub const MONEY: Type = Type(Inner::Money); - - /// MONEY[] - pub const MONEY_ARRAY: Type = Type(Inner::MoneyArray); - - /// MACADDR - XX:XX:XX:XX:XX:XX, MAC address - pub const MACADDR: Type = Type(Inner::Macaddr); - - /// INET - IP address/netmask, host address, netmask optional - pub const INET: Type = Type(Inner::Inet); - - /// BOOL[] - pub const BOOL_ARRAY: Type = Type(Inner::BoolArray); - - /// BYTEA[] - pub const BYTEA_ARRAY: Type = Type(Inner::ByteaArray); - - /// CHAR[] - pub const CHAR_ARRAY: Type = Type(Inner::CharArray); - - /// NAME[] - pub const NAME_ARRAY: Type = Type(Inner::NameArray); - - /// INT2[] - pub const INT2_ARRAY: Type = Type(Inner::Int2Array); - - /// INT2VECTOR[] - pub const INT2_VECTOR_ARRAY: Type = Type(Inner::Int2VectorArray); - - /// INT4[] - pub const INT4_ARRAY: Type = Type(Inner::Int4Array); - - /// REGPROC[] - pub const REGPROC_ARRAY: Type = Type(Inner::RegprocArray); - - /// TEXT[] - pub const TEXT_ARRAY: Type = Type(Inner::TextArray); - - /// TID[] - pub const TID_ARRAY: Type = Type(Inner::TidArray); - - /// XID[] - pub const XID_ARRAY: Type = Type(Inner::XidArray); - - /// CID[] - pub const CID_ARRAY: Type = Type(Inner::CidArray); - - /// OIDVECTOR[] - pub const OID_VECTOR_ARRAY: Type = Type(Inner::OidVectorArray); - - /// BPCHAR[] - pub const BPCHAR_ARRAY: Type = Type(Inner::BpcharArray); - - /// VARCHAR[] - pub const VARCHAR_ARRAY: Type = Type(Inner::VarcharArray); - - /// INT8[] - pub const INT8_ARRAY: Type = Type(Inner::Int8Array); - - /// POINT[] - pub const POINT_ARRAY: Type = Type(Inner::PointArray); - - /// LSEG[] - pub const LSEG_ARRAY: Type = Type(Inner::LsegArray); - - /// PATH[] - pub const PATH_ARRAY: Type = Type(Inner::PathArray); - - /// BOX[] - pub const BOX_ARRAY: Type = Type(Inner::BoxArray); - - /// FLOAT4[] - pub const FLOAT4_ARRAY: Type = Type(Inner::Float4Array); - - /// FLOAT8[] - pub const FLOAT8_ARRAY: Type = Type(Inner::Float8Array); - - /// POLYGON[] - pub const POLYGON_ARRAY: Type = Type(Inner::PolygonArray); - - /// OID[] - pub const OID_ARRAY: Type = Type(Inner::OidArray); - - /// ACLITEM - access control list - pub const ACLITEM: Type = Type(Inner::Aclitem); - - /// ACLITEM[] - pub const ACLITEM_ARRAY: Type = Type(Inner::AclitemArray); - - /// MACADDR[] - pub const MACADDR_ARRAY: Type = Type(Inner::MacaddrArray); - - /// INET[] - pub const INET_ARRAY: Type = Type(Inner::InetArray); - - /// BPCHAR - char(length), blank-padded string, fixed storage length - pub const BPCHAR: Type = Type(Inner::Bpchar); - - /// VARCHAR - varchar(length), non-blank-padded string, variable storage length - pub const VARCHAR: Type = Type(Inner::Varchar); - - /// DATE - date - pub const DATE: Type = Type(Inner::Date); - - /// TIME - time of day - pub const TIME: Type = Type(Inner::Time); - - /// TIMESTAMP - date and time - pub const TIMESTAMP: Type = Type(Inner::Timestamp); - - /// TIMESTAMP[] - pub const TIMESTAMP_ARRAY: Type = Type(Inner::TimestampArray); - - /// DATE[] - pub const DATE_ARRAY: Type = Type(Inner::DateArray); - - /// TIME[] - pub const TIME_ARRAY: Type = Type(Inner::TimeArray); - - /// TIMESTAMPTZ - date and time with time zone - pub const TIMESTAMPTZ: Type = Type(Inner::Timestamptz); - - /// TIMESTAMPTZ[] - pub const TIMESTAMPTZ_ARRAY: Type = Type(Inner::TimestamptzArray); - - /// INTERVAL - @ <number> <units>, time interval - pub const INTERVAL: Type = Type(Inner::Interval); - - /// INTERVAL[] - pub const INTERVAL_ARRAY: Type = Type(Inner::IntervalArray); - - /// NUMERIC[] - pub const NUMERIC_ARRAY: Type = Type(Inner::NumericArray); - - /// CSTRING[] - pub const CSTRING_ARRAY: Type = Type(Inner::CstringArray); - - /// TIMETZ - time of day with time zone - pub const TIMETZ: Type = Type(Inner::Timetz); - - /// TIMETZ[] - pub const TIMETZ_ARRAY: Type = Type(Inner::TimetzArray); - - /// BIT - fixed-length bit string - pub const BIT: Type = Type(Inner::Bit); - - /// BIT[] - pub const BIT_ARRAY: Type = Type(Inner::BitArray); - - /// VARBIT - variable-length bit string - pub const VARBIT: Type = Type(Inner::Varbit); - - /// VARBIT[] - pub const VARBIT_ARRAY: Type = Type(Inner::VarbitArray); - - /// NUMERIC - numeric(precision, decimal), arbitrary precision number - pub const NUMERIC: Type = Type(Inner::Numeric); - - /// REFCURSOR - reference to cursor (portal name) - pub const REFCURSOR: Type = Type(Inner::Refcursor); - - /// REFCURSOR[] - pub const REFCURSOR_ARRAY: Type = Type(Inner::RefcursorArray); - - /// REGPROCEDURE - registered procedure (with args) - pub const REGPROCEDURE: Type = Type(Inner::Regprocedure); - - /// REGOPER - registered operator - pub const REGOPER: Type = Type(Inner::Regoper); - - /// REGOPERATOR - registered operator (with args) - pub const REGOPERATOR: Type = Type(Inner::Regoperator); - - /// REGCLASS - registered class - pub const REGCLASS: Type = Type(Inner::Regclass); - - /// REGTYPE - registered type - pub const REGTYPE: Type = Type(Inner::Regtype); - - /// REGPROCEDURE[] - pub const REGPROCEDURE_ARRAY: Type = Type(Inner::RegprocedureArray); - - /// REGOPER[] - pub const REGOPER_ARRAY: Type = Type(Inner::RegoperArray); - - /// REGOPERATOR[] - pub const REGOPERATOR_ARRAY: Type = Type(Inner::RegoperatorArray); - - /// REGCLASS[] - pub const REGCLASS_ARRAY: Type = Type(Inner::RegclassArray); - - /// REGTYPE[] - pub const REGTYPE_ARRAY: Type = Type(Inner::RegtypeArray); - - /// RECORD - pseudo-type representing any composite type - pub const RECORD: Type = Type(Inner::Record); - - /// CSTRING - C-style string - pub const CSTRING: Type = Type(Inner::Cstring); - - /// ANY - pseudo-type representing any type - pub const ANY: Type = Type(Inner::Any); - - /// ANYARRAY - pseudo-type representing a polymorphic array type - pub const ANYARRAY: Type = Type(Inner::Anyarray); - - /// VOID - pseudo-type for the result of a function with no real result - pub const VOID: Type = Type(Inner::Void); - - /// TRIGGER - pseudo-type for the result of a trigger function - pub const TRIGGER: Type = Type(Inner::Trigger); - - /// LANGUAGE_HANDLER - pseudo-type for the result of a language handler function - pub const LANGUAGE_HANDLER: Type = Type(Inner::LanguageHandler); - - /// INTERNAL - pseudo-type representing an internal data structure - pub const INTERNAL: Type = Type(Inner::Internal); - - /// ANYELEMENT - pseudo-type representing a polymorphic base type - pub const ANYELEMENT: Type = Type(Inner::Anyelement); - - /// RECORD[] - pub const RECORD_ARRAY: Type = Type(Inner::RecordArray); - - /// ANYNONARRAY - pseudo-type representing a polymorphic base type that is not an array - pub const ANYNONARRAY: Type = Type(Inner::Anynonarray); - - /// TXID_SNAPSHOT[] - pub const TXID_SNAPSHOT_ARRAY: Type = Type(Inner::TxidSnapshotArray); - - /// UUID - UUID datatype - pub const UUID: Type = Type(Inner::Uuid); - - /// UUID[] - pub const UUID_ARRAY: Type = Type(Inner::UuidArray); - - /// TXID_SNAPSHOT - txid snapshot - pub const TXID_SNAPSHOT: Type = Type(Inner::TxidSnapshot); - - /// FDW_HANDLER - pseudo-type for the result of an FDW handler function - pub const FDW_HANDLER: Type = Type(Inner::FdwHandler); - - /// PG_LSN - PostgreSQL LSN datatype - pub const PG_LSN: Type = Type(Inner::PgLsn); - - /// PG_LSN[] - pub const PG_LSN_ARRAY: Type = Type(Inner::PgLsnArray); - - /// TSM_HANDLER - pseudo-type for the result of a tablesample method function - pub const TSM_HANDLER: Type = Type(Inner::TsmHandler); - - /// PG_NDISTINCT - multivariate ndistinct coefficients - pub const PG_NDISTINCT: Type = Type(Inner::PgNdistinct); - - /// PG_DEPENDENCIES - multivariate dependencies - pub const PG_DEPENDENCIES: Type = Type(Inner::PgDependencies); - - /// ANYENUM - pseudo-type representing a polymorphic base type that is an enum - pub const ANYENUM: Type = Type(Inner::Anyenum); - - /// TSVECTOR - text representation for text search - pub const TS_VECTOR: Type = Type(Inner::TsVector); - - /// TSQUERY - query representation for text search - pub const TSQUERY: Type = Type(Inner::Tsquery); - - /// GTSVECTOR - GiST index internal text representation for text search - pub const GTS_VECTOR: Type = Type(Inner::GtsVector); - - /// TSVECTOR[] - pub const TS_VECTOR_ARRAY: Type = Type(Inner::TsVectorArray); - - /// GTSVECTOR[] - pub const GTS_VECTOR_ARRAY: Type = Type(Inner::GtsVectorArray); - - /// TSQUERY[] - pub const TSQUERY_ARRAY: Type = Type(Inner::TsqueryArray); - - /// REGCONFIG - registered text search configuration - pub const REGCONFIG: Type = Type(Inner::Regconfig); - - /// REGCONFIG[] - pub const REGCONFIG_ARRAY: Type = Type(Inner::RegconfigArray); - - /// REGDICTIONARY - registered text search dictionary - pub const REGDICTIONARY: Type = Type(Inner::Regdictionary); - - /// REGDICTIONARY[] - pub const REGDICTIONARY_ARRAY: Type = Type(Inner::RegdictionaryArray); - - /// JSONB - Binary JSON - pub const JSONB: Type = Type(Inner::Jsonb); - - /// JSONB[] - pub const JSONB_ARRAY: Type = Type(Inner::JsonbArray); - - /// ANYRANGE - pseudo-type representing a range over a polymorphic base type - pub const ANY_RANGE: Type = Type(Inner::AnyRange); - - /// EVENT_TRIGGER - pseudo-type for the result of an event trigger function - pub const EVENT_TRIGGER: Type = Type(Inner::EventTrigger); - - /// INT4RANGE - range of integers - pub const INT4_RANGE: Type = Type(Inner::Int4Range); - - /// INT4RANGE[] - pub const INT4_RANGE_ARRAY: Type = Type(Inner::Int4RangeArray); - - /// NUMRANGE - range of numerics - pub const NUM_RANGE: Type = Type(Inner::NumRange); - - /// NUMRANGE[] - pub const NUM_RANGE_ARRAY: Type = Type(Inner::NumRangeArray); - - /// TSRANGE - range of timestamps without time zone - pub const TS_RANGE: Type = Type(Inner::TsRange); - - /// TSRANGE[] - pub const TS_RANGE_ARRAY: Type = Type(Inner::TsRangeArray); - - /// TSTZRANGE - range of timestamps with time zone - pub const TSTZ_RANGE: Type = Type(Inner::TstzRange); - - /// TSTZRANGE[] - pub const TSTZ_RANGE_ARRAY: Type = Type(Inner::TstzRangeArray); - - /// DATERANGE - range of dates - pub const DATE_RANGE: Type = Type(Inner::DateRange); - - /// DATERANGE[] - pub const DATE_RANGE_ARRAY: Type = Type(Inner::DateRangeArray); - - /// INT8RANGE - range of bigints - pub const INT8_RANGE: Type = Type(Inner::Int8Range); - - /// INT8RANGE[] - pub const INT8_RANGE_ARRAY: Type = Type(Inner::Int8RangeArray); - - /// JSONPATH - JSON path - pub const JSONPATH: Type = Type(Inner::Jsonpath); - - /// JSONPATH[] - pub const JSONPATH_ARRAY: Type = Type(Inner::JsonpathArray); - - /// REGNAMESPACE - registered namespace - pub const REGNAMESPACE: Type = Type(Inner::Regnamespace); - - /// REGNAMESPACE[] - pub const REGNAMESPACE_ARRAY: Type = Type(Inner::RegnamespaceArray); - - /// REGROLE - registered role - pub const REGROLE: Type = Type(Inner::Regrole); - - /// REGROLE[] - pub const REGROLE_ARRAY: Type = Type(Inner::RegroleArray); - - /// REGCOLLATION - registered collation - pub const REGCOLLATION: Type = Type(Inner::Regcollation); - - /// REGCOLLATION[] - pub const REGCOLLATION_ARRAY: Type = Type(Inner::RegcollationArray); - - /// INT4MULTIRANGE - multirange of integers - pub const INT4MULTI_RANGE: Type = Type(Inner::Int4multiRange); - - /// NUMMULTIRANGE - multirange of numerics - pub const NUMMULTI_RANGE: Type = Type(Inner::NummultiRange); - - /// TSMULTIRANGE - multirange of timestamps without time zone - pub const TSMULTI_RANGE: Type = Type(Inner::TsmultiRange); - - /// TSTZMULTIRANGE - multirange of timestamps with time zone - pub const TSTZMULTI_RANGE: Type = Type(Inner::TstzmultiRange); - - /// DATEMULTIRANGE - multirange of dates - pub const DATEMULTI_RANGE: Type = Type(Inner::DatemultiRange); - - /// INT8MULTIRANGE - multirange of bigints - pub const INT8MULTI_RANGE: Type = Type(Inner::Int8multiRange); - - /// ANYMULTIRANGE - pseudo-type representing a polymorphic base type that is a multirange - pub const ANYMULTI_RANGE: Type = Type(Inner::AnymultiRange); - - /// ANYCOMPATIBLEMULTIRANGE - pseudo-type representing a multirange over a polymorphic common type - pub const ANYCOMPATIBLEMULTI_RANGE: Type = Type(Inner::AnycompatiblemultiRange); - - /// PG_BRIN_BLOOM_SUMMARY - BRIN bloom summary - pub const PG_BRIN_BLOOM_SUMMARY: Type = Type(Inner::PgBrinBloomSummary); - - /// PG_BRIN_MINMAX_MULTI_SUMMARY - BRIN minmax-multi summary - pub const PG_BRIN_MINMAX_MULTI_SUMMARY: Type = Type(Inner::PgBrinMinmaxMultiSummary); - - /// PG_MCV_LIST - multivariate MCV list - pub const PG_MCV_LIST: Type = Type(Inner::PgMcvList); - - /// PG_SNAPSHOT - snapshot - pub const PG_SNAPSHOT: Type = Type(Inner::PgSnapshot); - - /// PG_SNAPSHOT[] - pub const PG_SNAPSHOT_ARRAY: Type = Type(Inner::PgSnapshotArray); - - /// XID8 - full transaction id - pub const XID8: Type = Type(Inner::Xid8); - - /// ANYCOMPATIBLE - pseudo-type representing a polymorphic common type - pub const ANYCOMPATIBLE: Type = Type(Inner::Anycompatible); - - /// ANYCOMPATIBLEARRAY - pseudo-type representing an array of polymorphic common type elements - pub const ANYCOMPATIBLEARRAY: Type = Type(Inner::Anycompatiblearray); - - /// ANYCOMPATIBLENONARRAY - pseudo-type representing a polymorphic common type that is not an array - pub const ANYCOMPATIBLENONARRAY: Type = Type(Inner::Anycompatiblenonarray); - - /// ANYCOMPATIBLERANGE - pseudo-type representing a range over a polymorphic common type - pub const ANYCOMPATIBLE_RANGE: Type = Type(Inner::AnycompatibleRange); - - /// INT4MULTIRANGE[] - pub const INT4MULTI_RANGE_ARRAY: Type = Type(Inner::Int4multiRangeArray); - - /// NUMMULTIRANGE[] - pub const NUMMULTI_RANGE_ARRAY: Type = Type(Inner::NummultiRangeArray); - - /// TSMULTIRANGE[] - pub const TSMULTI_RANGE_ARRAY: Type = Type(Inner::TsmultiRangeArray); - - /// TSTZMULTIRANGE[] - pub const TSTZMULTI_RANGE_ARRAY: Type = Type(Inner::TstzmultiRangeArray); - - /// DATEMULTIRANGE[] - pub const DATEMULTI_RANGE_ARRAY: Type = Type(Inner::DatemultiRangeArray); - - /// INT8MULTIRANGE[] - pub const INT8MULTI_RANGE_ARRAY: Type = Type(Inner::Int8multiRangeArray); -} diff --git a/proxy/src/pg_client/prepare.rs b/proxy/src/pg_client/prepare.rs index 73dd3a7661..a7d6b13602 100644 --- a/proxy/src/pg_client/prepare.rs +++ b/proxy/src/pg_client/prepare.rs @@ -1,21 +1,14 @@ -// use crate::client::InnerClient; -// use crate::codec::FrontendMessage; -// use crate::connection::RequestMessages; -// use crate::error::SqlState; -// use crate::types::{Field, Kind, Oid, Type}; -// use crate::{query, slice_iter}; -// use crate::{Column, Error, Statement}; -use bytes::Bytes; use fallible_iterator::FallibleIterator; -// use futures_util::{pin_mut, TryStreamExt}; -// use log::debug; -use postgres_protocol::message::backend::Message; +use futures::StreamExt; +use postgres_protocol::message::backend::{DataRowRanges, Message}; use postgres_protocol::message::frontend; -use tokio_postgres::types::Type; use std::future::Future; use std::pin::Pin; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio_postgres::types::{Field, Kind, Oid, ToSql, Type}; + +use super::connection::Connection; +use super::error::Error; const TYPEINFO_QUERY: &str = "\ SELECT t.typname, t.typtype, t.typelem, r.rngsubtype, t.typbasetype, n.nspname, t.typrelid @@ -25,14 +18,6 @@ INNER JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid WHERE t.oid = $1 "; -// Range types weren't added until Postgres 9.2, so pg_range may not exist -const TYPEINFO_FALLBACK_QUERY: &str = "\ -SELECT t.typname, t.typtype, t.typelem, NULL::OID, t.typbasetype, n.nspname, t.typrelid -FROM pg_catalog.pg_type t -INNER JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid -WHERE t.oid = $1 -"; - const TYPEINFO_ENUM_QUERY: &str = "\ SELECT enumlabel FROM pg_catalog.pg_enum @@ -40,14 +25,6 @@ WHERE enumtypid = $1 ORDER BY enumsortorder "; -// Postgres 9.0 didn't have enumsortorder -const TYPEINFO_ENUM_FALLBACK_QUERY: &str = "\ -SELECT enumlabel -FROM pg_catalog.pg_enum -WHERE enumtypid = $1 -ORDER BY oid -"; - const TYPEINFO_COMPOSITE_QUERY: &str = "\ SELECT attname, atttypid FROM pg_catalog.pg_attribute @@ -57,207 +34,255 @@ AND attnum > 0 ORDER BY attnum "; -static NEXT_ID: AtomicUsize = AtomicUsize::new(0); - -// pub async fn prepare( -// client: &Arc, -// query: &str, -// types: &[Type], -// ) -> Result { -// let name = format!("s{}", NEXT_ID.fetch_add(1, Ordering::SeqCst)); -// let buf = encode(client, &name, query, types)?; -// let mut responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?; - -// match responses.next().await? { -// Message::ParseComplete => {} -// _ => return Err(Error::unexpected_message()), -// } - -// let parameter_description = match responses.next().await? { -// Message::ParameterDescription(body) => body, -// _ => return Err(Error::unexpected_message()), -// }; - -// let row_description = match responses.next().await? { -// Message::RowDescription(body) => Some(body), -// Message::NoData => None, -// _ => return Err(Error::unexpected_message()), -// }; - -// let mut parameters = vec![]; -// let mut it = parameter_description.parameters(); -// while let Some(oid) = it.next().map_err(Error::parse)? { -// let type_ = get_type(client, oid).await?; -// parameters.push(type_); -// } - -// let mut columns = vec![]; -// if let Some(row_description) = row_description { -// let mut it = row_description.fields(); -// while let Some(field) = it.next().map_err(Error::parse)? { -// let type_ = get_type(client, field.type_oid()).await?; -// let column = Column::new(field.name().to_string(), type_, field); -// columns.push(column); -// } -// } - -// Ok(Statement::new(client, name, parameters, columns)) -// } - -// fn prepare_rec<'a>( -// client: &'a Arc, -// query: &'a str, -// types: &'a [Type], -// ) -> Pin> + 'a + Send>> { -// Box::pin(prepare(client, query, types)) -// } - -// fn encode(client: &InnerClient, name: &str, query: &str, types: &[Type]) -> Result { -// if types.is_empty() { -// debug!("preparing query {}: {}", name, query); -// } else { -// debug!("preparing query {} with types {:?}: {}", name, types, query); -// } - -// client.with_buf(|buf| { -// frontend::parse(name, query, types.iter().map(Type::oid), buf).map_err(Error::encode)?; -// frontend::describe(b'S', name, buf).map_err(Error::encode)?; -// frontend::sync(buf); -// Ok(buf.split().freeze()) -// }) -// } - -pub async fn get_type(client: &Arc, oid: Oid) -> Result { - if let Some(type_) = Type::from_oid(oid) { - return Ok(type_); - } - - if let Some(type_) = client.type_(oid) { - return Ok(type_); - } - - let stmt = typeinfo_statement(client).await?; - - let rows = query::query(client, stmt, slice_iter(&[&oid])).await?; - pin_mut!(rows); - - let row = match rows.try_next().await? { - Some(row) => row, - None => return Err(Error::unexpected_message()), - }; - - let name: String = row.try_get(0)?; - let type_: i8 = row.try_get(1)?; - let elem_oid: Oid = row.try_get(2)?; - let rngsubtype: Option = row.try_get(3)?; - let basetype: Oid = row.try_get(4)?; - let schema: String = row.try_get(5)?; - let relid: Oid = row.try_get(6)?; - - let kind = if type_ == b'e' as i8 { - let variants = get_enum_variants(client, oid).await?; - Kind::Enum(variants) - } else if type_ == b'p' as i8 { - Kind::Pseudo - } else if basetype != 0 { - let type_ = get_type_rec(client, basetype).await?; - Kind::Domain(type_) - } else if elem_oid != 0 { - let type_ = get_type_rec(client, elem_oid).await?; - Kind::Array(type_) - } else if relid != 0 { - let fields = get_composite_fields(client, relid).await?; - Kind::Composite(fields) - } else if let Some(rngsubtype) = rngsubtype { - let type_ = get_type_rec(client, rngsubtype).await?; - Kind::Range(type_) - } else { - Kind::Simple - }; - - let type_ = Type::new(name, oid, kind, schema); - client.set_type(oid, &type_); - - Ok(type_) +#[derive(Clone)] +pub struct TypeinfoPreparedQueries { + query: String, + enum_query: String, + composite_query: String, } -fn get_type_rec<'a>( - client: &'a Arc, - oid: Oid, -) -> Pin> + Send + 'a>> { - Box::pin(get_type(client, oid)) +fn map_is_null(x: tokio_postgres::types::IsNull) -> postgres_protocol::IsNull { + match x { + tokio_postgres::types::IsNull::Yes => postgres_protocol::IsNull::Yes, + tokio_postgres::types::IsNull::No => postgres_protocol::IsNull::No, + } } -async fn typeinfo_statement(client: &Arc) -> Result { - if let Some(stmt) = client.typeinfo() { - return Ok(stmt); +fn read_column<'a, T: tokio_postgres::types::FromSql<'a>>( + buffer: &'a [u8], + type_: &Type, + ranges: &mut DataRowRanges<'a>, +) -> Result { + let range = ranges.next()?; + match range { + Some(range) => T::from_sql_nullable(type_, range.map(|r| &buffer[r])), + None => T::from_sql_null(type_), } + .map_err(|e| Error::from_sql(e, 0)) +} - let stmt = match prepare_rec(client, TYPEINFO_QUERY, &[]).await { - Ok(stmt) => stmt, - Err(ref e) if e.code() == Some(&SqlState::UNDEFINED_TABLE) => { - prepare_rec(client, TYPEINFO_FALLBACK_QUERY, &[]).await? +impl TypeinfoPreparedQueries { + pub async fn new< + S: AsyncRead + AsyncWrite + Unpin + Send, + T: AsyncRead + AsyncWrite + Unpin + Send, + >( + c: &mut Connection, + ) -> Result { + if let Some(ti) = &c.typeinfo { + return Ok(ti.clone()); } - Err(e) => return Err(e), - }; - client.set_typeinfo(&stmt); - Ok(stmt) -} + let query = c.statement_name(); + let enum_query = c.statement_name(); + let composite_query = c.statement_name(); -async fn get_enum_variants(client: &Arc, oid: Oid) -> Result, Error> { - let stmt = typeinfo_enum_statement(client).await?; + frontend::parse(&query, TYPEINFO_QUERY, [Type::OID.oid()], &mut c.raw.buf)?; + frontend::parse( + &enum_query, + TYPEINFO_ENUM_QUERY, + [Type::OID.oid()], + &mut c.raw.buf, + )?; + c.sync().await?; + frontend::parse( + &composite_query, + TYPEINFO_COMPOSITE_QUERY, + [Type::OID.oid()], + &mut c.raw.buf, + )?; + c.sync().await?; - query::query(client, stmt, slice_iter(&[&oid])) - .await? - .and_then(|row| async move { row.try_get(0) }) - .try_collect() - .await -} + let Message::ParseComplete = c.raw.next_message().await? else { return Err(Error::expecting("parse")) }; + let Message::ParseComplete = c.raw.next_message().await? else { return Err(Error::expecting("parse")) }; + let Message::ParseComplete = c.raw.next_message().await? else { return Err(Error::expecting("parse")) }; + c.wait_for_ready().await?; -async fn typeinfo_enum_statement(client: &Arc) -> Result { - if let Some(stmt) = client.typeinfo_enum() { - return Ok(stmt); + Ok(c.typeinfo + .insert(TypeinfoPreparedQueries { + query, + enum_query, + composite_query, + }) + .clone()) } - let stmt = match prepare_rec(client, TYPEINFO_ENUM_QUERY, &[]).await { - Ok(stmt) => stmt, - Err(ref e) if e.code() == Some(&SqlState::UNDEFINED_COLUMN) => { - prepare_rec(client, TYPEINFO_ENUM_FALLBACK_QUERY, &[]).await? + fn get_type_rec< + S: AsyncRead + AsyncWrite + Unpin + Send, + T: AsyncRead + AsyncWrite + Unpin + Send, + >( + c: &mut Connection, + oid: Oid, + ) -> Pin> + Send + '_>> { + Box::pin(Self::get_type(c, oid)) + } + + pub async fn get_type< + S: AsyncRead + AsyncWrite + Unpin + Send, + T: AsyncRead + AsyncWrite + Unpin + Send, + >( + c: &mut Connection, + oid: Oid, + ) -> Result { + if let Some(type_) = Type::from_oid(oid) { + return Ok(type_); } - Err(e) => return Err(e), - }; - client.set_typeinfo_enum(&stmt); - Ok(stmt) -} + if let Some(type_) = c.typecache.get(&oid) { + return Ok(type_.clone()); + } -async fn get_composite_fields(client: &Arc, oid: Oid) -> Result, Error> { - let stmt = typeinfo_composite_statement(client).await?; + let queries = Self::new(c).await?; - let rows = query::query(client, stmt, slice_iter(&[&oid])) - .await? - .try_collect::>() - .await?; + frontend::bind( + "", + &queries.query, + [1], // the only parameter is in binary format + [oid], + |param, buf| param.to_sql(&Type::OID, buf).map(map_is_null), + Some(1), // binary return type + &mut c.raw.buf, + ) + .map_err(|e| match e { + frontend::BindError::Conversion(e) => std::io::Error::new(std::io::ErrorKind::Other, e), + frontend::BindError::Serialization(io) => io, + })?; + frontend::execute("", 0, &mut c.raw.buf)?; - let mut fields = vec![]; - for row in rows { - let name = row.try_get(0)?; - let oid = row.try_get(1)?; - let type_ = get_type_rec(client, oid).await?; - fields.push(Field::new(name, type_)); + c.sync().await?; + + let mut stream = c.stream_query_results().await?; + + let Some(row) = stream.next().await.transpose()? else { + todo!() + }; + + let b = row.buffer(); + let mut ranges = row.ranges(); + + let name: String = read_column(b, &Type::NAME, &mut ranges)?; + let type_: i8 = read_column(b, &Type::CHAR, &mut ranges)?; + let elem_oid: Oid = read_column(b, &Type::OID, &mut ranges)?; + let rngsubtype: Option = read_column(b, &Type::OID, &mut ranges)?; + let basetype: Oid = read_column(b, &Type::OID, &mut ranges)?; + let schema: String = read_column(b, &Type::NAME, &mut ranges)?; + let relid: Oid = read_column(b, &Type::OID, &mut ranges)?; + + { + // should be none + let None = stream.next().await.transpose()? else { + todo!() + }; + drop(stream); + } + + let kind = if type_ == b'e' as i8 { + let variants = Self::get_enum_variants(c, oid).await?; + Kind::Enum(variants) + } else if type_ == b'p' as i8 { + Kind::Pseudo + } else if basetype != 0 { + let type_ = Self::get_type_rec(c, basetype).await?; + Kind::Domain(type_) + } else if elem_oid != 0 { + let type_ = Self::get_type_rec(c, elem_oid).await?; + Kind::Array(type_) + } else if relid != 0 { + let fields = Self::get_composite_fields(c, relid).await?; + Kind::Composite(fields) + } else if let Some(rngsubtype) = rngsubtype { + let type_ = Self::get_type_rec(c, rngsubtype).await?; + Kind::Range(type_) + } else { + Kind::Simple + }; + + let type_ = Type::new(name, oid, kind, schema); + c.typecache.insert(oid, type_.clone()); + + Ok(type_) } - Ok(fields) -} + async fn get_enum_variants< + S: AsyncRead + AsyncWrite + Unpin + Send, + T: AsyncRead + AsyncWrite + Unpin + Send, + >( + c: &mut Connection, + oid: Oid, + ) -> Result, Error> { + let queries = Self::new(c).await?; -async fn typeinfo_composite_statement(client: &Arc) -> Result { - if let Some(stmt) = client.typeinfo_composite() { - return Ok(stmt); + frontend::bind( + "", + &queries.enum_query, + [1], // the only parameter is in binary format + [oid], + |param, buf| param.to_sql(&Type::OID, buf).map(map_is_null), + Some(1), // binary return type + &mut c.raw.buf, + ) + .map_err(|e| match e { + frontend::BindError::Conversion(e) => std::io::Error::new(std::io::ErrorKind::Other, e), + frontend::BindError::Serialization(io) => io, + })?; + frontend::execute("", 0, &mut c.raw.buf)?; + + c.sync().await?; + + let mut stream = c.stream_query_results().await?; + let mut variants = Vec::new(); + while let Some(row) = stream.next().await.transpose()? { + let variant: String = read_column(row.buffer(), &Type::NAME, &mut row.ranges())?; + variants.push(variant); + } + + c.wait_for_ready().await?; + + Ok(variants) } - let stmt = prepare_rec(client, TYPEINFO_COMPOSITE_QUERY, &[]).await?; + async fn get_composite_fields< + S: AsyncRead + AsyncWrite + Unpin + Send, + T: AsyncRead + AsyncWrite + Unpin + Send, + >( + c: &mut Connection, + oid: Oid, + ) -> Result, Error> { + let queries = Self::new(c).await?; - client.set_typeinfo_composite(&stmt); - Ok(stmt) + frontend::bind( + "", + &queries.composite_query, + [1], // the only parameter is in binary format + [oid], + |param, buf| param.to_sql(&Type::OID, buf).map(map_is_null), + Some(1), // binary return type + &mut c.raw.buf, + ) + .map_err(|e| match e { + frontend::BindError::Conversion(e) => std::io::Error::new(std::io::ErrorKind::Other, e), + frontend::BindError::Serialization(io) => io, + })?; + frontend::execute("", 0, &mut c.raw.buf)?; + + c.sync().await?; + + let mut stream = c.stream_query_results().await?; + let mut fields = Vec::new(); + while let Some(row) = stream.next().await.transpose()? { + let mut ranges = row.ranges(); + let name: String = read_column(row.buffer(), &Type::NAME, &mut ranges)?; + let oid: Oid = read_column(row.buffer(), &Type::OID, &mut ranges)?; + fields.push((name, oid)); + } + + c.wait_for_ready().await?; + + let mut output_fields = Vec::with_capacity(fields.len()); + for (name, oid) in fields { + let type_ = Self::get_type_rec(c, oid).await?; + output_fields.push(Field::new(name, type_)) + } + + Ok(output_fields) + } }