Skip to content

Commit

Permalink
Support for functors that accept different types.
Browse files Browse the repository at this point in the history
Slight refactoring.
  • Loading branch information
dasatomic committed May 20, 2021
1 parent 5e7144a commit b7aee72
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 121 deletions.
143 changes: 143 additions & 0 deletions QueryProcessing/ArithmeticFunctions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using MetadataManager;
using PageManager;
using System;
using System.Linq;

namespace QueryProcessing
{
static class FunctorArgChecks
{
public static void CheckInputArguments(MetadataColumn[] sourceArguments, ColumnType[] acceptedColumnTypes)
{
if (sourceArguments.Length != acceptedColumnTypes.Length)
{
throw new ArgumentException("Invalid number of arguments");
}

foreach (MetadataColumn md in sourceArguments)
{
if (!acceptedColumnTypes.Any(acc => md.ColumnType.ColumnType == acc))
{
throw new ArgumentException($"Type {md.ColumnType.ColumnType} is not accepted by Add functor");
}
}
}
}

public static class AddFunctorOutputMappingHandler
{
public static MetadataColumn GetMetadataInfoForOutput(Sql.columnSelect.Func func, MetadataColumn[] metadataColumns)
{
Sql.scalarArgs args = func.Item.Item2;

if (!args.IsArgs2)
{
throw new ArgumentException("Add accepts two args");
}

var args2 = ((Sql.scalarArgs.Args2)args).Item;
Sql.value argOne = args2.Item1;
Sql.value argTwo = args2.Item2;

if (!argOne.IsId || !argTwo.IsId)
{
throw new NotImplementedException("Currently we only support ids in as arguments");
}

Sql.value.Id idOne = (Sql.value.Id)argOne;
Sql.value.Id idTwo = (Sql.value.Id)argTwo;

ColumnInfo argOneMd = QueryProcessingAccessors.GetMetadataColumn(idOne.Item, metadataColumns).ColumnType;
ColumnInfo argTwoMd = QueryProcessingAccessors.GetMetadataColumn(idTwo.Item, metadataColumns).ColumnType;

// both need to be double or int.
// TODO: Need generic way to express this.
if (!((argOneMd.ColumnType == ColumnType.Double || argOneMd.ColumnType == ColumnType.Int) &&
argTwoMd.ColumnType == ColumnType.Double || argTwoMd.ColumnType == ColumnType.Int))
{
throw new ArgumentException("Invalid argument type for add");
}

if (argOneMd.ColumnType == ColumnType.Double || argTwoMd.ColumnType == ColumnType.Double)
{
// If one of them is double map result to double.
return new MetadataColumn(0, 0, "ADD_Result", new ColumnInfo(ColumnType.Double));
}
else
{
return new MetadataColumn(0, 0, "ADD_Result", new ColumnInfo(ColumnType.Int));
}
}

public static IFunctionCall MapToFunctor(MetadataColumn arg1, MetadataColumn arg2)
{
return ((arg1.ColumnType.ColumnType, arg2.ColumnType.ColumnType)) switch
{
(ColumnType.Int, ColumnType.Int) => new AddFunctorInt(),
(ColumnType.Int, ColumnType.Double) => new AddFunctorIntDouble(),
(ColumnType.Double, ColumnType.Int) => new AddFunctorDoubleInt(),
(ColumnType.Double, ColumnType.Double) => new AddFunctorDouble(),
_ => throw new ArgumentException("Invalid type"),
};
}
}

public class AddFunctorInt : IFunctionCall
{
public void ExecCompute(RowHolder inputRowHolder, RowHolder outputRowHolder, MetadataColumn[] sourceArguments, int outputPosition)
{
FunctorArgChecks.CheckInputArguments(sourceArguments, new[] { ColumnType.Int, ColumnType.Int });
int argOneExtracted = inputRowHolder.GetField<int>(sourceArguments[0].ColumnId);
int argTwoExtracted = inputRowHolder.GetField<int>(sourceArguments[1].ColumnId);

int res = argOneExtracted + argTwoExtracted;

outputRowHolder.SetField<int>(outputPosition, res);
}
}

public class AddFunctorDouble : IFunctionCall
{
public void ExecCompute(RowHolder inputRowHolder, RowHolder outputRowHolder, MetadataColumn[] sourceArguments, int outputPosition)
{
FunctorArgChecks.CheckInputArguments(sourceArguments, new[] { ColumnType.Double, ColumnType.Double});

double argOneExtracted = inputRowHolder.GetField<double>(sourceArguments[0].ColumnId);
double argTwoExtracted = inputRowHolder.GetField<double>(sourceArguments[1].ColumnId);

double res = argOneExtracted + argTwoExtracted;

outputRowHolder.SetField<double>(outputPosition, res);
}
}

public class AddFunctorDoubleInt : IFunctionCall
{
public void ExecCompute(RowHolder inputRowHolder, RowHolder outputRowHolder, MetadataColumn[] sourceArguments, int outputPosition)
{
FunctorArgChecks.CheckInputArguments(sourceArguments, new[] { ColumnType.Double, ColumnType.Int});

double argOneExtracted = inputRowHolder.GetField<double>(sourceArguments[0].ColumnId);
double argTwoExtracted = inputRowHolder.GetField<int>(sourceArguments[1].ColumnId);

double res = argOneExtracted + argTwoExtracted;

outputRowHolder.SetField<double>(outputPosition, res);
}
}

public class AddFunctorIntDouble : IFunctionCall
{
public void ExecCompute(RowHolder inputRowHolder, RowHolder outputRowHolder, MetadataColumn[] sourceArguments, int outputPosition)
{
FunctorArgChecks.CheckInputArguments(sourceArguments, new[] { ColumnType.Double, ColumnType.Int});

double argOneExtracted = inputRowHolder.GetField<int>(sourceArguments[0].ColumnId);
double argTwoExtracted = inputRowHolder.GetField<double>(sourceArguments[1].ColumnId);

double res = argOneExtracted + argTwoExtracted;

outputRowHolder.SetField<double>(outputPosition, res);
}
}
}
64 changes: 64 additions & 0 deletions QueryProcessing/FuncCallMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using MetadataManager;
using PageManager;
using System;
using System.Collections.Generic;
using System.Text;

