Skip to content

Commit

Permalink
Merge ec5ba5a into 6bc54f1
Browse files Browse the repository at this point in the history
  • Loading branch information
dasatomic committed May 27, 2021
2 parents 6bc54f1 + ec5ba5a commit 7c0e6a9
Show file tree
Hide file tree
Showing 21 changed files with 1,472 additions and 253 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: .NET

on:
push:
branches: [ master, image_processing_proto ]
branches: [ master, image_processing_proto, functions_support ]
pull_request:
branches: [ master, image_processing_proto ]
branches: [ master, image_processing_proto, functions_support ]

jobs:
build:
Expand Down
47 changes: 47 additions & 0 deletions PageManager/RowHolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,43 @@

namespace PageManager
{
/// <summary>
/// Arguments of project/extend request against row holder.
/// Specifies columns that are to be copied from source row holder
/// and ones that are to be initialized with default values.
/// </summary>
public struct ProjectExtendInfo
{
/// <summary>
/// True if item on given position is to be projected. False otherwise.
/// </summary>
public bool[] IsProjection;

/// <summary>
/// Position in source rowholder for projection.
/// To be applied only if isProjection[currPos] == true.
/// </summary>
public int[] ProjectSourcePositions;

/// <summary>
/// Extension info.
/// To be applied only if isProjection[currPos] == false.
/// </summary>
public ColumnInfo[] ExtendColumnInfo;

public ProjectExtendInfo(bool[] isProjection, int[] projectSourcePositions, ColumnInfo[] extendColumnInfo)
{
if (isProjection.Length != projectSourcePositions.Length + extendColumnInfo.Length)
{
throw new ArgumentException("All elements in is projection array need to be covered by either project source pos or extend column info.");
}

IsProjection = isProjection;
ProjectSourcePositions = projectSourcePositions;
ExtendColumnInfo = extendColumnInfo;
}
}

public unsafe struct RowHolder
{
public readonly byte[] Storage;
Expand Down Expand Up @@ -109,6 +146,11 @@ public void SetField(int col, char[] val)
short colPos = this.ColumnPosition[col];
byte[] length = BitConverter.GetBytes((ushort)val.Length);

if (this.Storage.Length < colPos + val.Length + sizeof(short))
{
throw new ArgumentException("This val can't fit in this rowholder");
}

this.Storage[colPos] = length[0];
this.Storage[colPos + 1] = length[1];

Expand Down Expand Up @@ -181,6 +223,11 @@ public RowHolder Project(int[] cols)
return new RowHolder(newColPositions, newStorage);
}

public RowHolder ProjectAndExtend(ProjectExtendInfo projectExtendInfo)
{
throw new NotImplementedException();
}

/// <summary>
/// Each column in new RowHolder will be either projected from source RowHolder
/// by using first element of tuple, or extended with new type by using given type and filled with default value.
Expand Down
9 changes: 7 additions & 2 deletions ParserLexerFSharp/Sql.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ type value =

type aggType = Min | Max | Count | Sum

type scalarArgs =
| Args1 of value
| Args2 of (value * value)
| Args3 of (value * value * value)

type dir = Asc | Desc
type op = Eq | Gt | Ge | Lt | Le

Expand All @@ -20,13 +25,13 @@ type where =

type columnSelect =
| Aggregate of (aggType * string)
| Projection of string
| Projection of value
| Func of (string * scalarArgs)

type selectType =
| ColumnList of columnSelect list
| Star


type joinType = Inner | Left | Right

type join = string * joinType * where option // table name, join, optional on clause
Expand Down
466 changes: 267 additions & 199 deletions ParserLexerFSharp/SqlParser.fs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions ParserLexerFSharp/SqlParser.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ type nonTerminalId =
| NONTERM_columnSelect
| NONTERM_columnList
| NONTERM_aggregate
| NONTERM_func
| NONTERM_joinList
| NONTERM_joinClause
| NONTERM_joinOnClause
Expand Down
15 changes: 11 additions & 4 deletions ParserLexerFSharp/SqlParser.fsp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%{
%{
open Sql
%}

Expand Down Expand Up @@ -104,17 +104,24 @@ columnSelect:
| columnList { ColumnList(List.rev $1) }

columnList:
| ID { [Projection($1)] }
| columnList COMMA ID { Projection($3) :: $1 }
| aggregate { [$1] }
| value { [Projection($1)] }
| columnList COMMA value { Projection($3) :: $1 }
| aggregate { [$1] }
| columnList COMMA aggregate { $3 :: $1 }
| func { [$1] }
| columnList COMMA func { $3 :: $1 }

aggregate:
| MAX OBRCK ID CBRCK { Aggregate(Max, $3) }
| MIN OBRCK ID CBRCK { Aggregate(Min, $3) }
| COUNT OBRCK ID CBRCK { Aggregate(Count, $3) }
| SUM OBRCK ID CBRCK { Aggregate(Sum, $3) }

func:
| ID OBRCK value CBRCK { Func($1, Args1($3)) }
| ID OBRCK value COMMA value CBRCK { Func($1, Args2($3, $5)) }
| ID OBRCK value COMMA value COMMA value CBRCK { Func($1, Args3($3, $5, $7)) }

// join clause
joinList:
| { [] }
Expand Down
11 changes: 11 additions & 0 deletions QueryProcessing/Exceptions/InvalidFunctionArgument.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace QueryProcessing.Exceptions
{
public class InvalidFunctionArgument : Exception
{
public InvalidFunctionArgument(string message): base(message)
{
}
}
}
8 changes: 8 additions & 0 deletions QueryProcessing/Exceptions/InvalidFunctionNameException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System;

namespace QueryProcessing.Exceptions
{
public class InvalidFunctionNameException : Exception
{
}
}
206 changes: 206 additions & 0 deletions QueryProcessing/FuncCallMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
using MetadataManager;
using PageManager;
using System;
using QueryProcessing.Utilities;
using QueryProcessing.Exceptions;
using System.Collections.Generic;
using QueryProcessing.Functions;

namespace QueryProcessing
{
/// <summary>
/// Responsible for mapping function calls from syntax tree to functor class.
/// </summary>
public static class FuncCallMapper
{
private struct MetadataOutputFunctorBuilderPair
{
public Func<Sql.columnSelect.Func, MetadataColumn[] /* source columns */, MetadataColumn /* ret - output type */> GetMetadataInfoForOutput;
public Func<Sql.columnSelect.Func, int /* output position */, MetadataColumn[] /* source columns */, Action<RowHolder, RowHolder> /* ret - Action mapper */> FunctorBuilder;
}

private static AddFunctorOutputMappingHandler addMappingHandler = new AddFunctorOutputMappingHandler();
private static StringConcatOutputMappingHandler concatMappingHandler = new StringConcatOutputMappingHandler();

private static Action<RowHolder, RowHolder> FunctionBuilder(Sql.columnSelect.Func func, int output, MetadataColumn[] sourceColumns, IFunctionMappingHandler mappingHandler)
{
ColumnType[] funcCallTypes = ExtractCallTypes(func, sourceColumns);
var functor = mappingHandler.MapToFunctor(funcCallTypes);
Union2Type<MetadataColumn, Sql.value>[] fetchers = BuildFunctionArgumentFetchers(func, sourceColumns);

return (RowHolder inputRh, RowHolder outputRh) =>
{
functor.ExecCompute(
inputRh,
outputRh,
fetchers,
output
);
};
}

private static Dictionary<string, MetadataOutputFunctorBuilderPair> FuncDictionary = new Dictionary<string, MetadataOutputFunctorBuilderPair>()
{
{
"ADD", new MetadataOutputFunctorBuilderPair()
{
GetMetadataInfoForOutput = (func, mds) => addMappingHandler.GetMetadataInfoForOutput(func, mds),
FunctorBuilder = (func, output, mds) => FunctionBuilder(func, output, mds, addMappingHandler),
}
},
{
"CONCAT", new MetadataOutputFunctorBuilderPair()
{
GetMetadataInfoForOutput = (func, mds) => concatMappingHandler.GetMetadataInfoForOutput(func, mds),
FunctorBuilder = (func, output, mds) => FunctionBuilder(func, output, mds, concatMappingHandler),
}
}
};

public static MetadataColumn GetMetadataInfoForOutput(Sql.columnSelect.Func func, MetadataColumn[] sourceInput)
{
string funcName = func.Item.Item1;

if (FuncDictionary.TryGetValue(funcName, out MetadataOutputFunctorBuilderPair metadataOutFetcher))
{
return metadataOutFetcher.GetMetadataInfoForOutput(func, sourceInput);
}

throw new InvalidFunctionNameException();
}

private static int GetNumOfArguments(Sql.columnSelect.Func func)
{
if (func.Item.Item2.IsArgs1)
{
return 1;
}
else if (func.Item.Item2.IsArgs2)
{
return 2;
}
else if (func.Item.Item2.IsArgs3)
{
return 3;
}
else
{
throw new NotImplementedException("No support for 3+ arguments");
}
}

private static Sql.value GetArgNum(int argNum, Sql.scalarArgs args)
{
if (args.IsArgs1)
{
if (argNum == 0)
{
return ((Sql.scalarArgs.Args1)args).Item;
}
else
{
throw new ArgumentException("Invalid argument requested");
}
}
else if (args.IsArgs2)
{
if (argNum == 0)
{
return ((Sql.scalarArgs.Args2)args).Item.Item1;
}
else if (argNum == 1)
{
return ((Sql.scalarArgs.Args2)args).Item.Item2;
}
else
{
throw new ArgumentException("Invalid argument requested");
}
}
else if (args.IsArgs3)
{
if (argNum == 0)
{
return ((Sql.scalarArgs.Args3)args).Item.Item1;
}
else if (argNum == 1)
{
return ((Sql.scalarArgs.Args3)args).Item.Item2;
}
else if (argNum == 2)
{
return ((Sql.scalarArgs.Args3)args).Item.Item3;
}
else
{
throw new ArgumentException("Invalid argument requested");
}
}
else
{
throw new NotImplementedException("Only up to 3 args supported");
}
}

public static ColumnType[] ExtractCallTypes(Sql.columnSelect.Func func, MetadataColumn[] metadataColumns)
{
int numOfArguments = GetNumOfArguments(func);
ColumnType[] result = new ColumnType[numOfArguments];

for (int i = 0; i < numOfArguments; i++)
{
Sql.value value = GetArgNum(i, func.Item.Item2);

if (value.IsId)
{
string columnName = ((Sql.value.Id)value).Item;
MetadataColumn md = QueryProcessingAccessors.GetMetadataColumn(columnName, metadataColumns);
result[i] = md.ColumnType.ColumnType;
}
else
{
result[i] = QueryProcessingAccessors.ValueToType(value);
}
}

return result;
}

private static Union2Type<MetadataColumn, Sql.value>[] BuildFunctionArgumentFetchers(Sql.columnSelect.Func func, MetadataColumn[] sourceColumns)
{
Sql.scalarArgs args = func.Item.Item2;
int numOfArgumnets = GetNumOfArguments(func);
Union2Type<MetadataColumn, Sql.value>[] fetchers = new Union2Type<MetadataColumn, Sql.value>[numOfArgumnets];

for (int argNum = 0; argNum < numOfArgumnets; argNum++)
{
Sql.value arg = GetArgNum(argNum, args);

if (arg.IsId)
{
Sql.value.Id idArg = (Sql.value.Id)(arg);
MetadataColumn mc = QueryProcessingAccessors.GetMetadataColumn(idArg.Item, sourceColumns);
fetchers[argNum] = new Union2Type<MetadataColumn, Sql.value>.Case1(mc);
}
else
{
fetchers[argNum] = new Union2Type<MetadataColumn, Sql.value>.Case2(arg);
}
}

return fetchers;
}

public static Action<RowHolder, RowHolder> BuildFunctor(Sql.columnSelect.Func func, int outputPosition, MetadataColumn[] sourceColumns)
{
string funcName = func.Item.Item1;

if (FuncDictionary.TryGetValue(funcName, out MetadataOutputFunctorBuilderPair metadataOutFetcher))
{
return metadataOutFetcher.FunctorBuilder(func, outputPosition, sourceColumns);
}

throw new InvalidFunctionNameException();
}
}
}
Loading

0 comments on commit 7c0e6a9

Please sign in to comment.