Victor Barasuol

70 papers A* 6A 8C 1Journal 41Unranked 13
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Robotics Autom. Lett.
Lorenzo Amatucci, João Sousa Pinto, Giulio Turrisi, Dominique Orban, Victor Barasuol, Claudio Semini
2025 J jnl
CoRR
Giovanni Minelli, Giulio Turrisi, Victor Barasuol, Claudio Semini
2025 J jnl
CoRR
Lucas Schulze, Juliano Negri, Victor Barasuol, Vivian Suzano Medeiros, Marcelo Becker, Jan Peters, Oleg Arenz
2025 conf
ICAR
Sinan Emre, Victor Barasuol, Matteo Villa, Claudio Semini
2025 J jnl
CoRR
Sinan Emre, Victor Barasuol, Matteo Villa, Claudio Semini
2025 J jnl
IEEE Robotics Autom. Lett.
Vivian Suzano Medeiros, Giovanni Dessy, Thiago Boaventura, Marcelo Becker, Claudio Semini, Victor Barasuol
2025 J jnl
CoRR
Vivian Suzano Medeiros, Giovanni Dessy, Thiago Boaventura, Marcelo Becker, Claudio Semini, Victor Barasuol
2025 J jnl
IEEE Robotics Autom. Lett.
Ilyass Taouil, Lorenzo Amatucci, Majid Khadiv, Angela Dai, Victor Barasuol, Giulio Turrisi, Claudio Semini
2025 J jnl
CoRR
Lorenzo Amatucci, João Sousa Pinto, Giulio Turrisi, Dominique Orban, Victor Barasuol, Claudio Semini
2025 J jnl
CoRR
Gabriel Fischer Abati, João Carlos Virgolino Soares, Giulio Turrisi, Victor Barasuol, Claudio Semini
2025 conf
ICAR
Mattia Risiglione, Abdelrahman Abdalla, Victor Barasuol, Kim Tien Ly, Ioannis Havoutis, Claudio Semini
2025 J jnl
CoRR
Mattia Risiglione, Abdelrahman Abdalla, Victor Barasuol, Kim Tien Ly, Ioannis Havoutis, Claudio Semini
2025 J jnl
CoRR
Alberto Sánchez-Delgado, João Carlos Virgolino Soares, David Omar Al Tawil, Alessia Li Noce, Matteo Villa, Victor Barasuol, Paolo Arena, Claudio Semini
2025 J jnl
CoRR
Alberto Sánchez-Delgado, João Carlos Virgolino Soares, Victor Barasuol, Claudio Semini
2024 conf
CLAWAR (2)
Alex T. Leonardi, Vivian Suzano Medeiros, Claudio Semini, Victor Barasuol
2024 A conf
IROS
Lorenzo Amatucci, Giulio Turrisi, Angelo Bratta, Victor Barasuol, Claudio Semini
2024 J jnl
CoRR
Lorenzo Amatucci, Giulio Turrisi, Angelo Bratta, Victor Barasuol, Claudio Semini
2024 A* conf
ICRA
Victor Barasuol, Sinan Emre, Vivian Suzano Medeiros, Angelo Bratta, Claudio Semini
2024 J jnl
CoRR
Ilyass Taouil, Lorenzo Amatucci, Majid Khadiv, Angela Dai, Victor Barasuol, Giulio Turrisi, Claudio Semini
2024 A conf
IROS
Giulio Turrisi, Lucas Schulze, Vivian Suzano Medeiros, Claudio Semini, Victor Barasuol
2024 J jnl
CoRR
Giulio Turrisi, Lucas Schulze, Vivian Suzano Medeiros, Claudio Semini, Victor Barasuol
2024 J jnl
J. Field Robotics
Lorenzo Amatucci, Giulio Turrisi, Angelo Bratta, Victor Barasuol, Claudio Semini
2023 J jnl
CoRR
Shafeef Omar, Lorenzo Amatucci, Giulio Turrisi, Victor Barasuol, Claudio Semini
2023 A conf
IROS
Riccardo Parosi, Mattia Risiglione, Darwin G. Caldwell, Claudio Semini, Victor Barasuol
2023 J jnl
CoRR
Riccardo Parosi, Mattia Risiglione, Darwin G. Caldwell, Claudio Semini, Victor Barasuol
2023 A conf
IROS
Ilyass Taouil, Giulio Turrisi, Daniel Schleich, Victor Barasuol, Claudio Semini, Sven Behnke
2023 J jnl
CoRR
Ilyass Taouil, Giulio Turrisi, Daniel Schleich, Victor Barasuol, Claudio Semini, Sven Behnke
2023 conf
Humanoids
Shafeef Omar, Lorenzo Amatucci, Victor Barasuol, Giulio Turrisi, Claudio Semini
2023 J jnl
CoRR
Shafeef Omar, Lorenzo Amatucci, Victor Barasuol, Giulio Turrisi, Claudio Semini
2023 conf
CLAWAR (1)
Victor Barasuol, Sinan Emre, Claudio Semini
2023 J jnl
IEEE Trans. Robotics
Shamel Fahmi, Victor Barasuol, Domingo Esteban, Octavio Villarreal, Claudio Semini
2022 A conf
IROS
Mattia Risiglione, Victor Barasuol, Darwin G. Caldwell, Claudio Semini
2022 J jnl
CoRR
Mattia Risiglione, Victor Barasuol, Darwin G. Caldwell, Claudio Semini
2022 A* conf
ICRA
Luca Clemente, Octavio Villarreal, Angelo Bratta, Michele Focchi, Victor Barasuol, Giovanni Gerardo Muscolo, Claudio Semini
2022 J jnl
CoRR
Luca Clemente, Octavio Villarreal, Angelo Bratta, Michele Focchi, Victor Barasuol, Giovanni Gerardo Muscolo, Claudio Semini
2022 conf
LARS/SBR/WRE
Aureo Guilherme Dobrikopf, Lucas Schulze, Douglas Wildgrube Bertol, Victor Barasuol
2022 J jnl
CoRR
Shamel Fahmi, Victor Barasuol, Domingo Esteban, Octavio Villarreal, Claudio Semini
2021 J jnl
Auton. Robots
Gabriel Urbain, Victor Barasuol, Claudio Semini, Joni Dambre, Francis Wyffels
2020 J jnl
IEEE Trans. Robotics
Romeo Orsolino, Michele Focchi, Stéphane Caron, Gennaro Raiola, Victor Barasuol, Darwin G. Caldwell, Claudio Semini
2020 ch.
ECHORD++
Michele Focchi, Romeo Orsolino, Marco Camurri, Victor Barasuol, Carlos Mastalli, Darwin G. Caldwell, Claudio Semini
2020 A conf
IROS
Carlos Gonzalez, Victor Barasuol, Marco Frigerio, Roy Featherstone, Darwin G. Caldwell, Claudio Semini
2020 J jnl
CoRR
Carlos Gonzalez, Victor Barasuol, Marco Frigerio, Roy Featherstone, Darwin G. Caldwell, Claudio Semini
2020 A* conf
ICRA
Octavio Villarreal, Victor Barasuol, Patrick M. Wensing, Darwin G. Caldwell, Claudio Semini
2020 A* conf
ICRA
Angelo Bratta, Romeo Orsolino, Michele Focchi, Victor Barasuol, Giovanni Gerardo Muscolo, Claudio Semini
2020 J jnl
IEEE Trans. Robotics
Shamel Fahmi, Michele Focchi, Andreea Radulescu, Geoff Fink, Victor Barasuol, Claudio Semini
2020 A* conf
ICRA
Gabriel Urbain, Victor Barasuol, Claudio Semini, Joni Dambre, Francis Wyffels
2020 J jnl
CoRR
Gabriel Urbain, Victor Barasuol, Claudio Semini, Joni Dambre, Francis Wyffels
2019 J jnl
IEEE Robotics Autom. Lett.
Octavio Antonio Villarreal-Magaña, Victor Barasuol, Marco Camurri, Luca Franceschi, Michele Focchi, Massimiliano Pontil, Darwin G. Caldwell, Claudio Semini
2019 J jnl
CoRR
Romeo Orsolino, Michele Focchi, Stéphane Caron, Gennaro Raiola, Victor Barasuol, Claudio Semini
2019 J jnl
CoRR
Octavio Antonio Villarreal-Magaña, Victor Barasuol, Patrick M. Wensing, Claudio Semini
2019 J jnl
CoRR
Angelo Bratta, Romeo Orsolino, Michele Focchi, Victor Barasuol, Giovanni Gerardo Muscolo, Claudio Semini
2019 J jnl
CoRR
Shamel Fahmi, Michele Focchi, Andreea Radulescu, Geoff Fink, Victor Barasuol, Claudio Semini
2018 J jnl
CoRR
Octavio Antonio Villarreal-Magaña, Victor Barasuol, Marco Camurri, Michele Focchi, Luca Franceschi, Massimiliano Pontil, Darwin G. Caldwell, Claudio Semini
2018 J jnl
CoRR
Michele Focchi, Romeo Orsolino, Marco Camurri, Victor Barasuol, Carlos Mastalli, Darwin G. Caldwell, Claudio Semini
2018 J jnl
Frontiers Robotics AI
Victor Barasuol, Octavio Antonio Villarreal-Magaña, Dhinesh Sangiah, Marco Frigerio, Mike Baker, Robert Morgan, Gustavo A. Medrano-Cerda, Darwin G. Caldwell, Claudio Semini
2017 conf
Robotics: Science and Systems
Simona Nobili, Marco Camurri, Victor Barasuol, Michele Focchi, Darwin G. Caldwell, Claudio Semini, Maurice F. Fallon
2017 conf
ICARM
Yifu Gao, Victor Barasuol, Darwin G. Caldwell, Claudio Semini
2017 conf
Humanoids
Elco Heijmink, Andreea Radulescu, Brahayam Ponton, Victor Barasuol, Darwin G. Caldwell, Claudio Semini
2017 J jnl
IEEE Robotics Autom. Lett.
Marco Camurri, Maurice F. Fallon, Stéphane Bazeille, Andreea Radulescu, Victor Barasuol, Darwin G. Caldwell, Claudio Semini
2016 conf
ROBIO
Yifu Gao, Victor Barasuol, Darwin G. Caldwell, Claudio Semini
2016 J jnl
CoRR
Marco Frigerio, Victor Barasuol, Michele Focchi, Claudio Semini
2015 conf
TePRA
Hamza Khan, Satoshi Kitano, Marco Frigerio, Marco Camurri, Victor Barasuol, Roy Featherstone, Darwin G. Caldwell, Claudio Semini
2015 A conf
IROS
Victor Barasuol, Marco Camurri, Stéphane Bazeille, Darwin G. Caldwell, Claudio Semini
2015 conf
ISRR (2)
Michele Focchi, Victor Barasuol, Marco Frigerio, Darwin G. Caldwell, Claudio Semini
2015 J jnl
Int. J. Robotics Res.
Claudio Semini, Victor Barasuol, Thiago Boaventura Cunha, Marco Frigerio, Michele Focchi, Darwin G. Caldwell, Jonas Buchli
2014 J jnl
Intell. Serv. Robotics
Stéphane Bazeille, Victor Barasuol, Michele Focchi, Ioannis Havoutis, Marco Frigerio, Jonas Buchli, Darwin G. Caldwell, Claudio Semini
2013 A* conf
ICRA
Victor Barasuol, Jonas Buchli, Claudio Semini, Marco Frigerio, Edson R. de Pieri, Darwin G. Caldwell
2013 C conf
ISRR
Claudio Semini, Victor Barasuol, Thiago Boaventura Cunha, Marco Frigerio, Jonas Buchli
2013 A conf
IROS
Ioannis Havoutis, Jesús Ortiz, Stéphane Bazeille, Victor Barasuol, Claudio Semini, Darwin G. Caldwell
2013 conf
TePRA
Stéphane Bazeille, Victor Barasuol, Michele Focchi, Ioannis Havoutis, Marco Frigerio, Jonas Buchli, Claudio Semini, Darwin G. Caldwell
redb/extractors/database_exporters.py
← Index redb/extractors/database_exporters.py python
from abc import ABC, abstractmethod
from datetime import datetime, timezone
from dataclasses import asdict
import hashlib
import json
import inspect
from typing import Any, Dict, List, Union
from redb import settings
import traceback
from contextlib import contextmanager

