justinmclean opened a new issue, #10165:
URL: https://github.com/apache/gravitino/issues/10165

   ### What would you like to be improved?
   
   LancePartitionStatisticStorage.dropStatisticsImpl(...) builds 
dataset.delete(...) filter strings by concatenating raw partitionName and 
statisticNames into SQL literals. If a value contains a single quote (for 
example, partition'01), the generated filter is invalid and deletion fails; 
crafted input can also broaden the deletion scope.
   
   ### How should we improve?
   
   Sanitize all string literals before embedding in filter SQL, at minimum by 
escaping single quotes (' -> '') for:
   - partition_name = '...'
   - each item in statistic_name IN ('...')
   
   Prefer a small helper like escapeSqlLiteral(String) and use it consistently 
in dropStatisticsImpl (and any similar filter builders).
   
   Here's a unit test to help:
   ```
   public class TestLancePartitionStatisticStorageSqlEscapeBug {
   
     @Test
     public void testDropStatisticsWithQuoteInPartitionName() throws Exception {
       PartitionStatisticStorageFactory factory = new 
LancePartitionStatisticStorageFactory();
       String metalakeName = "metalake";
       MetadataObject metadataObject =
           MetadataObjects.of(Lists.newArrayList("catalog", "schema", "table"), 
MetadataObject.Type.TABLE);
   
       EntityStore entityStore = mock(EntityStore.class);
       TableEntity tableEntity = mock(TableEntity.class);
       when(entityStore.get(any(), any(), any())).thenReturn(tableEntity);
       when(tableEntity.id()).thenReturn(1L);
       FieldUtils.writeField(GravitinoEnv.getInstance(), "entityStore", 
entityStore, true);
   
       String location = 
Files.createTempDirectory("lance_stats_test_quote").toString();
       Map<String, String> properties = Maps.newHashMap();
       properties.put("location", location);
   
       LancePartitionStatisticStorage storage =
           (LancePartitionStatisticStorage) factory.create(properties);
       try {
         String quotedPartition = "partition'01";
         Map<String, StatisticValue<?>> stats = Maps.newHashMap();
         stats.put("statistic0", StatisticValues.stringValue("value0"));
   
         storage.updateStatistics(
             metalakeName,
             Lists.newArrayList(
                 MetadataObjectStatisticsUpdate.of(
                     metadataObject,
                     Lists.newArrayList(
                         
PartitionStatisticsModification.update(quotedPartition, stats)))));
   
         PartitionStatisticsDrop drop =
             PartitionStatisticsModification.drop(quotedPartition, 
Lists.newArrayList("statistic0"));
   
         Assertions.assertDoesNotThrow(
             () ->
                 storage.dropStatistics(
                     metalakeName,
                     Lists.newArrayList(
                         MetadataObjectStatisticsDrop.of(metadataObject, 
Lists.newArrayList(drop)))));
       } finally {
         FileUtils.deleteDirectory(new File(location + "/" + tableEntity.id() + 
".lance"));
         storage.close();
       }
     }
   }
   ```
   
   You'll likley need to run  ./gradlew :core:spotlessApply to correctly format 
this.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to