@@ -492,6 +492,169 @@ protected long calculateBytesUsed() {
492492 + InsertNodeMemoryEstimator .sizeOfColumns (columns , measurementSchemas );
493493 }
494494
495+ /**
496+ * Convert this InsertTabletStatement to Tablet. This method constructs a Tablet object from this
497+ * statement, converting all necessary fields. All arrays are copied to rowSize length to ensure
498+ * immutability.
499+ *
500+ * @return Tablet object
501+ * @throws MetadataException if conversion fails
502+ */
503+ public Tablet convertToTablet () throws MetadataException {
504+ try {
505+ // Get deviceId/tableName from devicePath
506+ final String deviceIdOrTableName =
507+ this .getDevicePath () != null ? this .getDevicePath ().getFullPath () : "" ;
508+
509+ // Get schemas from measurementSchemas
510+ final MeasurementSchema [] measurementSchemas = this .getMeasurementSchemas ();
511+ final String [] measurements = this .getMeasurements ();
512+ final TSDataType [] dataTypes = this .getDataTypes ();
513+ // If measurements and dataTypes are not null, use measurements.length as the standard length
514+ final int originalSchemaSize = measurements != null ? measurements .length : 0 ;
515+
516+ // Build schemas and track valid column indices (skip null columns)
517+ // measurements and dataTypes being null is standard - skip those columns
518+ final List <MeasurementSchema > schemas = new ArrayList <>(originalSchemaSize );
519+ final int [] validColumnIndices = new int [originalSchemaSize ];
520+ int validColumnCount = 0 ;
521+ if (dataTypes != null ) {
522+ final int dataTypeSize = Math .min (originalSchemaSize , dataTypes .length );
523+ for (int i = 0 ; i < dataTypeSize ; i ++) {
524+ if (measurements [i ] != null && dataTypes [i ] != null ) {
525+ final MeasurementSchema measurementSchema =
526+ measurementSchemas != null && i < measurementSchemas .length
527+ ? measurementSchemas [i ]
528+ : null ;
529+ schemas .add (
530+ measurementSchema != null
531+ && Objects .equals (measurementSchema .getMeasurementId (), measurements [i ])
532+ && measurementSchema .getType () == dataTypes [i ]
533+ ? measurementSchema
534+ : new MeasurementSchema (measurements [i ], dataTypes [i ]));
535+ validColumnIndices [validColumnCount ++] = i ;
536+ }
537+ }
538+ }
539+
540+ final int schemaSize = validColumnCount ;
541+
542+ // Get timestamps - always copy to ensure immutability
543+ final long [] times = this .getTimes ();
544+ final int rowSize = this .getRowCount ();
545+ final long [] timestamps ;
546+ if (rowSize == 0 ) {
547+ timestamps = new long [0 ];
548+ } else if (times != null && times .length >= rowSize ) {
549+ timestamps = Arrays .copyOf (times , rowSize );
550+ } else {
551+ LOGGER .warn (
552+ "Times array is null or too small. times.length={}, rowSize={}, deviceId={}" ,
553+ times != null ? times .length : 0 ,
554+ rowSize ,
555+ deviceIdOrTableName );
556+ timestamps = new long [0 ];
557+ }
558+
559+ // Get values - convert Statement columns to Tablet format, only for valid columns
560+ // All arrays are copied to rowSize length
561+ final Object [] statementColumns = this .getColumns ();
562+ final Object [] tabletValues = new Object [schemaSize ];
563+ if (statementColumns != null && statementColumns .length > 0 ) {
564+ for (int i = 0 ; i < schemaSize ; i ++) {
565+ final int originalIndex = validColumnIndices [i ];
566+ if (originalIndex < statementColumns .length
567+ && statementColumns [originalIndex ] != null
568+ && dataTypes [originalIndex ] != null ) {
569+ tabletValues [i ] =
570+ convertColumnToTablet (
571+ statementColumns [originalIndex ], dataTypes [originalIndex ], rowSize );
572+ } else {
573+ tabletValues [i ] = null ;
574+ }
575+ }
576+ }
577+
578+ // Get bitMaps - copy and truncate to rowSize, only for valid columns
579+ final BitMap [] originalBitMaps = this .getBitMaps ();
580+ BitMap [] bitMaps = null ;
581+ if (originalBitMaps != null && originalBitMaps .length > 0 ) {
582+ final BitMap [] copiedBitMaps = new BitMap [schemaSize ];
583+ for (int i = 0 ; i < schemaSize ; i ++) {
584+ final int originalIndex = validColumnIndices [i ];
585+ if (originalIndex < originalBitMaps .length && originalBitMaps [originalIndex ] != null ) {
586+ final BitMap originalBitMap = originalBitMaps [originalIndex ];
587+ if (!originalBitMap .isAllUnmarked ()) {
588+ copiedBitMaps [i ] =
589+ originalBitMap .getRegion (0 , Math .min (rowSize , originalBitMap .getSize ()));
590+ }
591+ } else {
592+ copiedBitMaps [i ] = null ;
593+ }
594+ }
595+ bitMaps = BitMapUtils .compactBitMaps (copiedBitMaps , rowSize );
596+ }
597+
598+ return new Tablet (deviceIdOrTableName , schemas , timestamps , tabletValues , bitMaps , rowSize );
599+ } catch (final Exception e ) {
600+ throw new MetadataException ("Failed to convert InsertTabletStatement to Tablet: " , e );
601+ }
602+ }
603+
604+ /**
605+ * Convert a single column value from Statement format to Tablet format. Statement uses primitive
606+ * arrays (e.g., int[], long[], float[]), while Tablet may need different format. All arrays are
607+ * copied to rowSize length to ensure immutability - even if the original array is modified, the
608+ * converted array remains unchanged.
609+ *
610+ * @param columnValue column value from Statement (primitive array)
611+ * @param dataType data type of the column
612+ * @param rowSize number of rows to copy
613+ * @return column value in Tablet format (copied to rowSize)
614+ */
615+ private Object convertColumnToTablet (
616+ final Object columnValue , final TSDataType dataType , final int rowSize ) {
617+
618+ if (columnValue == null ) {
619+ return null ;
620+ }
621+
622+ if (TSDataType .DATE .equals (dataType )) {
623+ final int [] values = (int []) columnValue ;
624+ final LocalDate [] localDateValue = new LocalDate [rowSize ];
625+ final int size = Math .min (values .length , rowSize );
626+ for (int i = 0 ; i < size ; i ++) {
627+ localDateValue [i ] = DateUtils .parseIntToLocalDate (values [i ]);
628+ }
629+ return localDateValue ;
630+ }
631+
632+ // For primitive arrays, copy to rowSize
633+ if (columnValue instanceof boolean []) {
634+ final boolean [] original = (boolean []) columnValue ;
635+ return Arrays .copyOf (original , rowSize );
636+ } else if (columnValue instanceof int []) {
637+ final int [] original = (int []) columnValue ;
638+ return Arrays .copyOf (original , rowSize );
639+ } else if (columnValue instanceof long []) {
640+ final long [] original = (long []) columnValue ;
641+ return Arrays .copyOf (original , rowSize );
642+ } else if (columnValue instanceof float []) {
643+ final float [] original = (float []) columnValue ;
644+ return Arrays .copyOf (original , rowSize );
645+ } else if (columnValue instanceof double []) {
646+ final double [] original = (double []) columnValue ;
647+ return Arrays .copyOf (original , rowSize );
648+ } else if (columnValue instanceof Binary []) {
649+ // For Binary arrays, create a new array and copy references to rowSize
650+ final Binary [] original = (Binary []) columnValue ;
651+ return Arrays .copyOf (original , rowSize );
652+ }
653+
654+ // For other types, return as-is (should not happen for standard types)
655+ return columnValue ;
656+ }
657+
495658 @ Override
496659 public String toString () {
497660 final int size = CommonDescriptor .getInstance ().getConfig ().getPathLogMaxSize ();
0 commit comments