class DatabaseExporter(ABC):
    @abstractmethod
    def export(self, data: Any, **kwargs) -> bool:
        """Export data to the database"""
        pass

class ElasticsearchExporter(DatabaseExporter):
    def __init__(self, logger: Any, index_prefix: str):
        self.client = settings.get_elasticsearch_client()
        self.index_prefix = index_prefix
        self.log = logger

    def export(self, data: Any, **kwargs) -> bool:
        self.log.debug(inspect.currentframe().f_code.co_name)
        if not isinstance(data, list):
            data = [data]
            
        now_t = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
        index = kwargs.get('index')
        tag = kwargs.get('tag')
        hashes = kwargs.get('hashes')
        
        for dataclass_ in data:
            try:
                # Convert dataclass to dict and filter out None values
                document = {k: v for k, v in asdict(dataclass_).items() if v is not None}
                
                if tag:
                    document["tag"] = tag
                document |= hashes
                document["timestamp_utc"] = now_t
                document["known_benign"] = kwargs.get('known_benign', False)
                document["known_malicious"] = kwargs.get('known_malicious', False)

                if "_id" in document:
                    tmp_id = document.pop("_id") + document["sha256"]
                    _id = hashlib.sha256(tmp_id.encode()).hexdigest()
                else:
                    _id = document["sha256"]

                doc_dump = json.dumps(document)
                self.client.index(index=index, id=_id, document=doc_dump)
                
            except Exception as e:
                self.log.error(f"Failed to export to Elasticsearch: {e}")
                return False
                
        return True

