@@ -359,13 +359,50 @@ def update_from_clause(
359
359
for t in extra_froms
360
360
)
361
361
362
+ def _get_regexp_args (self , binary , kw ):
363
+ string = self .process (binary .left , ** kw )
364
+ pattern = self .process (binary .right , ** kw )
365
+ flags = binary .modifiers ["flags" ]
366
+ if flags is not None :
367
+ flags = self .process (flags , ** kw )
368
+ return string , pattern , flags
369
+
370
+ def visit_regexp_match_op_binary (self , binary , operator , ** kw ):
371
+ string , pattern , flags = self ._get_regexp_args (binary , kw )
372
+ if flags is None :
373
+ return f"REGEXP_LIKE({ string } , { pattern } )"
374
+ else :
375
+ return f"REGEXP_LIKE({ string } , { pattern } , { flags } )"
376
+
377
+ def visit_regexp_replace_op_binary (self , binary , operator , ** kw ):
378
+ string , pattern , flags = self ._get_regexp_args (binary , kw )
379
+ replacement = self .process (binary .modifiers ["replacement" ], ** kw )
380
+ if flags is None :
381
+ return "REGEXP_REPLACE({}, {}, {})" .format (
382
+ string ,
383
+ pattern ,
384
+ replacement ,
385
+ )
386
+ else :
387
+ return "REGEXP_REPLACE({}, {}, {}, {})" .format (
388
+ string ,
389
+ pattern ,
390
+ replacement ,
391
+ flags ,
392
+ )
393
+
394
+ def visit_not_regexp_match_op_binary (self , binary , operator , ** kw ):
395
+ return f"NOT { self .visit_regexp_match_op_binary (binary , operator , ** kw )} "
396
+
397
+ def render_literal_value (self , value , type_ ):
398
+ # escape backslash
399
+ return super ().render_literal_value (value , type_ ).replace ("\\ " , "\\ \\ " )
400
+
362
401
363
402
class SnowflakeExecutionContext (default .DefaultExecutionContext ):
364
403
def fire_sequence (self , seq , type_ ):
365
404
return self ._execute_scalar (
366
- "SELECT "
367
- + self .dialect .identifier_preparer .format_sequence (seq )
368
- + ".nextval" ,
405
+ f"SELECT { self .identifier_preparer .format_sequence (seq )} .nextval" ,
369
406
type_ ,
370
407
)
371
408
@@ -387,6 +424,35 @@ def should_autocommit(self):
387
424
else :
388
425
return autocommit and not self .isddl
389
426
427
+ def pre_exec (self ):
428
+ if self .compiled :
429
+ # for compiled statements, percent is doubled for escape, we turn on _interpolate_empty_sequences
430
+ if hasattr (self ._dbapi_connection , "driver_connection" ):
431
+ # _dbapi_connection is a _ConnectionFairy which proxies raw SnowflakeConnection
432
+ self ._dbapi_connection .driver_connection ._interpolate_empty_sequences = (
433
+ True
434
+ )
435
+ else :
436
+ # _dbapi_connection is a raw SnowflakeConnection
437
+ self ._dbapi_connection ._interpolate_empty_sequences = True
438
+
439
+ def post_exec (self ):
440
+ if self .compiled :
441
+ # for compiled statements, percent is doubled for escapeafter execution
442
+ # we reset _interpolate_empty_sequences to false which is turned on in pre_exec
443
+ if hasattr (self ._dbapi_connection , "driver_connection" ):
444
+ # _dbapi_connection is a _ConnectionFairy which proxies raw SnowflakeConnection
445
+ self ._dbapi_connection .driver_connection ._interpolate_empty_sequences = (
446
+ False
447
+ )
448
+ else :
449
+ # _dbapi_connection is a raw SnowflakeConnection
450
+ self ._dbapi_connection ._interpolate_empty_sequences = False
451
+
452
+ @property
453
+ def rowcount (self ):
454
+ return self .cursor .rowcount
455
+
390
456
391
457
class SnowflakeDDLCompiler (compiler .DDLCompiler ):
392
458
def denormalize_column_name (self , name ):
@@ -406,6 +472,10 @@ def get_column_specification(self, column, **kwargs):
406
472
self .dialect .type_compiler .process (column .type , type_expression = column ),
407
473
]
408
474
475
+ has_identity = (
476
+ column .identity is not None and self .dialect .supports_identity_columns
477
+ )
478
+
409
479
if not column .nullable :
410
480
colspec .append ("NOT NULL" )
411
481
@@ -422,10 +492,15 @@ def get_column_specification(self, column, **kwargs):
422
492
and column .server_default is None
423
493
):
424
494
if isinstance (column .default , Sequence ):
425
- colspec .append (f"DEFAULT { column .default .name } .nextval" )
495
+ colspec .append (
496
+ f"DEFAULT { self .dialect .identifier_preparer .format_sequence (column .default )} .nextval"
497
+ )
426
498
else :
427
499
colspec .append ("AUTOINCREMENT" )
428
500
501
+ if has_identity :
502
+ colspec .append (self .process (column .identity ))
503
+
429
504
return " " .join (colspec )
430
505
431
506
def post_create_table (self , table ):
@@ -512,6 +587,14 @@ def visit_drop_column_comment(self, drop, **kw):
512
587
self .preparer .format_column (drop .element ),
513
588
)
514
589
590
+ def visit_identity_column (self , identity , ** kw ):
591
+ text = " IDENTITY"
592
+ if identity .start is not None or identity .increment is not None :
593
+ start = 1 if identity .start is None else identity .start
594
+ increment = 1 if identity .increment is None else identity .increment
595
+ text += f"({ start } ,{ increment } )"
596
+ return text
597
+
515
598
516
599
class SnowflakeTypeCompiler (compiler .GenericTypeCompiler ):
517
600
def visit_BYTEINT (self , type_ , ** kw ):
0 commit comments