DiegoEmilio01 / IIC3413

Repositorio del curso Implementación de Sistemas de Bases de Datos
16 stars 1 forks source link

Valores de devolución Left Outer Join #41

Open TomasAlcalde opened 3 months ago

TomasAlcalde commented 3 months ago

Hola, Logré implementar la lógica del left outer join y devuelve las tuplas buscadas. Sin embargo, las tuplas del lado izquierdo que no coinciden con ninguna del lado derecho las estoy retornando con los valores de la última tupla del lado derecho. No entiendo muy bien como sobreescribir los valores con -1. Muchas gracias

cirojas commented 3 months ago

tu clase debería tener un atributo RecordRef out. Esta clase no tiene valores sino punteros a valores, por lo que puedes crear un valor representante de null en alguna parte (ojo que no se destruya antes de tiempo, por ejemplo puedes tenerlo como atributo de clase) y apuntar a él cuando sea necesario.

Por ejemplo, si la columna i es la que quieres asignar null, puedes hacer out.values[i] = &my_null_value;, pero ojo que cuando deje de ser null debes reasignar para que apunte al lugar original.

TomasAlcalde commented 3 months ago

Muchas gracias, aunque tengo la duda de como hacer para que no se destruya antes de tiempo.

Actualmente, lo declaré como un atributo de clase de los iteradores, de la siguiente manera:

Value int_null_value = Value(-1);

Value str_null_value = Value("-1");

Entonces dependiendo del datatype de la columna hago:

out.values[offset + i] = &int_null_value;

Sin embargo, al imprimir la tabla no aparecen los cambios a -1.

TomasAlcalde commented 3 months ago

Tampoco me queda claro la última parte de que cuando deje de ser null debo reasignar para que apunte al lugar original.

cirojas commented 3 months ago

con lugar original me refiero al que se setea en el constructor, por ejemplo en el join sería esto:

for (size_t i = 0; i < projected_lhs_columns_pos.size(); i++) {
    out.values[i] = lhs_out.values[projected_lhs_columns_pos[i]];
}

size_t offset = projected_lhs_columns_pos.size();
for (size_t i = 0; i < projected_rhs_columns_pos.size(); i++) {
    out.values[offset + i] = rhs_out.values[projected_rhs_columns_pos[i]];
}
TomasAlcalde commented 3 months ago

Gracias.

TomasAlcalde commented 3 months ago

Aun quedé con la duda de como implementar los punteros a valores nulos. Los cree como atributo de clase, pero al imprimir el resultado estos quedan como la última tupla de rhs.

cirojas commented 3 months ago

Disculpa, lo que dije estaba mal, creo que van a tener que manejar una copia del record, y sobreescribir este cada vez que se actualice rhs o lhs, y en esa copia van a tener que setear el nulo cuando corresponda. Voy a pensarlo un poco más y trataré de dejar un ejemplo.

cirojas commented 3 months ago

acá dejo un ejemplo del operador join, pero que ahora out apunta a una copia de los valores en vez de apuntar directamente a los valores de los hijos.

#pragma once

#include "query/executor/query_iter.h"

class Join : public QueryIter {
public:
    // helper function for construction of lhs_record_copy and rhs_record_copy
    static std::vector<DataType> get_datatypes(const std::vector<Column>& columns) {
        std::vector<DataType> res;

        for (auto& column : columns) {
            res.push_back(column.datatype);
        }

        return res;
    }

