@@ -127,6 +127,14 @@ def joins(self) -> bool:
127
127
"""
128
128
return False
129
129
130
+ @property
131
+ @abc .abstractmethod
132
+ def order_ambiguous (self ) -> bool :
133
+ """
134
+ Whether row ordering is potentially ambiguous. For example, ReadTable (without a primary key) could be ordered in different ways.
135
+ """
136
+ ...
137
+
130
138
@functools .cached_property
131
139
def total_variables (self ) -> int :
132
140
return self .variables_introduced + sum (
@@ -177,6 +185,10 @@ def transform_children(
177
185
) -> BigFrameNode :
178
186
return replace (self , child = t (self .child ))
179
187
188
+ @property
189
+ def order_ambiguous (self ) -> bool :
190
+ return self .child .order_ambiguous
191
+
180
192
181
193
@dataclass (frozen = True )
182
194
class JoinNode (BigFrameNode ):
@@ -196,6 +208,10 @@ def non_local(self) -> bool:
196
208
def child_nodes (self ) -> typing .Sequence [BigFrameNode ]:
197
209
return (self .left_child , self .right_child )
198
210
211
+ @property
212
+ def order_ambiguous (self ) -> bool :
213
+ return True
214
+
199
215
def __hash__ (self ):
200
216
return self ._node_hash
201
217
@@ -247,6 +263,10 @@ def __post_init__(self):
247
263
def child_nodes (self ) -> typing .Sequence [BigFrameNode ]:
248
264
return self .children
249
265
266
+ @property
267
+ def order_ambiguous (self ) -> bool :
268
+ return any (child .order_ambiguous for child in self .children )
269
+
250
270
def __hash__ (self ):
251
271
return self ._node_hash
252
272
@@ -293,6 +313,10 @@ def variables_introduced(self) -> int:
293
313
"""Defines the number of variables generated by the current node. Used to estimate query planning complexity."""
294
314
return len (self .schema .items ) + 1
295
315
316
+ @property
317
+ def order_ambiguous (self ) -> bool :
318
+ return False
319
+
296
320
def transform_children (
297
321
self , t : Callable [[BigFrameNode ], BigFrameNode ]
298
322
) -> BigFrameNode :
@@ -350,6 +374,10 @@ def relation_ops_created(self) -> int:
350
374
# Assume worst case, where readgbq actually has baked in analytic operation to generate index
351
375
return 3
352
376
377
+ @property
378
+ def order_ambiguous (self ) -> bool :
379
+ return len (self .total_order_cols ) == 0
380
+
353
381
@functools .cached_property
354
382
def variables_introduced (self ) -> int :
355
383
return len (self .schema .items ) + 1
@@ -417,6 +445,10 @@ def hidden_columns(self) -> typing.Tuple[str, ...]:
417
445
if col not in self .schema .names
418
446
)
419
447
448
+ @property
449
+ def order_ambiguous (self ) -> bool :
450
+ return not isinstance (self .ordering , orderings .TotalOrdering )
451
+
420
452
def transform_children (
421
453
self , t : Callable [[BigFrameNode ], BigFrameNode ]
422
454
) -> BigFrameNode :
@@ -600,6 +632,10 @@ def schema(self) -> schemata.ArraySchema:
600
632
def variables_introduced (self ) -> int :
601
633
return len (self .aggregations ) + len (self .by_column_ids )
602
634
635
+ @property
636
+ def order_ambiguous (self ) -> bool :
637
+ return False
638
+
603
639
604
640
@dataclass (frozen = True )
605
641
class WindowOpNode (UnaryNode ):
0 commit comments