private static ISqlFragment WriteInstanceFunctionCall(
            SqlGenerator sqlgen, string functionName, DbFunctionExpression functionExpression, bool isPropertyAccess,
            string castReturnTypeTo)
        {
            Debug.Assert(
                !isPropertyAccess || functionExpression.Arguments.Count == 1,
                "Property accessor instance functions should have only the single instance argument");

            return WrapWithCast(
                castReturnTypeTo, result =>
                                      {
                                          var instanceExpression = functionExpression.Arguments[0];

                                          // Write the instance - if this is another function call, it need not be enclosed in parentheses.
                                          if (instanceExpression.ExpressionKind
                                              != DbExpressionKind.Function)
                                          {
                                              sqlgen.ParenthesizeExpressionIfNeeded(instanceExpression, result);
                                          }
                                          else
                                          {
                                              result.Append(instanceExpression.Accept(sqlgen));
                                          }
                                          result.Append(".");
                                          result.Append(functionName);

                                          if (!isPropertyAccess)
                                          {
                                              WriteFunctionArguments(sqlgen, functionExpression.Arguments.Skip(1), result);
                                          }
                                      });
        }
        /// <summary>
        /// Helper for all date and time types creating functions. 
        /// 
        /// The given expression is in general trainslated into:
        /// 
        /// CONVERT(@typename, [datePart] + [timePart] + [timeZonePart], 121), where the datePart and the timeZonePart are optional
        /// 
        /// Only on Katmai, if a date part is present it is wrapped with a call for adding years as shown below.
        /// The individual parts are translated as:
        /// 
        /// Date part:  
        ///     PRE KATMAI: convert(varchar(255), @year) + '-' + convert(varchar(255), @month) + '-' + convert(varchar(255), @day)
        ///         KATMAI: DateAdd(year, @year-1, covert(@typename, '0001' + '-' + convert(varchar(255), @month) + '-' + convert(varchar(255), @day)  + [possibly time ], 121)     
        /// 
        /// Time part: 
        /// PRE KATMAI:  convert(varchar(255), @hour)+ ':' + convert(varchar(255), @minute)+ ':' + str(@second, 6, 3)
        ///     KATMAI:  convert(varchar(255), @hour)+ ':' + convert(varchar(255), @minute)+ ':' + str(@second, 10, 7)
        /// 
        /// Time zone part:
        ///     (case when @tzoffset >= 0 then '+' else '-' end) + convert(varchar(255), ABS(@tzoffset)/60) + ':' + convert(varchar(255), ABS(@tzoffset)%60) 
        /// 
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="args"></param>
        /// <param name="hasDatePart"></param>
        /// <param name="hasTimeZonePart"></param>
        /// <returns></returns>
        private static ISqlFragment HandleCanonicalFunctionDateTimeTypeCreation(
            SqlGenerator sqlgen, string typeName, IList<DbExpression> args, bool hasDatePart, bool hasTimeZonePart)
        {
            Debug.Assert(
                args.Count == (hasDatePart ? 3 : 0) + 3 + (hasTimeZonePart ? 1 : 0),
                "Invalid number of parameters for a date time creating function");

            var result = new SqlBuilder();
            var currentArgumentIndex = 0;

            if (!sqlgen.IsPreKatmai && hasDatePart)
            {
                result.Append("DATEADD(year, ");
                sqlgen.ParenthesizeExpressionIfNeeded(args[currentArgumentIndex++], result);
                result.Append(" - 1, ");
            }

            result.Append("convert (");
            result.Append(typeName);
            result.Append(",");

            //Building the string representation
            if (hasDatePart)
            {
                //  YEAR:   PREKATMAI:               CONVERT(VARCHAR, @YEAR)
                //          KATMAI   :              '0001'
                if (!sqlgen.IsPreKatmai)
                {
                    result.Append("'0001'");
                }
                else
                {
                    AppendConvertToVarchar(sqlgen, result, args[currentArgumentIndex++]);
                }

                //  MONTH
                result.Append(" + '-' + ");
                AppendConvertToVarchar(sqlgen, result, args[currentArgumentIndex++]);

                //  DAY 
                result.Append(" + '-' + ");
                AppendConvertToVarchar(sqlgen, result, args[currentArgumentIndex++]);
                result.Append(" + ' ' + ");
            }

            //  HOUR
            AppendConvertToVarchar(sqlgen, result, args[currentArgumentIndex++]);

            // MINUTE
            result.Append(" + ':' + ");
            AppendConvertToVarchar(sqlgen, result, args[currentArgumentIndex++]);

            // SECOND
            result.Append(" + ':' + str(");
            result.Append(args[currentArgumentIndex++].Accept(sqlgen));

            if (sqlgen.IsPreKatmai)
            {
                result.Append(", 6, 3)");
            }
            else
            {
                result.Append(", 10, 7)");
            }

            //  TZOFFSET
            if (hasTimeZonePart)
            {
                result.Append(" + (CASE WHEN ");
                sqlgen.ParenthesizeExpressionIfNeeded(args[currentArgumentIndex], result);
                result.Append(" >= 0 THEN '+' ELSE '-' END) + convert(varchar(255), ABS(");
                sqlgen.ParenthesizeExpressionIfNeeded(args[currentArgumentIndex], result);
                result.Append("/60)) + ':' + convert(varchar(255), ABS(");
                sqlgen.ParenthesizeExpressionIfNeeded(args[currentArgumentIndex], result);
                result.Append("%60))");
            }

            result.Append(", 121)");

            if (!sqlgen.IsPreKatmai && hasDatePart)
            {
                result.Append(")");
            }
            return result;
        }