namespace QueryProcessing
{
/// <summary>
/// Responsible for mapping function calls from syntax tree to functor class.
/// </summary>
public static class FuncCallMapper
{
public static MetadataColumn GetMetadataInfoForOutput(Sql.columnSelect.Func func, MetadataColumn[] sourceInput)
{
Sql.FuncType funcType = func.Item.Item1;

if (funcType.IsAdd)
{
return AddFunctorOutputMappingHandler.GetMetadataInfoForOutput(func, sourceInput);
}

throw new NotImplementedException();
}

public static Action<RowHolder, RowHolder> BuildFunctor(Sql.columnSelect.Func func, int outputPosition, MetadataColumn[] sourceColumns)
{
Sql.FuncType funcType = func.Item.Item1;
Sql.scalarArgs args = func.Item.Item2;

if (funcType.IsAdd)
{
Sql.scalarArgs.Args2 argsExtracted = (Sql.scalarArgs.Args2)args;
Sql.value arg1 = argsExtracted.Item.Item1;
Sql.value arg2 = argsExtracted.Item.Item2;

if (!arg1.IsId || !arg2.IsId)
{
// TODO:
throw new Exception("Only support for ids as function arguments");
}

Sql.value.Id arg1Id = (Sql.value.Id)(arg1);
Sql.value.Id arg2Id = (Sql.value.Id)(arg2);

MetadataColumn mc1 = QueryProcessingAccessors.GetMetadataColumn(arg1Id.Item, sourceColumns);
MetadataColumn mc2 = QueryProcessingAccessors.GetMetadataColumn(arg2Id.Item, sourceColumns);
var functor = AddFunctorOutputMappingHandler.MapToFunctor(mc1, mc2);

return (RowHolder inputRh, RowHolder outputRh) =>
{
functor.ExecCompute(
inputRh,
outputRh,
new MetadataColumn[] { mc1, mc2 },
outputPosition
);
};
}

throw new NotImplementedException();
}
}
}
10 changes: 10 additions & 0 deletions QueryProcessing/IFunctionCall.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using MetadataManager;
using PageManager;

namespace QueryProcessing
{
public interface IFunctionCall
{
void ExecCompute(RowHolder inputRowHolder, RowHolder outputRowHolder, MetadataColumn[] sourceArguments, int outputPosition);
}
}
93 changes: 6 additions & 87 deletions QueryProcessing/ProjectOpBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,32 +60,8 @@ private MetadataColumn[] GetOutputSchema(Sql.columnSelect[] columns, IPhysicalOp
}
else if (column.IsFunc)
{
var func = ((Sql.columnSelect.Func)column).Item;
Sql.FuncType funcType = func.Item1;
// TODO: Map func type to the right function.
// This should go to new class.
Sql.scalarArgs args = func.Item2;

if (funcType.IsAdd)
{
if (!args.IsArgs2)
{
throw new Exception("Sum requires 2 arguments");
}

var args2 = ((Sql.scalarArgs.Args2)args).Item;
Sql.value argOne = args2.Item1;
Sql.value argTwo = args2.Item2;
// TODO: Some rules should be applied here to determine output type.
// TODO: For now always return int.
// TODO is keeping 0, 0 here ok?
result[pos] = new MetadataColumn(0, 0, "ADD_Result", new ColumnInfo(ColumnType.Int));
}
else
{
// TODO:
throw new NotImplementedException();
}
var func = ((Sql.columnSelect.Func)column);
result[pos] = FuncCallMapper.GetMetadataInfoForOutput(func, source.GetOutputColumns());
}