class PrintExporter(DatabaseExporter):
    """Exporter that prints results instead of uploading to database (for dry-run mode)"""
    def __init__(self, logger: Any, index_prefix: str):
        self.index_prefix = index_prefix
        self.log = logger
        self.log.debug(f"PrintExporter initialized with index_prefix: {index_prefix}")

    def export(self, data: Any, **kwargs) -> bool:
        try:
            import json
            from dataclasses import asdict, is_dataclass

            self.log.debug(f"PrintExporter.export called with data type: {type(data)}")

            if data is None:
                self.log.debug("PrintExporter.export: data is None, returning True")
                return True

            if not isinstance(data, list):
                data = [data]

            for i, item in enumerate(data):
                if is_dataclass(item) and not isinstance(item, type):
                    # Convert dataclass instance to dict
                    try:
                        item_dict = asdict(item)
                        print(json.dumps(item_dict, indent=2, default=str))
                    except Exception as e:
                        self.log.error(f"PrintExporter.export: Error converting dataclass: {e}")
                        print(str(item))
                elif isinstance(item, dict):
                    # Already a dict, print as JSON
                    print(json.dumps(item, indent=2, default=str))
                else:
                    # Fallback for other types
                    print(json.dumps(item, indent=2, default=str) if not isinstance(item, str) else item)

            self.log.debug("PrintExporter.export: completed successfully")
            return True
        except Exception as e:
            self.log.error(f"PrintExporter.export: Failed to print data: {e}")
            return False


