jupyter-duckdb 1.4.100__py3-none-any.whl → 1.4.106__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
duckdb_kernel/kernel.py CHANGED
@@ -13,6 +13,7 @@ from .db import Connection, DatabaseError, Table
13
13
  from .db.error import *
14
14
  from .magics import *
15
15
  from .parser import RAParser, DCParser, ParserError
16
+ from .parser.util.QuerySplitter import split_queries, get_last_query
16
17
  from .util.ResultSetComparator import ResultSetComparator
17
18
  from .util.SQL import SQL_KEYWORDS
18
19
  from .util.TestError import TestError
@@ -27,9 +28,11 @@ class DuckDBKernel(Kernel):
27
28
  implementation_version = '1.0'
28
29
  banner = 'DuckDB Kernel'
29
30
  language_info = {
30
- 'name': 'duckdb',
31
- 'mimetype': 'application/sql',
31
+ 'name': 'sql',
32
32
  'file_extension': '.sql',
33
+ 'mimetype': 'text/x-sql',
34
+ 'codemirror_mode': 'sql',
35
+ 'pygments_lexer': 'sql',
33
36
  }
34
37
 
35
38
  def __init__(self, **kwargs):
@@ -166,7 +169,9 @@ class DuckDBKernel(Kernel):
166
169
  # print result if not silent
167
170
  if not silent:
168
171
  # print EXPLAIN queries as raw text if using DuckDB
169
- if query.strip().startswith('EXPLAIN') and state.db.plain_explain():
172
+ last_query = get_last_query(query, remove_comments=True).strip()
173
+
174
+ if last_query.startswith('EXPLAIN') and state.db.plain_explain():
170
175
  for ekey, evalue in rows:
171
176
  html = f'<b>{ekey}</b><br><pre>{evalue}</pre>'
172
177
  break
@@ -273,8 +278,7 @@ class DuckDBKernel(Kernel):
273
278
 
274
279
  # You can only execute one statement at a time using SQLite.
275
280
  if not state.db.multiple_statements_per_query():
276
- statements = re.split(r';\r?\n', content)
277
- for statement in statements:
281
+ for statement in split_queries(content):
278
282
  try:
279
283
  state.db.execute(statement)
280
284
  except EmptyResultError:
@@ -2,6 +2,7 @@ from .LogicParser import LogicParser
2
2
  from .ParserError import RAParserError
3
3
  from .elements import *
4
4
  from .tokenizer import *
5
+ from .util.QuerySplitter import get_last_query
5
6
 
6
7
 
7
8
  # Instead of multiple nested loops, a tree with rotation can
@@ -10,6 +11,10 @@ from .tokenizer import *
10
11
  class RAParser:
11
12
  @staticmethod
12
13
  def parse_query(query: str) -> RAElement:
14
+ # remove comments from query
15
+ query = get_last_query(query, split_at=None, remove_comments=True)
16
+
17
+ # parse query
13
18
  initial_token = Token(query)
14
19
  return RAParser.parse_tokens(initial_token, depth=0)
15
20
 
@@ -36,10 +36,13 @@ class RAElement:
36
36
  # if all columns are from the same relation we can skip the relation name
37
37
  if len(set(c.table for c in columns)) == 1:
38
38
  column_names = ', '.join(f'{c.current_name} AS "{c.name}"' for c in columns)
39
+ order_names = ', '.join(f'"{c.name}" ASC' for c in columns)
39
40
  else:
40
41
  column_names = ', '.join(f'{c.current_name} AS "{c.full_name}"' for c in columns)
42
+ order_names = ', '.join(f'"{c.full_name}" ASC' for c in columns)
41
43
 
42
- return f'SELECT {column_names} FROM ({sql}) {self._name()}'
44
+ # create sql
45
+ return f'SELECT {column_names} FROM ({sql}) {self._name()} ORDER BY {order_names}'
43
46
 
44
47
  def to_sql_with_count(self, tables: Dict[str, Table]) -> str:
45
48
  sql, _ = self.to_sql(tables)
@@ -8,7 +8,7 @@ class And(LogicOperator):
8
8
 
9
9
  @staticmethod
10
10
  def symbols() -> Tuple[str, ...]:
11
- return '∧', 'and', 'and'
11
+ return '∧', 'and'
12
12
 
13
13
  @property
14
14
  def sql_symbol(self) -> str:
@@ -347,7 +347,13 @@ class ConditionalSet:
347
347
  sql_join_filters += f' AND {join_filter}'
348
348
 
349
349
  sql_condition = condition.to_sql(joined_columns) if condition is not None else '1=1'
350
- sql_query = f'SELECT DISTINCT {sql_select} FROM {sql_tables} WHERE ({sql_join_filters}) AND ({sql_condition})'
350
+
351
+ if self.projection == ('*',):
352
+ sql_order = ', '.join(f'{rc.name} ASC' for rcl in rcls for rc in rcl)
353
+ else:
354
+ sql_order = ', '.join(f'{col} ASC' for col in self.projection)
355
+
356
+ sql_query = f'SELECT DISTINCT {sql_select} FROM {sql_tables} WHERE ({sql_join_filters}) AND ({sql_condition}) ORDER BY {sql_order}'
351
357
 
352
358
  # Create a mapping from intermediate column names to constant values.
