Implement a C++ program that reads data from a CSV file and inserts it into an SQLite database. The program should support command line arguments for specifying the input file path, table name, and column names in the database.
PLAINFORMAT
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <sqlite3.h>

// Function to create a table in the SQLite database
void create_table(sqlite3 *db, const std::string &table_name, const std::vector<std::string> &column_names) {
    std::stringstream ss;
    ss << "CREATE TABLE IF NOT EXISTS " << table_name << " (";
    for (size_t i = 0; i < column_names.size(); ++i) {
        ss << column_names[i] << " TEXT" << (i + 1 < column_names.size() ? ", " : ");");
    }

    char *error_message = nullptr;
    if (sqlite3_exec(db, ss.str().c_str(), nullptr, nullptr, &error_message) != SQLITE_OK) {
        std::cerr << "Error creating table: " << error_message << std::endl;
        sqlite3_free(error_message);
    }
}

// Function to insert data into the SQLite database
void insert_data(sqlite3 *db, const std::string &table_name, const std::vector<std::vector<std::string>> &data) {
    for (const auto &row : data) {
        std::stringstream ss;
        ss << "INSERT INTO " << table_name << " VALUES(";
        for (size_t i = 0; i < row.size(); ++i) {
            ss << "'" << row[i] << "'" << (i + 1 < row.size() ? ", " : ");");
        }

        char *error_message = nullptr;
        if (sqlite3_exec(db, ss.str().c_str(), nullptr, nullptr, &error_message) != SQLITE_OK) {
            std::cerr << "Error inserting data: " << error_message << std::endl;
            sqlite3_free(error_message);
        }
    }
}

// Function to read data from a CSV file
std::vector<std::vector<std::string>> read_csv(const std::string &file_path) {
    std::ifstream file(file_path);
    if (!file.is_open()) {
        throw std::runtime_error("Could not open CSV file");
    }

    std::vector<std::vector<std::string>> data;
    std::string line;

    while (std::getline(file, line)) {
        std::stringstream ss(line);
        std::vector<std::string> row;
        std::string cell;

        while (std::getline(ss, cell, ',')) {
            row.push_back(cell);
        }

        data.push_back(row);
    }

    return data;
}

int main(int argc, char *argv[]) {
    if (argc < 5) {
        std::cerr << "Usage: " << argv[0] << " <input_file> <db_name> <table_name> <column1,column2,...>" << std::endl;
        return 1;
    }

    const std::string input_file = argv[1];
    const std::string db_name = argv[2];
    const std::string table_name = argv[3];

    std::stringstream column_stream(argv[4]);
    std::vector<std::string> column_names;
    std::string column;

    while (std::getline(column_stream, column, ',')) {
        column_names.push_back(column);
    }

    sqlite3 *db;
    if (sqlite3_open(db_name.c_str(), &db) != SQLITE_OK) {
        std::cerr << "Error opening database: " << sqlite3_errmsg(db) << std::endl;
        return 1;
    }

    create_table(db, table_name, column_names);

    try {
        auto data = read_csv(input_file);
        insert_data(db, table_name, data);
    } catch (const std::runtime_error &e) {
        std::cerr << "Error reading CSV file: " << e.what() << std::endl;
        sqlite3_close(db);
        return 1;
    }

    sqlite3_close(db);
    return 0;
}