class ClickHouseExporter(DatabaseExporter):
    def __init__(self, logger: Any, index_prefix: str, client=None):
        self.index_prefix = index_prefix
        self.log = logger
        self.client = client

    @contextmanager
    def clickhouse_connection(self):
        client = settings.create_clickhouse_client()
        try:
            yield client
        finally:
            try:
                client.close()
            except:
                pass
    # def export(self, data: Any, **kwargs) -> bool:
    #     try:
    #         # Handle multi-table export case
    #         # if isinstance(data, dict) and 'multi_table' in data:
    #         #     for table_name, table_data in data.items():
    #         #         if table_name != 'multi_table' and isinstance(table_data, dict) and 'table' in table_data:
    #         #             self.log.debug(f"Exporting to table: {table_data['table']}")
    #         #             self.log.debug(f"Column names: {table_data['column_names']}")
    #         #             self.log.debug(f"Column types: {table_data['column_type_names']}")
    #         #             self.log.debug(f"Data sample: {table_data['data'][0] if table_data['data'] else 'No data'}")
                        
    #         #             try:
    #         #                 result = self.client.insert(
    #         #                     table_data['table'],
    #         #                     table_data['data'],
    #         #                     column_names=table_data['column_names'],
    #         #                     column_type_names=table_data['column_type_names']
    #         #                 )
    #         #                 if not result:
    #         #                     self.log.error(f"Failed to insert into table {table_data['table']}")
    #         #                     return False
    #         #             except Exception as e:
    #         #                 self.log.error(f"Error inserting into table {table_data['table']}: {e}")
    #         #                 self.log.error(f"Data that caused error: {table_data['data']}")
    #         #                 return False
    #         #     return True

    #         if isinstance(data, dict) and 'multi_table' in data:
    #             for table_name, table_data in data.items():
    #                 if table_name != 'multi_table' and isinstance(table_data, dict) and 'table' in table_data:
    #                     self.log.debug(f"Exporting to table: {table_data['table']}")
                        
    #                     # Validate each row before insert
    #                     for row in table_data['data']:
    #                         for val, col_name, col_type in zip(row, table_data['column_names'], 
    #                                                         table_data['column_type_names']):
    #                             # Check for empty strings
    #                             if isinstance(val, str) and not val:
    #                                 self.log.error(f"Empty string found for column {col_name}")
    #                                 raise ValueError(f"Empty string not allowed for column {col_name}")
                                
    #                             # Log all string values for certificate_serial_number
    #                             if col_name == 'certificate_serial_number':
    #                                 self.log.debug(f"Serial number value: '{val}', type: {type(val)}, "
    #                                             f"repr: {repr(val)}")
                        
    #                     try:
    #                         result = self.client.insert(
    #                             table_data['table'],
    #                             table_data['data'],
    #                             column_names=table_data['column_names'],
    #                             column_type_names=table_data['column_type_names']
    #                         )
    #                         if not result:
    #                             self.log.error(f"Failed to insert into table {table_data['table']}")
    #                             return False
    #                     except Exception as e:
    #                         self.log.error(f"Error inserting into table {table_data['table']}: {e}")
    #                         self.log.error(f"Data that caused error: {table_data['data']}")
    #                         return False
    #             return True

    #         # Handle single table case
    #         table = kwargs.get('table')
    #         if not table:
    #             raise ValueError("Table name must be provided for ClickHouse export")
            
    #         # Unpack the tuple returned by prepare_export_data
    #         if isinstance(data, tuple):
    #             if len(data) != 3:
    #                 raise ValueError("Data tuple must contain exactly 3 elements: (data, column_names, column_type_names)")
    #             insert_data, column_names, column_type_names = data
    #         else:
    #             # Use provided column names and types from kwargs
    #             insert_data = data
    #             column_names = kwargs.get('column_names')
    #             column_type_names = kwargs.get('column_type_names')
                
    #         if not (column_names and column_type_names):
    #             raise ValueError("column_names and column_type_names must be provided")

    #         # Ensure data is in list format for batch insert
    #         if not isinstance(insert_data, list):
    #             insert_data = [insert_data]
                
    #         self.client.insert(
    #             table,
    #             insert_data,
    #             column_names=column_names,
    #             column_type_names=column_type_names
    #         )
    #         return True
            
    #     except Exception as e:
    #         self.log.error(f"Failed to export to ClickHouse: {e}")
    #         return False

    def get_client(self):
        """Get existing client or create new one if needed"""
        if self.client:
            return self.client
        try:
            return settings.create_clickhouse_client() 
        except Exception as e:
            self.log.error(f"Failed to create ClickHouse client: {e}")
            return None
            
    # WORKING SIMPLE VERSION
    def export(self, data: Any, **kwargs) -> bool:
        try:
            # # Handle multi-table export case
            # # if isinstance(data, dict) and 'multi_table' in data:
            # #     for table_data in data.values():
            # #         if isinstance(table_data, dict) and 'table' in table_data:
            # #             result = self.client.insert(
            # #                 table_data['table'],
            # #                 table_data['data'],
            # #                 column_names=table_data['column_names'],
            # #                 column_type_names=table_data['column_type_names']
            # #             )
            # #             if not result:  # If any insert fails, return False
            # #                 return False
            # #     return True
            # if isinstance(data, dict) and 'multi_table' in data:
            #     for key, table_data in data.items():
            #         if key != 'multi_table' and isinstance(table_data, dict) and 'table' in table_data:
            #             # Add type hints
            #             typed_data = []
            #             for row in table_data['data']:
            #                 typed_row = []
            #                 for val, type_name in zip(row, table_data['column_type_names']):
            #                     if isinstance(val, str) and not val:
            #                         val = 'UNKNOWN'
            #                     if type_name == 'String' or 'LowCardinality(String)' in type_name:
            #                         val = str(val) if val is not None else 'UNKNOWN'
            #                     typed_row.append(val)
            #                 typed_data.append(typed_row)
                        
            #             table_data['data'] = typed_data
                        
            #             result = self.client.insert(
            #                 table_data['table'],
            #                 table_data['data'],
            #                 column_names=table_data['column_names'],
            #                 column_type_names=table_data['column_type_names'],
            #                 settings={'input_format_values_interpret_expressions': 0}  # Disable type inference
            #             )
            #             if not result:
            #                 return False
            #         return True

            # Get a new client connection for this export operation
            with self.clickhouse_connection() as client:
                if not client:
                    return False

                # LAST WORKING VERSION
                if isinstance(data, dict) and 'multi_table' in data:
                    for key, table_data in data.items():
                        if key != 'multi_table' and isinstance(table_data, dict) and 'table' in table_data:
                            # Debug logging
                            self.log.debug(f"Processing table: {table_data['table']}")
                            self.log.debug(f"Column names: {table_data['column_names']}")
                            self.log.debug(f"Column types: {table_data['column_type_names']}")
                            
                            typed_data = []
                            for row_idx, row in enumerate(table_data['data']):
                                typed_row = []
                                for val_idx, (val, type_name, col_name) in enumerate(
                                    zip(row, table_data['column_type_names'], table_data['column_names'])
                                ):
                                    try:
                                        # Handle different types
                                        if val is None:
                                            if 'Nullable' in type_name:
                                                val = None  # Keep None for Nullable columns
                                            elif 'Array' in type_name:
                                                val = []
                                            elif 'Int' in type_name or 'UInt' in type_name:
                                                val = 0
                                            elif 'FixedString(16)' in type_name:
                                                val = b'\x00' * 16  # Binary FixedString
                                            elif 'String' in type_name or 'LowCardinality' in type_name:
                                                val = 'UNKNOWN'
                                            elif 'DateTime' in type_name:
                                                val = datetime.now(timezone.utc)
                                            elif 'Boolean' in type_name:
                                                val = False
                                            else:
                                                self.log.error(f"Unhandled type {type_name} for null value")
                                                val = 'UNKNOWN'
                                        
                                        # Log problematic values
                                        if isinstance(val, str) and not val.strip():
                                            self.log.warning(f"Empty string found in table {table_data['table']}, "
                                                        f"column {col_name}, row {row_idx}")
                                        
                                        # Ensure array types are always lists
                                        if 'Array' in type_name and not isinstance(val, list):
                                            val = [val]
                                        
                                        typed_row.append(val)
                                    except Exception as e:
                                        self.log.error(f"Error processing value in table {table_data['table']}, "
                                                    f"column {col_name} ({type_name}), "
                                                    f"row {row_idx}, value: {repr(val)}")
                                        raise
                                        
                                typed_data.append(typed_row)
                            
                            table_data['data'] = typed_data

                            # Skip insert if there is nothing to insert
                            if not typed_data:
                                self.log.debug(f"No data to insert for table {table_data['table']}, skipping.")
                                continue

                            # Debug log the first row of data
                            self.log.debug(f"Sample row for {table_data['table']}: {typed_data[0]}")

                            result = client.insert(
                                table_data['table'],
                                table_data['data'],
                                column_names=table_data['column_names'],
                                column_type_names=table_data['column_type_names'],
                                settings={'input_format_values_interpret_expressions': 0}
                            )
                            if not result:
                                self.log.error(f"Insert failed for table {table_data['table']}")
                                return False
                    return True

                # Handle single table case
                table = kwargs.get('table')
                if not table:
                    raise ValueError("Table name must be provided for ClickHouse export")
                
                # Unpack the tuple returned by prepare_export_data
                if isinstance(data, tuple):
                    if len(data) != 3:
                        raise ValueError("Data tuple must contain exactly 3 elements: (data, column_names, column_type_names)")
                    insert_data, column_names, column_type_names = data
                else:
                    # Use provided column names and types from kwargs
                    insert_data = data
                    column_names = kwargs.get('column_names')
                    column_type_names = kwargs.get('column_type_names')
                    
                if not (column_names and column_type_names):
                    raise ValueError("column_names and column_type_names must be provided")

                # Ensure data is in list format for batch insert
                if not isinstance(insert_data, list):
                    insert_data = [insert_data]

                # Skip insert if there is nothing to insert
                if not insert_data:
                    self.log.debug(f"No data to insert for table {table}, skipping.")
                    return True

                client.insert(
                    table,
                    insert_data,
                    column_names=column_names,
                    column_type_names=column_type_names,
                    settings={'input_format_values_interpret_expressions': 0}  # Disable type inference
                )
                return True

        except TypeError as e:
            # Get the actual value causing the error from the exception traceback
            import sys
            exc_type, exc_value, exc_traceback = sys.exc_info()
            
            # Walk through the traceback to find the frame with the problematic value
            current = exc_traceback
            while current:
                if 'string.py' in current.tb_frame.f_code.co_filename and '_data_size' in current.tb_frame.f_code.co_name:
                    locals_dict = current.tb_frame.f_locals
                    problematic_value = locals_dict.get('x')
                    self.log.error(f"TypeError with value: {problematic_value} (type: {type(problematic_value)})")
                    self.log.error(f"Full locals at error: {locals_dict}")
                    break
                current = current.tb_next
            
            self.log.error(f"Failed to export to ClickHouse: {e}")
            self.log.error("Full traceback:")
            self.log.error(traceback.format_exc())
            return False
        except Exception as e:
            self.log.error(f"Failed to export to ClickHouse: {e}")
            self.log.error(traceback.format_exc())
            return False
        finally:
            # Only close if we created a new client
            if client and client != self.client:
                # Close the client connection
                try:
                    client.close()
                except:
                    pass