353
359
  column_name_mapping = {
@@ -8,7 +8,7 @@ from ...util.RenamableColumnList import RenamableColumnList
8
8
  class Cross(RABinaryOperator):
9
9
  @staticmethod
10
10
  def symbols() -> Tuple[str, ...]:
11
- return chr(215), 'x'
11
+ return chr(215), 'x', 'times'
12
12
 
13
13
  def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
14
14
  # execute subqueries
@@ -0,0 +1,24 @@
1
+ from typing import Tuple, Dict
2
+
3
+ from duckdb_kernel.db import Table
4
+ from ..RABinaryOperator import RABinaryOperator
5
+ from ...util.RenamableColumnList import RenamableColumnList
6
+
7
+
8
+ class LeftSemiJoin(RABinaryOperator):
9
+ @staticmethod
10
+ def symbols() -> Tuple[str, ...]:
11
+ return chr(8905), 'lsjoin'
12
+
13
+ def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
14
+ # execute subqueries
15
+ lq, lcols = self.left.to_sql(tables)
16
+ rq, rcols = self.right.to_sql(tables)
17
+
18
+ # find matching columns
19
+ join_cols, all_cols = lcols.intersect(rcols)
20
+
21
+ on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
22
+
23
+ # create sql
24
+ return f'SELECT {lcols.list} FROM ({lq}) {self._name()} JOIN ({rq}) {self._name()} ON {on_clause}', lcols
@@ -0,0 +1,24 @@
1
+ from typing import Tuple, Dict
2
+
3
+ from duckdb_kernel.db import Table
4
+ from ..RABinaryOperator import RABinaryOperator
5
+ from ...util.RenamableColumnList import RenamableColumnList
6
+
7
+
8
+ class RightSemiJoin(RABinaryOperator):
9
+ @staticmethod
10
+ def symbols() -> Tuple[str, ...]:
11
+ return chr(8906), 'rsjoin'
12
+
13
+ def to_sql(self, tables: Dict[str, Table]) -> Tuple[str, RenamableColumnList]:
14
+ # execute subqueries
15
+ lq, lcols = self.left.to_sql(tables)
16
+ rq, rcols = self.right.to_sql(tables)
17
+
18
+ # find matching columns
19
+ join_cols, all_cols = lcols.intersect(rcols, prefer_right=True)
20
+
21
+ on_clause = ' AND '.join(f'{l.current_name} = {r.current_name}' for l, r in join_cols)
22
+
23
+ # create sql
24
+ return f'SELECT {rcols.list} FROM ({lq}) {self._name()} JOIN ({rq}) {self._name()} ON {on_clause}', rcols
@@ -3,7 +3,9 @@ from .Difference import Difference
3
3
  from .Intersection import Intersection
4
4
  from .Join import Join
5
5
  from .LeftOuterJoin import LeftOuterJoin
6
+ from .LeftSemiJoin import LeftSemiJoin
6
7
  from .RightOuterJoin import RightOuterJoin
8
+ from .RightSemiJoin import RightSemiJoin
7
9
  from .FullOuterJoin import FullOuterJoin
8
10
  from .Union import Union
9
11
 
@@ -37,7 +39,7 @@ RA_BINARY_OPERATORS = [
37
39
  [Union],
38
40
  [Intersection],
39
41
  [Join],
40
- [LeftOuterJoin, RightOuterJoin, FullOuterJoin],
42
+ [LeftOuterJoin, RightOuterJoin, FullOuterJoin, LeftSemiJoin, RightSemiJoin],
41
43
  [Cross],
42
44
  [Division]
43
45
  ]
@@ -0,0 +1,87 @@
1
+ from typing import Iterator
2
+
3
+
4
+ def split_queries(query: str, split_at: str | None = ';', remove_comments: bool = False) -> Iterator[str]:
5
+ quotes = '\'"`'
6
+
7
+ escaped = False
8
+ in_quotes = None
9
+ in_singleline_comment = False
10
+ in_multiline_comment = False
11
+
12
+ previous = None
13
+ current_query = []
14
+
15
+ for symbol in query:
16
+ keep_symbol = True
17
+
18
+ # escaped symbol
19
+ if escaped:
20
+ escaped = False
21
+
22
+ # backslash (escape)
23
+ elif symbol == '\\':
24
+ escaped = True
25
+
26
+ # if in quotes
27
+ elif in_quotes is not None:
28
+ if symbol == in_quotes:
29
+ in_quotes = False
30
+
31
+ # if in single line comment
32
+ elif in_singleline_comment:
33
+ if symbol == '\n':
34
+ in_singleline_comment = False
35
+ elif remove_comments:
36
+ keep_symbol = False
37
+
38
+ # if in multiline comment
39
+ elif in_multiline_comment:
40
+ if previous == '*' and symbol == '/':
41
+ in_multiline_comment = False
42
+
43
+ if remove_comments:
44
+ keep_symbol = False
45
+
46
+ # start of quotes
47
+ elif symbol in quotes:
48
+ in_quotes = symbol
49
+
50
+ # start of single line comment
51
+ elif previous == '-' and symbol == '-':
52
+ in_singleline_comment = True
53
+
54
+ if remove_comments:
55
+ keep_symbol = False
56
+ current_query.pop()
57
+
58
+ # start of multiline comment
59
+ elif previous == '/' and symbol == '*':
60
+ in_multiline_comment = True
61
+
62
+ if remove_comments:
63
+ keep_symbol = False
64
+ current_query.pop()
65
+
66
+ # semicolon
67
+ elif split_at is not None and symbol == split_at:
68
+ yield ''.join(current_query)
69
+
70
+ current_query = []
71
+ keep_symbol = False
72
+
73
+ # store symbol
74
+ if keep_symbol:
75
+ current_query.append(symbol)
76
+
77
+ previous = symbol
78
+
79
+ # yield remaining symbols
80
+ yield ''.join(current_query)
81
+
82
+
83
+ def get_last_query(query: str, split_at: str | None = ';', remove_comments: bool = False) -> str:
84
+ for query in split_queries(query, split_at, remove_comments):
85
+ pass
86
+
87
+ return query
@@ -56,7 +56,7 @@ class Connection:
56
56
  sql = root.to_sql_with_renamed_columns(self.tables)
57
57
  cols, rows = self.execute_sql_return_cols(sql)
58
58
 
59
- return cols, sorted(rows, key=lambda t: tuple(-1 if x is None else x for x in t))
59
+ return cols, rows # sorted(rows, key=lambda t: tuple(-1 if x is None else x for x in t))
60
60
 
61
61
  def execute_ra(self, root: RAElement) -> List:
62
62
  _, rows = self.execute_ra_return_cols(root)
@@ -66,7 +66,7 @@ class Connection:
66
66
  sql, cnm = root.to_sql_with_renamed_columns(self.tables)
67
67
  cols, rows = self.execute_sql_return_cols(sql)
68
68
 
69
- return [cnm.get(c, c) for c in cols], sorted(rows)
69
+ return [cnm.get(c, c) for c in cols], rows # sorted(rows)
70
70
 
71
71
  def execute_dc(self, root: ConditionalSet) -> List:
72
72
  _, rows = self.execute_dc_return_cols(root)
@@ -79,9 +79,33 @@ def test_case_insensitivity():
79
79
  ]
80
80
 
81
81
 
82
+ def test_comments():
83
+ for query in (
84
+ # single line
85
+ 'Shows -- x Users\n x Seasons',
86
+ 'Shows x Seasons -- x Users',
87
+ 'Shows x Seasons--',
88
+ 'Shows x Seasons--\n',
89
+ # multi line
90
+ 'Shows /* x Users */ x Seasons',
91
+ 'Shows /* x Users */\n x Seasons',
92
+ 'Shows /* x Users\n */ x Seasons',
93
+ 'Shows x Seasons/**/',
94
+ 'Shows x Seasons/*\n*/',
95
+ 'Shows x Seasons\n/**/',
96
+ 'Shows x Seasons/* x Users'
97
+ ):
98
+ root = RAParser.parse_query(query)
99
+
100
+ assert isinstance(root, BinaryOperators.Cross)
101
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Shows'
102
+ assert isinstance(root.right, RAOperand) and root.right.name == 'Seasons'
103
+
104
+
82
105
  def test_binary_operator_cross():
83
106
  for query in (
84
107
  r'Shows x Seasons',
108
+ r'Shows times Seasons',
85
109
  ):
