(
&self,
client: &C,
sql: &str,
types: &[Option<Type>],
)
| 120 | type Statement = ParsedStatement; |
| 121 | |
| 122 | async fn parse_sql<C>( |
| 123 | &self, |
| 124 | client: &C, |
| 125 | sql: &str, |
| 126 | types: &[Option<Type>], |
| 127 | ) -> PgWireResult<Self::Statement> |
| 128 | where |
| 129 | C: ClientInfo + Unpin + Send + Sync, |
| 130 | { |
| 131 | // Wire-streaming COPY shapes for backup/restore: bypass nodedb-sql |
| 132 | // entirely. The Execute handler intercepts these via |
| 133 | // `control::backup::detect`. Returning early avoids a fruitless |
| 134 | // sqlparser pass on syntax it doesn't model. |
| 135 | if crate::control::backup::detect(sql).is_some() { |
| 136 | return Ok(ParsedStatement { |
| 137 | sql: sql.to_owned(), |
| 138 | param_types: Vec::new(), |
| 139 | result_fields: Vec::new(), |
| 140 | is_dsl: false, |
| 141 | pg_catalog_table: None, |
| 142 | }); |
| 143 | } |
| 144 | |
| 145 | // pg_catalog virtual tables: bypass the planner entirely — they |
| 146 | // aren't real collections. Populate result_fields from the static |
| 147 | // catalog schema so Describe can report column types before Bind. |
| 148 | let upper = sql.to_uppercase(); |
| 149 | if let Some(table) = |
| 150 | crate::control::server::pgwire::pg_catalog::extract_pg_catalog_table(&upper) |
| 151 | { |
| 152 | // Parse the SELECT now so Describe can report the *projected* |
| 153 | // column schema rather than the full table schema. The |
| 154 | // evaluator-produced result must match what Describe announces |
| 155 | // — drivers (tokio-postgres, JDBC) decode the wire response |
| 156 | // against the Describe shape and will panic on column-count |
| 157 | // mismatch. Fall back to the full schema if parsing fails so |
| 158 | // drivers that probe with malformed-but-permissive queries still |
| 159 | // get a usable Describe. |
| 160 | let result_fields = |
| 161 | crate::control::server::pgwire::pg_catalog::pg_catalog_projected_schema(sql, table) |
| 162 | .or_else(|| { |
| 163 | crate::control::server::pgwire::pg_catalog::pg_catalog_schema(table) |
| 164 | }) |
| 165 | .unwrap_or_default(); |
| 166 | let count = count_placeholders(sql).max(types.len()); |
| 167 | let param_types: Vec<Option<Type>> = (0..count) |
| 168 | .map(|i| types.get(i).and_then(|t| t.clone())) |
| 169 | .collect(); |
| 170 | return Ok(ParsedStatement { |
| 171 | sql: sql.to_owned(), |
| 172 | param_types, |
| 173 | result_fields, |
| 174 | is_dsl: false, |
| 175 | pg_catalog_table: Some(table), |
| 176 | }); |
| 177 | } |
| 178 | |
| 179 | // Resolve the connecting user's tenant from pgwire metadata so |
nothing calls this directly
no test coverage detected