    Join(
        std::unique_ptr<QueryIter>             _lhs,
        std::unique_ptr<QueryIter>             _rhs,
        std::vector<Column>                    _projected_lhs_columns,
        std::vector<Column>                    _projected_rhs_columns,
        std::vector<size_t>                    _projected_lhs_columns_pos,
        std::vector<size_t>                    _projected_rhs_columns_pos,
        std::vector<std::pair<size_t, size_t>> _equalities
    ) :
        lhs                       (std::move(_lhs)),
        rhs                       (std::move(_rhs)),
        projected_lhs_columns     (std::move(_projected_lhs_columns)),
        projected_rhs_columns     (std::move(_projected_rhs_columns)),
        projected_lhs_columns_pos (std::move(_projected_lhs_columns_pos)),
        projected_rhs_columns_pos (std::move(_projected_rhs_columns_pos)),
        equalities                (std::move(_equalities)),
        lhs_out                   (lhs->get_output()),
        rhs_out                   (rhs->get_output()),
        out                       (projected_lhs_columns.size() + projected_rhs_columns.size()),
        lhs_record_copy           (get_datatypes(lhs->get_columns())),
        rhs_record_copy           (get_datatypes(rhs->get_columns()))
    {
        assert(equalities.size() > 0);
        assert(projected_lhs_columns.size() == projected_lhs_columns_pos.size());
        assert(projected_rhs_columns.size() == projected_rhs_columns_pos.size());

        for (size_t i = 0; i < projected_lhs_columns_pos.size(); i++) {
            out.values[i] = &lhs_record_copy.values[projected_lhs_columns_pos[i]];
        }

        size_t offset = projected_lhs_columns_pos.size();
        for (size_t i = 0; i < projected_rhs_columns_pos.size(); i++) {
            out.values[offset + i] = &rhs_record_copy.values[projected_rhs_columns_pos[i]];
        }
    }

    void begin() override {
        lhs->begin();
        rhs->begin();

        valid_lhs = false;
    }

    // simple nested loop join
    bool next() override {
        while (true) {
            if (valid_lhs) {
                while (rhs->next()) {
                    // copy rhs new values
                    for (size_t i = 0; i < rhs_record_copy.values.size(); i++) {
                        rhs_record_copy.values[i] = *rhs_out.values[i];
                    }

                    // if compatible return true, else continue
                    bool compatible = true;
                    for (auto& eq: equalities) {
                        if (*lhs_out.values[eq.first] != *rhs_out.values[eq.second]) {
                            compatible = false;
                            break;
                        }
                    }
                    if (compatible) return true;
                }
                valid_lhs = false;
            } else {
                if (lhs->next()) {
                    // copy lhs new values
                    for (size_t i = 0; i < lhs_record_copy.values.size(); i++) {
                        lhs_record_copy.values[i] = *lhs_out.values[i];
                    }

                    valid_lhs = true;
                    rhs->reset();
                } else {
                    return false;
                }
            }
        }
        return false;
    }

    void reset() override {
        lhs->reset();
        rhs->reset();
    }

    RecordRef& get_output() override {
        return out;
    }

    std::vector<Column> get_columns() override {
        std::vector<Column> res = projected_lhs_columns;

        for (auto& c : projected_rhs_columns) {
            res.push_back(c);
        }
        return res;
    }

    std::ostream& print_to_ostream(std::ostream& os, int indent = 0) const override {
        os << std::string(indent, ' ');
        os << "Join(";
        os << projected_lhs_columns[equalities[0].first].alias << "." << projected_lhs_columns[equalities[0].first].column;
        os << " == ";
        os << projected_rhs_columns[equalities[0].second].alias << "." << projected_rhs_columns[equalities[0].second].column;

        for (size_t i = 1; i < equalities.size(); ++i) {
            os << " AND ";
            os << projected_lhs_columns[equalities[1].first].alias << "." << projected_lhs_columns[equalities[1].first].column;
            os << " == ";
            os << projected_rhs_columns[equalities[1].second].alias << "." << projected_rhs_columns[equalities[1].second].column;
        }
        os << ")\n";
        lhs->print_to_ostream(os, indent + 2);
        rhs->print_to_ostream(os, indent + 2);
        return os;
    }

private:
    std::unique_ptr<QueryIter> lhs;

    std::unique_ptr<QueryIter> rhs;

    std::vector<Column> projected_lhs_columns;

    std::vector<Column> projected_rhs_columns;

    std::vector<size_t> projected_lhs_columns_pos;

    std::vector<size_t> projected_rhs_columns_pos;

    std::vector<std::pair<size_t, size_t>> equalities;

    RecordRef& lhs_out;

    RecordRef& rhs_out;

    RecordRef out;

    Record lhs_record_copy;

    Record rhs_record_copy;

    bool valid_lhs;
};

En este caso puedes asignar un nulo modificando la copia, ej:

lhs_record_copy.values[projected_lhs_columns_pos[i]] = Value(-1);