86
110
  root = RAParser.parse_query(query)
87
111
 
@@ -292,6 +316,52 @@ def test_binary_operator_fjoin():
292
316
  ]
293
317
 
294
318
 
319
+ def test_binary_operator_lsjoin():
320
+ for query in (
321
+ r'Users ⋉ BannedUsers',
322
+ r'Users lsjoin BannedUsers'
323
+ ):
324
+ root = RAParser.parse_query(query)
325
+
326
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
327
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
328
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
329
+
330
+ with Connection() as con:
331
+ cols, rows = con.execute_ra_return_cols(root)
332
+
333
+ assert [c.lower() for c in cols] == [
334
+ 'id',
335
+ 'username'
336
+ ]
337
+ assert rows == [
338
+ (2, 'Bob')
339
+ ]
340
+
341
+
342
+ def test_binary_operator_rsjoin():
343
+ for query in (
344
+ r'Users ⋊ BannedUsers',
345
+ r'Users rsjoin BannedUsers'
346
+ ):
347
+ root = RAParser.parse_query(query)
348
+
349
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
350
+ assert isinstance(root.left, RAOperand) and root.left.name == 'Users'
351
+ assert isinstance(root.right, RAOperand) and root.right.name == 'BannedUsers'
352
+
353
+ with Connection() as con:
354
+ cols, rows = con.execute_ra_return_cols(root)
355
+
356
+ assert [c.lower() for c in cols] == [
357
+ 'id',
358
+ 'bannedusername'
359
+ ]
360
+ assert rows == [
361
+ (2, 'Bob')
362
+ ]
363
+
364
+
295
365
  def test_binary_operator_union():
