1use rupg_common::{Error, Object, Result, SqlState};
4
5use super::{Catalog, DepKind, ObjRef, PG_NAMESPACE, PG_PROC};
6
7pub const PG_TS_TEMPLATE: u32 = 3764;
9pub const PG_TS_DICT: u32 = 3600;
11pub const PG_TS_PARSER: u32 = 3601;
13pub const PG_TS_CONFIG: u32 = 3602;
15
16#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct TsTemplate {
19 pub oid: u32,
21 pub name: String,
23 pub namespace: u32,
25 pub init: u32,
27 pub lexize: u32,
29}
30
31#[derive(Clone, Debug, PartialEq, Eq)]
33pub struct TsParser {
34 pub oid: u32,
36 pub name: String,
38 pub namespace: u32,
40 pub start: u32,
42 pub token: u32,
44 pub end: u32,
46 pub headline: u32,
48 pub lextype: u32,
50}
51
52#[derive(Clone, Debug, PartialEq, Eq)]
54pub struct TsDictionary {
55 pub oid: u32,
57 pub name: String,
59 pub namespace: u32,
61 pub owner: u32,
63 pub template: u32,
65 pub options: Option<String>,
67}
68
69#[derive(Clone, Debug, PartialEq, Eq)]
71pub struct TsConfig {
72 pub oid: u32,
74 pub name: String,
76 pub namespace: u32,
78 pub owner: u32,
80 pub parser: u32,
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq)]
86pub struct TsMapping {
87 pub config: u32,
89 pub token: i32,
91 pub seqno: i32,
93 pub dict: u32,
95}
96
97fn duplicate(catalog: &str, prefix: &str, name: &str, namespace: u32) -> Error {
99 Error::new(
100 SqlState::UNIQUE_VIOLATION,
101 format!("duplicate key value violates unique constraint \"{catalog}_{prefix}name_index\""),
102 )
103 .with_detail(format!(
104 "Key ({prefix}name, {prefix}namespace)=({name}, {namespace}) already exists."
105 ))
106 .with_object(Object::Schema, "pg_catalog")
107 .with_object(Object::Table, catalog)
108 .with_object(Object::Constraint, format!("{catalog}_{prefix}name_index"))
109}
110
111impl Catalog {
112 pub fn create_ts_template(&mut self, mut new: TsTemplate) -> Result<u32> {
118 let oid = self.new_oid();
119 if self.ts_template_by_name(new.namespace, &new.name).is_some() {
120 return Err(duplicate("pg_ts_template", "tmpl", &new.name, new.namespace));
121 }
122 new.oid = oid;
123 let mut refs =
124 vec![ObjRef::new(PG_NAMESPACE, new.namespace), ObjRef::new(PG_PROC, new.lexize)];
125 if new.init != 0 {
126 refs.push(ObjRef::new(PG_PROC, new.init));
127 }
128 self.depend_all(ObjRef::new(PG_TS_TEMPLATE, oid), refs);
129 self.ts_templates.insert(oid, new);
130 Ok(oid)
131 }
132
133 pub fn create_ts_parser(&mut self, mut new: TsParser) -> Result<u32> {
139 let oid = self.new_oid();
140 if self.ts_parser_by_name(new.namespace, &new.name).is_some() {
141 return Err(duplicate("pg_ts_parser", "prs", &new.name, new.namespace));
142 }
143 new.oid = oid;
144 let mut refs = vec![ObjRef::new(PG_NAMESPACE, new.namespace)];
145 for function in [new.start, new.token, new.end, new.lextype, new.headline] {
146 if function != 0 {
147 refs.push(ObjRef::new(PG_PROC, function));
148 }
149 }
150 self.depend_all(ObjRef::new(PG_TS_PARSER, oid), refs);
151 self.ts_parsers.insert(oid, new);
152 Ok(oid)
153 }
154
155 pub fn create_ts_dictionary(&mut self, mut new: TsDictionary) -> Result<u32> {
161 let oid = self.new_oid();
162 if self.ts_dictionary_by_name(new.namespace, &new.name).is_some() {
163 return Err(duplicate("pg_ts_dict", "dict", &new.name, new.namespace));
164 }
165 new.oid = oid;
166 let refs = vec![
167 ObjRef::new(PG_NAMESPACE, new.namespace),
168 ObjRef::new(PG_TS_TEMPLATE, new.template),
169 ];
170 self.depend_all(ObjRef::new(PG_TS_DICT, oid), refs);
171 self.ts_dictionaries.insert(oid, new);
172 Ok(oid)
173 }
174
175 pub fn create_ts_config(&mut self, mut new: TsConfig, copy: &[TsMapping]) -> Result<u32> {
181 let oid = self.new_oid();
182 if self.ts_config_by_name(new.namespace, &new.name).is_some() {
183 return Err(duplicate("pg_ts_config", "cfg", &new.name, new.namespace));
184 }
185 new.oid = oid;
186 self.ts_configs.insert(oid, new);
187 self.ts_mappings.extend(copy.iter().map(|m| TsMapping { config: oid, ..*m }));
188 self.ts_config_depends(oid);
189 Ok(oid)
190 }
191
192 fn ts_config_depends(&mut self, oid: u32) {
194 let Some(config) = self.ts_configs.get(&oid) else { return };
195 let me = ObjRef::new(PG_TS_CONFIG, oid);
196 let mut refs = vec![
197 ObjRef::new(PG_NAMESPACE, config.namespace),
198 ObjRef::new(PG_TS_PARSER, config.parser),
199 ];
200 refs.extend(
201 self.ts_mappings
202 .iter()
203 .filter(|m| m.config == oid)
204 .map(|m| ObjRef::new(PG_TS_DICT, m.dict)),
205 );
206 self.depends.retain(|d| d.object != me || d.kind == DepKind::Extension);
207 self.depend_all(me, refs);
208 }
209
210 pub(crate) fn depend_all(&mut self, me: ObjRef, mut refs: Vec<ObjRef>) {
212 refs.sort_unstable_by(|a, b| {
213 b.oid.cmp(&a.oid).then(a.class.cmp(&b.class)).then(a.sub.cmp(&b.sub))
214 });
215 refs.dedup();
216 for referenced in refs {
217 self.depend(me, referenced, DepKind::Normal);
218 }
219 }
220
221 pub fn add_ts_mapping(&mut self, config: u32, tokens: &[i32], dicts: &[u32], replace: bool) {
223 if replace {
224 self.ts_mappings.retain(|m| m.config != config || !tokens.contains(&m.token));
225 }
226 for &token in tokens {
227 for (seqno, &dict) in (1..).zip(dicts) {
228 self.ts_mappings.push(TsMapping { config, token, seqno, dict });
229 }
230 }
231 self.ts_config_depends(config);
232 }
233
234 pub fn replace_ts_dictionary(&mut self, config: u32, tokens: &[i32], old: u32, new: u32) {
236 for m in &mut self.ts_mappings {
237 if m.config == config
238 && m.dict == old
239 && (tokens.is_empty() || tokens.contains(&m.token))
240 {
241 m.dict = new;
242 }
243 }
244 self.ts_config_depends(config);
245 }
246
247 pub fn drop_ts_mapping(&mut self, config: u32, token: i32) -> bool {
249 let before = self.ts_mappings.len();
250 self.ts_mappings.retain(|m| m.config != config || m.token != token);
251 self.ts_mappings.len() != before
252 }
253
254 pub fn update_ts_config_depends(&mut self, config: u32) {
256 self.ts_config_depends(config);
257 }
258
259 pub fn ts_templates(&self) -> impl Iterator<Item = &TsTemplate> {
261 self.ts_templates.values()
262 }
263
264 pub fn ts_template(&self, oid: u32) -> Option<&TsTemplate> {
266 self.ts_templates.get(&oid)
267 }
268
269 pub fn ts_template_by_name(&self, namespace: u32, name: &str) -> Option<&TsTemplate> {
271 self.ts_templates.values().find(|t| t.namespace == namespace && t.name == name)
272 }
273
274 pub fn ts_parsers(&self) -> impl Iterator<Item = &TsParser> {
276 self.ts_parsers.values()
277 }
278
279 pub fn ts_parser(&self, oid: u32) -> Option<&TsParser> {
281 self.ts_parsers.get(&oid)
282 }
283
284 pub fn ts_parser_by_name(&self, namespace: u32, name: &str) -> Option<&TsParser> {
286 self.ts_parsers.values().find(|p| p.namespace == namespace && p.name == name)
287 }
288
289 pub fn ts_dictionaries(&self) -> impl Iterator<Item = &TsDictionary> {
291 self.ts_dictionaries.values()
292 }
293
294 pub fn ts_dictionary(&self, oid: u32) -> Option<&TsDictionary> {
296 self.ts_dictionaries.get(&oid)
297 }
298
299 pub fn ts_dictionary_by_name(&self, namespace: u32, name: &str) -> Option<&TsDictionary> {
301 self.ts_dictionaries.values().find(|d| d.namespace == namespace && d.name == name)
302 }
303
304 pub fn ts_configs(&self) -> impl Iterator<Item = &TsConfig> {
306 self.ts_configs.values()
307 }
308
309 pub fn ts_config(&self, oid: u32) -> Option<&TsConfig> {
311 self.ts_configs.get(&oid)
312 }
313
314 pub fn ts_config_by_name(&self, namespace: u32, name: &str) -> Option<&TsConfig> {
316 self.ts_configs.values().find(|c| c.namespace == namespace && c.name == name)
317 }
318
319 pub fn ts_mappings(&self) -> &[TsMapping] {
321 &self.ts_mappings
322 }
323}