func()

in query/time_bucketizer.go [72:174]


func (qc *AQLQueryContext) buildTimeDimensionExpr(timeBucketizerString string, timeColumn expr.Expr) (expr.Expr, error) {
	var bucketizerExpr expr.Expr
	var err error
	timeColumnWithOffsetExpr := timeColumn

	// construct TimeSeriesBucketizer expr
	if qc.timezoneTable.tableColumn != "" {
		var timezoneTableID, timezoneColumnID int
		timezoneColumn := fmt.Sprintf("%s.%s", qc.timezoneTable.tableAlias, qc.timezoneTable.tableColumn)
		timezoneTableID = qc.TableIDByAlias[qc.timezoneTable.tableAlias]
		timezoneColumnID = qc.TableScanners[timezoneTableID].Schema.ColumnIDs[qc.timezoneTable.tableColumn]
		// expand ast by offsetting timezone column
		timeColumnWithOffsetExpr = &expr.BinaryExpr{
			Op:  expr.CONVERT_TZ,
			LHS: timeColumn,
			RHS: &expr.VarRef{
				Val:      timezoneColumn,
				TableID:  timezoneTableID,
				ColumnID: timezoneColumnID,
			},
		}
	} else if qc.fixedTimezone.String() != time.UTC.String() {
		_, fromOffset := qc.fromTime.Time.Zone()
		_, toOffset := qc.toTime.Time.Zone()
		if fromOffset != toOffset {
			offsetDiff := fromOffset - toOffset
			switchTs, err := utils.CalculateDSTSwitchTs(qc.fromTime.Time.Unix(), qc.toTime.Time.Unix(), qc.fixedTimezone)
			if err != nil {
				return nil, err
			}
			qc.dstswitch = switchTs
			// simulate IF statement. sub ast: timeCol + fromOffset + (timeCol > switchTs) * offsetDiff
			// where (timeCol > switchTs) will return 1 or 0
			timeColumnWithOffsetExpr = &expr.BinaryExpr{
				Op:  expr.ADD,
				LHS: timeColumn,
				RHS: &expr.BinaryExpr{
					Op: expr.ADD,
					LHS: &expr.NumberLiteral{
						Expr:     strconv.Itoa(fromOffset),
						Int:      fromOffset,
						ExprType: expr.Signed,
					},
					RHS: &expr.BinaryExpr{
						Op: expr.MUL,
						LHS: &expr.NumberLiteral{
							Expr:     strconv.Itoa(offsetDiff),
							Int:      offsetDiff,
							ExprType: expr.Signed,
						},
						RHS: &expr.BinaryExpr{
							Op:  expr.GTE,
							LHS: timeColumn,
							RHS: &expr.NumberLiteral{
								Expr: strconv.Itoa(int(switchTs)),
								Int:  int(switchTs),
							},
							ExprType: expr.Boolean,
						},
						ExprType: expr.Signed,
					},
				},
			}
		} else {
			timeColumnWithOffsetExpr = &expr.BinaryExpr{
				Op:  expr.CONVERT_TZ,
				LHS: timeColumn,
				RHS: &expr.NumberLiteral{
					Expr: strconv.Itoa(fromOffset),
					Int:  fromOffset,
				},
			}
		}

	}

	bucketizerExpr, err = parseRecurringTimeBucketizer(timeBucketizerString, timeColumnWithOffsetExpr)
	if err != nil || bucketizerExpr != nil {
		return bucketizerExpr, err
	}

	if bucketizerExpr = parseIrregularTimeBucketizer(timeBucketizerString, timeColumnWithOffsetExpr); bucketizerExpr != nil {
		return bucketizerExpr, nil
	}

	timeBucket, err := common.ParseRegularTimeBucketizer(timeBucketizerString)
	if err != nil {
		return nil, err
	}
	bucketInSeconds := timeBucket.Size * common.BucketSizeToseconds[timeBucket.Unit]

	bucketizerExpr = &expr.BinaryExpr{
		Op:  expr.FLOOR,
		LHS: timeColumnWithOffsetExpr,
		RHS: &expr.NumberLiteral{
			Expr:     strconv.Itoa(bucketInSeconds),
			Int:      bucketInSeconds,
			ExprType: expr.Unsigned,
		},
	}

	return bucketizerExpr, nil
}