296
366
  for query in (
297
367
  r'Users ∪ BannedUsers',
@@ -566,7 +636,7 @@ def test_binary_left_to_right_evaluation_order():
566
636
  assert root.right.name == 'c'
567
637
 
568
638
  # outer join
569
- root = RAParser.parse_query(r'a ⟕ b ⟕ c')
639
+ root = RAParser.parse_query(r'a ⟕ b ⟕ c') # left outer, left outer
570
640
  assert isinstance(root, BinaryOperators.LeftOuterJoin)
571
641
  assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
572
642
  assert isinstance(root.left.left, RAOperand)
@@ -576,7 +646,7 @@ def test_binary_left_to_right_evaluation_order():
576
646
  assert isinstance(root.right, RAOperand)
577
647
  assert root.right.name == 'c'
578
648
 
579
- root = RAParser.parse_query(r'a ⟖ b ⟖ c')
649
+ root = RAParser.parse_query(r'a ⟖ b ⟖ c') # right outer, right outer
580
650
  assert isinstance(root, BinaryOperators.RightOuterJoin)
581
651
  assert isinstance(root.left, BinaryOperators.RightOuterJoin)
582
652
  assert isinstance(root.left.left, RAOperand)
@@ -586,7 +656,7 @@ def test_binary_left_to_right_evaluation_order():
586
656
  assert isinstance(root.right, RAOperand)
587
657
  assert root.right.name == 'c'
588
658
 
589
- root = RAParser.parse_query(r'a ⟗ b ⟗ c')
659
+ root = RAParser.parse_query(r'a ⟗ b ⟗ c') # full outer, full outer
590
660
  assert isinstance(root, BinaryOperators.FullOuterJoin)
591
661
  assert isinstance(root.left, BinaryOperators.FullOuterJoin)
592
662
  assert isinstance(root.left.left, RAOperand)
@@ -596,8 +666,29 @@ def test_binary_left_to_right_evaluation_order():
596
666
  assert isinstance(root.right, RAOperand)
597
667
  assert root.right.name == 'c'
598
668
 
599
- # mixed outer joins
600
- root = RAParser.parse_query(r'a b c')
669
+ # semi join
670
+ root = RAParser.parse_query(r'a b c') # left semi, left semi
671
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
672
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
673
+ assert isinstance(root.left.left, RAOperand)
674
+ assert root.left.left.name == 'a'
675
+ assert isinstance(root.left.right, RAOperand)
676
+ assert root.left.right.name == 'b'
677
+ assert isinstance(root.right, RAOperand)
678
+ assert root.right.name == 'c'
679
+
680
+ root = RAParser.parse_query(r'a ⋊ b ⋊ c') # right semi, right semi
681
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
682
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
683
+ assert isinstance(root.left.left, RAOperand)
684
+ assert root.left.left.name == 'a'
685
+ assert isinstance(root.left.right, RAOperand)
686
+ assert root.left.right.name == 'b'
687
+ assert isinstance(root.right, RAOperand)
688
+ assert root.right.name == 'c'
689
+
690
+ # mixed outer and semi joins
691
+ root = RAParser.parse_query(r'a ⟕ b ⟖ c') # left outer, right outer
601
692
  assert isinstance(root, BinaryOperators.RightOuterJoin)
602
693
  assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
603
694
  assert isinstance(root.left.left, RAOperand)
@@ -607,7 +698,7 @@ def test_binary_left_to_right_evaluation_order():
607
698
  assert isinstance(root.right, RAOperand)
608
699
  assert root.right.name == 'c'
609
700
 
610
- root = RAParser.parse_query(r'a ⟕ b ⟗ c')
701
+ root = RAParser.parse_query(r'a ⟕ b ⟗ c') # left outer, full outer
611
702
  assert isinstance(root, BinaryOperators.FullOuterJoin)
612
703
  assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
613
704
  assert isinstance(root.left.left, RAOperand)
@@ -617,7 +708,27 @@ def test_binary_left_to_right_evaluation_order():
617
708
  assert isinstance(root.right, RAOperand)
618
709
  assert root.right.name == 'c'
619
710
 
620
- root = RAParser.parse_query(r'a b c')
711
+ root = RAParser.parse_query(r'a b c') # left outer, left semi
712
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
713
+ assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
714
+ assert isinstance(root.left.left, RAOperand)
715
+ assert root.left.left.name == 'a'
716
+ assert isinstance(root.left.right, RAOperand)
717
+ assert root.left.right.name == 'b'
718
+ assert isinstance(root.right, RAOperand)
719
+ assert root.right.name == 'c'
720
+
721
+ root = RAParser.parse_query(r'a ⟕ b ⋊ c') # left outer, right semi
722
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
723
+ assert isinstance(root.left, BinaryOperators.LeftOuterJoin)
724
+ assert isinstance(root.left.left, RAOperand)
725
+ assert root.left.left.name == 'a'
726
+ assert isinstance(root.left.right, RAOperand)
727
+ assert root.left.right.name == 'b'
728
+ assert isinstance(root.right, RAOperand)
729
+ assert root.right.name == 'c'
730
+
731
+ root = RAParser.parse_query(r'a ⟖ b ⟕ c') # right outer, left outer
621
732
  assert isinstance(root, BinaryOperators.LeftOuterJoin)
622
733
  assert isinstance(root.left, BinaryOperators.RightOuterJoin)
623
734
  assert isinstance(root.left.left, RAOperand)
@@ -627,7 +738,7 @@ def test_binary_left_to_right_evaluation_order():
627
738
  assert isinstance(root.right, RAOperand)
628
739
  assert root.right.name == 'c'
629
740
 
630
- root = RAParser.parse_query(r'a ⟖ b ⟗ c')
741
+ root = RAParser.parse_query(r'a ⟖ b ⟗ c') # right outer, full outer
631
742
  assert isinstance(root, BinaryOperators.FullOuterJoin)
632
743
  assert isinstance(root.left, BinaryOperators.RightOuterJoin)
633
744
  assert isinstance(root.left.left, RAOperand)
@@ -637,7 +748,27 @@ def test_binary_left_to_right_evaluation_order():
637
748
  assert isinstance(root.right, RAOperand)
638
749
  assert root.right.name == 'c'
639
750
 
640
- root = RAParser.parse_query(r'a b c')
751
+ root = RAParser.parse_query(r'a b c') # right outer, left semi
752
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
753
+ assert isinstance(root.left, BinaryOperators.RightOuterJoin)
754
+ assert isinstance(root.left.left, RAOperand)
755
+ assert root.left.left.name == 'a'
756
+ assert isinstance(root.left.right, RAOperand)
757
+ assert root.left.right.name == 'b'
758
+ assert isinstance(root.right, RAOperand)
759
+ assert root.right.name == 'c'
760
+
761
+ root = RAParser.parse_query(r'a ⟖ b ⋊ c') # right outer, right semi
762
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
763
+ assert isinstance(root.left, BinaryOperators.RightOuterJoin)
764
+ assert isinstance(root.left.left, RAOperand)
765
+ assert root.left.left.name == 'a'
766
+ assert isinstance(root.left.right, RAOperand)
767
+ assert root.left.right.name == 'b'
768
+ assert isinstance(root.right, RAOperand)
769
+ assert root.right.name == 'c'
770
+
771
+ root = RAParser.parse_query(r'a ⟗ b ⟕ c') # full outer, left outer
641
772
  assert isinstance(root, BinaryOperators.LeftOuterJoin)
642
773
  assert isinstance(root.left, BinaryOperators.FullOuterJoin)
643
774
  assert isinstance(root.left.left, RAOperand)
@@ -647,7 +778,7 @@ def test_binary_left_to_right_evaluation_order():
647
778
  assert isinstance(root.right, RAOperand)
648
779
  assert root.right.name == 'c'
649
780
 
650
- root = RAParser.parse_query(r'a ⟗ b ⟖ c')
781
+ root = RAParser.parse_query(r'a ⟗ b ⟖ c') # full outer, right outer
651
782
  assert isinstance(root, BinaryOperators.RightOuterJoin)
652
783
  assert isinstance(root.left, BinaryOperators.FullOuterJoin)
653
784
  assert isinstance(root.left.left, RAOperand)
@@ -657,6 +788,106 @@ def test_binary_left_to_right_evaluation_order():
657
788
  assert isinstance(root.right, RAOperand)
658
789
  assert root.right.name == 'c'
659
790
 
791
+ root = RAParser.parse_query(r'a ⟗ b ⋉ c') # full outer, left semi
792
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
793
+ assert isinstance(root.left, BinaryOperators.FullOuterJoin)
794
+ assert isinstance(root.left.left, RAOperand)
795
+ assert root.left.left.name == 'a'
796
+ assert isinstance(root.left.right, RAOperand)
797
+ assert root.left.right.name == 'b'
798
+ assert isinstance(root.right, RAOperand)
799
+ assert root.right.name == 'c'
800
+
801
+ root = RAParser.parse_query(r'a ⟗ b ⋊ c') # full outer, right semi
802
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
803
+ assert isinstance(root.left, BinaryOperators.FullOuterJoin)
804
+ assert isinstance(root.left.left, RAOperand)
805
+ assert root.left.left.name == 'a'
806
+ assert isinstance(root.left.right, RAOperand)
807
+ assert root.left.right.name == 'b'
808
+ assert isinstance(root.right, RAOperand)
809
+ assert root.right.name == 'c'
810
+
811
+ root = RAParser.parse_query(r'a ⋉ b ⟕ c') # left semi, left outer
812
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
813
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
814
+ assert isinstance(root.left.left, RAOperand)
815
+ assert root.left.left.name == 'a'
816
+ assert isinstance(root.left.right, RAOperand)
817
+ assert root.left.right.name == 'b'
818
+ assert isinstance(root.right, RAOperand)
819
+ assert root.right.name == 'c'
820
+
821
+ root = RAParser.parse_query(r'a ⋉ b ⟖ c') # left semi, right outer
822
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
823
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
824
+ assert isinstance(root.left.left, RAOperand)
825
+ assert root.left.left.name == 'a'
826
+ assert isinstance(root.left.right, RAOperand)
827
+ assert root.left.right.name == 'b'
828
+ assert isinstance(root.right, RAOperand)
829
+ assert root.right.name == 'c'
830
+
831
+ root = RAParser.parse_query(r'a ⋉ b ⟗ c') # left semi, full outer
832
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
833
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
834
+ assert isinstance(root.left.left, RAOperand)
835
+ assert root.left.left.name == 'a'
836
+ assert isinstance(root.left.right, RAOperand)
837
+ assert root.left.right.name == 'b'
838
+ assert isinstance(root.right, RAOperand)
839
+ assert root.right.name == 'c'
840
+
841
+ root = RAParser.parse_query(r'a ⋉ b ⋊ c') # left semi, right semi
842
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
843
+ assert isinstance(root.left, BinaryOperators.LeftSemiJoin)
844
+ assert isinstance(root.left.left, RAOperand)
845
+ assert root.left.left.name == 'a'
846
+ assert isinstance(root.left.right, RAOperand)
847
+ assert root.left.right.name == 'b'
848
+ assert isinstance(root.right, RAOperand)
849
+ assert root.right.name == 'c'
850
+
851
+ root = RAParser.parse_query(r'a ⋊ b ⟕ c') # right semi, left outer
852
+ assert isinstance(root, BinaryOperators.LeftOuterJoin)
853
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
854
+ assert isinstance(root.left.left, RAOperand)
855
+ assert root.left.left.name == 'a'
856
+ assert isinstance(root.left.right, RAOperand)
857
+ assert root.left.right.name == 'b'
858
+ assert isinstance(root.right, RAOperand)
859
+ assert root.right.name == 'c'
860
+
861
+ root = RAParser.parse_query(r'a ⋊ b ⟖ c') # right semi, right outer
862
+ assert isinstance(root, BinaryOperators.RightOuterJoin)
863
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
864
+ assert isinstance(root.left.left, RAOperand)
865
+ assert root.left.left.name == 'a'
866
+ assert isinstance(root.left.right, RAOperand)
867
+ assert root.left.right.name == 'b'
868
+ assert isinstance(root.right, RAOperand)
869
+ assert root.right.name == 'c'
870
+
871
+ root = RAParser.parse_query(r'a ⋊ b ⟗ c') # right semi, full outer
872
+ assert isinstance(root, BinaryOperators.FullOuterJoin)
873
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
874
+ assert isinstance(root.left.left, RAOperand)
875
+ assert root.left.left.name == 'a'
876
+ assert isinstance(root.left.right, RAOperand)
877
+ assert root.left.right.name == 'b'
878
+ assert isinstance(root.right, RAOperand)
879
+ assert root.right.name == 'c'
880
+
881
+ root = RAParser.parse_query(r'a ⋊ b ⋉ c') # right semi, left semi
882
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
883
+ assert isinstance(root.left, BinaryOperators.RightSemiJoin)
884
+ assert isinstance(root.left.left, RAOperand)
885
+ assert root.left.left.name == 'a'
886
+ assert isinstance(root.left.right, RAOperand)
887
+ assert root.left.right.name == 'b'
888
+ assert isinstance(root.right, RAOperand)
889
+ assert root.right.name == 'c'
890
+
660
891
  # cross join
661
892
  root = RAParser.parse_query(r'a x b x c')
662
893
  assert isinstance(root, BinaryOperators.Cross)
@@ -747,6 +978,22 @@ def test_binary_evaluation_order():
747
978
  assert isinstance(root, BinaryOperators.Difference)
748
979
  assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
749
980
 
981
+ root = RAParser.parse_query(r'a \ b ⋉ c')
982
+ assert isinstance(root, BinaryOperators.Difference)
983
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
984
+
985
+ root = RAParser.parse_query(r'a ⋉ b \ c')
986
+ assert isinstance(root, BinaryOperators.Difference)
987
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
988
+
989
+ root = RAParser.parse_query(r'a \ b ⋊ c')
990
+ assert isinstance(root, BinaryOperators.Difference)
991
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
992
+
993
+ root = RAParser.parse_query(r'a ⋊ b \ c')
994
+ assert isinstance(root, BinaryOperators.Difference)
995
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
996
+
750
997
  # difference <-> cross
751
998
  root = RAParser.parse_query(r'a \ b x c')
752
999
  assert isinstance(root, BinaryOperators.Difference)
@@ -807,6 +1054,22 @@ def test_binary_evaluation_order():
807
1054
  assert isinstance(root, BinaryOperators.Union)
808
1055
  assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
809
1056
 
1057
+ root = RAParser.parse_query(r'a ∪ b ⋉ c')
1058
+ assert isinstance(root, BinaryOperators.Union)
1059
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
1060
+
1061
+ root = RAParser.parse_query(r'a ⋉ b ∪ c')
1062
+ assert isinstance(root, BinaryOperators.Union)
1063
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
1064
+
1065
+ root = RAParser.parse_query(r'a ∪ b ⋊ c')
1066
+ assert isinstance(root, BinaryOperators.Union)
1067
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
1068
+
1069
+ root = RAParser.parse_query(r'a ⋊ b ∪ c')
1070
+ assert isinstance(root, BinaryOperators.Union)
1071
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
1072
+
810
1073
  # union <-> cross
811
1074
  root = RAParser.parse_query(r'a ∪ b x c')
812
1075
  assert isinstance(root, BinaryOperators.Union)
@@ -858,6 +1121,22 @@ def test_binary_evaluation_order():
858
1121
  assert isinstance(root, BinaryOperators.Intersection)
859
1122
  assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
860
1123
 
1124
+ root = RAParser.parse_query(r'a ∩ b ⋉ c')
1125
+ assert isinstance(root, BinaryOperators.Intersection)
1126
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
1127
+
1128
+ root = RAParser.parse_query(r'a ⋉ b ∩ c')
1129
+ assert isinstance(root, BinaryOperators.Intersection)
1130
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
1131
+
1132
+ root = RAParser.parse_query(r'a ∩ b ⋊ c')
1133
+ assert isinstance(root, BinaryOperators.Intersection)
1134
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
1135
+
1136
+ root = RAParser.parse_query(r'a ⋊ b ∩ c')
1137
+ assert isinstance(root, BinaryOperators.Intersection)
1138
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
1139
+
861
1140
  # intersection <-> cross
862
1141
  root = RAParser.parse_query(r'a ∩ b x c')
863
1142
  assert isinstance(root, BinaryOperators.Intersection)
@@ -909,6 +1188,22 @@ def test_binary_evaluation_order():
909
1188
  assert isinstance(root, BinaryOperators.FullOuterJoin)
910
1189
  assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
911
1190
 
1191
+ root = RAParser.parse_query(r'a ⋉ b x c')
1192
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1193
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1194
+
1195
+ root = RAParser.parse_query(r'a x b ⋉ c')
1196
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1197
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1198
+
1199
+ root = RAParser.parse_query(r'a ⋊ b x c')
1200
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1201
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Cross)
1202
+
1203
+ root = RAParser.parse_query(r'a x b ⋊ c')
1204
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1205
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Cross)
1206
+
912
1207
  # join <-> division
