27
27
import com .google .common .collect .Sets ;
28
28
import jakarta .enterprise .context .ApplicationScoped ;
29
29
import jakarta .inject .Inject ;
30
-
31
30
import java .lang .reflect .Field ;
32
- import java .lang .reflect .Modifier ;
33
31
import java .time .OffsetDateTime ;
34
32
import java .time .ZoneOffset ;
35
33
import java .util .*;
36
34
import java .util .concurrent .atomic .AtomicBoolean ;
37
- import java .util .regex .Matcher ;
38
35
import java .util .regex .Pattern ;
39
36
import java .util .stream .Collectors ;
37
+ import net .sf .jsqlparser .expression .Expression ;
38
+ import net .sf .jsqlparser .expression .Function ;
39
+ import net .sf .jsqlparser .expression .StringValue ;
40
+ import net .sf .jsqlparser .expression .operators .relational .ExpressionList ;
41
+ import net .sf .jsqlparser .parser .CCJSqlParserUtil ;
42
+ import net .sf .jsqlparser .statement .Statement ;
43
+ import net .sf .jsqlparser .statement .select .Select ;
44
+ import net .sf .jsqlparser .util .deparser .ExpressionDeParser ;
45
+ import net .sf .jsqlparser .util .deparser .SelectDeParser ;
40
46
import org .apache .iceberg .BaseMetadataTable ;
41
47
import org .apache .iceberg .BaseTable ;
42
48
import org .apache .iceberg .BaseTransaction ;
@@ -91,10 +97,11 @@ public class CatalogHandlerUtils {
91
97
private static final String INITIAL_PAGE_TOKEN = "" ;
92
98
93
99
// is_principal_role('ANALYST')
94
- private static final Pattern IS_PRINCIPAL_ROLE = Pattern .compile (
100
+ private static final Pattern IS_PRINCIPAL_ROLE =
101
+ Pattern .compile (
95
102
"is_principal_role\\ (\\ s*'([^']+)'\\ s*\\ )" ,
96
- Pattern .CASE_INSENSITIVE // drop this flag if you want case-sensitive
97
- );
103
+ Pattern .CASE_INSENSITIVE // drop this flag if you want case-sensitive
104
+ );
98
105
99
106
private final PolarisCallContext polarisCallContext ;
100
107
private final PolarisConfigurationStore configurationStore ;
@@ -521,28 +528,91 @@ public LoadViewResponse createView(
521
528
return viewResponse (view , Set .of ());
522
529
}
523
530
531
+ // NOTE: This is just put together to do a quick POC
532
+ public static String rewriteIdentityFunctions (String sql , Set <String > authenticatedPrincipals ) {
533
+ Statement statement = null ;
534
+ try {
535
+ statement = CCJSqlParserUtil .parse (sql );
536
+ } catch (Exception e ) {
537
+ return sql ;
538
+ }
539
+
540
+ class CustomExpressionDeParser extends ExpressionDeParser {
541
+ private boolean isConverted = false ;
542
+
543
+ @ Override
544
+ public void visit (Function function ) {
545
+ String name = function .getName ().toLowerCase (Locale .ROOT );
546
+ if (Set .of ("is_principal" , "is_principal_role" , "is_catalog_role" ).contains (name )) {
547
+ ExpressionList params = function .getParameters ();
548
+ if (params != null && !params .getExpressions ().isEmpty ()) {
549
+ Expression argExpr = params .getExpressions ().getFirst ();
550
+ String arg =
551
+ argExpr instanceof StringValue
552
+ ? ((StringValue ) argExpr ).getValue ()
553
+ : argExpr .toString ();
554
+
555
+ boolean result = evaluateFunction (name , arg );
556
+ getBuffer ().append (result ? "TRUE" : "FALSE" );
557
+ isConverted = true ;
558
+ } else {
559
+ super .visit (function );
560
+ }
561
+ } else {
562
+ super .visit (function );
563
+ }
564
+ }
565
+
566
+ private boolean evaluateFunction (String functionName , String arg ) {
567
+ return switch (functionName ) {
568
+ case "is_principal" , "is_catalog_role" , "is_principal_role" ->
569
+ authenticatedPrincipals .contains (arg );
570
+ default -> false ;
571
+ };
572
+ }
573
+
574
+ public boolean isConverted () {
575
+ return isConverted ;
576
+ }
577
+ }
578
+
579
+ StringBuilder buffer = new StringBuilder ();
580
+ CustomExpressionDeParser exprDeParser = new CustomExpressionDeParser ();
581
+
582
+ SelectDeParser selectDeParser = new SelectDeParser ((ExpressionDeParser ) exprDeParser , buffer );
583
+ exprDeParser .setSelectVisitor (selectDeParser );
584
+ exprDeParser .setBuffer (buffer );
585
+
586
+ if (statement instanceof Select select ) {
587
+ select .getSelectBody ().accept (selectDeParser );
588
+ }
589
+
590
+ if (exprDeParser .isConverted ()) {
591
+ return buffer .toString ();
592
+ } else {
593
+ return sql ;
594
+ }
595
+ }
596
+
524
597
private LoadViewResponse viewResponse (View view , Set <String > authenticatedPrincipals ) {
525
598
ViewMetadata metadata = asBaseView (view ).operations ().current ();
526
- // in all the representations, find and replace the is_principal_role('ANALYST')
527
599
ViewVersion version = metadata .currentVersion ();
528
600
List <ViewRepresentation > representations = version .representations ();
529
601
List <ViewRepresentation > identityResolved = new ArrayList <>(representations .size ());
530
602
for (ViewRepresentation viewRepresentation : representations ) {
531
603
if (viewRepresentation instanceof SQLViewRepresentation sqlView ) {
532
- Matcher m = IS_PRINCIPAL_ROLE .matcher (sqlView .sql ());
533
- StringBuffer sb = new StringBuffer (); // efficient incremental builder
534
- while (m .find ()) {
535
- String groupName = m .group (1 ); // captured expected principal name
536
- String replacement = authenticatedPrincipals .contains (groupName ) ? "TRUE" : "FALSE" ;
537
- m .appendReplacement (sb , replacement );
538
- }
539
- m .appendTail (sb );
540
- identityResolved .add (ImmutableSQLViewRepresentation .builder ().sql (sb .toString ()).dialect (sqlView .dialect ()).build ());
604
+ String modifiedSQL = rewriteIdentityFunctions (sqlView .sql (), authenticatedPrincipals );
605
+ identityResolved .add (
606
+ ImmutableSQLViewRepresentation .builder ()
607
+ .sql (modifiedSQL )
608
+ .dialect (sqlView .dialect ())
609
+ .build ());
541
610
} else {
542
611
identityResolved .add (viewRepresentation );
543
612
}
544
613
}
545
- ImmutableViewVersion resolvedViewVersion = ImmutableViewVersion .builder ().from (version ).build ().withRepresentations (identityResolved );
614
+ ImmutableViewVersion resolvedViewVersion =
615
+ ImmutableViewVersion .builder ().from (version ).build ().withRepresentations (identityResolved );
546
616
547
617
// This is a temp hack, for quick POC
548
618
Class <?> clazz = metadata .getClass ();
@@ -567,7 +637,8 @@ public void viewExists(ViewCatalog catalog, TableIdentifier viewIdentifier) {
567
637
}
568
638
}
569
639
570
- public LoadViewResponse loadView (ViewCatalog catalog , TableIdentifier viewIdentifier , Set <String > principal ) {
640
+ public LoadViewResponse loadView (
641
+ ViewCatalog catalog , TableIdentifier viewIdentifier , Set <String > principal ) {
571
642
View view = catalog .loadView (viewIdentifier );
572
643
return viewResponse (view , principal );
573
644
}
0 commit comments