예제 #1
0
        public static Field GetField(
            this ScalarExpression scalarExpression,
            string columnName,
            ILogger logger,
            SchemaFile file
            )
        {
            switch (scalarExpression)
            {
            case ValueExpression valueExpression:
                return(valueExpression.GetField(columnName, logger, file));

            case UnaryExpression unaryExpression:
                return(unaryExpression.Expression.GetField(columnName, logger, file));

            case ParenthesisExpression parenthesisExpression:
                return(parenthesisExpression.Expression.GetField(columnName, logger, file));

            case ColumnReferenceExpression columnReferenceExpression:
                return(columnReferenceExpression.GetField(columnName, logger, file));

            case BinaryExpression binaryExpression:
            {
                // TODO : what if you're working with different types, which one should be reported? (..compute the value)
                var first  = binaryExpression.FirstExpression.GetField(columnName, logger, file);
                var second = binaryExpression.SecondExpression.GetField(columnName, logger, file);
                var result = first.Type != FieldType.NotSpecified ? first : second;
                return(result.Copy(columnName ?? binaryExpression.GetTokenText()));
            }

            case ConvertCall convertCall:
            {
                // TODO : is the result nullable if the column we're converting is nullable?
                var isNullable = convertCall.Parameter.GetField(columnName, logger, file).IsNullable;
                return(convertCall.DataType.GetField(columnName, isNullable, logger, file));
            }

            case TryConvertCall tryConvertCall:
            {
                // TODO : is the result nullable if the column we're converting is nullable?
                var isNullable = tryConvertCall.Parameter.GetField(columnName, logger, file).IsNullable;
                return(tryConvertCall.DataType.GetField(columnName, isNullable, logger, file));
            }

            case CastCall castCall:
            {
                // TODO : is the result nullable if the column we're casting is nullable?
                var isNullable = castCall.Parameter.GetField(columnName, logger, file).IsNullable;
                return(castCall.DataType.GetField(columnName, isNullable, logger, file));
            }

            case TryCastCall tryCastCall:
            {
                // TODO : is the result nullable if the column we're casting is nullable?
                var isNullable = tryCastCall.Parameter.GetField(columnName, logger, file).IsNullable;
                return(tryCastCall.DataType.GetField(columnName, isNullable, logger, file));
            }

            case FunctionCall functionCall:
                return(functionCall.GetField(columnName, logger, file));

            // TODO : consolidate left and right
            case LeftFunctionCall leftFunctionCall:
                var leftField = leftFunctionCall.Parameters.Last().GetField(columnName, logger, file);
                return(new StringField()
                {
                    Name = columnName,
                    IsNullable = false,
                    Length = (leftField as StringField)?.Length ?? 0,
                    Type = FieldType.String,
                });

            case RightFunctionCall rightFunctionCall:
                var rightField = rightFunctionCall.Parameters.Last().GetField(columnName, logger, file);
                return(new StringField()
                {
                    Name = columnName,
                    IsNullable = false,
                    Length = (rightField as StringField)?.Length ?? 0,
                    Type = FieldType.String,
                });

            case SearchedCaseExpression searchedCaseExpression:
            {
                var columns = searchedCaseExpression
                              .WhenClauses // TODO : do we care about these boolean expressions?
                              .Select(x => x.ThenExpression.GetField(columnName, logger, file))
                              .ToList();

                var elseColumn = searchedCaseExpression
                                 .ElseExpression
                                 ?.GetField(columnName, logger, file);

                if (elseColumn != null)
                {
                    columns.Add(elseColumn);
                }

                // TODO : compute column type, do not return first..
                // https://docs.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-2017#implicit-conversions

                return(columns.First());
            }

            case SimpleCaseExpression simpleCaseExpression:
            {
                var columns = simpleCaseExpression
                              .WhenClauses
                              .Select(x => x.ThenExpression.GetField(columnName, logger, file))
                              .ToList();

                var elseColumn = simpleCaseExpression
                                 .ElseExpression
                                 ?.GetField(columnName, logger, file);

                if (elseColumn != null)
                {
                    columns.Add(elseColumn);
                }

                // TODO : compute column type, do not return first..
                return(columns.First());
            }

            case ScalarSubquery scalarSubquery:
            {
                var column = scalarSubquery
                             .QueryExpression
                             .GetFields(logger, file)
                             .First()
                             .Copy(columnName);

                return(column);
            }

            case CoalesceExpression coalesceExpression:
            {
                var columns = coalesceExpression
                              .Expressions
                              .Select(x => x.GetField(columnName, logger, file))
                              .Where(x => x.Type != FieldType.NotSpecified)
                              .ToList();

                // TODO : compute column type, do not return first..
                // https://docs.microsoft.com/en-us/sql/t-sql/language-elements/coalesce-transact-sql?view=sql-server-2017
                // Returns the data type of expression with the highest data type precedence. If all expressions are nonnullable, the result is typed as nonnullable.
                return(columns
                       .FirstOrDefault()
                       ?.Copy(columnName) ?? new UnknownField()
                    {
                        Name = columnName,
                    });
            }

            case NullIfExpression nullIfExpression:
            {
                // Returns the same type as the first expression
                return(nullIfExpression
                       .FirstExpression
                       .GetField(columnName, logger, file)
                       .Copy(columnName));
            }

            case AtTimeZoneCall atTimeZoneCall:
            {
                return(atTimeZoneCall
                       .DateValue
                       .GetField(columnName, logger, file));
            }

            case IIfCall iifCall:
            {
                var firstField  = iifCall.ThenExpression.GetField(columnName, logger, file);
                var secondField = iifCall.ElseExpression.GetField(columnName, logger, file);
                // TODO : Returns the data type with the highest precedence from the types in true_value and false_value. For more information
                return(firstField);
            }

            case ParameterlessCall parameterlessCall:
                return(parameterlessCall.GetField(columnName, logger, file));

            default:
            {
                logger.Log(LogLevel.Warning,
                           LogType.NotSupportedYet,
                           file.Path,
                           $"Unable to determine column type from scalar expression. Fragment: \"{scalarExpression.GetTokenText()}\"");

                return(new UnknownField()
                    {
                        Name = columnName,
                    });
            }
            }
        }