pos++;
Expand All @@ -112,32 +88,8 @@ private MetadataColumn[] GetOutputSchema(Sql.columnSelect[] columns, IPhysicalOp
}
else if (c.IsFunc)
{
var func = ((Sql.columnSelect.Func)c).Item;
Sql.FuncType funcType = func.Item1;
// TODO: Map func type to the right function.
// This should go to new class.
Sql.scalarArgs args = func.Item2;
if (funcType.IsAdd)
{
if (!args.IsArgs2)
{
throw new Exception("Sum requires 2 arguments");
}
var args2 = ((Sql.scalarArgs.Args2)args).Item;
Sql.value argOne = args2.Item1;
Sql.value argTwo = args2.Item2;
// TODO: Some rules should be applied here to determine output type.
// TODO: For now always return int.
return (null, new ColumnInfo(ColumnType.Int));
}
else
{
// TODO:
throw new NotImplementedException();
}
var func = ((Sql.columnSelect.Func)c);
return (null, FuncCallMapper.GetMetadataInfoForOutput(func, source.GetOutputColumns()).ColumnType);
}
else
{
Expand All @@ -161,41 +113,8 @@ private MetadataColumn[] GetOutputSchema(Sql.columnSelect[] columns, IPhysicalOp
continue;
}

var func = ((Sql.columnSelect.Func)select).Item;
Sql.FuncType funcType = func.Item1;
// TODO: Map func type to the right function.
// This should go to new class.
Sql.scalarArgs args = func.Item2;

if (funcType.IsAdd)
{
Sql.scalarArgs.Args2 argsExtracted = (Sql.scalarArgs.Args2)args;
Sql.value arg1 = argsExtracted.Item.Item1;
Sql.value arg2 = argsExtracted.Item.Item2;

if (!arg1.IsId || !arg2.IsId)
{
// TODO:
throw new Exception("Only support for ids as function arguments");
}

Sql.value.Id arg1Id = (Sql.value.Id)(arg1);
Sql.value.Id arg2Id = (Sql.value.Id)(arg2);

MetadataColumn mc1 = QueryProcessingAccessors.GetMetadataColumn(arg1Id.Item, sourceColumns);
MetadataColumn mc2 = QueryProcessingAccessors.GetMetadataColumn(arg2Id.Item, sourceColumns);

listOfActions.Add((RowHolder inputRh, RowHolder outputRh) =>
{
QueryProcessingAccessors.ApplyFuncInPlace(
new MetadataColumn[] { mc1, mc2 },
outputPosition,
inputRh,
outputRh,
funcType
);
});
}
var func = ((Sql.columnSelect.Func)select);
listOfActions.Add(FuncCallMapper.BuildFunctor(func, outputPosition, sourceColumns));
}

// Execute all the actions.
Expand Down
34 changes: 0 additions & 34 deletions QueryProcessing/QueryProcessingAccessors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,40 +104,6 @@ public static IComparable MetadataColumnRowsetHolderFetcher(MetadataColumn mc, R
}
}

/// <summary>
/// Applies given function to given row holder.
/// </summary>
/// <param name="sourcesMds">List of source metadata columns, ordered by scalar args. First arg maps to sourcesMds[0] and so on. Null if arg is not an id.</param>
/// <param name="outputPosition">Target positions in output rowholder.</param>
/// <param name="inputRowHolder">Input rowholder</param>
/// <param name="funcType">Func type.</param>
/// <param name="args">Arguments</param>
/// <param name="outputRowHolder">Output rowholder.</param>
public static void ApplyFuncInPlace(MetadataColumn[] sourcesMds, int outputPosition, RowHolder inputRowHolder, RowHolder outputRowHolder, Sql.FuncType funcType)
{
if (funcType.IsAdd)
{
MetadataColumn columnOneMd = sourcesMds[0];
MetadataColumn columnTwoMd = sourcesMds[1];

if (columnOneMd.ColumnType.ColumnType != ColumnType.Int || columnTwoMd.ColumnType.ColumnType != ColumnType.Int)
{
// TODO:
throw new Exception("Only support for ints in sum");
}

int argOneExtracted = inputRowHolder.GetField<int>(columnOneMd.ColumnId);
int argTwoExtracted = inputRowHolder.GetField<int>(columnTwoMd.ColumnId);

int res = argOneExtracted + argTwoExtracted;
outputRowHolder.SetField<int>(outputPosition, res);
}
else
{
throw new NotImplementedException();
}
}

// TODO: This is just bad.
// It is very hard to keep all type -> agg mappings.
// Needs refactoring.
Expand Down
Loading

0 comments on commit b7aee72

Please sign in to comment.