913
1208
  root = RAParser.parse_query(r'a ⋈ b ÷ c')
914
1209
  assert isinstance(root, BinaryOperators.Join)
@@ -942,6 +1237,22 @@ def test_binary_evaluation_order():
942
1237
  assert isinstance(root, BinaryOperators.FullOuterJoin)
943
1238
  assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
944
1239
 
1240
+ root = RAParser.parse_query(r'a ⋉ b ÷ c')
1241
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1242
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1243
+
1244
+ root = RAParser.parse_query(r'a ÷ b ⋉ c')
1245
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1246
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1247
+
1248
+ root = RAParser.parse_query(r'a ⋊ b ÷ c')
1249
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1250
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.Division)
1251
+
1252
+ root = RAParser.parse_query(r'a ÷ b ⋊ c')
1253
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1254
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.Division)
1255
+
945
1256
  # natural join <-> outer join
946
1257
  root = RAParser.parse_query(r'a ⋈ b ⟕ c')
947
1258
  assert isinstance(root, BinaryOperators.Join)
@@ -967,6 +1278,22 @@ def test_binary_evaluation_order():
967
1278
  assert isinstance(root, BinaryOperators.Join)
968
1279
  assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.FullOuterJoin)
969
1280
 
1281
+ root = RAParser.parse_query(r'a ⋈ b ⋉ c')
1282
+ assert isinstance(root, BinaryOperators.Join)
1283
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.LeftSemiJoin)
1284
+
1285
+ root = RAParser.parse_query(r'a ⋉ b ⋈ c')
1286
+ assert isinstance(root, BinaryOperators.Join)
1287
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.LeftSemiJoin)
1288
+
1289
+ root = RAParser.parse_query(r'a ⋈ b ⋊ c')
1290
+ assert isinstance(root, BinaryOperators.Join)
1291
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, BinaryOperators.RightSemiJoin)
1292
+
1293
+ root = RAParser.parse_query(r'a ⋊ b ⋈ c')
1294
+ assert isinstance(root, BinaryOperators.Join)
1295
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, BinaryOperators.RightSemiJoin)
1296
+
970
1297
  # cross <-> division
