1use crate::ast::RootStmt;
2use crate::error::{PGQueryError, ParseError};
3use libpg_query::{pg_query_free_parse_result, pg_query_parse};
4use serde::Deserialize;
5use serde_json::Value;
6use std::ffi::{CStr, CString};
7
8fn c_ptr_to_string(str_ptr: *mut ::std::os::raw::c_char) -> Option<String> {
9 if str_ptr.is_null() {
10 None
11 } else {
12 unsafe { CStr::from_ptr(str_ptr) }
13 .to_str()
14 .ok()
15 .map(|s| s.to_owned())
16 }
17}
18
19fn parse_sql_query_base<'a, T>(query: &'a str) -> Result<Vec<T>, PGQueryError>
20where
21 T: Deserialize<'a>,
22{
23 let c_str = CString::new(query)?;
24 let pg_parse_result = unsafe { pg_query_parse(c_str.as_ptr()) };
25
26 if !pg_parse_result.error.is_null() {
27 let err = unsafe { *pg_parse_result.error };
28 let parse_error = ParseError {
29 message: c_ptr_to_string(err.message),
30 funcname: c_ptr_to_string(err.funcname),
31 filename: c_ptr_to_string(err.filename),
32 lineno: err.lineno,
33 cursorpos: err.cursorpos,
34 context: c_ptr_to_string(err.context),
35 };
36 return Err(PGQueryError::PGParseError(parse_error));
37 }
38
39 if pg_parse_result.parse_tree.is_null() {
41 return Err(PGQueryError::ParsingCString);
42 }
43
44 let parse_tree = unsafe { CStr::from_ptr(pg_parse_result.parse_tree) }.to_str()?;
45 let output =
46 serde_json::from_str(parse_tree).map_err(|e| PGQueryError::JsonParse(e.to_string()));
47
48 unsafe {
49 pg_query_free_parse_result(pg_parse_result);
50 };
51
52 output
53}
54
55pub fn parse_sql_query_json(query: &str) -> Result<Vec<Value>, PGQueryError> {
56 parse_sql_query_base(query)
57}
58
59pub fn parse_sql_query(query: &str) -> Result<Vec<RootStmt>, PGQueryError> {
60 parse_sql_query_base(query)
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 use insta::assert_debug_snapshot;
68
69 #[test]
70 fn test_span_with_indent() {
71 let sql = r#" SELECT 1;"#;
74 let res = parse_sql_query(sql);
75 assert_debug_snapshot!(res);
76 }
77 #[test]
78 fn test_span_with_new_line_and_indent() {
79 let sql = r#"
80 SELECT 1;"#;
81 let res = parse_sql_query(sql);
82 assert_debug_snapshot!(res);
83 }
84
85 #[test]
86 fn test_adding_index_non_concurrently() {
87 let sql = r#"
88 -- instead of
89 CREATE INDEX "field_name_idx" ON "table_name" ("field_name");
90 -- use CONCURRENTLY
91 CREATE INDEX CONCURRENTLY "field_name_idx" ON "table_name" ("field_name");
92 "#;
93
94 let res = parse_sql_query(sql);
95
96 assert_debug_snapshot!(res);
97 }
98
99 #[test]
100 fn test_error_paths() {
101 let sql = r#"lsakdjf;asdlfkjasd;lfj"#;
102 let res = parse_sql_query(sql);
103 assert_debug_snapshot!(res);
104 }
105
106 #[test]
107 fn test_migration() {
108 let sql = r#"
109BEGIN;
110CREATE INDEX "table_name_field_name_idx" ON "table_name" ("field_name");
111CREATE INDEX "table_name_field_name_idx" ON "table_name" ("field_name" varchar_pattern_ops);
112COMMIT;
113"#;
114 let res = parse_sql_query(sql);
115 assert_debug_snapshot!(res);
116 }
117
118 #[test]
119 fn test_select_string_literal() {
120 let sql = r#"SELECT 'some string';"#;
121 let res = parse_sql_query(sql);
122 assert_debug_snapshot!(res);
123 }
124
125 #[test]
126 fn test_select_one() {
127 let sql = r#"SELECT 1;"#;
128 let res = parse_sql_query(sql);
129 assert_debug_snapshot!(res);
130 }
131 #[test]
132 fn test_parse_sql_create_index_concurrently() {
133 let sql = r#"CREATE INDEX CONCURRENTLY "table_name_idx" ON "table_name" ("table_field");"#;
134 let res = parse_sql_query(sql);
135 assert_debug_snapshot!(res);
136 }
137
138 #[test]
139 fn test_parsing_insert_stmt() {
140 let sql = r#"INSERT INTO table_name VALUES (1, 2, 3);"#;
141 let res = parse_sql_query(sql);
142 assert_debug_snapshot!(res)
143 }
144
145 #[test]
146 fn test_parsing_update_stmt() {
147 let sql = r#"UPDATE table_name SET foo = 'bar' WHERE buzz > 10;"#;
148 let res = parse_sql_query(sql);
149 assert_debug_snapshot!(res)
150 }
151
152 #[test]
153 fn test_parsing_create_table() {
154 let sql = r#"
155BEGIN;
156CREATE TABLE "core_foo" (
157 "id" serial NOT NULL PRIMARY KEY,
158 "created" timestamp with time zone NOT NULL,
159 "modified" timestamp with time zone NOT NULL,
160 "mongo_id" varchar(255) NOT NULL UNIQUE,
161 "description" text NOT NULL,
162 "metadata" jsonb NOT NULL,
163 "kind" varchar(255) NOT NULL,
164 "age" integer NOT NULL,
165 "tenant_id" integer NULL
166);
167CREATE INDEX "age_index" ON "core_foo" ("age");
168COMMIT;
169"#;
170 let res = parse_sql_query(sql);
171 assert_debug_snapshot!(res)
172 }
173
174 #[test]
175 fn test_parse_sql_create_index() {
176 let sql = r#"CREATE INDEX "table_name_idx" ON "table_name" ("table_field");"#;
177 let res = parse_sql_query(sql);
178 assert_debug_snapshot!(res);
179 }
180 #[test]
181 fn test_parse_sql_create_unique_index_safe() {
182 let sql = r#"
183ALTER TABLE "legacy_questiongrouppg"
184 ADD CONSTRAINT "legacy_questiongrouppg_mongo_id_1f8f47d9_uniq" UNIQUE
185 USING INDEX "legacy_questiongrouppg_mongo_id_1f8f47d9_uniq_idx";
186"#;
187 let res = parse_sql_query(sql);
188 assert_debug_snapshot!(res);
189 }
190 #[test]
191 fn test_parse_delete_stmt() {
192 let sql = r#"DELETE FROM "table_name";"#;
193 let res = parse_sql_query(sql);
194 assert_debug_snapshot!(res);
195
196 let sql = r#"DELETE FROM "table_name" WHERE account_age > 10;"#;
197 let res = parse_sql_query(sql);
198 assert_debug_snapshot!(res);
199 }
200
201 #[test]
202 fn test_parse_set_operations_stmt() {
203 let sql = r#"SELECT * from "table_name" UNION SELECT * from "table_foo";"#;
204 let res = parse_sql_query(sql);
205 assert_debug_snapshot!(res);
206
207 let sql = r#"SELECT * from "table_name" UNION ALL SELECT * from "table_foo";"#;
208 let res = parse_sql_query(sql);
209 assert_debug_snapshot!(res);
210 }
211
212 #[test]
213 fn test_parse_create_schema_stmt() {
214 let sql = r#"CREATE SCHEMA schema_name;"#;
215 let res = parse_sql_query(sql);
216 assert_debug_snapshot!(res);
217 }
218
219 #[test]
220 fn test_parse_replica_identity_stmt() {
221 let sql = "ALTER TABLE aa REPLICA IDENTITY FULL;";
222 let res = parse_sql_query(sql);
223 assert_debug_snapshot!(res);
224 }
225
226 #[test]
227 fn test_parse_alter_collation_stmt() {
228 let sql = "ALTER COLLATION name RENAME TO new_name;";
229 let res = parse_sql_query(sql);
230 assert_debug_snapshot!(res);
231 }
232
233 #[test]
234 fn test_parse_alter_domain_stmt() {
235 let sql = "ALTER DOMAIN zipcode SET NOT NULL;";
236 let res = parse_sql_query(sql);
237 assert_debug_snapshot!(res);
238 }
239
240 #[test]
241 fn test_parsing_grant_stmt() {
242 let sql = "GRANT INSERT ON films TO PUBLIC;";
243 let res = parse_sql_query(sql);
244 assert_debug_snapshot!(res);
245 }
246
247 #[test]
248 fn test_parsing_grant_role() {
249 let sql = "GRANT admins TO joe;";
250 let res = parse_sql_query(sql);
251 assert_debug_snapshot!(res);
252 }
253
254 #[test]
255 fn test_alter_default_privileges_stmt() {
256 let sql = "ALTER DEFAULT PRIVILEGES IN SCHEMA myschema GRANT SELECT ON TABLES TO PUBLIC;";
257 let res = parse_sql_query(sql);
258 assert_debug_snapshot!(res);
259 }
260
261 #[test]
262 fn test_parsing_copy_stmt() {
263 let sql = "COPY country FROM '/usr1/proj/bray/sql/country_data';";
264 let res = parse_sql_query(sql);
265 assert_debug_snapshot!(res);
266 }
267
268 #[test]
269 fn test_parsing_variable_set_stmt() {
270 let sql = "set session my.vars.id = '1';";
271 let res = parse_sql_query(sql);
272 assert_debug_snapshot!(res);
273 }
274
275 #[test]
276 fn test_parsing_variable_show_stmt() {
277 let sql = "SHOW name";
278 let res = parse_sql_query(sql);
279 assert_debug_snapshot!(res);
280 }
281
282 #[test]
283 fn test_parsing_create_table_space_stmt() {
284 let sql = "CREATE TABLESPACE dbspace LOCATION '/data/dbs';";
285 let res = parse_sql_query(sql);
286 assert_debug_snapshot!(res);
287 }
288
289 #[test]
290 fn test_parsing_drop_table_space_stmt() {
291 let sql = "DROP TABLESPACE dbspace;";
292 let res = parse_sql_query(sql);
293 assert_debug_snapshot!(res);
294 }
295
296 #[test]
297 fn test_alter_table_space_stmt() {
298 let sql = "ALTER TABLESPACE index_space RENAME TO fast_raid;";
299 let res = parse_sql_query(sql);
300 assert_debug_snapshot!(res);
301 }
302
303 #[test]
304 fn test_create_extension() {
305 let sql = "CREATE EXTENSION hstore;";
306 let res = parse_sql_query(sql);
307 assert_debug_snapshot!(res);
308 }
309
310 #[test]
311 fn test_alter_table_extension() {
312 let sql = "ALTER EXTENSION hstore UPDATE TO '2.0';";
313 let res = parse_sql_query(sql);
314 assert_debug_snapshot!(res);
315 }
316
317 #[test]
318 fn test_drop_extension() {
319 let sql = "DROP EXTENSION hstore;";
320 let res = parse_sql_query(sql);
321 assert_debug_snapshot!(res);
322 }
323
324 #[test]
325 fn test_alter_extension_contents_stmt() {
326 let sql = "ALTER EXTENSION hstore SET SCHEMA utils;";
327 let res = parse_sql_query(sql);
328 assert_debug_snapshot!(res);
329
330 let sql = "ALTER EXTENSION hstore ADD FUNCTION populate_record(anyelement, hstore);";
331 let res = parse_sql_query(sql);
332 assert_debug_snapshot!(res);
333 }
334
335 #[test]
336 fn test_create_foreign_data_wrapper() {
337 let sql = "CREATE FOREIGN DATA WRAPPER dummy;";
338 let res = parse_sql_query(sql);
339 assert_debug_snapshot!(res);
340 }
341
342 #[test]
343 fn test_alter_foreign_data_wrapper() {
344 let sql = "ALTER FOREIGN DATA WRAPPER dbi OPTIONS (ADD foo '1', DROP 'bar');";
345 let res = parse_sql_query(sql);
346 assert_debug_snapshot!(res);
347 }
348
349 #[test]
350 fn test_create_foreign_server_stmt() {
351 let sql = "CREATE SERVER myserver FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host 'foo', dbname 'foodb', port '5432');";
352 let res = parse_sql_query(sql);
353 assert_debug_snapshot!(res);
354 }
355
356 #[test]
357 fn test_alter_foreign_server_stmt() {
358 let sql = "ALTER SERVER foo OPTIONS (host 'foo', dbname 'foodb');";
359 let res = parse_sql_query(sql);
360 assert_debug_snapshot!(res);
361 }
362
363 #[test]
364 fn test_create_foriegn_table_stmt() {
365 let sql = r#"
366CREATE FOREIGN TABLE films (
367 code char(5) NOT NULL,
368 title varchar(40) NOT NULL,
369 did integer NOT NULL,
370 date_prod date,
371 kind varchar(10),
372 len interval hour to minute
373)
374SERVER film_server;
375"#;
376 let res = parse_sql_query(sql);
377 assert_debug_snapshot!(res);
378 }
379
380 #[test]
381 fn test_create_user_mapping_stmt() {
382 let sql = "CREATE USER MAPPING FOR bob SERVER foo OPTIONS (user 'bob', password 'secret');";
383 let res = parse_sql_query(sql);
384 assert_debug_snapshot!(res);
385 }
386
387 #[test]
388 fn test_alter_user_mapping_stmt() {
389 let sql = "ALTER USER MAPPING FOR bob SERVER foo OPTIONS (SET password 'public');";
390 let res = parse_sql_query(sql);
391 assert_debug_snapshot!(res);
392 }
393
394 #[test]
395 fn test_drop_user_mapping_stmt() {
396 let sql = "DROP USER MAPPING IF EXISTS FOR bob SERVER foo;";
397 let res = parse_sql_query(sql);
398 assert_debug_snapshot!(res);
399 }
400
401 #[test]
402 fn test_import_foreign_schema_stmt() {
403 let sql = r#"
404IMPORT FOREIGN SCHEMA foreign_films
405 FROM SERVER film_server INTO films;
406"#;
407 let res = parse_sql_query(sql);
408 assert_debug_snapshot!(res);
409 }
410
411 #[test]
412 fn test_create_policy_stmt() {
413 let sql = "CREATE POLICY name ON table_name FOR ALL;";
414 let res = parse_sql_query(sql);
415 assert_debug_snapshot!(res);
416 }
417
418 #[test]
419 fn test_alter_policy_stmt() {
420 let sql = "ALTER POLICY name ON table_name RENAME TO new_name;";
421 let res = parse_sql_query(sql);
422 assert_debug_snapshot!(res);
423
424 let sql = "ALTER POLICY name ON table_name TO PUBLIC WITH CHECK (account_age > 10);";
425 let res = parse_sql_query(sql);
426 assert_debug_snapshot!(res);
427 }
428
429 #[test]
430 fn test_create_access_method_stmt() {
431 let sql = "CREATE ACCESS METHOD heptree TYPE INDEX HANDLER heptree_handler;";
432 let res = parse_sql_query(sql);
433 assert_debug_snapshot!(res);
434 }
435
436 #[test]
437 fn test_create_trigger_stmt() {
438 let sql = r#"
439CREATE TRIGGER check_update
440 BEFORE UPDATE ON accounts
441 FOR EACH ROW
442 EXECUTE PROCEDURE check_account_update();
443"#;
444 let res = parse_sql_query(sql);
445 assert_debug_snapshot!(res);
446 }
447
448 #[test]
449 fn test_create_event_trigger_stmt() {
450 let sql = r#"
451CREATE EVENT TRIGGER abort_ddl ON ddl_command_start
452 EXECUTE PROCEDURE abort_any_command();
453"#;
454 let res = parse_sql_query(sql);
455 assert_debug_snapshot!(res);
456 }
457
458 #[test]
459 fn test_alter_event_trigger_stmt() {
460 let sql = r#"
461ALTER EVENT TRIGGER name DISABLE;
462"#;
463 let res = parse_sql_query(sql);
464 assert_debug_snapshot!(res);
465 }
466
467 #[test]
469 fn test_create_procedure_stmt() {
470 let sql = r#"
471CREATE PROCEDURE insert_data(a integer, b integer)
472LANGUAGE SQL
473AS $$
474INSERT INTO tbl VALUES (a);
475INSERT INTO tbl VALUES (b);
476$$;
477
478CALL insert_data(1, 2);
479"#;
480 let res = parse_sql_query(sql);
481 assert_debug_snapshot!(res);
482 }
483
484 #[test]
485 fn test_create_function_stmt() {
486 let sql = r#"
487CREATE FUNCTION populate() RETURNS integer AS $$
488DECLARE
489 -- declarations
490BEGIN
491 PERFORM my_function();
492END;
493$$ LANGUAGE plpgsql;
494"#;
495 let res = parse_sql_query(sql);
496 assert_debug_snapshot!(res);
497 }
498
499 #[test]
500 fn test_create_plang_stmt() {
501 let sql = r#"
502CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
503 HANDLER plpgsql_call_handler
504 VALIDATOR plpgsql_validator;
505"#;
506 let res = parse_sql_query(sql);
507 assert_debug_snapshot!(res);
508 }
509
510 #[test]
511 fn test_create_role_stmt() {
512 let sql = r#"
513CREATE ROLE miriam
514 WITH LOGIN PASSWORD 'jw8s0F4'
515 VALID UNTIL '2005-01-01';
516"#;
517 let res = parse_sql_query(sql);
518 assert_debug_snapshot!(res);
519 }
520
521 #[test]
522 fn test_alter_role_stmt() {
523 let sql = r#"
524ALTER ROLE miriam CREATEROLE CREATEDB;
525"#;
526 let res = parse_sql_query(sql);
527 assert_debug_snapshot!(res);
528 }
529
530 #[test]
531 fn test_alter_role_set_stmt() {
532 let sql = r#"
533ALTER ROLE worker_bee SET maintenance_work_mem = 100000;
534"#;
535 let res = parse_sql_query(sql);
536 assert_debug_snapshot!(res);
537 }
538
539 #[test]
540 fn test_drop_role_set_stmt() {
541 let sql = r#"
542DROP ROLE jonathan;
543"#;
544 let res = parse_sql_query(sql);
545 assert_debug_snapshot!(res);
546 }
547
548 #[test]
549 fn test_create_sequence_stmt() {
550 let sql = r#"
551CREATE SEQUENCE serial START 101;
552"#;
553 let res = parse_sql_query(sql);
554 assert_debug_snapshot!(res);
555 }
556
557 #[test]
558 fn test_alter_sequence_stmt() {
559 let sql = r#"
560ALTER SEQUENCE serial RESTART WITH 105;
561"#;
562 let res = parse_sql_query(sql);
563 assert_debug_snapshot!(res);
564 }
565
566 #[test]
567 fn test_define_stmt() {
568 let sql = r#"
569CREATE AGGREGATE sum (complex)
570(
571 sfunc = complex_add,
572 stype = complex,
573 initcond = '(0,0)'
574);
575"#;
576 let res = parse_sql_query(sql);
577 assert_debug_snapshot!(res);
578
579 let sql = r#"
580CREATE OPERATOR === (
581 LEFTARG = box,
582 RIGHTARG = box,
583 PROCEDURE = area_equal_procedure,
584 COMMUTATOR = ===,
585 NEGATOR = !==,
586 RESTRICT = area_restriction_procedure,
587 JOIN = area_join_procedure,
588 HASHES, MERGES
589);
590"#;
591 let res = parse_sql_query(sql);
592 assert_debug_snapshot!(res);
593
594 let sql = r#"
595CREATE TYPE box (
596 INTERNALLENGTH = 16,
597 INPUT = my_box_in_function,
598 OUTPUT = my_box_out_function,
599 ELEMENT = float4
600);
601"#;
602 let res = parse_sql_query(sql);
603 assert_debug_snapshot!(res);
604 }
605
606 #[test]
607 fn test_create_domain_stmt() {
608 let sql = r#"
609CREATE DOMAIN us_postal_code AS TEXT
610CHECK(
611 VALUE ~ '^\d{5}$'
612OR VALUE ~ '^\d{5}-\d{4}$'
613);
614"#;
615 let res = parse_sql_query(sql);
616 assert_debug_snapshot!(res);
617 }
618
619 #[test]
620 fn test_create_op_class_stmt() {
621 let sql = r#"
622CREATE OPERATOR CLASS gist__int_ops
623 DEFAULT FOR TYPE _int4 USING gist AS
624 OPERATOR 3 &&,
625 OPERATOR 6 = (anyarray, anyarray),
626 OPERATOR 7 @>,
627 OPERATOR 8 <@,
628 OPERATOR 20 @@ (_int4, query_int),
629 FUNCTION 1 g_int_consistent (internal, _int4, int, oid, internal),
630 FUNCTION 2 g_int_union (internal, internal),
631 FUNCTION 3 g_int_compress (internal),
632 FUNCTION 4 g_int_decompress (internal),
633 FUNCTION 5 g_int_penalty (internal, internal, internal),
634 FUNCTION 6 g_int_picksplit (internal, internal),
635 FUNCTION 7 g_int_same (_int4, _int4, internal);
636"#;
637 let res = parse_sql_query(sql);
638 assert_debug_snapshot!(res);
639 }
640
641 #[test]
642 fn test_alter_op_class_stmt() {
643 let sql = r#"
644ALTER OPERATOR CLASS name USING index_method RENAME TO new_name;
645ALTER OPERATOR CLASS name USING index_method
646 OWNER TO CURRENT_USER;
647ALTER OPERATOR CLASS name USING index_method
648 SET SCHEMA new_schema;
649"#;
650 let res = parse_sql_query(sql);
651 assert_debug_snapshot!(res);
652 }
653
654 #[test]
655 fn test_alter_op_family_stmt() {
656 let sql = r#"
657ALTER OPERATOR FAMILY integer_ops USING btree ADD
658
659 -- int4 vs int2
660 OPERATOR 1 < (int4, int2) ,
661 OPERATOR 2 <= (int4, int2) ,
662 OPERATOR 3 = (int4, int2) ,
663 OPERATOR 4 >= (int4, int2) ,
664 OPERATOR 5 > (int4, int2) ,
665 FUNCTION 1 btint42cmp(int4, int2) ,
666
667 -- int2 vs int4
668 OPERATOR 1 < (int2, int4) ,
669 OPERATOR 2 <= (int2, int4) ,
670 OPERATOR 3 = (int2, int4) ,
671 OPERATOR 4 >= (int2, int4) ,
672 OPERATOR 5 > (int2, int4) ,
673 FUNCTION 1 btint24cmp(int2, int4) ;
674"#;
675 let res = parse_sql_query(sql);
676 assert_debug_snapshot!(res);
677 }
678
679 #[test]
680 fn test_truncate_stmt() {
681 let sql = r#"
682TRUNCATE bigtable, fattable, bar RESTART IDENTITY;
683TRUNCATE foo CASCADE;
684"#;
685 let res = parse_sql_query(sql);
686 assert_debug_snapshot!(res);
687 }
688
689 #[test]
690 fn test_comment_on_stmt() {
691 let sql = r#"
692COMMENT ON AGGREGATE my_aggregate (double precision) IS 'Computes sample variance';
693"#;
694 let res = parse_sql_query(sql);
695 assert_debug_snapshot!(res);
696 }
697
698 #[test]
699 fn test_security_label_stmt() {
700 let sql = r#"
701SECURITY LABEL FOR selinux ON TABLE mytable IS 'system_u:object_r:sepgsql_table_t:s0';
702"#;
703 let res = parse_sql_query(sql);
704 assert_debug_snapshot!(res);
705 }
706
707 #[test]
708 fn test_declare_cursor_stmt() {
709 let sql = r#"
710DECLARE
711 curs2 CURSOR FOR SELECT * FROM tenk1;
712"#;
713 let res = parse_sql_query(sql);
714 assert_debug_snapshot!(res);
715 }
716
717 #[test]
718 fn test_close_portal_stmt() {
719 let sql = r#"
720CLOSE curs1;
721"#;
722 let res = parse_sql_query(sql);
723 assert_debug_snapshot!(res);
724 }
725
726 #[test]
727 fn test_fetch_stmt() {
728 let sql = r#"
729FETCH FORWARD 5 FROM foo;
730"#;
731 let res = parse_sql_query(sql);
732 assert_debug_snapshot!(res);
733 }
734
735 #[test]
736 fn test_create_stats_stmt() {
737 let sql = r#"
738CREATE STATISTICS s1 (dependencies) ON a, b FROM t1;
739"#;
740 let res = parse_sql_query(sql);
741 assert_debug_snapshot!(res);
742 }
743
744 #[test]
745 fn test_explain_stmt() {
746 let sql = r#"
747EXPLAIN ANALYZE SELECT * FROM t1 WHERE (a = 1) AND (b = 0);
748"#;
749 let res = parse_sql_query(sql);
750 assert_debug_snapshot!(res);
751 }
752
753 #[test]
754 fn test_alter_function_stmt() {
755 let sql = r#"
756ALTER FUNCTION sqrt(integer) RENAME TO square_root;
757ALTER FUNCTION sqrt(integer) OWNER TO joe;
758ALTER FUNCTION sqrt(integer) SET SCHEMA maths;
759ALTER FUNCTION check_password(text) SET search_path = admin, pg_temp;
760ALTER FUNCTION check_password(text) RESET search_path;
761"#;
762 let res = parse_sql_query(sql);
763 assert_debug_snapshot!(res);
764 }
765
766 #[test]
767 fn test_do_stmt() {
768 let sql = r#"
769DO $$DECLARE r record;
770BEGIN
771 FOR r IN SELECT table_schema, table_name FROM information_schema.tables
772 WHERE table_type = 'VIEW' AND table_schema = 'public'
773 LOOP
774 EXECUTE 'GRANT ALL ON ' || quote_ident(r.table_schema) || '.' || quote_ident(r.table_name) || ' TO webuser';
775 END LOOP;
776END$$;
777"#;
778 let res = parse_sql_query(sql);
779 assert_debug_snapshot!(res);
780 }
781
782 #[test]
783 fn test_alter_object_depends_stmt() {
784 let sql = r#"
785ALTER TRIGGER name ON table_name
786 DEPENDS ON EXTENSION extension_name;
787ALTER FUNCTION sqrt(integer)
788 DEPENDS ON EXTENSION extension_name;
789"#;
790 let res = parse_sql_query(sql);
791 assert_debug_snapshot!(res);
792 }
793
794 #[test]
795 fn test_alter_operator_stmt() {
796 let sql = r#"
797ALTER OPERATOR @@ (text, text) OWNER TO joe;
798ALTER OPERATOR @@ (text, text) SET SCHEMA bar;
799ALTER OPERATOR && (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
800"#;
801 let res = parse_sql_query(sql);
802 assert_debug_snapshot!(res);
803 }
804
805 #[test]
806 fn test_rule_stmt() {
807 let sql = r#"
808CREATE RULE "_RETURN" AS
809 ON SELECT TO t1
810 DO INSTEAD
811 SELECT * FROM t2;
812
813CREATE RULE notify_me AS ON UPDATE TO mytable DO ALSO NOTIFY mytable;
814"#;
815 let res = parse_sql_query(sql);
816 assert_debug_snapshot!(res);
817 }
818
819 #[test]
820 fn test_notify_stmt() {
821 let sql = r#"
822NOTIFY virtual;
823NOTIFY virtual, 'This is the payload';
824"#;
825 let res = parse_sql_query(sql);
826 assert_debug_snapshot!(res);
827 }
828
829 #[test]
830 fn test_listen_stmt() {
831 let sql = r#"
832LISTEN virtual;
833"#;
834 let res = parse_sql_query(sql);
835 assert_debug_snapshot!(res);
836 }
837
838 #[test]
839 fn test_unlisten_stmt() {
840 let sql = r#"
841UNLISTEN virtual;
842"#;
843 let res = parse_sql_query(sql);
844 assert_debug_snapshot!(res);
845 }
846
847 #[test]
848 fn test_composite_type_stmt() {
849 let sql = r#"
850CREATE TYPE complex AS (
851 r double precision,
852 i double precision
853);
854"#;
855 let res = parse_sql_query(sql);
856 assert_debug_snapshot!(res);
857 }
858
859 #[test]
860 fn test_create_enum_stmt() {
861 let sql = r#"
862CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
863"#;
864 let res = parse_sql_query(sql);
865 assert_debug_snapshot!(res);
866 }
867
868 #[test]
869 fn test_create_range_stmt() {
870 let sql = r#"
871CREATE TYPE floatrange AS RANGE (
872 subtype = float8,
873 subtype_diff = float8mi
874);
875"#;
876 let res = parse_sql_query(sql);
877 assert_debug_snapshot!(res);
878 }
879
880 #[test]
881 fn test_alter_enum_stmt() {
882 let sql = r#"
883ALTER TYPE colors ADD VALUE 'orange' AFTER 'red';
884"#;
885 let res = parse_sql_query(sql);
886 assert_debug_snapshot!(res);
887 }
888
889 #[test]
890 fn test_create_view_stmt() {
891 let sql = r#"
892CREATE VIEW vista AS SELECT 'Hello World';
893CREATE VIEW comedies AS
894 SELECT *
895 FROM films
896 WHERE kind = 'Comedy';
897"#;
898 let res = parse_sql_query(sql);
899 assert_debug_snapshot!(res);
900 }
901
902 #[test]
903 fn test_load_stmt() {
904 let sql = r#"
905LOAD 'filename';
906"#;
907 let res = parse_sql_query(sql);
908 assert_debug_snapshot!(res);
909 }
910
911 #[test]
912 fn test_create_database_stmt() {
913 let sql = r#"
914CREATE DATABASE lusiadas;
915CREATE DATABASE sales OWNER salesapp TABLESPACE salesspace;
916CREATE DATABASE music ENCODING 'LATIN1' TEMPLATE template0;
917"#;
918 let res = parse_sql_query(sql);
919 assert_debug_snapshot!(res);
920 }
921
922 #[test]
923 fn test_alter_database_stmt() {
924 let sql = r#"
925ALTER DATABASE name RENAME TO new_name;
926ALTER DATABASE name OWNER TO new_owner;
927ALTER DATABASE name SET TABLESPACE new_tablespace;
928ALTER DATABASE name RESET configuration_parameter;
929ALTER DATABASE name RESET ALL;
930"#;
931 let res = parse_sql_query(sql);
932 assert_debug_snapshot!(res);
933 }
934
935 #[test]
936 fn test_drop_database_stmt() {
937 let sql = r#"
938DROP DATABASE name;
939DROP DATABASE IF EXISTS name;
940"#;
941 let res = parse_sql_query(sql);
942 assert_debug_snapshot!(res);
943 }
944
945 #[test]
946 fn test_alter_system_stmt() {
947 let sql = r#"
948ALTER SYSTEM SET wal_level = hot_standby;
949ALTER SYSTEM RESET wal_level;
950"#;
951 let res = parse_sql_query(sql);
952 assert_debug_snapshot!(res);
953 }
954
955 #[test]
956 fn test_cluster_stmt() {
957 let sql = r#"
958CLUSTER employees USING employees_ind;
959CLUSTER employees;
960CLUSTER;
961"#;
962 let res = parse_sql_query(sql);
963 assert_debug_snapshot!(res);
964 }
965
966 #[test]
967 fn test_vacuum_stmt() {
968 let sql = r#"
969VACUUM (VERBOSE, ANALYZE) foo;
970"#;
971 let res = parse_sql_query(sql);
972 assert_debug_snapshot!(res);
973 }
974
975 #[test]
976 fn test_create_table_as_stmt() {
977 let sql = r#"
978CREATE TABLE films2 AS
979 TABLE films;
980"#;
981 let res = parse_sql_query(sql);
982 assert_debug_snapshot!(res);
983 }
984
985 #[test]
986 fn test_refresh_material_view_stmt() {
987 let sql = r#"
988REFRESH MATERIALIZED VIEW order_summary;
989REFRESH MATERIALIZED VIEW annual_statistics_basis WITH NO DATA;
990"#;
991 let res = parse_sql_query(sql);
992 assert_debug_snapshot!(res);
993 }
994
995 #[test]
996 fn test_checkpoint() {
997 let sql = r#"
998CHECKPOINT;
999"#;
1000 let res = parse_sql_query(sql);
1001 assert_debug_snapshot!(res);
1002 }
1003
1004 #[test]
1005 fn test_discard_stmt() {
1006 let sql = r#"
1007DISCARD PLANS;
1008DISCARD SEQUENCES;
1009DISCARD TEMP;
1010"#;
1011 let res = parse_sql_query(sql);
1012 assert_debug_snapshot!(res);
1013 }
1014
1015 #[test]
1016 fn test_lock_stmt() {
1017 let sql = r#"
1018LOCK TABLE films IN SHARE MODE;
1019LOCK TABLE films IN SHARE ROW EXCLUSIVE MODE;
1020"#;
1021 let res = parse_sql_query(sql);
1022 assert_debug_snapshot!(res);
1023 }
1024
1025 #[test]
1026 fn test_set_constraints() {
1027 let sql = r#"
1028SET CONSTRAINTS ALL DEFERRED;
1029SET CONSTRAINTS ALL IMMEDIATE;
1030SET CONSTRAINTS foo IMMEDIATE;
1031"#;
1032 let res = parse_sql_query(sql);
1033 assert_debug_snapshot!(res);
1034 }
1035
1036 #[test]
1037 fn test_reindex_stmt() {
1038 let sql = r#"
1039REINDEX INDEX my_index;
1040REINDEX TABLE table_name;
1041REINDEX DATABASE table_name;
1042REINDEX SYSTEM table_name;
1043"#;
1044 let res = parse_sql_query(sql);
1045 assert_debug_snapshot!(res);
1046 }
1047
1048 #[test]
1049 fn test_create_conversion_stmt() {
1050 let sql = r#"
1051CREATE CONVERSION myconv FOR 'UTF8' TO 'LATIN1' FROM myfunc;
1052"#;
1053 let res = parse_sql_query(sql);
1054 assert_debug_snapshot!(res);
1055 }
1056
1057 #[test]
1058 fn test_create_cast_stmt() {
1059 let sql = r#"
1060CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;
1061"#;
1062 let res = parse_sql_query(sql);
1063 assert_debug_snapshot!(res);
1064 }
1065
1066 #[test]
1067 fn test_create_transform_stmt() {
1068 let sql = r#"
1069CREATE TRANSFORM FOR hstore LANGUAGE plpythonu (
1070 FROM SQL WITH FUNCTION hstore_to_plpython(internal),
1071 TO SQL WITH FUNCTION plpython_to_hstore(internal)
1072);
1073"#;
1074 let res = parse_sql_query(sql);
1075 assert_debug_snapshot!(res);
1076 }
1077
1078 #[test]
1079 fn test_prepare_stmt() {
1080 let sql = r#"
1081PREPARE fooplan (int, text, bool, numeric) AS
1082 INSERT INTO foo VALUES($1, $2, $3, $4);
1083"#;
1084 let res = parse_sql_query(sql);
1085 assert_debug_snapshot!(res);
1086 }
1087
1088 #[test]
1089 fn test_execute_stmt() {
1090 let sql = r#"
1091EXECUTE fooplan(1, 'Hunter Valley', 't', 200.00);
1092"#;
1093 let res = parse_sql_query(sql);
1094 assert_debug_snapshot!(res);
1095 }
1096
1097 #[test]
1098 fn test_deallocate_stmt() {
1099 let sql = r#"
1100DEALLOCATE PREPARE ALL;
1101"#;
1102 let res = parse_sql_query(sql);
1103 assert_debug_snapshot!(res);
1104 }
1105
1106 #[test]
1107 fn test_drop_owned_stmt() {
1108 let sql = r#"
1109DROP OWNED BY foo CASCADE;
1110"#;
1111 let res = parse_sql_query(sql);
1112 assert_debug_snapshot!(res);
1113 }
1114
1115 #[test]
1116 fn test_reassign_owned_stmt() {
1117 let sql = r#"
1118REASSIGN OWNED BY old_role TO new_role;
1119"#;
1120 let res = parse_sql_query(sql);
1121 assert_debug_snapshot!(res);
1122 }
1123
1124 #[test]
1125 fn test_alter_ts_dictionary_stmt() {
1126 let sql = r#"
1127ALTER TEXT SEARCH DICTIONARY my_dict ( StopWords = newrussian );
1128"#;
1129 let res = parse_sql_query(sql);
1130 assert_debug_snapshot!(res);
1131 }
1132
1133 #[test]
1134 fn test_alter_ts_configuration_stmt() {
1135 let sql = r#"
1136ALTER TEXT SEARCH CONFIGURATION astro_en
1137 ADD MAPPING FOR asciiword WITH astrosyn, english_ispell, english_stem;
1138"#;
1139 let res = parse_sql_query(sql);
1140 assert_debug_snapshot!(res);
1141 }
1142
1143 #[test]
1144 fn test_create_publication_stmt() {
1145 let sql = r#"
1146CREATE PUBLICATION mypublication FOR TABLE users, departments;
1147CREATE PUBLICATION insert_only FOR TABLE mydata
1148 WITH (publish = 'insert');
1149"#;
1150 let res = parse_sql_query(sql);
1151 assert_debug_snapshot!(res);
1152 }
1153
1154 #[test]
1155 fn test_alter_publication() {
1156 let sql = r#"
1157ALTER PUBLICATION noinsert SET (publish = 'update, delete');
1158ALTER PUBLICATION mypublication ADD TABLE users, departments;
1159ALTER PUBLICATION name RENAME TO new_name
1160"#;
1161 let res = parse_sql_query(sql);
1162 assert_debug_snapshot!(res);
1163 }
1164
1165 #[test]
1166 fn test_create_subscription_stmt() {
1167 let sql = r#"
1168CREATE SUBSCRIPTION mysub
1169 CONNECTION 'host=192.168.1.50 port=5432 user=foo dbname=foodb'
1170 PUBLICATION mypublication, insert_only;
1171"#;
1172 let res = parse_sql_query(sql);
1173 assert_debug_snapshot!(res);
1174 }
1175
1176 #[test]
1177 fn test_alter_subscription_stmt() {
1178 let sql = r#"
1179ALTER SUBSCRIPTION mysub SET PUBLICATION insert_only;
1180ALTER SUBSCRIPTION mysub DISABLE;
1181"#;
1182 let res = parse_sql_query(sql);
1183 assert_debug_snapshot!(res);
1184 }
1185
1186 #[test]
1187 fn test_drop_subscription_stmt() {
1188 let sql = r#"
1189DROP SUBSCRIPTION mysub;
1190"#;
1191 let res = parse_sql_query(sql);
1192 assert_debug_snapshot!(res);
1193 }
1194}