예제 #2
0
        public static Field GetField(
            this ScalarExpression scalarExpression,
            ColumnDefinition column,
            IEnumerable <ColumnDefinition> columns,
            ILogger logger,
            SchemaFile file
            )
        {
            switch (scalarExpression)
            {
            case ValueExpression valueExpression:
                return(valueExpression.GetField(column.ColumnIdentifier.Value, logger, file));

            case ParenthesisExpression parenthesisExpression:
                return(parenthesisExpression.Expression.GetField(column, columns, logger, file));

            case ColumnReferenceExpression columnReferenceExpression:
                return(columnReferenceExpression.GetField(logger, file, columns));

            case BinaryExpression binaryExpression:
            {
                // TODO : what if you're working with different types, which one should be reported? (..compute the value)
                var first  = binaryExpression.FirstExpression.GetField(column, columns, logger, file);
                var second = binaryExpression.SecondExpression.GetField(column, columns, logger, file);
                var result = first.Type != FieldType.NotSpecified ? first : second;
                return(result.Copy(column.ColumnIdentifier.Value));
            }

            case ConvertCall convertCall:
            {
                var name       = column.ColumnIdentifier.Value;
                var isNullable = column.IsNullable();
                return(convertCall.DataType.GetField(name, isNullable, logger, file));
            }

            case FunctionCall functionCall:
            {
                // TODO : do not return first.. compute the value
                var first = functionCall
                            .Parameters
                            .Select(x => x.GetField(column, columns, logger, file))
                            .FirstOrDefault(x => x.Type != FieldType.NotSpecified);

                if (first != null)
                {
                    return(first);
                }

                break;
            }
            }

            logger.Log(LogLevel.Error, $"Unable to determine column type from scalar expression. Fragment: \"{scalarExpression.GetTokenText()}\"");

            return(new UnknownField()
            {
                Name = column.ColumnIdentifier.Value,
            });
        }