971
1298
  root = RAParser.parse_query(r'a x b ÷ c')
972
1299
  assert isinstance(root, BinaryOperators.Cross)
@@ -1092,6 +1419,22 @@ def test_mixed_evaluation_order():
1092
1419
  assert isinstance(root, BinaryOperators.FullOuterJoin)
1093
1420
  assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1094
1421
 
1422
+ root = RAParser.parse_query(r'a ⋉ π [ Id ] b')
1423
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1424
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1425
+
1426
+ root = RAParser.parse_query(r'π [ Id ] a ⋉ b')
1427
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1428
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1429
+
1430
+ root = RAParser.parse_query(r'a ⋊ π [ Id ] b')
1431
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1432
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Projection)
1433
+
1434
+ root = RAParser.parse_query(r'π [ Id ] a ⋊ b')
1435
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1436
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Projection)
1437
+
1095
1438
  # join <-> rename
1096
1439
  root = RAParser.parse_query(r'a ⋈ β [ Id2 ← Id ] b')
1097
1440
  assert isinstance(root, BinaryOperators.Join)
@@ -1125,6 +1468,22 @@ def test_mixed_evaluation_order():
1125
1468
  assert isinstance(root, BinaryOperators.FullOuterJoin)
1126
1469
  assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1127
1470
 
1471
+ root = RAParser.parse_query(r'a ⋉ β [ Id2 ← Id ] b')
1472
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1473
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1474
+
1475
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋉ b')
1476
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1477
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1478
+
1479
+ root = RAParser.parse_query(r'a ⋊ β [ Id2 ← Id ] b')
1480
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1481
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Rename)
1482
+
1483
+ root = RAParser.parse_query(r'β [ Id2 ← Id ] a ⋊ b')
1484
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1485
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Rename)
1486
+
1128
1487
  # join <-> selection
1129
1488
  root = RAParser.parse_query(r'a ⋈ σ [ Id > 1 ] b')
1130
1489
  assert isinstance(root, BinaryOperators.Join)
@@ -1158,6 +1517,22 @@ def test_mixed_evaluation_order():
1158
1517
  assert isinstance(root, BinaryOperators.FullOuterJoin)
1159
1518
  assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1160
1519
 
1520
+ root = RAParser.parse_query(r'a ⋉ σ [ Id > 1 ] b')
1521
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1522
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1523
+
1524
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ⋉ b')
1525
+ assert isinstance(root, BinaryOperators.LeftSemiJoin)
1526
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1527
+
1528
+ root = RAParser.parse_query(r'a ⋊ σ [ Id > 1 ] b')
1529
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1530
+ assert isinstance(root.left, RAOperand) and isinstance(root.right, UnaryOperators.Selection)
1531
+
1532
+ root = RAParser.parse_query(r'σ [ Id > 1 ] a ⋊ b')
1533
+ assert isinstance(root, BinaryOperators.RightSemiJoin)
1534
+ assert isinstance(root.right, RAOperand) and isinstance(root.left, UnaryOperators.Selection)
1535
+
1161
1536
  # cross <-> projection
1162
1537
  root = RAParser.parse_query(r'a x π [ Id ] b')
1163
1538
  assert isinstance(root, BinaryOperators.Cross)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jupyter-duckdb
3
- Version: 1.4.100
3
+ Version: 1.4.106
4
4
  Summary: a basic wrapper kernel for DuckDB
5
5
  Home-page: https://github.com/erictroebs/jupyter-duckdb
6
6
  Author: Eric Tröbs
@@ -45,6 +45,7 @@ There are some magic commands that make teaching easier with this kernel.
45
45
  - [Ship Tests With Your Notebook](#ship-tests-with-your-notebooks)
46
46
  - [Relational Algebra](#relational-algebra)
47
47
  - [Domain Calculus](#domain-calculus)
48
+ - [Automated Parser Selection](#automated-parser-selection)
48
49
 
49
50
  ## Setup
50
51
 
@@ -281,6 +282,8 @@ The supported operations are:
281
282
  The optional flag `ANALYZE` can be used to add an execution diagram to the
282
283
  output.
283
284
 
285
+ You can also add comments to queries using `--` or `/* */`, just like in SQL.
286
+
284
287
  The Dockerfile also installs the Jupyter Lab plugin
285
288
  [jupyter-ra-extension](https://pypi.org/project/jupyter-ra-extension/). It adds
286
289
  the symbols mentioned above and some other supported symbols to the toolbar for
@@ -304,4 +307,3 @@ executed cells.
304
307
  If the magic command `%AUTO_PARSER` is added to a cell, a parser is
305
308
  automatically selected. If `%GUESS_PARSER` is executed, the parser is
306
309
  automatically selected for all subsequent cells.
307
-
@@ -1,7 +1,7 @@
1
1
  duckdb_kernel/__init__.py,sha256=6auU6zeJrsA4fxPSr2PYamS8fG-SMXTn5YQFXF2cseo,33
2
2
  duckdb_kernel/__main__.py,sha256=Z3GwHEBWoQjNm2Y84ijnbA0Lk66L7nsFREuqhZ_ptk0,165
3
3
  duckdb_kernel/kernel.json,sha256=_7E8Ci2FSdCvnzCjsOaue8QE8AvpS5JLQuxORO5IGtA,127
4
- duckdb_kernel/kernel.py,sha256=jgmFdxNfv89_r6pbDMK1F5azjhCz7ABJRlS_Nn9hq1s,28237
4
+ duckdb_kernel/kernel.py,sha256=pn7I_mZj910A1o_RF2_n1fU2aIRIU0fKgvUzU0GdxUw,28386
5
5
  duckdb_kernel/db/Column.py,sha256=GM5P6sFdlYK92hiKln5-6038gIDOTxh1AYbR4kiga_w,559
6
6
  duckdb_kernel/db/Connection.py,sha256=tBXQBYt9c52RLbpl9sakNuAm0Z84--fhZ4efo8ACz-U,670
7
7
  duckdb_kernel/db/Constraint.py,sha256=1YgUHk7s8mHCVedbcuJKyXDykj7_ybbwT3Dk9p2VMis,287
@@ -27,23 +27,23 @@ duckdb_kernel/magics/__init__.py,sha256=ggxzDzDEsKMZzYsWw9JqYVJhciJPvPVYGV7oNo9Y
27
27
  duckdb_kernel/parser/DCParser.py,sha256=16c1mxa494KP9OreUKQHsSQKoDGZ7NNp2u_gi_D-dkw,2293
28
28
  duckdb_kernel/parser/LogicParser.py,sha256=_vZwE5OPRUEN8aEC_fSZAYKR_dpexqNthXog9OFHYRY,1233
29
29
  duckdb_kernel/parser/ParserError.py,sha256=qJQVloFtID1HgVDQ1Io247bODT1ic3oO9Z1ZrWR-2Mk,321
30
- duckdb_kernel/parser/RAParser.py,sha256=vLR2X8zJIJ3cPKdLvU3PKjNakEOvsoFuoK8pr4bA-Fg,3102
30
+ duckdb_kernel/parser/RAParser.py,sha256=YiXjJGdofnajqDbL3UYofIEj3mXll8Hb6dc2bX58ZNY,3284
31
31
  duckdb_kernel/parser/__init__.py,sha256=nTmDm1ADvNPDHhVJQLxKYmArNJk6967EUXqn5AkT8FM,126
32
32
  duckdb_kernel/parser/elements/DCOperand.py,sha256=qEg_6Us4WV1eK4Bq6oUsmFt_L_x5pJPGce_wSapzIYA,1149
33
33
  duckdb_kernel/parser/elements/LogicElement.py,sha256=YasKHxWLDDP8UdyLIKbXzqIRA8-XaakjmvTj-1Iuzyc,280
34
34
  duckdb_kernel/parser/elements/LogicOperand.py,sha256=B9NvriloQE5eP734dNMZBZwrdaaIfsuAmZlG1t2eMhs,1021
35
35
  duckdb_kernel/parser/elements/LogicOperator.py,sha256=lkM4TAGkXUhsO4w4PLKVA0bgCRGPQQFpNA1FcWWOW9Q,1028
36
36
  duckdb_kernel/parser/elements/RABinaryOperator.py,sha256=XN41stGc1e-a4dZ1AQVtQ3lEgjUGNt3dMfYXp85LEeE,538
37
- duckdb_kernel/parser/elements/RAElement.py,sha256=d6QWO8KlWcwhA4tXtWsf8K4oT3OMMjTvEnUD4yaWQ_c,1468
37
+ duckdb_kernel/parser/elements/RAElement.py,sha256=3qf-ZLQU5WAH_3TvEnfXUg8Y9lE2Fg01D82XutIfgjg,1661
38
38
  duckdb_kernel/parser/elements/RAOperand.py,sha256=pghnTYCrrT6MkvynJRgVFPRoMvxIGNB3FTjaq-uCpDQ,1078
39
39
  duckdb_kernel/parser/elements/RAOperator.py,sha256=rtqMFBIBBqT-Bwg7Qm4WQwbDrE28Nb74F_7XMeR3ks4,255
40
40
  duckdb_kernel/parser/elements/RAUnaryOperator.py,sha256=XC1nphkSm88JaEu5V_HKnb_8JNoeBfE3EvNL4o0qh2c,654
41
41
  duckdb_kernel/parser/elements/__init__.py,sha256=t5H6SVOm3z8r6UWRYOI7HmMIuB4Yh6TLNu4_N3jg2t0,566
42
42
  duckdb_kernel/parser/elements/binary/Add.py,sha256=XGkZMfab01huk9EaI6JUfzkd2STbV1C_-TyC2guKE8I,190
43
- duckdb_kernel/parser/elements/binary/And.py,sha256=0jgetTG8yo5TJSeK70Kj-PI9ERyek1eyMQXX5HBxa4Y,274
43
+ duckdb_kernel/parser/elements/binary/And.py,sha256=p6TQE49DtHlMlTkH9GqyrQVcYWsVgdIMTTCxNuNORuQ,267
44
44
  duckdb_kernel/parser/elements/binary/ArrowLeft.py,sha256=u4fZSoyT9lfvWXBwuhUl4DdjVZAOqyVIKmMVbpElLD4,203
45
- duckdb_kernel/parser/elements/binary/ConditionalSet.py,sha256=sZ3qrxPux7pb3fMrlyBg4Hw7n4-Ln-AeN70_Jp5dAPo,17652
46
- duckdb_kernel/parser/elements/binary/Cross.py,sha256=jVY3cvD6qDWZkJ7q74lFUPO2VdDt4aAjdk2YAfg-ZC4,687
45
+ duckdb_kernel/parser/elements/binary/ConditionalSet.py,sha256=yzUPWO4KL8BEIQ-SiV00bdLulwHoxgoJRxebyhsRSPU,17884
46
+ duckdb_kernel/parser/elements/binary/Cross.py,sha256=2tsPBPGN2Bmbx50-cCdZcSj7AqQwJugA7B4gECrMdlI,696
47
47
  duckdb_kernel/parser/elements/binary/Difference.py,sha256=4nyHhjo09UmYjtGNC3xGQxV5ROzCGOpPkyerUN-AlF4,746
48
48
  duckdb_kernel/parser/elements/binary/Divide.py,sha256=ubekU4C1wkCTidUSMLEj5neheRx0QjhWSrsPGuXTa1g,265
49
49
  duckdb_kernel/parser/elements/binary/Division.py,sha256=FOYxmeNGljRETwygtVn102POCUmt71t9DXdAnLFCXZM,1535
@@ -54,15 +54,17 @@ duckdb_kernel/parser/elements/binary/GreaterThanEqual.py,sha256=gO1I3J5CZwrpqZb5
54
54
  duckdb_kernel/parser/elements/binary/Intersection.py,sha256=K6NrwcLTJ1BUccifVQ2R2YHR5B71LhjuLhOalxZcM0g,757
55
55
  duckdb_kernel/parser/elements/binary/Join.py,sha256=9Z3JinEav3ulLbZZZM9DLbprloHC0oGuSm40Kf1A0mM,836
56
56
  duckdb_kernel/parser/elements/binary/LeftOuterJoin.py,sha256=qCyHLMboNjzSDK_FREtYVwZx4UYkfRcy3FMo2pEf93o,846
57
+ duckdb_kernel/parser/elements/binary/LeftSemiJoin.py,sha256=u5Xv-vS0wfZsG4X5go--r3JnoDVoeeaI07zKaS2pJiM,828
57
58
  duckdb_kernel/parser/elements/binary/LessThan.py,sha256=gNlyAvew0VyvU8x3ol88zbdh_t9GU51Kd2P_PmHUrAc,201
58
59
  duckdb_kernel/parser/elements/binary/LessThanEqual.py,sha256=BKKXBZ4TZQ4EBxBDSNzIpFl4Oz1IGI0tI0Oj7KZUoDo,283
59
60
  duckdb_kernel/parser/elements/binary/Minus.py,sha256=1XUTXCA0GcAcCnv9nq4B9ewT0XHJ91LlZGEW1y60POA,192
60
61
  duckdb_kernel/parser/elements/binary/Multiply.py,sha256=OctlfN71izFYxIpMo09Qwq-3BmQmSh6-PNKBljMsBrg,195
61
62
  duckdb_kernel/parser/elements/binary/Or.py,sha256=e1H_BuY7TQD7XHKGqJYLOebYQvrh1euWOUsXF0FT5dY,264
62
63
  duckdb_kernel/parser/elements/binary/RightOuterJoin.py,sha256=bDxTEQ_dJZ-MUuGbU1YL69kPFR0Hdkc1fow3wxOxfAY,867
64
+ duckdb_kernel/parser/elements/binary/RightSemiJoin.py,sha256=QYDR27H4sA57vCKIip5o_UKfHAOLpYW6cq36fdUUO4M,848
63
65
  duckdb_kernel/parser/elements/binary/Unequal.py,sha256=1hnC1RcPMxwKKv65OL5prunGgh9cRVDmzJutmtl7gtY,269
64
66
  duckdb_kernel/parser/elements/binary/Union.py,sha256=VYTj4M2PVEhWiDwjnyP8qpVVbGvIBSVshlEt-SZYCBY,739
65
- duckdb_kernel/parser/elements/binary/__init__.py,sha256=BieXw51EBgIwUEK-hn4jBb1b4VKJT6sRzaxwOrSXw2A,1342
67
+ duckdb_kernel/parser/elements/binary/__init__.py,sha256=-4ZY6vpsiyT8eDkLwyFGHJFWXIMCNYNz9ejFFcjEG5U,1451
66
68
  duckdb_kernel/parser/elements/unary/Not.py,sha256=kG0a-dp3TNjPodUMPiQ6ihtsBrbvn1iWeIPCvtyAwdo,632
67
69
  duckdb_kernel/parser/elements/unary/Projection.py,sha256=CJ-MIf1-__1ewTjNZVy5hOz3Z18CWnCDNJBxUdpWXVQ,1112
68
70
  duckdb_kernel/parser/elements/unary/Rename.py,sha256=Zr2n9EJ3nA476lND0Djz2b6493nnsbSpJ9kkEgk5B_Y,1273
@@ -71,12 +73,13 @@ duckdb_kernel/parser/elements/unary/__init__.py,sha256=48EDygy0pD7l3J_BlXGc-b7HY
71
73
  duckdb_kernel/parser/tokenizer/Token.py,sha256=gsCzgU_zLiA-yD0FWvd2qS9LQUXbivESYH-34Glffqs,2404
72
74
  duckdb_kernel/parser/tokenizer/Tokenizer.py,sha256=PWGgS7gYgpULiKGDho842UbaXuqmwEkccixuF10oi5g,5081
73
75
  duckdb_kernel/parser/tokenizer/__init__.py,sha256=EOSmfc2RJwtB5cE1Hhj1JAra97tckxxS8-legybPy60,58
76
+ duckdb_kernel/parser/util/QuerySplitter.py,sha256=CXpF--muxC5NuSr1xc6-EVaP-ZBXLCkDNZb6zYkRTJk,2222
74
77
  duckdb_kernel/parser/util/RenamableColumn.py,sha256=LxJhFDMUv_OxYYDLwKn63QGpBRfs08jVvhuJTzRtc9c,704
75
78
  duckdb_kernel/parser/util/RenamableColumnList.py,sha256=5oEDbtvl4YfHbkxu_Ny2pc0EYnhCZsf7EeoNQvftbrU,3281
76
79
  duckdb_kernel/parser/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- duckdb_kernel/tests/__init__.py,sha256=MxC-m85ZyYQVn5_AJyEtXX1T5oQPngjW-Zxa_gpfXLE,2715
80
+ duckdb_kernel/tests/__init__.py,sha256=-BoPfo1FNQKnvAYt22Ioc21dbuO67QVFaV_SmS1zQw8,2731
78
81
  duckdb_kernel/tests/test_dc.py,sha256=HPJ6JGB7yXVKIOnDHB8KwX1A16ljU0I5Y8VFcJs-KVI,15192
79
- duckdb_kernel/tests/test_ra.py,sha256=UENizwUqSnaObrvfliwkOakBQqNIh8tsQsgtYQ807MY,52371
82
+ duckdb_kernel/tests/test_ra.py,sha256=z7ItArWzCIoPp07pgnk8NCxZ0WsjSYIeHChmi-jWE5c,69610
80
83
  duckdb_kernel/tests/test_result_comparison.py,sha256=TQVLPKKNyV2k3i4jCfasetPfVfCzgYZr92wxQmlzPnA,3859
81
84
  duckdb_kernel/tests/test_sql.py,sha256=p7UEokoJs2xc-url7xQ4PmWKxtExrDDYnMeoyR1JD0A,1208
82
85
  duckdb_kernel/util/ResultSetComparator.py,sha256=RZDIfjJyx8-eR-HIqQlEYgZd_V1ympbszpVRF4TlA7o,2262
@@ -93,7 +96,7 @@ duckdb_kernel/visualization/lib/__init__.py,sha256=LYi0YPtn5fXOejbLIqbt_3KzP-Xrw
93
96
  duckdb_kernel/visualization/lib/plotly-3.0.1.min.js,sha256=oy6Be7Eh6eiQFs5M7oXuPxxm9qbJXEtTpfSI93dW16Q,4653932
94
97
  duckdb_kernel/visualization/lib/ra.css,sha256=foz1v69EQ117BDduB9QyHH978PbRs2TG1kBS4VGqZbI,57
95
98
  duckdb_kernel/visualization/lib/ra.js,sha256=VzMRn55ztcd5Kfu2B6gdRPARpi8n-fvs8oNFnfp55Ec,1845
96
- jupyter_duckdb-1.4.100.dist-info/METADATA,sha256=J_PSMGBEBr3NsQRcIOPh-T2a9RFN58PrXkx0k3GXRx4,9130
97
- jupyter_duckdb-1.4.100.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
98
- jupyter_duckdb-1.4.100.dist-info/top_level.txt,sha256=KvRRPMnmkQNuhyBsXoPmwyt26LRDp0O-0HN6u0Dm5jA,14
99
- jupyter_duckdb-1.4.100.dist-info/RECORD,,
99
+ jupyter_duckdb-1.4.106.dist-info/METADATA,sha256=IRd1kZI21gT9o4a8GopNzkctOcDixojRttR3ZMk7V4I,9272
100
+ jupyter_duckdb-1.4.106.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
101
+ jupyter_duckdb-1.4.106.dist-info/top_level.txt,sha256=KvRRPMnmkQNuhyBsXoPmwyt26LRDp0O-0HN6u0Dm5jA,14
102
+ jupyter_duckdb-1.4.106.dist-info/RECORD,,