github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/query/aql_processor_test.go (about)

     1  //  Copyright (c) 2017-2018 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package query
    16  
    17  import (
    18  	"unsafe"
    19  
    20  	"encoding/binary"
    21  	"encoding/json"
    22  	"math"
    23  	"strconv"
    24  	"sync"
    25  	"time"
    26  
    27  	"github.com/onsi/ginkgo"
    28  	. "github.com/onsi/gomega"
    29  	"github.com/stretchr/testify/mock"
    30  	"github.com/uber-go/tally"
    31  	"github.com/uber/aresdb/common"
    32  	"github.com/uber/aresdb/diskstore"
    33  	diskMocks "github.com/uber/aresdb/diskstore/mocks"
    34  	"github.com/uber/aresdb/memstore"
    35  	memCom "github.com/uber/aresdb/memstore/common"
    36  	memComMocks "github.com/uber/aresdb/memstore/common/mocks"
    37  	memMocks "github.com/uber/aresdb/memstore/mocks"
    38  	"github.com/uber/aresdb/memutils"
    39  	"github.com/uber/aresdb/metastore"
    40  	metaCom "github.com/uber/aresdb/metastore/common"
    41  	metaMocks "github.com/uber/aresdb/metastore/mocks"
    42  	queryCom "github.com/uber/aresdb/query/common"
    43  	"github.com/uber/aresdb/query/expr"
    44  	"github.com/uber/aresdb/utils"
    45  )
    46  
    47  // readDeviceVPSlice reads a vector party from file and also translate it to device vp format:
    48  // counts, nulls and values will be stored in a continuous memory space.
    49  func readDeviceVPSlice(factory memstore.TestFactoryT, name string, stream unsafe.Pointer,
    50  	device int) (deviceVectorPartySlice, error) {
    51  	sourceVP, err := factory.ReadArchiveVectorParty(name, &sync.RWMutex{})
    52  	if err != nil {
    53  		return deviceVectorPartySlice{}, err
    54  	}
    55  
    56  	hostVPSlice := sourceVP.GetHostVectorPartySlice(0, sourceVP.GetLength())
    57  	deviceVPSlice := hostToDeviceColumn(hostVPSlice, device)
    58  	copyHostToDevice(hostVPSlice, deviceVPSlice, stream, device)
    59  	return deviceVPSlice, nil
    60  }
    61  
    62  var _ = ginkgo.Describe("aql_processor", func() {
    63  	var batch99, batch101, batch110, batch120, batch130 *memstore.Batch
    64  	var vs memstore.LiveStore
    65  	var archiveBatch0 *memstore.ArchiveBatch
    66  	var archiveBatch1 *memstore.ArchiveBatch
    67  	var memStore memstore.MemStore
    68  	var metaStore metastore.MetaStore
    69  	var diskStore diskstore.DiskStore
    70  	var hostMemoryManager memCom.HostMemoryManager
    71  	var shard *memstore.TableShard
    72  	table := "table1"
    73  	shardID := 0
    74  
    75  	testFactory := memstore.TestFactoryT{
    76  		RootPath:   "../testing/data",
    77  		FileSystem: utils.OSFileSystem{},
    78  	}
    79  
    80  	ginkgo.BeforeEach(func() {
    81  		hostMemoryManager = new(memComMocks.HostMemoryManager)
    82  		hostMemoryManager.(*memComMocks.HostMemoryManager).On("ReportUnmanagedSpaceUsageChange", mock.Anything).Return()
    83  		memStore = new(memMocks.MemStore)
    84  		diskStore = new(diskMocks.DiskStore)
    85  
    86  		var err error
    87  		batch110, err = testFactory.ReadLiveBatch("archiving/batch-110")
    88  		Ω(err).Should(BeNil())
    89  		batch101, err = testFactory.ReadLiveBatch("archiving/batch-101")
    90  		Ω(err).Should(BeNil())
    91  		batch99, err = testFactory.ReadLiveBatch("archiving/batch-99")
    92  		Ω(err).Should(BeNil())
    93  		batch120, err = testFactory.ReadLiveBatch("live/batch-120")
    94  		Ω(err).Should(BeNil())
    95  		batch130, err = testFactory.ReadLiveBatch("live/batch-130")
    96  		Ω(err).Should(BeNil())
    97  		tmpBatch, err := testFactory.ReadArchiveBatch("archiving/archiveBatch0")
    98  		tmpBatch1, err := testFactory.ReadArchiveBatch("archiving/archiveBatch1")
    99  
   100  		Ω(err).Should(BeNil())
   101  
   102  		metaStore = new(metaMocks.MetaStore)
   103  		metaStore.(*metaMocks.MetaStore).On("GetArchiveBatchVersion", table, 0, mock.Anything, mock.Anything).Return(uint32(0), uint32(0), 0, nil)
   104  
   105  		diskStore = new(diskMocks.DiskStore)
   106  		diskStore.(*diskMocks.DiskStore).On(
   107  			"OpenVectorPartyFileForRead", table, mock.Anything, shardID, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
   108  
   109  		shard = memstore.NewTableShard(&memstore.TableSchema{
   110  			Schema: metaCom.Table{
   111  				Name: table,
   112  				Config: metaCom.TableConfig{
   113  					ArchivingDelayMinutes:    500,
   114  					ArchivingIntervalMinutes: 300,
   115  				},
   116  				IsFactTable:          true,
   117  				ArchivingSortColumns: []int{1, 2},
   118  				Columns: []metaCom.Column{
   119  					{Deleted: false, Name: "c0", Type: metaCom.Uint32},
   120  					{Deleted: false, Name: "c1", Type: metaCom.Bool},
   121  					{Deleted: false, Name: "c2", Type: metaCom.Float32},
   122  				},
   123  			},
   124  			ColumnIDs: map[string]int{
   125  				"c0": 0,
   126  				"c1": 1,
   127  				"c2": 2,
   128  			},
   129  			ValueTypeByColumn: []memCom.DataType{memCom.Uint32, memCom.Bool, memCom.Float32},
   130  			DefaultValues:     []*memCom.DataValue{&memCom.NullDataValue, &memCom.NullDataValue, &memCom.NullDataValue},
   131  		}, metaStore, diskStore, hostMemoryManager, shardID)
   132  
   133  		shardMap := map[int]*memstore.TableShard{
   134  			shardID: shard,
   135  		}
   136  
   137  		archiveBatch0 = &memstore.ArchiveBatch{
   138  			Version: 0,
   139  			Size:    5,
   140  			Shard:   shard,
   141  			Batch: memstore.Batch{
   142  				RWMutex: &sync.RWMutex{},
   143  				Columns: tmpBatch.Columns,
   144  			},
   145  		}
   146  		archiveBatch1 = &memstore.ArchiveBatch{
   147  			Version: 0,
   148  			Size:    5,
   149  			Shard:   shard,
   150  			Batch: memstore.Batch{
   151  				RWMutex: &sync.RWMutex{},
   152  				Columns: tmpBatch1.Columns,
   153  			},
   154  		}
   155  
   156  		shard.ArchiveStore = &memstore.ArchiveStore{CurrentVersion: memstore.NewArchiveStoreVersion(100, shard)}
   157  		shard.ArchiveStore.CurrentVersion.Batches[0] = archiveBatch0
   158  
   159  		memStore.(*memMocks.MemStore).On("GetTableShard", "table1", 0).Run(func(args mock.Arguments) {
   160  			shard.Users.Add(1)
   161  		}).Return(shard, nil).Once()
   162  
   163  		memStore.(*memMocks.MemStore).On("RLock").Return()
   164  		memStore.(*memMocks.MemStore).On("RUnlock").Return()
   165  		memStore.(*memMocks.MemStore).On("GetSchemas").Return(map[string]*memstore.TableSchema{
   166  			table: shard.Schema,
   167  		})
   168  
   169  		vs = memstore.LiveStore{
   170  			LastReadRecord: memstore.RecordID{BatchID: -101, Index: 3},
   171  			Batches: map[int32]*memstore.LiveBatch{
   172  				-110: {
   173  					Batch: memstore.Batch{
   174  						RWMutex: &sync.RWMutex{},
   175  						Columns: batch110.Columns,
   176  					},
   177  					Capacity: 5,
   178  				},
   179  				-101: {
   180  					Batch: memstore.Batch{
   181  						RWMutex: &sync.RWMutex{},
   182  						Columns: batch101.Columns,
   183  					},
   184  					Capacity: 5,
   185  				},
   186  				-99: {
   187  					Batch: memstore.Batch{
   188  						RWMutex: &sync.RWMutex{},
   189  						Columns: batch99.Columns,
   190  					},
   191  					Capacity: 5,
   192  				},
   193  			},
   194  			PrimaryKey:        memstore.NewPrimaryKey(16, true, 0, hostMemoryManager),
   195  			HostMemoryManager: hostMemoryManager,
   196  		}
   197  
   198  		shardMap[shardID].LiveStore = &vs
   199  		shardMap[shardID].ArchiveStore.CurrentVersion.ArchivingCutoff = 100
   200  		shardMap[shardID].ArchiveStore.CurrentVersion.Batches[0] = archiveBatch0
   201  	})
   202  
   203  	ginkgo.AfterEach(func() {
   204  		batch110.SafeDestruct()
   205  		batch101.SafeDestruct()
   206  		batch99.SafeDestruct()
   207  		da := getDeviceAllocator()
   208  		Ω(da.(*memoryTrackingDeviceAllocatorImpl).memoryUsage[0]).Should(BeEquivalentTo(0))
   209  	})
   210  
   211  	ginkgo.It("prefilterSlice", func() {
   212  		vp1, err := testFactory.ReadArchiveVectorParty("sortedVP7", nil)
   213  		vp2, err := testFactory.ReadArchiveVectorParty("sortedVP6", nil)
   214  		vp3, err := testFactory.ReadArchiveVectorParty("sortedVP8", nil)
   215  		Ω(err).Should(BeNil())
   216  
   217  		qc1 := AQLQueryContext{
   218  			TableScanners: []*TableScanner{
   219  				{
   220  					EqualityPrefilterValues:  []uint32{1, 2},
   221  					RangePrefilterBoundaries: [2]boundaryType{inclusiveBoundary, exclusiveBoundary},
   222  					RangePrefilterValues:     [2]uint32{1, 3},
   223  				},
   224  			},
   225  		}
   226  
   227  		lowerBound, upperBound, vpSlice1 := qc1.prefilterSlice(vp1, 0, 0, 20)
   228  		Ω(vpSlice1.ValueStartIndex).Should(Equal(0))
   229  		Ω(vpSlice1.ValueBytes).Should(Equal(64))
   230  		Ω(vpSlice1.NullStartIndex).Should(Equal(0))
   231  		Ω(vpSlice1.NullBytes).Should(Equal(64))
   232  		Ω(vpSlice1.CountStartIndex).Should(Equal(0))
   233  		Ω(vpSlice1.CountBytes).Should(Equal(64))
   234  
   235  		lowerBound, upperBound, vpSlice2 := qc1.prefilterSlice(vp2, 1, lowerBound, upperBound)
   236  		Ω(vpSlice2.ValueStartIndex).Should(Equal(1))
   237  		Ω(vpSlice2.ValueBytes).Should(Equal(64))
   238  		Ω(vpSlice2.NullStartIndex).Should(Equal(1))
   239  		Ω(vpSlice2.NullBytes).Should(Equal(64))
   240  		Ω(vpSlice2.CountStartIndex).Should(Equal(1))
   241  		Ω(vpSlice2.CountBytes).Should(Equal(64))
   242  
   243  		lowerBound, upperBound, vpSlice3 := qc1.prefilterSlice(vp3, 2, lowerBound, upperBound)
   244  
   245  		Ω(vpSlice3.ValueStartIndex).Should(Equal(1))
   246  		Ω(vpSlice3.ValueBytes).Should(Equal(64))
   247  		Ω(vpSlice3.NullStartIndex).Should(Equal(1))
   248  		Ω(vpSlice3.NullBytes).Should(Equal(64))
   249  		Ω(vpSlice3.CountStartIndex).Should(Equal(1))
   250  		Ω(vpSlice3.CountBytes).Should(Equal(64))
   251  
   252  		Ω(lowerBound).Should(Equal(2))
   253  		Ω(upperBound).Should(Equal(4))
   254  
   255  		qc2 := AQLQueryContext{
   256  			TableScanners: []*TableScanner{
   257  				{
   258  					EqualityPrefilterValues:  []uint32{1},
   259  					RangePrefilterBoundaries: [2]boundaryType{noBoundary, inclusiveBoundary},
   260  					RangePrefilterValues:     [2]uint32{0, 1},
   261  				},
   262  			},
   263  		}
   264  
   265  		lowerBound, upperBound, vpSlice1 = qc2.prefilterSlice(vp1, 0, 0, 20)
   266  		Ω(vpSlice1.ValueStartIndex).Should(Equal(0))
   267  		Ω(vpSlice1.ValueBytes).Should(Equal(64))
   268  		Ω(vpSlice1.NullStartIndex).Should(Equal(0))
   269  		Ω(vpSlice1.NullBytes).Should(Equal(64))
   270  		Ω(vpSlice1.CountStartIndex).Should(Equal(0))
   271  		Ω(vpSlice1.CountBytes).Should(Equal(64))
   272  
   273  		lowerBound, upperBound, vpSlice2 = qc2.prefilterSlice(vp2, 1, lowerBound, upperBound)
   274  		Ω(vpSlice2.ValueStartIndex).Should(Equal(0))
   275  		Ω(vpSlice2.ValueBytes).Should(Equal(64))
   276  		Ω(vpSlice2.NullStartIndex).Should(Equal(0))
   277  		Ω(vpSlice2.NullBytes).Should(Equal(64))
   278  		Ω(vpSlice2.CountStartIndex).Should(Equal(0))
   279  		Ω(vpSlice2.CountBytes).Should(Equal(64))
   280  
   281  		lowerBound, upperBound, vpSlice3 = qc2.prefilterSlice(vp3, 2, lowerBound, upperBound)
   282  		Ω(vpSlice3.ValueStartIndex).Should(Equal(0))
   283  		Ω(vpSlice3.ValueBytes).Should(Equal(64))
   284  		Ω(vpSlice3.NullStartIndex).Should(Equal(0))
   285  		Ω(vpSlice3.NullBytes).Should(Equal(64))
   286  		Ω(vpSlice3.CountStartIndex).Should(Equal(0))
   287  		Ω(vpSlice3.CountBytes).Should(Equal(64))
   288  
   289  		Ω(lowerBound).Should(Equal(0))
   290  		Ω(upperBound).Should(Equal(2))
   291  
   292  		qc3 := AQLQueryContext{
   293  			TableScanners: []*TableScanner{
   294  				{
   295  					EqualityPrefilterValues:  []uint32{1},
   296  					RangePrefilterBoundaries: [2]boundaryType{exclusiveBoundary, noBoundary},
   297  					RangePrefilterValues:     [2]uint32{1, 0},
   298  				},
   299  			},
   300  		}
   301  
   302  		lowerBound, upperBound, vpSlice1 = qc3.prefilterSlice(vp1, 0, 0, 20)
   303  		Ω(vpSlice1.ValueStartIndex).Should(Equal(0))
   304  		Ω(vpSlice1.ValueBytes).Should(Equal(64))
   305  		Ω(vpSlice1.NullStartIndex).Should(Equal(0))
   306  		Ω(vpSlice1.NullBytes).Should(Equal(64))
   307  		Ω(vpSlice1.CountStartIndex).Should(Equal(0))
   308  		Ω(vpSlice1.CountBytes).Should(Equal(64))
   309  
   310  		lowerBound, upperBound, vpSlice2 = qc3.prefilterSlice(vp2, 1, lowerBound, upperBound)
   311  		Ω(vpSlice2.ValueStartIndex).Should(Equal(1))
   312  		Ω(vpSlice2.ValueBytes).Should(Equal(64))
   313  		Ω(vpSlice2.NullStartIndex).Should(Equal(1))
   314  		Ω(vpSlice2.NullBytes).Should(Equal(64))
   315  		Ω(vpSlice2.CountStartIndex).Should(Equal(1))
   316  		Ω(vpSlice2.CountBytes).Should(Equal(64))
   317  
   318  		lowerBound, upperBound, vpSlice3 = qc3.prefilterSlice(vp3, 2, lowerBound, upperBound)
   319  		Ω(vpSlice3.ValueStartIndex).Should(Equal(1))
   320  		Ω(vpSlice3.ValueBytes).Should(Equal(64))
   321  		Ω(vpSlice3.NullStartIndex).Should(Equal(1))
   322  		Ω(vpSlice3.NullBytes).Should(Equal(64))
   323  		Ω(vpSlice3.CountStartIndex).Should(Equal(1))
   324  		Ω(vpSlice3.CountBytes).Should(Equal(64))
   325  
   326  		Ω(lowerBound).Should(Equal(2))
   327  		Ω(upperBound).Should(Equal(5))
   328  	})
   329  
   330  	ginkgo.It("makeForeignColumnVectorInput", func() {
   331  		values := [64]byte{}
   332  		nulls := [64]byte{}
   333  
   334  		table := foreignTable{
   335  			batches: [][]deviceVectorPartySlice{
   336  				{
   337  					{
   338  						values:    devicePointer{pointer: unsafe.Pointer(&values[0])},
   339  						nulls:     devicePointer{pointer: unsafe.Pointer(&nulls[0])},
   340  						length:    10,
   341  						valueType: memCom.Uint16,
   342  					},
   343  					{
   344  						values:    devicePointer{pointer: unsafe.Pointer(&values[0])},
   345  						nulls:     devicePointer{pointer: unsafe.Pointer(&nulls[0])},
   346  						length:    10,
   347  						valueType: memCom.Uint8,
   348  					},
   349  				},
   350  				{
   351  					{
   352  						values:    devicePointer{pointer: unsafe.Pointer(&values[0])},
   353  						nulls:     devicePointer{pointer: unsafe.Pointer(&nulls[0])},
   354  						length:    10,
   355  						valueType: memCom.Uint16,
   356  					},
   357  					{
   358  						values:    devicePointer{pointer: unsafe.Pointer(&values[0])},
   359  						nulls:     devicePointer{pointer: unsafe.Pointer(&nulls[0])},
   360  						length:    10,
   361  						valueType: memCom.Uint8,
   362  					},
   363  				},
   364  			},
   365  		}
   366  
   367  		inputVector := makeForeignColumnInput(0, unsafe.Pointer(uintptr(0)), table, nil, 0)
   368  		Ω(inputVector.Type).Should(Equal(uint32(3)))
   369  	})
   370  
   371  	ginkgo.It("makeVectorPartySliceInput", func() {
   372  		values := [64]byte{}
   373  		nulls := [64]byte{}
   374  		counts := [64]byte{}
   375  
   376  		column := deviceVectorPartySlice{
   377  			values:          devicePointer{pointer: unsafe.Pointer(&values[0])},
   378  			nulls:           devicePointer{pointer: unsafe.Pointer(&nulls[0])},
   379  			counts:          devicePointer{pointer: unsafe.Pointer(&counts[0])},
   380  			length:          10,
   381  			valueType:       memCom.Uint16,
   382  			valueStartIndex: 1,
   383  			nullStartIndex:  0,
   384  			countStartIndex: 1,
   385  		}
   386  		inputVector := makeVectorPartySliceInput(column)
   387  		// uint32(0) corresponds to VectorPartySlice in C.enum_InputVectorType
   388  		Ω(inputVector.Type).Should(Equal(uint32(0)))
   389  	})
   390  
   391  	ginkgo.It("makeConstantInput", func() {
   392  		inputVector := makeConstantInput(float64(1.0), false)
   393  		// uint32(2) corresponds to ConstantInput in C.enum_InputVectorType
   394  		Ω(inputVector.Type).Should(Equal(uint32(2)))
   395  
   396  		inputVector = makeConstantInput(int(1), false)
   397  		Ω(inputVector.Type).Should(Equal(uint32(2)))
   398  
   399  		v := &expr.GeopointLiteral{Val: [2]float32{1.1, 2.2}}
   400  		inputVector = makeConstantInput(v, false)
   401  		Ω(inputVector.Type).Should(Equal(uint32(2)))
   402  	})
   403  
   404  	ginkgo.It("makeScratchSpaceInput", func() {
   405  		values := [64]byte{}
   406  		nulls := [64]byte{}
   407  		inputVector := makeScratchSpaceInput(unsafe.Pointer(&values[0]), unsafe.Pointer(&nulls[0]), uint32(1))
   408  		// uint32(1) corresponds to ScratchSpaceInput in C.enum_InputVectorType
   409  		Ω(inputVector.Type).Should(Equal(uint32(1)))
   410  	})
   411  
   412  	ginkgo.It("makeScratchSpaceOutput", func() {
   413  		values := [64]byte{}
   414  		nulls := [64]byte{}
   415  		outputVector := makeScratchSpaceOutput(unsafe.Pointer(&values[0]), unsafe.Pointer(&nulls[0]), uint32(0))
   416  		// uint32(0) corresponds to ScratchSpaceOutput in C.enum_OutputVectorType
   417  		Ω(outputVector.Type).Should(Equal(uint32(0)))
   418  	})
   419  
   420  	ginkgo.It("makeMeasureVectorOutput", func() {
   421  		measureValues := [64]byte{}
   422  		outputVector := makeMeasureVectorOutput(unsafe.Pointer(&measureValues[0]), uint32(6), uint32(0))
   423  		// uint32(0) corresponds to ScratchSpaceOutput in C.enum_OutputVectorType
   424  		Ω(outputVector.Type).Should(Equal(uint32(1)))
   425  	})
   426  
   427  	ginkgo.It("makeDimensionVectorOutput", func() {
   428  		dimValues := [64]byte{}
   429  		outputVector := makeDimensionVectorOutput(unsafe.Pointer(&dimValues[0]), 0, 4, uint32(0))
   430  		// uint32(0) corresponds to ScratchSpaceOutput in C.enum_OutputVectorType
   431  		Ω(outputVector.Type).Should(Equal(uint32(2)))
   432  	})
   433  
   434  	ginkgo.It("evaluateFilterExpression", func() {
   435  		ctx := oopkBatchContext{}
   436  		defer ctx.cleanupDeviceResultBuffers()
   437  		defer ctx.cleanupBeforeAggregation()
   438  		defer ctx.swapResultBufferForNextBatch()
   439  		var stream unsafe.Pointer
   440  		vp0, err := readDeviceVPSlice(testFactory, "sortedVP8", stream, ctx.device)
   441  		Ω(err).Should(BeNil())
   442  		vp1, err := readDeviceVPSlice(testFactory, "sortedVP7", stream, ctx.device)
   443  		Ω(err).Should(BeNil())
   444  		vp2, err := readDeviceVPSlice(testFactory, "sortedVP6", stream, ctx.device)
   445  		Ω(err).Should(BeNil())
   446  		columns := []deviceVectorPartySlice{
   447  			vp0,
   448  			vp1,
   449  			vp2,
   450  		}
   451  
   452  		tableScanners := []*TableScanner{
   453  			{
   454  				ColumnsByIDs: map[int]int{
   455  					1: 1,
   456  					2: 2,
   457  				},
   458  			},
   459  		}
   460  		foreignTables := make([]*foreignTable, 0)
   461  
   462  		ctx.prepareForFiltering(columns, 0, 0, stream)
   463  		Ω(ctx.size).Should(Equal(6))
   464  		initIndexVector(ctx.indexVectorD.getPointer(), 0, ctx.size, stream, 0)
   465  
   466  		// expr: -vp1 == -2 || vp2 >= 2
   467  
   468  		// id| vp0 | vp1 | vp2 | res |
   469  		// ---------------------------
   470  		// 0 | 1 0 | 1 0 | 1 0 |     |
   471  		// 1 | 1 2 |	 | 2 2 |  y  |
   472  		// 2 | 2 3 |	 |     |  y  |
   473  		// 3 | 3 4 |     |     |  y  |
   474  		// 4 | 2 5 | 2 5 | 1 5 |  y  |
   475  		// 5 | 2 10|	 | 2 10|  y  |
   476  
   477  		exp := &expr.BinaryExpr{
   478  			Op: expr.OR,
   479  			LHS: &expr.BinaryExpr{
   480  				Op: expr.EQ,
   481  				LHS: &expr.UnaryExpr{
   482  					Op: expr.UNARY_MINUS,
   483  					Expr: &expr.VarRef{
   484  						Val:      "vp1",
   485  						ColumnID: 1,
   486  					},
   487  				},
   488  				RHS: &expr.NumberLiteral{
   489  					Val:      0,
   490  					Int:      -2,
   491  					ExprType: expr.Signed,
   492  				},
   493  			},
   494  			RHS: &expr.BinaryExpr{
   495  				Op: expr.GTE,
   496  				LHS: &expr.VarRef{
   497  					Val:      "vp2",
   498  					ColumnID: 2,
   499  				},
   500  				RHS: &expr.NumberLiteral{
   501  					Val:      0,
   502  					Int:      2,
   503  					ExprType: expr.Unsigned,
   504  				},
   505  			},
   506  		}
   507  
   508  		ctx.processExpression(exp, nil, tableScanners, foreignTables, stream, 0, ctx.filterAction)
   509  		Ω(ctx.size).Should(Equal(5))
   510  		ctx.cleanupBeforeAggregation()
   511  		ctx.swapResultBufferForNextBatch()
   512  
   513  		vp0, err = readDeviceVPSlice(testFactory, "sortedVP8", stream, ctx.device)
   514  		Ω(err).Should(BeNil())
   515  		vp1, err = readDeviceVPSlice(testFactory, "sortedVP7", stream, ctx.device)
   516  		Ω(err).Should(BeNil())
   517  		vp2, err = readDeviceVPSlice(testFactory, "sortedVP6", stream, ctx.device)
   518  		Ω(err).Should(BeNil())
   519  		columns = []deviceVectorPartySlice{
   520  			vp0,
   521  			vp1,
   522  			vp2,
   523  		}
   524  
   525  		// expr: vp2 / 2 == 0
   526  		exp = &expr.BinaryExpr{
   527  			Op: expr.EQ,
   528  			LHS: &expr.BinaryExpr{
   529  				Op: expr.DIV,
   530  				LHS: &expr.VarRef{
   531  					Val:      "vp2",
   532  					ColumnID: 2,
   533  				},
   534  				RHS: &expr.NumberLiteral{
   535  					Val:      2,
   536  					Int:      2,
   537  					Expr:     "2",
   538  					ExprType: expr.Signed,
   539  				},
   540  			},
   541  			RHS: &expr.NumberLiteral{
   542  				Val:      0,
   543  				Int:      0,
   544  				Expr:     "0",
   545  				ExprType: expr.Signed,
   546  			},
   547  		}
   548  		ctx.prepareForFiltering(columns, 0, 0, stream)
   549  		initIndexVector(ctx.indexVectorD.getPointer(), 0, ctx.size, stream, 0)
   550  		ctx.processExpression(exp, nil, tableScanners, foreignTables, stream, 0, ctx.filterAction)
   551  		Ω(ctx.size).Should(Equal(2))
   552  		Ω(*(*uint32)(utils.MemAccess(ctx.indexVectorD.getPointer(), 0))).Should(Equal(uint32(0)))
   553  		Ω(*(*uint32)(utils.MemAccess(ctx.indexVectorD.getPointer(), 4))).Should(Equal(uint32(4)))
   554  		ctx.cleanupBeforeAggregation()
   555  		ctx.swapResultBufferForNextBatch()
   556  	})
   557  
   558  	ginkgo.It("evaluateVarRefDimensionExpression", func() {
   559  		var stream unsafe.Pointer
   560  		ctx := oopkBatchContext{}
   561  		vpSlice0, err := readDeviceVPSlice(testFactory, "sortedVP8", stream, ctx.device)
   562  		Ω(err).Should(BeNil())
   563  		vpSlice1, err := readDeviceVPSlice(testFactory, "sortedVP7", stream, ctx.device)
   564  		Ω(err).Should(BeNil())
   565  		vpSlice2, err := readDeviceVPSlice(testFactory, "sortedVP6", stream, ctx.device)
   566  		Ω(err).Should(BeNil())
   567  		columns := []deviceVectorPartySlice{
   568  			vpSlice0,
   569  			vpSlice1,
   570  			vpSlice2,
   571  		}
   572  		tableScanners := []*TableScanner{
   573  			{
   574  				ColumnsByIDs: map[int]int{
   575  					1: 1,
   576  					2: 2,
   577  				},
   578  			},
   579  		}
   580  
   581  		foreignTables := make([]*foreignTable, 0)
   582  		oopkContext := OOPKContext{
   583  			// only one 2 byte dimension
   584  			NumDimsPerDimWidth: queryCom.DimCountsPerDimWidth{0, 0, 0, 1, 0},
   585  			// 2 bytes + 1 validity byte
   586  			DimRowBytes: 3,
   587  		}
   588  
   589  		// test boolean dimension value
   590  		ctx.prepareForFiltering(columns, 0, 0, stream)
   591  		initIndexVector(ctx.indexVectorD.getPointer(), 0, ctx.size, stream, 0)
   592  		ctx.prepareForDimAndMeasureEval(oopkContext.DimRowBytes, 4, oopkContext.NumDimsPerDimWidth, false, stream)
   593  		valueOffset, nullOffset := queryCom.GetDimensionStartOffsets(oopkContext.NumDimsPerDimWidth, 0, ctx.resultCapacity)
   594  		dimensionExprRootAction := ctx.makeWriteToDimensionVectorAction(valueOffset, nullOffset, 0)
   595  		// vp2
   596  		exp := &expr.VarRef{
   597  			Val:      "vp2",
   598  			ExprType: expr.Unsigned,
   599  			TableID:  0,
   600  			ColumnID: 2,
   601  			DataType: memCom.Uint16,
   602  		}
   603  		ctx.processExpression(exp, nil, tableScanners, foreignTables, stream, 0, dimensionExprRootAction)
   604  		Ω(*(*[18]uint8)(ctx.dimensionVectorD[0].getPointer())).Should(Equal([18]uint8{1, 0, 2, 0, 2, 0, 2, 0, 1, 0, 2, 0, 1, 1, 1, 1, 1, 1}))
   605  		ctx.cleanupBeforeAggregation()
   606  		ctx.swapResultBufferForNextBatch()
   607  		ctx.cleanupDeviceResultBuffers()
   608  	})
   609  
   610  	ginkgo.It("evaluateBooleanDimensionExpression", func() {
   611  		var stream unsafe.Pointer
   612  		ctx := oopkBatchContext{}
   613  		vpSlice0, err := readDeviceVPSlice(testFactory, "sortedVP8", stream, ctx.device)
   614  		Ω(err).Should(BeNil())
   615  		vpSlice1, err := readDeviceVPSlice(testFactory, "sortedVP7", stream, ctx.device)
   616  		Ω(err).Should(BeNil())
   617  		vpSlice2, err := readDeviceVPSlice(testFactory, "sortedVP6", stream, ctx.device)
   618  		Ω(err).Should(BeNil())
   619  
   620  		columns := []deviceVectorPartySlice{
   621  			vpSlice0,
   622  			vpSlice1,
   623  			vpSlice2,
   624  		}
   625  		tableScanners := []*TableScanner{
   626  			{
   627  				ColumnsByIDs: map[int]int{
   628  					1: 1,
   629  					2: 2,
   630  				},
   631  			},
   632  		}
   633  		foreignTables := make([]*foreignTable, 0)
   634  		oopkContext := OOPKContext{
   635  			NumDimsPerDimWidth: queryCom.DimCountsPerDimWidth{0, 0, 0, 0, 1},
   636  			// test boolean dimension value
   637  			// 1 byte + 1 validity byte
   638  			DimRowBytes: 2,
   639  		}
   640  
   641  		ctx.prepareForFiltering(columns, 0, 0, stream)
   642  		initIndexVector(ctx.indexVectorD.getPointer(), 0, ctx.size, stream, 0)
   643  		ctx.prepareForDimAndMeasureEval(oopkContext.DimRowBytes, 4, oopkContext.NumDimsPerDimWidth, false, stream)
   644  		valueOffset, nullOffset := queryCom.GetDimensionStartOffsets(oopkContext.NumDimsPerDimWidth, 0, ctx.resultCapacity)
   645  		dimensionExprRootAction := ctx.makeWriteToDimensionVectorAction(valueOffset, nullOffset, 0)
   646  		// vp2 == 2
   647  		exp := &expr.BinaryExpr{
   648  			Op: expr.EQ,
   649  			LHS: &expr.VarRef{
   650  				Val:      "vp2",
   651  				ColumnID: 2,
   652  			},
   653  			RHS: &expr.NumberLiteral{
   654  				Val:      2,
   655  				Int:      2,
   656  				Expr:     "2",
   657  				ExprType: expr.Signed,
   658  			},
   659  			ExprType: expr.Boolean,
   660  		}
   661  		ctx.processExpression(exp, nil, tableScanners, foreignTables, stream, 0, dimensionExprRootAction)
   662  		Ω(*(*[12]uint8)(ctx.dimensionVectorD[0].getPointer())).Should(Equal([12]uint8{0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1}))
   663  		ctx.cleanupBeforeAggregation()
   664  		ctx.swapResultBufferForNextBatch()
   665  		ctx.cleanupDeviceResultBuffers()
   666  	})
   667  
   668  	ginkgo.It("evaluateDimensionExpression", func() {
   669  		ctx := oopkBatchContext{}
   670  		var stream unsafe.Pointer
   671  		vpSlice0, err := readDeviceVPSlice(testFactory, "sortedVP8", stream, ctx.device)
   672  		Ω(err).Should(BeNil())
   673  		vpSlice1, err := readDeviceVPSlice(testFactory, "sortedVP7", stream, ctx.device)
   674  		Ω(err).Should(BeNil())
   675  		vpSlice2, err := readDeviceVPSlice(testFactory, "sortedVP6", stream, ctx.device)
   676  		Ω(err).Should(BeNil())
   677  
   678  		columns := []deviceVectorPartySlice{
   679  			vpSlice0,
   680  			vpSlice1,
   681  			vpSlice2,
   682  		}
   683  		tableScanners := []*TableScanner{
   684  			{
   685  				ColumnsByIDs: map[int]int{
   686  					1: 1,
   687  					2: 2,
   688  				},
   689  			},
   690  		}
   691  		foreignTables := make([]*foreignTable, 0)
   692  		oopkContext := OOPKContext{
   693  			NumDimsPerDimWidth: queryCom.DimCountsPerDimWidth{0, 0, 1, 0, 0},
   694  			DimRowBytes:        5,
   695  		}
   696  
   697  		// id|vp0|vp1|vp2|
   698  		// ---------------------
   699  		// 0 | 1 | 1 | 1 |
   700  		// 1 | 1 | 1 | 2 |
   701  		// 2 | 2 | 1 | 2 |
   702  		// 3 | 3 | 1 | 2 |
   703  		// 4 | 2 | 2 | 1 |
   704  		// 5 | 2 | 2 | 2 |
   705  
   706  		// vp2 / 2
   707  		exp := &expr.BinaryExpr{
   708  			Op: expr.DIV,
   709  			LHS: &expr.VarRef{
   710  				Val:      "vp2",
   711  				ColumnID: 2,
   712  			},
   713  			RHS: &expr.NumberLiteral{
   714  				Val:      2,
   715  				Int:      2,
   716  				Expr:     "2",
   717  				ExprType: expr.Signed,
   718  			},
   719  			ExprType: expr.Signed,
   720  		}
   721  
   722  		ctx.prepareForFiltering(columns, 0, 0, stream)
   723  		initIndexVector(ctx.indexVectorD.getPointer(), 0, ctx.size, stream, 0)
   724  		ctx.prepareForDimAndMeasureEval(oopkContext.DimRowBytes, 4, oopkContext.NumDimsPerDimWidth, false, stream)
   725  		valueOffset, nullOffset := queryCom.GetDimensionStartOffsets(oopkContext.NumDimsPerDimWidth, 0, ctx.resultCapacity)
   726  		dimensionExprRootAction := ctx.makeWriteToDimensionVectorAction(valueOffset, nullOffset, 0)
   727  		ctx.processExpression(exp, nil, tableScanners, foreignTables, stream, 0, dimensionExprRootAction)
   728  		Ω(*(*[30]uint8)(ctx.dimensionVectorD[0].getPointer())).Should(Equal([30]uint8{0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1}))
   729  		ctx.cleanupBeforeAggregation()
   730  		ctx.swapResultBufferForNextBatch()
   731  		ctx.cleanupDeviceResultBuffers()
   732  
   733  	})
   734  
   735  	ginkgo.It("evaluateMeasureExpression", func() {
   736  		ctx := oopkBatchContext{}
   737  		var stream unsafe.Pointer
   738  		vpSlice0, err := readDeviceVPSlice(testFactory, "sortedVP8", stream, ctx.device)
   739  		Ω(err).Should(BeNil())
   740  		vpSlice1, err := readDeviceVPSlice(testFactory, "sortedVP7", stream, ctx.device)
   741  		Ω(err).Should(BeNil())
   742  		vpSlice2, err := readDeviceVPSlice(testFactory, "sortedVP6", stream, ctx.device)
   743  		Ω(err).Should(BeNil())
   744  
   745  		columns := []deviceVectorPartySlice{
   746  			vpSlice0,
   747  			vpSlice1,
   748  			vpSlice2,
   749  		}
   750  
   751  		tableScanners := []*TableScanner{
   752  			{
   753  				ColumnsByIDs: map[int]int{
   754  					1: 1,
   755  					2: 2,
   756  				},
   757  			},
   758  		}
   759  		foreignTables := make([]*foreignTable, 0)
   760  
   761  		// id|cnt|vp0|vp1|vp2|
   762  		// ---------------------
   763  		// 0 | 2 | 1 | 1 | 1 |
   764  		// 1 | 1 | 1 | 1 | 2 |
   765  		// 2 | 1 | 2 | 1 | 2 |
   766  		// 3 | 1 | 3 | 1 | 2 |
   767  		// 4 | 5 | 2 | 2 | 1 |
   768  		// 5 |10 | 2 | 2 | 2 |
   769  
   770  		// vp2 / 2
   771  		exp := &expr.BinaryExpr{
   772  			Op: expr.DIV,
   773  			LHS: &expr.VarRef{
   774  				Val:      "vp2",
   775  				ColumnID: 2,
   776  			},
   777  			RHS: &expr.NumberLiteral{
   778  				Val:      2,
   779  				Int:      2,
   780  				Expr:     "2",
   781  				ExprType: expr.Signed,
   782  			},
   783  		}
   784  
   785  		dimRowBytes := 8
   786  		ctx.prepareForFiltering(columns, 0, 0, stream)
   787  		initIndexVector(ctx.indexVectorD.getPointer(), 0, ctx.size, stream, 0)
   788  
   789  		ctx.prepareForDimAndMeasureEval(dimRowBytes, 4, queryCom.DimCountsPerDimWidth{}, false, stream)
   790  		measureExprRootAction := ctx.makeWriteToMeasureVectorAction(uint32(1), 4)
   791  		ctx.processExpression(exp, nil, tableScanners, foreignTables, stream, 0, measureExprRootAction)
   792  
   793  		Ω(*(*uint32)(ctx.measureVectorD[0].getPointer())).Should(Equal(uint32(0)))
   794  		Ω(*(*uint32)(utils.MemAccess(ctx.measureVectorD[0].getPointer(), 4))).Should(Equal(uint32(1)))
   795  		Ω(*(*uint32)(utils.MemAccess(ctx.measureVectorD[0].getPointer(), 8))).Should(Equal(uint32(1)))
   796  		Ω(*(*uint32)(utils.MemAccess(ctx.measureVectorD[0].getPointer(), 12))).Should(Equal(uint32(1)))
   797  		Ω(*(*uint32)(utils.MemAccess(ctx.measureVectorD[0].getPointer(), 16))).Should(Equal(uint32(0)))
   798  		Ω(*(*uint32)(utils.MemAccess(ctx.measureVectorD[0].getPointer(), 20))).Should(Equal(uint32(10)))
   799  		ctx.cleanupBeforeAggregation()
   800  		ctx.swapResultBufferForNextBatch()
   801  		ctx.cleanupDeviceResultBuffers()
   802  	})
   803  
   804  	ginkgo.It("sort", func() {
   805  		var stream unsafe.Pointer
   806  		// 3 total elements
   807  		dimensionVectorH := [9]uint8{2, 0, 1, 0, 2, 0, 1, 1, 1}
   808  		dimensionVectorD := deviceAllocate(3*3, 0)
   809  		memutils.AsyncCopyHostToDevice(dimensionVectorD.getPointer(), unsafe.Pointer(&dimensionVectorH), 3*3, stream, 0)
   810  
   811  		hashVectorD := deviceAllocate(8*3, 0)
   812  		dimIndexVectorH := [3]uint32{}
   813  		dimIndexVectorD := deviceAllocate(4*3, 0)
   814  		initIndexVector(dimIndexVectorD.getPointer(), 0, 3, stream, 0)
   815  
   816  		measureVectorH := [3]uint32{22, 11, 22}
   817  		measureVectorD := deviceAllocate(4*3, 0)
   818  		memutils.AsyncCopyHostToDevice(measureVectorD.getPointer(), unsafe.Pointer(&measureVectorH), 4*3, stream, 0)
   819  
   820  		numDims := queryCom.DimCountsPerDimWidth{0, 0, 0, 1, 0}
   821  		batchCtx := oopkBatchContext{
   822  			dimensionVectorD: [2]devicePointer{dimensionVectorD, nullDevicePointer},
   823  			hashVectorD:      [2]devicePointer{hashVectorD, nullDevicePointer},
   824  			dimIndexVectorD:  [2]devicePointer{dimIndexVectorD, nullDevicePointer},
   825  			measureVectorD:   [2]devicePointer{measureVectorD, nullDevicePointer},
   826  			size:             3,
   827  			resultSize:       0,
   828  			resultCapacity:   3,
   829  		}
   830  
   831  		batchCtx.sortByKey(numDims, stream, 0)
   832  		memutils.AsyncCopyDeviceToHost(unsafe.Pointer(&measureVectorH), measureVectorD.getPointer(), 12, stream, 0)
   833  		memutils.AsyncCopyDeviceToHost(unsafe.Pointer(&dimIndexVectorH), dimIndexVectorD.getPointer(), 12, stream, 0)
   834  
   835  		Ω(dimIndexVectorH).Should(Or(Equal([3]uint32{0, 2, 1}), Equal([3]uint32{1, 0, 2}), Equal([3]uint32{1, 2, 0}), Equal([3]uint32{2, 0, 1})))
   836  
   837  		deviceFreeAndSetNil(&dimensionVectorD)
   838  		deviceFreeAndSetNil(&dimIndexVectorD)
   839  		deviceFreeAndSetNil(&hashVectorD)
   840  		deviceFreeAndSetNil(&measureVectorD)
   841  	})
   842  
   843  	ginkgo.It("reduce", func() {
   844  		// one 4 byte dim
   845  		numDims := queryCom.DimCountsPerDimWidth{0, 0, 1, 0, 0}
   846  		var stream unsafe.Pointer
   847  
   848  		dimensionInputVector := [5]uint32{1, 1, 1, 2, 0x01010101}
   849  		hashInputVector := [4]uint64{1, 1, 1, 2}
   850  		dimIndexInputVector := [4]uint32{0, 1, 2, 3}
   851  		measureInputVector := [4]uint32{1, 2, 3, 4}
   852  
   853  		var dimensionOutputVector [5]uint32
   854  		var hashOutputVector [4]uint64
   855  		var dimIndexOutputVector [4]uint32
   856  		var measureOutputVector [4]uint32
   857  
   858  		batchCtx := oopkBatchContext{
   859  			dimensionVectorD: [2]devicePointer{{pointer: unsafe.Pointer(&dimensionInputVector)}, {pointer: unsafe.Pointer(&dimensionOutputVector)}},
   860  			hashVectorD:      [2]devicePointer{{pointer: unsafe.Pointer(&hashInputVector)}, {pointer: unsafe.Pointer(&hashOutputVector)}},
   861  			dimIndexVectorD:  [2]devicePointer{{pointer: unsafe.Pointer(&dimIndexInputVector)}, {pointer: unsafe.Pointer(&dimIndexOutputVector)}},
   862  			measureVectorD:   [2]devicePointer{{pointer: unsafe.Pointer(&measureInputVector)}, {pointer: unsafe.Pointer(&measureOutputVector)}},
   863  			size:             4,
   864  			resultSize:       0,
   865  			resultCapacity:   4,
   866  		}
   867  
   868  		// 1 is AGGR_SUM_UNSIGNED
   869  		batchCtx.reduceByKey(numDims, 4, uint32(1), stream, 0)
   870  		Ω(dimensionOutputVector).Should(Equal([5]uint32{1, 2, 0, 0, 0x0101}))
   871  		Ω(measureOutputVector).Should(Equal([4]uint32{6, 4, 0, 0}))
   872  	})
   873  
   874  	ginkgo.It("estimateScratchSpaceMemUsage should work", func() {
   875  		expression, _ := expr.ParseExpr(`a`)
   876  		currentMemUsage, maxMemUsage := estimateScratchSpaceMemUsage(expression, 100, true)
   877  		Ω(currentMemUsage).Should(Equal(0))
   878  		Ω(maxMemUsage).Should(Equal(0))
   879  
   880  		currentMemUsage, maxMemUsage = estimateScratchSpaceMemUsage(expression, 100, false)
   881  		Ω(currentMemUsage).Should(Equal(0))
   882  		Ω(maxMemUsage).Should(Equal(0))
   883  
   884  		expression, _ = expr.ParseExpr(`a + b`)
   885  		currentMemUsage, maxMemUsage = estimateScratchSpaceMemUsage(expression, 100, true)
   886  		Ω(currentMemUsage).Should(Equal(0))
   887  		Ω(maxMemUsage).Should(Equal(0))
   888  
   889  		currentMemUsage, maxMemUsage = estimateScratchSpaceMemUsage(expression, 100, false)
   890  		Ω(currentMemUsage).Should(Equal(500))
   891  		Ω(maxMemUsage).Should(Equal(500))
   892  
   893  		expression, _ = expr.ParseExpr(`(a+b) + (c+d)`)
   894  		currentMemUsage, maxMemUsage = estimateScratchSpaceMemUsage(expression, 100, true)
   895  		Ω(currentMemUsage).Should(Equal(0))
   896  		Ω(maxMemUsage).Should(Equal(1000))
   897  
   898  		currentMemUsage, maxMemUsage = estimateScratchSpaceMemUsage(expression, 100, false)
   899  		Ω(currentMemUsage).Should(Equal(500))
   900  		Ω(maxMemUsage).Should(Equal(1500))
   901  
   902  		expression, _ = expr.ParseExpr(`((a1+b1) + (c1+d1)) * ((a2+b2) + (c2+d2))`)
   903  		currentMemUsage, maxMemUsage = estimateScratchSpaceMemUsage(expression, 100, true)
   904  		Ω(currentMemUsage).Should(Equal(0))
   905  		Ω(maxMemUsage).Should(Equal(1500))
   906  
   907  		currentMemUsage, maxMemUsage = estimateScratchSpaceMemUsage(expression, 100, false)
   908  		Ω(currentMemUsage).Should(Equal(500))
   909  		Ω(maxMemUsage).Should(Equal(1500))
   910  	})
   911  
   912  	ginkgo.It("copy dimension vector should work", func() {
   913  		dvDevice := [40]uint8{2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 2, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}
   914  		dvHostExpected := [20]uint8{2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 1, 0, 2, 1, 1, 1, 1, 1, 1, 1}
   915  		ctx := oopkBatchContext{
   916  			dimensionVectorD: [2]devicePointer{{pointer: unsafe.Pointer(&dvDevice[0])}, nullDevicePointer},
   917  			resultSize:       2,
   918  			resultCapacity:   4,
   919  		}
   920  		dvHost := [20]uint8{}
   921  		dimensionVectorHost := unsafe.Pointer(&dvHost[0])
   922  		numDims := queryCom.DimCountsPerDimWidth{0, 0, 1, 1, 1}
   923  		var stream unsafe.Pointer
   924  		asyncCopyDimensionVector(dimensionVectorHost, ctx.dimensionVectorD[0].getPointer(), ctx.resultSize, 0,
   925  			numDims, ctx.resultSize, ctx.resultCapacity, memutils.AsyncCopyDeviceToHost, stream, 0)
   926  		Ω(dvHost).Should(Equal(dvHostExpected))
   927  	})
   928  
   929  	ginkgo.It("copy dimension vector with offset should work", func() {
   930  		dvDevice := [40]uint8{2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 2, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}
   931  		dvHostExpected := [40]uint8{0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 2, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0}
   932  		ctx := oopkBatchContext{
   933  			dimensionVectorD: [2]devicePointer{{pointer: unsafe.Pointer(&dvDevice[0])}, nullDevicePointer},
   934  			resultSize:       2,
   935  			resultCapacity:   4,
   936  		}
   937  		dvHost := [40]uint8{}
   938  		dimensionVectorHost := unsafe.Pointer(&dvHost[0])
   939  		numDims := queryCom.DimCountsPerDimWidth{0, 0, 1, 1, 1}
   940  		var stream unsafe.Pointer
   941  		asyncCopyDimensionVector(dimensionVectorHost, ctx.dimensionVectorD[0].getPointer(), ctx.resultSize, 1,
   942  			numDims, ctx.resultCapacity, ctx.resultCapacity, memutils.AsyncCopyDeviceToHost, stream, 0)
   943  		Ω(dvHost).Should(Equal(dvHostExpected))
   944  	})
   945  
   946  	ginkgo.It("prepareTimezoneTable", func() {
   947  		memStore := new(memMocks.MemStore)
   948  		memStore.On("GetSchema", mock.Anything).Return(&memstore.TableSchema{
   949  			EnumDicts: map[string]memstore.EnumDict{
   950  				"timezone": {
   951  					ReverseDict: []string{"America/Los_Angeles"},
   952  				},
   953  			},
   954  		}, nil)
   955  
   956  		utils.Init(common.AresServerConfig{Query: common.QueryConfig{TimezoneTable: common.TimezoneConfig{
   957  			TableName: "tableName",
   958  		}}}, common.NewLoggerFactory().GetDefaultLogger(), common.NewLoggerFactory().GetDefaultLogger(), tally.NewTestScope("test", nil))
   959  		qc := &AQLQueryContext{
   960  			timezoneTable: timezoneTableContext{tableColumn: "timezone"},
   961  		}
   962  		qc.prepareTimezoneTable(memStore)
   963  		Ω(qc.Error).Should(BeNil())
   964  		Ω(da.(*memoryTrackingDeviceAllocatorImpl).memoryUsage[0]).Should(BeEquivalentTo(2))
   965  		deviceFreeAndSetNil(&qc.OOPK.currentBatch.timezoneLookupD)
   966  		utils.ResetDefaults()
   967  	})
   968  
   969  	ginkgo.It("ProcessQuery should work", func() {
   970  		qc := &AQLQueryContext{}
   971  		q := &AQLQuery{
   972  			Table: table,
   973  			Dimensions: []Dimension{
   974  				{Expr: "c0", TimeBucketizer: "m", TimeUnit: "millisecond"},
   975  			},
   976  			Measures: []Measure{
   977  				{Expr: "count(c1)"},
   978  			},
   979  			TimeFilter: TimeFilter{
   980  				Column: "c0",
   981  				From:   "1970-01-01",
   982  				To:     "1970-01-02",
   983  			},
   984  		}
   985  		qc.Query = q
   986  
   987  		qc = q.Compile(memStore, false)
   988  		Ω(qc.Error).Should(BeNil())
   989  		qc.ProcessQuery(memStore)
   990  		Ω(qc.Error).Should(BeNil())
   991  		qc.Results = qc.Postprocess()
   992  		qc.ReleaseHostResultsBuffers()
   993  		bs, err := json.Marshal(qc.Results)
   994  		Ω(err).Should(BeNil())
   995  		Ω(bs).Should(MatchJSON(` {
   996  			"0": 5,
   997  			"60000": 4,
   998  			"120000": 3
   999  		  }`))
  1000  
  1001  		bc := qc.OOPK.currentBatch
  1002  		// Check whether pointers are properly cleaned up.
  1003  		Ω(len(qc.OOPK.foreignTables)).Should(BeZero())
  1004  		Ω(qc.cudaStreams[0]).Should(BeZero())
  1005  		Ω(qc.cudaStreams[1]).Should(BeZero())
  1006  
  1007  		Ω(bc.dimensionVectorD[0]).Should(BeZero())
  1008  		Ω(bc.dimensionVectorD[1]).Should(BeZero())
  1009  
  1010  		Ω(bc.dimIndexVectorD[0]).Should(BeZero())
  1011  		Ω(bc.dimIndexVectorD[1]).Should(BeZero())
  1012  
  1013  		Ω(bc.hashVectorD[0]).Should(BeZero())
  1014  		Ω(bc.hashVectorD[1]).Should(BeZero())
  1015  
  1016  		Ω(bc.measureVectorD[0]).Should(BeZero())
  1017  		Ω(bc.measureVectorD[1]).Should(BeZero())
  1018  
  1019  		Ω(bc.resultSize).Should(BeZero())
  1020  		Ω(bc.resultCapacity).Should(BeZero())
  1021  
  1022  		Ω(len(bc.columns)).Should(BeZero())
  1023  
  1024  		Ω(bc.indexVectorD).Should(BeZero())
  1025  		Ω(bc.predicateVectorD).Should(BeZero())
  1026  
  1027  		Ω(bc.size).Should(BeZero())
  1028  
  1029  		Ω(len(bc.foreignTableRecordIDsD)).Should(BeZero())
  1030  		Ω(len(bc.exprStackD)).Should(BeZero())
  1031  
  1032  		Ω(qc.OOPK.measureVectorH).Should(BeZero())
  1033  		Ω(qc.OOPK.dimensionVectorH).Should(BeZero())
  1034  
  1035  		Ω(qc.OOPK.hllVectorD).Should(BeZero())
  1036  		Ω(qc.OOPK.hllDimRegIDCountD).Should(BeZero())
  1037  	})
  1038  
  1039  	ginkgo.It("ProcessQuery should work for timezone column queries", func() {
  1040  		timezoneTable := "table2"
  1041  		memStore := new(memMocks.MemStore)
  1042  
  1043  		mainTableSchema := metaCom.Table{
  1044  			Name: table,
  1045  			Config: metaCom.TableConfig{
  1046  				ArchivingDelayMinutes:    500,
  1047  				ArchivingIntervalMinutes: 300,
  1048  			},
  1049  			IsFactTable: true,
  1050  			Columns: []metaCom.Column{
  1051  				{Deleted: false, Name: "c0", Type: metaCom.Uint32},
  1052  				{Deleted: false, Name: "city_id", Type: metaCom.Uint32},
  1053  			},
  1054  		}
  1055  		timezoneTableSchema := metaCom.Table{
  1056  			Name: timezoneTable,
  1057  			Config: metaCom.TableConfig{
  1058  				ArchivingDelayMinutes:    500,
  1059  				ArchivingIntervalMinutes: 300,
  1060  			},
  1061  			IsFactTable: false,
  1062  			Columns: []metaCom.Column{
  1063  				{Deleted: false, Name: "id", Type: metaCom.Uint32},
  1064  				{Deleted: false, Name: "timezone", Type: metaCom.SmallEnum},
  1065  			},
  1066  			PrimaryKeyColumns: []int{0},
  1067  		}
  1068  		memStore.On("GetSchemas", mock.Anything).Return(map[string]*memstore.TableSchema{
  1069  			table: {
  1070  				Schema:            mainTableSchema,
  1071  				ColumnIDs:         map[string]int{"c0": 0, "city_id": 1},
  1072  				ValueTypeByColumn: []memCom.DataType{memCom.Uint32, memCom.Uint32},
  1073  				DefaultValues:     []*memCom.DataValue{&memCom.NullDataValue, &memCom.NullDataValue},
  1074  			},
  1075  			timezoneTable: {
  1076  				Schema:            timezoneTableSchema,
  1077  				ColumnIDs:         map[string]int{"id": 0, "timezone": 1},
  1078  				ValueTypeByColumn: []memCom.DataType{memCom.Uint32, memCom.SmallEnum},
  1079  				DefaultValues:     []*memCom.DataValue{&memCom.NullDataValue, &memCom.NullDataValue},
  1080  				EnumDicts: map[string]memstore.EnumDict{
  1081  					"id": {},
  1082  					"timezone": {
  1083  						ReverseDict: []string{"Africa/Algiers"},
  1084  					},
  1085  				},
  1086  			},
  1087  		})
  1088  		memStore.On("GetSchema", table).Return(&memstore.TableSchema{
  1089  			Schema:            mainTableSchema,
  1090  			ColumnIDs:         map[string]int{"c0": 0, "city_id": 1},
  1091  			ValueTypeByColumn: []memCom.DataType{memCom.Uint32, memCom.Uint32},
  1092  			DefaultValues:     []*memCom.DataValue{&memCom.NullDataValue, &memCom.NullDataValue},
  1093  		}, nil)
  1094  		memStore.On("GetSchema", timezoneTable).Return(&memstore.TableSchema{
  1095  			Schema:            timezoneTableSchema,
  1096  			ColumnIDs:         map[string]int{"id": 0, "timezone": 1},
  1097  			ValueTypeByColumn: []memCom.DataType{memCom.Uint32, memCom.SmallEnum},
  1098  			DefaultValues:     []*memCom.DataValue{&memCom.NullDataValue, &memCom.NullDataValue},
  1099  			EnumDicts: map[string]memstore.EnumDict{
  1100  				"id": {},
  1101  				"timezone": {
  1102  					ReverseDict: []string{"Africa/Algiers", "", ""},
  1103  				},
  1104  			},
  1105  		}, nil)
  1106  		memStore.On("RLock").Return(nil)
  1107  		memStore.On("RUnlock").Return(nil)
  1108  
  1109  		timezoneTableShard := memstore.NewTableShard(&memstore.TableSchema{
  1110  			Schema:            timezoneTableSchema,
  1111  			ValueTypeByColumn: []memCom.DataType{memCom.Uint32, memCom.SmallEnum},
  1112  			DefaultValues:     []*memCom.DataValue{&memCom.NullDataValue, &memCom.NullDataValue},
  1113  		}, metaStore, diskStore, hostMemoryManager, shardID)
  1114  		timezoneTableBatch := memstore.LiveBatch{
  1115  			Batch: memstore.Batch{
  1116  				RWMutex: &sync.RWMutex{},
  1117  				Columns: batch120.Columns,
  1118  			},
  1119  			Capacity: 5,
  1120  		}
  1121  		timezoneTableShard.LiveStore = &memstore.LiveStore{
  1122  			LastReadRecord: memstore.RecordID{BatchID: -90, Index: 0},
  1123  			Batches: map[int32]*memstore.LiveBatch{
  1124  				-2147483648: &timezoneTableBatch,
  1125  			},
  1126  			PrimaryKey:        memstore.NewPrimaryKey(4, false, 5, hostMemoryManager),
  1127  			HostMemoryManager: hostMemoryManager,
  1128  		}
  1129  		// build foreign table primary key index
  1130  		keyBytes := make([]byte, 4)
  1131  		recordID := memstore.RecordID{BatchID: -2147483648, Index: 0}
  1132  		for i := 0; i < 5; i++ {
  1133  			binary.LittleEndian.PutUint32(keyBytes, 100+uint32(i)*10)
  1134  			recordID.Index = uint32(i)
  1135  			timezoneTableShard.LiveStore.PrimaryKey.FindOrInsert(keyBytes, recordID, 0)
  1136  		}
  1137  
  1138  		mainTableShard := memstore.NewTableShard(&memstore.TableSchema{
  1139  			Schema:            mainTableSchema,
  1140  			ValueTypeByColumn: []memCom.DataType{memCom.Uint32, memCom.Uint32},
  1141  			DefaultValues:     []*memCom.DataValue{&memCom.NullDataValue, &memCom.NullDataValue},
  1142  		}, metaStore, diskStore, hostMemoryManager, shardID)
  1143  		mainTableShard.LiveStore = &memstore.LiveStore{
  1144  			LastReadRecord: memstore.RecordID{BatchID: -90, Index: 0},
  1145  			Batches: map[int32]*memstore.LiveBatch{
  1146  				-2147483648: {
  1147  					Batch: memstore.Batch{
  1148  						RWMutex: &sync.RWMutex{},
  1149  						Columns: batch130.Columns,
  1150  					},
  1151  					Capacity: 5,
  1152  				},
  1153  			},
  1154  			PrimaryKey:        memstore.NewPrimaryKey(16, true, 0, hostMemoryManager),
  1155  			HostMemoryManager: hostMemoryManager,
  1156  		}
  1157  		memStore.On("GetTableShard", timezoneTable, 0).Run(func(args mock.Arguments) {
  1158  			timezoneTableShard.Users.Add(1)
  1159  		}).Return(timezoneTableShard, nil).Once()
  1160  		memStore.On("GetTableShard", table, 0).Run(func(args mock.Arguments) {
  1161  			mainTableShard.Users.Add(1)
  1162  		}).Return(mainTableShard, nil).Once()
  1163  
  1164  		utils.Init(common.AresServerConfig{Query: common.QueryConfig{TimezoneTable: common.TimezoneConfig{
  1165  			TableName: timezoneTable,
  1166  		}}}, common.NewLoggerFactory().GetDefaultLogger(), common.NewLoggerFactory().GetDefaultLogger(), tally.NewTestScope("test", nil))
  1167  
  1168  		qc := &AQLQueryContext{}
  1169  		q := &AQLQuery{
  1170  			Table: table,
  1171  			Dimensions: []Dimension{
  1172  				{Expr: "c0", TimeBucketizer: "3m", TimeUnit: "second"},
  1173  			},
  1174  			Measures: []Measure{
  1175  				{Expr: "count(*)"},
  1176  			},
  1177  			TimeFilter: TimeFilter{
  1178  				Column: "c0",
  1179  				From:   "1970-01-01",
  1180  				To:     "1970-01-02",
  1181  			},
  1182  			Timezone: "timezone(city_id)",
  1183  		}
  1184  		qc.Query = q
  1185  
  1186  		qc = q.Compile(memStore, false)
  1187  		Ω(qc.Error).Should(BeNil())
  1188  		Ω(qc.TableScanners).Should(HaveLen(2))
  1189  		qc.ProcessQuery(memStore)
  1190  		Ω(qc.Error).Should(BeNil())
  1191  		Ω(qc.OOPK.currentBatch.timezoneLookupDSize).Should(Equal(3))
  1192  		qc.Results = qc.Postprocess()
  1193  		qc.ReleaseHostResultsBuffers()
  1194  		bs, err := json.Marshal(qc.Results)
  1195  		Ω(err).Should(BeNil())
  1196  		Ω(bs).Should(MatchJSON(` {
  1197  			"0": 4,
  1198  			"3600": 1
  1199  		}`))
  1200  
  1201  		bc := qc.OOPK.currentBatch
  1202  		Ω(bc.timezoneLookupD).Should(BeZero())
  1203  		utils.ResetDefaults()
  1204  	})
  1205  
  1206  	ginkgo.It("dimValResVectorSize should work", func() {
  1207  		Ω(dimValResVectorSize(3, queryCom.DimCountsPerDimWidth{0, 0, 1, 1, 1})).Should(Equal(30))
  1208  		Ω(dimValResVectorSize(3, queryCom.DimCountsPerDimWidth{0, 0, 2, 1, 1})).Should(Equal(45))
  1209  		Ω(dimValResVectorSize(3, queryCom.DimCountsPerDimWidth{0, 0, 1, 0, 0})).Should(Equal(15))
  1210  		Ω(dimValResVectorSize(3, queryCom.DimCountsPerDimWidth{0, 0, 1, 1, 0})).Should(Equal(24))
  1211  		Ω(dimValResVectorSize(3, queryCom.DimCountsPerDimWidth{0, 0, 1, 0, 1})).Should(Equal(21))
  1212  		Ω(dimValResVectorSize(3, queryCom.DimCountsPerDimWidth{0, 0, 0, 1, 1})).Should(Equal(15))
  1213  		Ω(dimValResVectorSize(3, queryCom.DimCountsPerDimWidth{0, 0, 0, 1, 0})).Should(Equal(9))
  1214  		Ω(dimValResVectorSize(3, queryCom.DimCountsPerDimWidth{0, 0, 0, 0, 1})).Should(Equal(6))
  1215  		Ω(dimValResVectorSize(0, queryCom.DimCountsPerDimWidth{0, 0, 1, 1, 1})).Should(Equal(0))
  1216  	})
  1217  
  1218  	ginkgo.It("getGeoShapeLatLongSlice", func() {
  1219  		var lats, longs []float32
  1220  
  1221  		shape := memCom.GeoShapeGo{
  1222  			Polygons: [][]memCom.GeoPointGo{
  1223  				{
  1224  					{
  1225  						90.0,
  1226  						-180.0,
  1227  					},
  1228  					{
  1229  						90.0,
  1230  						-180.0,
  1231  					},
  1232  				},
  1233  				{
  1234  					{
  1235  						90.0,
  1236  						-180.0,
  1237  					},
  1238  					{
  1239  						90.0,
  1240  						-180.0,
  1241  					},
  1242  				},
  1243  			},
  1244  		}
  1245  
  1246  		lats, longs, numPoints := getGeoShapeLatLongSlice(lats, longs, shape)
  1247  		Ω(numPoints).Should(Equal(5))
  1248  		expectedLats := []float32{
  1249  			90.0,
  1250  			90.0,
  1251  			math.MaxFloat32,
  1252  			90.0,
  1253  			90.0,
  1254  		}
  1255  		expectedLongs := []float32{
  1256  			-180.0,
  1257  			-180.0,
  1258  			math.MaxFloat32,
  1259  			-180.0,
  1260  			-180.0,
  1261  		}
  1262  		Ω(lats).Should(Equal(expectedLats))
  1263  		Ω(longs).Should(Equal(expectedLongs))
  1264  	})
  1265  
  1266  	ginkgo.It("evaluateGeoIntersect should work", func() {
  1267  		mockMemoryManager := new(memComMocks.HostMemoryManager)
  1268  		mockMemoryManager.On("ReportUnmanagedSpaceUsageChange", mock.Anything).Return()
  1269  
  1270  		// prepare trip table
  1271  		tripsSchema := &memstore.TableSchema{
  1272  			Schema: metaCom.Table{
  1273  				Name: "trips",
  1274  			},
  1275  			ColumnIDs:             map[string]int{"request_at": 0, "request_point": 1},
  1276  			ValueTypeByColumn:     []memCom.DataType{memCom.Uint32, memCom.GeoPoint},
  1277  			PrimaryKeyColumnTypes: []memCom.DataType{memCom.Uint32},
  1278  			PrimaryKeyBytes:       4,
  1279  		}
  1280  		tripTimeLiveVP := memstore.NewLiveVectorParty(5, memCom.Uint32, memCom.NullDataValue, mockMemoryManager)
  1281  		tripTimeLiveVP.Allocate(false)
  1282  		pointLiveVP := memstore.NewLiveVectorParty(5, memCom.GeoPoint, memCom.NullDataValue, mockMemoryManager)
  1283  		pointLiveVP.Allocate(false)
  1284  
  1285  		// 5 points (0,0),(3,2.5),(1.5, 3.5),(1.5,4.5),null
  1286  		//            in   in 2    in 3       out      out
  1287  		points := [4][2]float32{{0, 0}, {3, 2.5}, {1.5, 3.5}, {1.5, 4.5}}
  1288  		isPointValid := [5]bool{true, true, true, true, false}
  1289  		for i := 0; i < 5; i++ {
  1290  			requestTime := uint32(0)
  1291  			tripTimeLiveVP.SetDataValue(i, memCom.DataValue{Valid: true, OtherVal: unsafe.Pointer(&requestTime)}, memstore.IgnoreCount)
  1292  			if isPointValid[i] {
  1293  				pointLiveVP.SetDataValue(i, memCom.DataValue{Valid: true, OtherVal: unsafe.Pointer(&points[i])}, memstore.IgnoreCount)
  1294  			} else {
  1295  				pointLiveVP.SetDataValue(i, memCom.NullDataValue, memstore.IgnoreCount)
  1296  			}
  1297  		}
  1298  
  1299  		tripsTableShard := &memstore.TableShard{
  1300  			Schema: tripsSchema,
  1301  			ArchiveStore: &memstore.ArchiveStore{
  1302  				CurrentVersion: memstore.NewArchiveStoreVersion(0, shard),
  1303  			},
  1304  			LiveStore: &memstore.LiveStore{
  1305  				Batches: map[int32]*memstore.LiveBatch{
  1306  					memstore.BaseBatchID: {
  1307  						Batch: memstore.Batch{
  1308  							RWMutex: &sync.RWMutex{},
  1309  							Columns: []memCom.VectorParty{
  1310  								tripTimeLiveVP,
  1311  								pointLiveVP,
  1312  							},
  1313  						},
  1314  					},
  1315  				},
  1316  				LastReadRecord: memstore.RecordID{BatchID: memstore.BaseBatchID, Index: 5},
  1317  			},
  1318  			HostMemoryManager: mockMemoryManager,
  1319  		}
  1320  
  1321  		// prepare geofence table
  1322  		geofenceSchema := &memstore.TableSchema{
  1323  			Schema: metaCom.Table{
  1324  				Name: "geofence",
  1325  				Config: metaCom.TableConfig{
  1326  					InitialPrimaryKeyNumBuckets: 1,
  1327  				},
  1328  			},
  1329  			ColumnIDs:             map[string]int{"geofence_uuid": 0, "shape": 1},
  1330  			ValueTypeByColumn:     []memCom.DataType{memCom.UUID, memCom.GeoShape},
  1331  			PrimaryKeyColumnTypes: []memCom.DataType{memCom.UUID},
  1332  			PrimaryKeyBytes:       16,
  1333  		}
  1334  		shapeUUIDs := []string{"00000192F23D460DBE60400C32EA0667", "00001A3F088047D79343894698F221AB", "0000334BB6B0420986175F20F3FBF90D"}
  1335  		shapes := []memCom.GeoShapeGo{
  1336  			{
  1337  				Polygons: [][]memCom.GeoPointGo{
  1338  					{
  1339  						{1, 1}, {1, -1}, {-1, -1}, {-1, 1}, {1, 1},
  1340  					},
  1341  				},
  1342  			},
  1343  			{
  1344  				Polygons: [][]memCom.GeoPointGo{
  1345  					{
  1346  						{3, 3}, {2, 2}, {4, 2}, {3, 3},
  1347  					},
  1348  				},
  1349  			},
  1350  			{
  1351  				Polygons: [][]memCom.GeoPointGo{
  1352  					{
  1353  						{0, 6}, {3, 6}, {3, 3}, {0, 3}, {0, 6},
  1354  					},
  1355  					{
  1356  						{1, 5}, {2, 5}, {2, 4}, {1, 4}, {1, 5},
  1357  					},
  1358  				},
  1359  			},
  1360  		}
  1361  		shapeUUIDLiveVP := memstore.NewLiveVectorParty(3, memCom.UUID, memCom.NullDataValue, mockMemoryManager)
  1362  		shapeUUIDLiveVP.Allocate(false)
  1363  		shapeLiveVP := memstore.NewLiveVectorParty(3, memCom.GeoShape, memCom.NullDataValue, mockMemoryManager)
  1364  		shapeLiveVP.Allocate(false)
  1365  
  1366  		geoFenceTableShard := &memstore.TableShard{
  1367  			Schema:            geofenceSchema,
  1368  			HostMemoryManager: mockMemoryManager,
  1369  		}
  1370  		geoFenceLiveStore := memstore.NewLiveStore(10, geoFenceTableShard)
  1371  		geoFenceLiveStore.Batches = map[int32]*memstore.LiveBatch{
  1372  			memstore.BaseBatchID: {
  1373  				Batch: memstore.Batch{
  1374  					RWMutex: &sync.RWMutex{},
  1375  					Columns: []memCom.VectorParty{
  1376  						shapeUUIDLiveVP,
  1377  						shapeLiveVP,
  1378  					},
  1379  				},
  1380  			},
  1381  		}
  1382  		geoFenceLiveStore.LastReadRecord = memstore.RecordID{BatchID: memstore.BaseBatchID, Index: 4}
  1383  		geoFenceTableShard.LiveStore = geoFenceLiveStore
  1384  		for i := 0; i < 3; i++ {
  1385  			uuidValue, _ := memCom.ValueFromString(shapeUUIDs[i], memCom.UUID)
  1386  			shapeUUIDLiveVP.SetDataValue(i, uuidValue, memstore.IgnoreCount)
  1387  			shapeLiveVP.SetDataValue(i, memCom.DataValue{Valid: true, GoVal: &shapes[i]}, memstore.IgnoreCount)
  1388  			key, err := memstore.GetPrimaryKeyBytes([]memCom.DataValue{uuidValue}, 16)
  1389  			Ω(err).Should(BeNil())
  1390  			geoFenceLiveStore.PrimaryKey.FindOrInsert(
  1391  				key,
  1392  				memstore.RecordID{
  1393  					BatchID: memstore.BaseBatchID,
  1394  					Index:   uint32(i)},
  1395  				0)
  1396  		}
  1397  
  1398  		mockMemStore := new(memMocks.MemStore)
  1399  		mockMemStore.On("GetTableShard", "geofence", 0).Run(func(args mock.Arguments) {
  1400  			geoFenceTableShard.Users.Add(1)
  1401  		}).Return(geoFenceTableShard, nil).Once()
  1402  
  1403  		mockMemStore.On("GetTableShard", "trips", 0).Run(func(args mock.Arguments) {
  1404  			tripsTableShard.Users.Add(1)
  1405  		}).Return(tripsTableShard, nil).Once()
  1406  
  1407  		mockMemStore.On("RLock").Return()
  1408  		mockMemStore.On("RUnlock").Return()
  1409  
  1410  		qc := AQLQueryContext{
  1411  			Query: &AQLQuery{
  1412  				Table: "trips",
  1413  				Dimensions: []Dimension{
  1414  					{Expr: "request_at"},
  1415  				},
  1416  				Measures: []Measure{
  1417  					{Expr: "count(1)"},
  1418  				},
  1419  				TimeFilter: TimeFilter{
  1420  					Column: "request_at",
  1421  					From:   "0",
  1422  					To:     "86400",
  1423  				},
  1424  			},
  1425  			TableScanners: []*TableScanner{
  1426  				{
  1427  					Columns: []int{0, 1},
  1428  					ColumnsByIDs: map[int]int{
  1429  						0: 0,
  1430  						1: 1,
  1431  					},
  1432  					ColumnUsages: map[int]columnUsage{
  1433  						0: columnUsedByAllBatches,
  1434  						1: columnUsedByAllBatches,
  1435  					},
  1436  					Schema:              tripsSchema,
  1437  					ArchiveBatchIDStart: 0,
  1438  					ArchiveBatchIDEnd:   1,
  1439  					Shards:              []int{0},
  1440  				},
  1441  				{
  1442  					ColumnsByIDs: map[int]int{
  1443  						0: 0,
  1444  						1: 1,
  1445  					},
  1446  					ColumnUsages: map[int]columnUsage{
  1447  						1: columnUsedByAllBatches,
  1448  					},
  1449  					Schema: geofenceSchema,
  1450  				},
  1451  			},
  1452  			OOPK: OOPKContext{
  1453  				DimRowBytes:          5,
  1454  				DimensionVectorIndex: []int{0},
  1455  				NumDimsPerDimWidth:   queryCom.DimCountsPerDimWidth{0, 0, 1, 0, 0},
  1456  				TimeFilters: [2]expr.Expr{
  1457  					&expr.BinaryExpr{
  1458  						ExprType: expr.Boolean,
  1459  						Op:       expr.GTE,
  1460  						LHS: &expr.VarRef{
  1461  							Val:      "request_at",
  1462  							ExprType: expr.Unsigned,
  1463  							TableID:  0,
  1464  							ColumnID: 0,
  1465  							DataType: memCom.Uint32,
  1466  						},
  1467  						RHS: &expr.NumberLiteral{
  1468  							Int:      0,
  1469  							Expr:     strconv.FormatInt(0, 10),
  1470  							ExprType: expr.Unsigned,
  1471  						},
  1472  					},
  1473  					&expr.BinaryExpr{
  1474  						ExprType: expr.Boolean,
  1475  						Op:       expr.LT,
  1476  						LHS: &expr.VarRef{
  1477  							Val:      "request_at",
  1478  							ExprType: expr.Unsigned,
  1479  							TableID:  0,
  1480  							ColumnID: 0,
  1481  							DataType: memCom.Uint32,
  1482  						},
  1483  						RHS: &expr.NumberLiteral{
  1484  							Int:      86400,
  1485  							Expr:     strconv.FormatInt(86400, 10),
  1486  							ExprType: expr.Unsigned,
  1487  						},
  1488  					},
  1489  				},
  1490  				Dimensions: []expr.Expr{
  1491  					&expr.VarRef{
  1492  						Val:      "request_at",
  1493  						ExprType: expr.Unsigned,
  1494  						TableID:  0,
  1495  						ColumnID: 0,
  1496  						DataType: memCom.Uint32,
  1497  					},
  1498  				},
  1499  				AggregateType: 1,
  1500  				MeasureBytes:  4,
  1501  				Measure: &expr.NumberLiteral{
  1502  					Val:      1,
  1503  					Int:      1,
  1504  					Expr:     "1",
  1505  					ExprType: expr.Unsigned,
  1506  				},
  1507  				geoIntersection: &geoIntersection{
  1508  					shapeTableID:  1,
  1509  					shapeColumnID: 1,
  1510  					pointColumnID: 1,
  1511  					shapeUUIDs:    shapeUUIDs,
  1512  					inOrOut:       false,
  1513  					dimIndex:      -1,
  1514  				},
  1515  			},
  1516  			fromTime: &alignedTime{time.Unix(0, 0), "s"},
  1517  			toTime:   &alignedTime{time.Unix(86400, 0), "s"},
  1518  		}
  1519  
  1520  		qc.ProcessQuery(mockMemStore)
  1521  		Ω(qc.Error).Should(BeNil())
  1522  		qc.Results = qc.Postprocess()
  1523  		Ω(qc.Error).Should(BeNil())
  1524  		bs, err := json.Marshal(qc.Results)
  1525  		Ω(err).Should(BeNil())
  1526  		Ω(bs).Should(MatchJSON(
  1527  			`{
  1528  				"0": 1
  1529  			}`,
  1530  		))
  1531  		qc.ReleaseHostResultsBuffers()
  1532  	})
  1533  
  1534  	ginkgo.It("evaluateGeoIntersectJoin should work", func() {
  1535  		mockMemoryManager := new(memComMocks.HostMemoryManager)
  1536  		mockMemoryManager.On("ReportUnmanagedSpaceUsageChange", mock.Anything).Return()
  1537  
  1538  		// prepare trip table
  1539  		tripsSchema := &memstore.TableSchema{
  1540  			Schema: metaCom.Table{
  1541  				Name: "trips",
  1542  			},
  1543  			ColumnIDs:             map[string]int{"request_at": 0, "request_point": 1},
  1544  			ValueTypeByColumn:     []memCom.DataType{memCom.Uint32, memCom.GeoPoint},
  1545  			PrimaryKeyColumnTypes: []memCom.DataType{memCom.Uint32},
  1546  			PrimaryKeyBytes:       4,
  1547  		}
  1548  		tripTimeLiveVP := memstore.NewLiveVectorParty(5, memCom.Uint32, memCom.NullDataValue, mockMemoryManager)
  1549  		tripTimeLiveVP.Allocate(false)
  1550  		pointLiveVP := memstore.NewLiveVectorParty(5, memCom.GeoPoint, memCom.NullDataValue, mockMemoryManager)
  1551  		pointLiveVP.Allocate(false)
  1552  
  1553  		// 5 points (0,0),(3,2.5),(1.5, 3.5),(1.5,4.5),null
  1554  		//            in   in 2    in 3       out      out
  1555  		points := [4][2]float32{{0, 0}, {3, 2.5}, {1.5, 3.5}, {1.5, 4.5}}
  1556  		isPointValid := [5]bool{true, true, true, true, false}
  1557  		for i := 0; i < 5; i++ {
  1558  			requestTime := uint32(0)
  1559  			tripTimeLiveVP.SetDataValue(i, memCom.DataValue{Valid: true, OtherVal: unsafe.Pointer(&requestTime)}, memstore.IgnoreCount)
  1560  			if isPointValid[i] {
  1561  				pointLiveVP.SetDataValue(i, memCom.DataValue{Valid: true, OtherVal: unsafe.Pointer(&points[i])}, memstore.IgnoreCount)
  1562  			} else {
  1563  				pointLiveVP.SetDataValue(i, memCom.NullDataValue, memstore.IgnoreCount)
  1564  			}
  1565  		}
  1566  
  1567  		tripsTableShard := &memstore.TableShard{
  1568  			Schema: tripsSchema,
  1569  			ArchiveStore: &memstore.ArchiveStore{
  1570  				CurrentVersion: memstore.NewArchiveStoreVersion(0, shard),
  1571  			},
  1572  			LiveStore: &memstore.LiveStore{
  1573  				Batches: map[int32]*memstore.LiveBatch{
  1574  					memstore.BaseBatchID: {
  1575  						Batch: memstore.Batch{
  1576  							RWMutex: &sync.RWMutex{},
  1577  							Columns: []memCom.VectorParty{
  1578  								tripTimeLiveVP,
  1579  								pointLiveVP,
  1580  							},
  1581  						},
  1582  					},
  1583  				},
  1584  				LastReadRecord: memstore.RecordID{BatchID: memstore.BaseBatchID, Index: 5},
  1585  			},
  1586  			HostMemoryManager: mockMemoryManager,
  1587  		}
  1588  
  1589  		// prepare geofence table
  1590  		geofenceSchema := &memstore.TableSchema{
  1591  			Schema: metaCom.Table{
  1592  				Name: "geofence",
  1593  				Config: metaCom.TableConfig{
  1594  					InitialPrimaryKeyNumBuckets: 1,
  1595  				},
  1596  			},
  1597  			ColumnIDs:             map[string]int{"geofence_uuid": 0, "shape": 1},
  1598  			ValueTypeByColumn:     []memCom.DataType{memCom.UUID, memCom.GeoShape},
  1599  			PrimaryKeyColumnTypes: []memCom.DataType{memCom.UUID},
  1600  			PrimaryKeyBytes:       16,
  1601  		}
  1602  		shapeUUIDs := []string{"00000192F23D460DBE60400C32EA0667", "00001A3F088047D79343894698F221AB", "0000334BB6B0420986175F20F3FBF90D"}
  1603  		shapes := []memCom.GeoShapeGo{
  1604  			{
  1605  				Polygons: [][]memCom.GeoPointGo{
  1606  					{
  1607  						{1, 1}, {1, -1}, {-1, -1}, {-1, 1}, {1, 1},
  1608  					},
  1609  				},
  1610  			},
  1611  			{
  1612  				Polygons: [][]memCom.GeoPointGo{
  1613  					{
  1614  						{3, 3}, {2, 2}, {4, 2}, {3, 3},
  1615  					},
  1616  				},
  1617  			},
  1618  			{
  1619  				Polygons: [][]memCom.GeoPointGo{
  1620  					{
  1621  						{0, 6}, {3, 6}, {3, 3}, {0, 3}, {0, 6},
  1622  					},
  1623  					{
  1624  						{1, 5}, {2, 5}, {2, 4}, {1, 4}, {1, 5},
  1625  					},
  1626  				},
  1627  			},
  1628  		}
  1629  		shapeUUIDLiveVP := memstore.NewLiveVectorParty(3, memCom.UUID, memCom.NullDataValue, mockMemoryManager)
  1630  		shapeUUIDLiveVP.Allocate(false)
  1631  		shapeLiveVP := memstore.NewLiveVectorParty(3, memCom.GeoShape, memCom.NullDataValue, mockMemoryManager)
  1632  		shapeLiveVP.Allocate(false)
  1633  
  1634  		geoFenceTableShard := &memstore.TableShard{
  1635  			Schema:            geofenceSchema,
  1636  			HostMemoryManager: mockMemoryManager,
  1637  		}
  1638  		geoFenceLiveStore := memstore.NewLiveStore(10, geoFenceTableShard)
  1639  		geoFenceLiveStore.Batches = map[int32]*memstore.LiveBatch{
  1640  			memstore.BaseBatchID: {
  1641  				Batch: memstore.Batch{
  1642  					RWMutex: &sync.RWMutex{},
  1643  					Columns: []memCom.VectorParty{
  1644  						shapeUUIDLiveVP,
  1645  						shapeLiveVP,
  1646  					},
  1647  				},
  1648  			},
  1649  		}
  1650  		geoFenceLiveStore.LastReadRecord = memstore.RecordID{BatchID: memstore.BaseBatchID, Index: 4}
  1651  		geoFenceTableShard.LiveStore = geoFenceLiveStore
  1652  		for i := 0; i < 3; i++ {
  1653  			uuidValue, _ := memCom.ValueFromString(shapeUUIDs[i], memCom.UUID)
  1654  			shapeUUIDLiveVP.SetDataValue(i, uuidValue, memstore.IgnoreCount)
  1655  			shapeLiveVP.SetDataValue(i, memCom.DataValue{Valid: true, GoVal: &shapes[i]}, memstore.IgnoreCount)
  1656  			key, err := memstore.GetPrimaryKeyBytes([]memCom.DataValue{uuidValue}, 16)
  1657  			Ω(err).Should(BeNil())
  1658  			geoFenceLiveStore.PrimaryKey.FindOrInsert(
  1659  				key,
  1660  				memstore.RecordID{
  1661  					BatchID: memstore.BaseBatchID,
  1662  					Index:   uint32(i)},
  1663  				0)
  1664  		}
  1665  
  1666  		mockMemStore := new(memMocks.MemStore)
  1667  		mockMemStore.On("GetTableShard", "geofence", 0).Run(func(args mock.Arguments) {
  1668  			geoFenceTableShard.Users.Add(1)
  1669  		}).Return(geoFenceTableShard, nil).Once()
  1670  
  1671  		mockMemStore.On("GetTableShard", "trips", 0).Run(func(args mock.Arguments) {
  1672  			tripsTableShard.Users.Add(1)
  1673  		}).Return(tripsTableShard, nil).Once()
  1674  
  1675  		mockMemStore.On("RLock").Return()
  1676  		mockMemStore.On("RUnlock").Return()
  1677  
  1678  		qc := AQLQueryContext{
  1679  			Query: &AQLQuery{
  1680  				Table: "trips",
  1681  				Dimensions: []Dimension{
  1682  					{Expr: "request_at"},
  1683  					{Expr: "geo_uuid"},
  1684  				},
  1685  				Measures: []Measure{
  1686  					{Expr: "count(1)"},
  1687  				},
  1688  				TimeFilter: TimeFilter{
  1689  					Column: "request_at",
  1690  					From:   "0",
  1691  					To:     "86400",
  1692  				},
  1693  			},
  1694  			TableScanners: []*TableScanner{
  1695  				{
  1696  					Columns: []int{0, 1},
  1697  					ColumnsByIDs: map[int]int{
  1698  						0: 0,
  1699  						1: 1,
  1700  					},
  1701  					ColumnUsages: map[int]columnUsage{
  1702  						0: columnUsedByAllBatches,
  1703  						1: columnUsedByAllBatches,
  1704  					},
  1705  					Schema:              tripsSchema,
  1706  					ArchiveBatchIDStart: 0,
  1707  					ArchiveBatchIDEnd:   1,
  1708  					Shards:              []int{0},
  1709  				},
  1710  				{
  1711  					ColumnsByIDs: map[int]int{
  1712  						0: 0,
  1713  						1: 1,
  1714  					},
  1715  					ColumnUsages: map[int]columnUsage{
  1716  						1: columnUsedByAllBatches,
  1717  					},
  1718  					Schema: geofenceSchema,
  1719  				},
  1720  			},
  1721  			OOPK: OOPKContext{
  1722  				DimRowBytes:          7,
  1723  				DimensionVectorIndex: []int{0, 1},
  1724  				NumDimsPerDimWidth:   queryCom.DimCountsPerDimWidth{0, 0, 1, 0, 1},
  1725  				TimeFilters: [2]expr.Expr{
  1726  					&expr.BinaryExpr{
  1727  						ExprType: expr.Boolean,
  1728  						Op:       expr.GTE,
  1729  						LHS: &expr.VarRef{
  1730  							Val:      "request_at",
  1731  							ExprType: expr.Unsigned,
  1732  							TableID:  0,
  1733  							ColumnID: 0,
  1734  							DataType: memCom.Uint32,
  1735  						},
  1736  						RHS: &expr.NumberLiteral{
  1737  							Int:      0,
  1738  							Expr:     strconv.FormatInt(0, 10),
  1739  							ExprType: expr.Unsigned,
  1740  						},
  1741  					},
  1742  					&expr.BinaryExpr{
  1743  						ExprType: expr.Boolean,
  1744  						Op:       expr.LT,
  1745  						LHS: &expr.VarRef{
  1746  							Val:      "request_at",
  1747  							ExprType: expr.Unsigned,
  1748  							TableID:  0,
  1749  							ColumnID: 0,
  1750  							DataType: memCom.Uint32,
  1751  						},
  1752  						RHS: &expr.NumberLiteral{
  1753  							Int:      86400,
  1754  							Expr:     strconv.FormatInt(86400, 10),
  1755  							ExprType: expr.Unsigned,
  1756  						},
  1757  					},
  1758  				},
  1759  				Dimensions: []expr.Expr{
  1760  					&expr.VarRef{
  1761  						Val:      "request_at",
  1762  						ExprType: expr.Unsigned,
  1763  						TableID:  0,
  1764  						ColumnID: 0,
  1765  						DataType: memCom.Uint32,
  1766  					},
  1767  					&expr.VarRef{
  1768  						Val:      "geo_uuid",
  1769  						ExprType: expr.GeoShape,
  1770  						TableID:  0,
  1771  						ColumnID: 0,
  1772  						DataType: memCom.Uint8,
  1773  					},
  1774  				},
  1775  				AggregateType: 1,
  1776  				MeasureBytes:  4,
  1777  				Measure: &expr.NumberLiteral{
  1778  					Val:      1,
  1779  					Int:      1,
  1780  					Expr:     "1",
  1781  					ExprType: expr.Unsigned,
  1782  				},
  1783  				geoIntersection: &geoIntersection{
  1784  					shapeTableID:  1,
  1785  					shapeColumnID: 1,
  1786  					pointColumnID: 1,
  1787  					shapeUUIDs:    shapeUUIDs,
  1788  					dimIndex:      1,
  1789  					inOrOut:       true,
  1790  				},
  1791  			},
  1792  			fromTime: &alignedTime{time.Unix(0, 0), "s"},
  1793  			toTime:   &alignedTime{time.Unix(86400, 0), "s"},
  1794  		}
  1795  
  1796  		qc.ProcessQuery(mockMemStore)
  1797  		Ω(qc.Error).Should(BeNil())
  1798  		qc.Results = qc.Postprocess()
  1799  		Ω(qc.Error).Should(BeNil())
  1800  		bs, err := json.Marshal(qc.Results)
  1801  		Ω(err).Should(BeNil())
  1802  		Ω(bs).Should(MatchJSON(
  1803  			`{
  1804  				"0": {
  1805  					"00000192F23D460DBE60400C32EA0667": 1,
  1806  					"00001A3F088047D79343894698F221AB": 1,
  1807  					"0000334BB6B0420986175F20F3FBF90D": 1
  1808  				}
  1809  			}`,
  1810  		))
  1811  		qc.ReleaseHostResultsBuffers()
  1812  	})
  1813  
  1814  	ginkgo.It("shouldSkipLiveBatch should work", func() {
  1815  		qc := &AQLQueryContext{}
  1816  
  1817  		column0 := new(memComMocks.LiveVectorParty)
  1818  		column0.On("GetMinMaxValue").Return(uint32(10), uint32(50))
  1819  		column1 := new(memComMocks.LiveVectorParty)
  1820  		column1.On("GetMinMaxValue").Return(uint32(50), uint32(99))
  1821  
  1822  		batch := &memstore.LiveBatch{
  1823  			Batch: memstore.Batch{
  1824  				RWMutex: &sync.RWMutex{},
  1825  				Columns: []memCom.VectorParty{
  1826  					column0,
  1827  					column1,
  1828  					nil,
  1829  				},
  1830  			},
  1831  		}
  1832  
  1833  		// No candidate filter.
  1834  		Ω(qc.shouldSkipLiveBatch(batch)).Should(BeFalse())
  1835  
  1836  		qc.OOPK.MainTableCommonFilters = append(qc.OOPK.MainTableCommonFilters, &expr.UnaryExpr{})
  1837  
  1838  		// UnaryExpr does not match.
  1839  		Ω(qc.shouldSkipLiveBatch(batch)).Should(BeFalse())
  1840  
  1841  		// we will swap lhs and rhs.
  1842  		// we will need skip this batch as column 0 does not pass the check.
  1843  		qc.OOPK.MainTableCommonFilters = append(qc.OOPK.MainTableCommonFilters, &expr.BinaryExpr{
  1844  			Op: expr.LT,
  1845  			RHS: &expr.VarRef{
  1846  				ColumnID: 0,
  1847  				DataType: memCom.Uint32,
  1848  			},
  1849  			LHS: &expr.NumberLiteral{
  1850  				Int: 100,
  1851  			},
  1852  		})
  1853  
  1854  		Ω(qc.shouldSkipLiveBatch(batch)).Should(BeTrue())
  1855  
  1856  		// We will pass this check
  1857  		qc.OOPK.MainTableCommonFilters = []expr.Expr{&expr.BinaryExpr{
  1858  			Op: expr.GT,
  1859  			LHS: &expr.VarRef{
  1860  				ColumnID: 1,
  1861  				DataType: memCom.Uint32,
  1862  			},
  1863  			RHS: &expr.NumberLiteral{
  1864  				Int: 50,
  1865  			},
  1866  		}}
  1867  		Ω(qc.shouldSkipLiveBatch(batch)).Should(BeFalse())
  1868  
  1869  		// This filter is not uint32.
  1870  		qc.OOPK.MainTableCommonFilters = append(qc.OOPK.MainTableCommonFilters, &expr.BinaryExpr{
  1871  			Op: expr.LT,
  1872  			LHS: &expr.VarRef{
  1873  				ColumnID: 0,
  1874  				DataType: memCom.Uint16,
  1875  			},
  1876  			RHS: &expr.NumberLiteral{
  1877  				Int: 5,
  1878  			},
  1879  		})
  1880  
  1881  		Ω(qc.shouldSkipLiveBatch(batch)).Should(BeFalse())
  1882  
  1883  		// column 2 is nil, so we should skip.
  1884  		qc.OOPK.MainTableCommonFilters = append(qc.OOPK.MainTableCommonFilters, &expr.BinaryExpr{
  1885  			Op: expr.LT,
  1886  			LHS: &expr.VarRef{
  1887  				ColumnID: 2,
  1888  				DataType: memCom.Uint32,
  1889  			},
  1890  			RHS: &expr.NumberLiteral{
  1891  				Int: 5,
  1892  			},
  1893  		})
  1894  
  1895  		Ω(qc.shouldSkipLiveBatch(batch)).Should(BeTrue())
  1896  
  1897  		qc.OOPK.MainTableCommonFilters = nil
  1898  
  1899  		// we will fail to pass time filter.
  1900  		qc.OOPK.TimeFilters = [2]expr.Expr{
  1901  			&expr.BinaryExpr{
  1902  				Op: expr.GTE,
  1903  				LHS: &expr.VarRef{
  1904  					ColumnID: 0,
  1905  					DataType: memCom.Uint32,
  1906  				},
  1907  				RHS: &expr.NumberLiteral{
  1908  					Int: 100,
  1909  				},
  1910  			},
  1911  			&expr.BinaryExpr{
  1912  				Op: expr.LT,
  1913  				LHS: &expr.VarRef{
  1914  					ColumnID: 0,
  1915  					DataType: memCom.Uint32,
  1916  				},
  1917  				RHS: &expr.NumberLiteral{
  1918  					Int: 200,
  1919  				},
  1920  			},
  1921  		}
  1922  
  1923  		Ω(qc.shouldSkipLiveBatch(batch)).Should(BeTrue())
  1924  	})
  1925  
  1926  	ginkgo.It("evaluateGeoPoint query should work", func() {
  1927  		mockMemoryManager := new(memComMocks.HostMemoryManager)
  1928  		mockMemoryManager.On("ReportUnmanagedSpaceUsageChange", mock.Anything).Return()
  1929  
  1930  		// prepare trip table
  1931  		tripsSchema := &memstore.TableSchema{
  1932  			Schema: metaCom.Table{
  1933  				Name: "trips",
  1934  			},
  1935  			ColumnIDs:             map[string]int{"request_at": 0, "request_point": 1},
  1936  			ValueTypeByColumn:     []memCom.DataType{memCom.Uint32, memCom.GeoPoint},
  1937  			PrimaryKeyColumnTypes: []memCom.DataType{memCom.Uint32},
  1938  			PrimaryKeyBytes:       4,
  1939  		}
  1940  		tripTimeLiveVP := memstore.NewLiveVectorParty(6, memCom.Uint32, memCom.NullDataValue, mockMemoryManager)
  1941  		tripTimeLiveVP.Allocate(false)
  1942  		pointLiveVP := memstore.NewLiveVectorParty(6, memCom.GeoPoint, memCom.NullDataValue, mockMemoryManager)
  1943  		pointLiveVP.Allocate(false)
  1944  
  1945  		points := [5][2]float32{{0, 0}, {1.5, 3.5}, {1.5, 3.5}, {37.617994, -122.386177}, {37.617994, -122.386177}}
  1946  		isPointValid := [6]bool{true, true, true, true, true, false}
  1947  		for i := 0; i < 6; i++ {
  1948  			requestTime := uint32(0)
  1949  			tripTimeLiveVP.SetDataValue(i, memCom.DataValue{Valid: true, OtherVal: unsafe.Pointer(&requestTime)}, memstore.IgnoreCount)
  1950  			if isPointValid[i] {
  1951  				pointLiveVP.SetDataValue(i, memCom.DataValue{Valid: true, OtherVal: unsafe.Pointer(&points[i])}, memstore.IgnoreCount)
  1952  			} else {
  1953  				pointLiveVP.SetDataValue(i, memCom.NullDataValue, memstore.IgnoreCount)
  1954  			}
  1955  		}
  1956  
  1957  		tripsTableShard := &memstore.TableShard{
  1958  			Schema: tripsSchema,
  1959  			ArchiveStore: &memstore.ArchiveStore{
  1960  				CurrentVersion: memstore.NewArchiveStoreVersion(0, shard),
  1961  			},
  1962  			LiveStore: &memstore.LiveStore{
  1963  				Batches: map[int32]*memstore.LiveBatch{
  1964  					memstore.BaseBatchID: {
  1965  						Batch: memstore.Batch{
  1966  							RWMutex: &sync.RWMutex{},
  1967  							Columns: []memCom.VectorParty{
  1968  								tripTimeLiveVP,
  1969  								pointLiveVP,
  1970  							},
  1971  						},
  1972  					},
  1973  				},
  1974  				LastReadRecord: memstore.RecordID{BatchID: memstore.BaseBatchID, Index: 5},
  1975  			},
  1976  			HostMemoryManager: mockMemoryManager,
  1977  		}
  1978  
  1979  		mockMemStore := new(memMocks.MemStore)
  1980  
  1981  		mockMemStore.On("GetTableShard", "trips", 0).Run(func(args mock.Arguments) {
  1982  			tripsTableShard.Users.Add(1)
  1983  		}).Return(tripsTableShard, nil).Once()
  1984  
  1985  		mockMemStore.On("RLock").Return()
  1986  		mockMemStore.On("RUnlock").Return()
  1987  
  1988  		qc := AQLQueryContext{
  1989  			Query: &AQLQuery{
  1990  				Table: "trips",
  1991  				Dimensions: []Dimension{
  1992  					{Expr: "request_at"},
  1993  				},
  1994  				Measures: []Measure{
  1995  					{Expr: "count(1)"},
  1996  				},
  1997  			},
  1998  			TableScanners: []*TableScanner{
  1999  				{
  2000  					Columns: []int{0, 1},
  2001  					ColumnsByIDs: map[int]int{
  2002  						0: 0,
  2003  						1: 1,
  2004  					},
  2005  					ColumnUsages: map[int]columnUsage{
  2006  						0: columnUsedByAllBatches,
  2007  						1: columnUsedByAllBatches,
  2008  					},
  2009  					Schema:              tripsSchema,
  2010  					ArchiveBatchIDStart: 0,
  2011  					ArchiveBatchIDEnd:   1,
  2012  					Shards:              []int{0},
  2013  				},
  2014  			},
  2015  			OOPK: OOPKContext{
  2016  				DimRowBytes:          5,
  2017  				DimensionVectorIndex: []int{0},
  2018  				NumDimsPerDimWidth:   queryCom.DimCountsPerDimWidth{0, 0, 1, 0, 0},
  2019  				Prefilters: []expr.Expr{
  2020  					&expr.BinaryExpr{
  2021  						Op:       expr.EQ,
  2022  						LHS:      &expr.VarRef{Val: "request_point", ColumnID: 1, TableID: 0, ExprType: expr.GeoPoint, DataType: memCom.GeoPoint},
  2023  						RHS:      &expr.GeopointLiteral{Val: [2]float32{37.617994, -122.386177}},
  2024  						ExprType: expr.Boolean,
  2025  					},
  2026  				},
  2027  				Dimensions: []expr.Expr{
  2028  					&expr.VarRef{
  2029  						Val:      "request_at",
  2030  						ExprType: expr.Unsigned,
  2031  						TableID:  0,
  2032  						ColumnID: 0,
  2033  						DataType: memCom.Uint32,
  2034  					},
  2035  				},
  2036  				AggregateType: 1,
  2037  				MeasureBytes:  4,
  2038  				Measure: &expr.NumberLiteral{
  2039  					Val:      1,
  2040  					Int:      1,
  2041  					Expr:     "1",
  2042  					ExprType: expr.Unsigned,
  2043  				},
  2044  			},
  2045  			fromTime: &alignedTime{time.Unix(0, 0), "s"},
  2046  			toTime:   &alignedTime{time.Unix(86400, 0), "s"},
  2047  		}
  2048  
  2049  		qc.ProcessQuery(mockMemStore)
  2050  		Ω(qc.Error).Should(BeNil())
  2051  		qc.Results = qc.Postprocess()
  2052  		Ω(qc.Error).Should(BeNil())
  2053  		bs, err := json.Marshal(qc.Results)
  2054  		Ω(err).Should(BeNil())
  2055  		Ω(bs).Should(MatchJSON(
  2056  			`{
  2057  				"0": 2
  2058  			}`,
  2059  		))
  2060  		qc.ReleaseHostResultsBuffers()
  2061  	})
  2062  
  2063  	ginkgo.It("ProcessQuery for non-aggregation query should work", func() {
  2064  		shard.ArchiveStore.CurrentVersion.Batches[0] = archiveBatch1
  2065  		qc := &AQLQueryContext{}
  2066  		q := &AQLQuery{
  2067  			Table: table,
  2068  			Dimensions: []Dimension{
  2069  				{Expr: "c0"},
  2070  				{Expr: "c1"},
  2071  				{Expr: "c2"},
  2072  			},
  2073  			Measures: []Measure{
  2074  				{Expr: "1"},
  2075  			},
  2076  			TimeFilter: TimeFilter{
  2077  				Column: "c0",
  2078  				From:   "1970-01-01",
  2079  				To:     "1970-01-02",
  2080  			},
  2081  			Limit: 10,
  2082  		}
  2083  		qc.Query = q
  2084  
  2085  		qc = q.Compile(memStore, false)
  2086  		Ω(qc.Error).Should(BeNil())
  2087  		qc.ProcessQuery(memStore)
  2088  		Ω(qc.Error).Should(BeNil())
  2089  
  2090  		qc.Results = qc.Postprocess()
  2091  		qc.ReleaseHostResultsBuffers()
  2092  		bs, err := json.Marshal(qc.Results)
  2093  		Ω(err).Should(BeNil())
  2094  
  2095  		Ω(bs).Should(MatchJSON(` {
  2096  			"headers": ["c0", "c1", "c2"],
  2097  			"matrixData": [
  2098  				["100", "0", "1"],
  2099            		["110", "1", "NULL" ],
  2100            		["120", "NULL", "1.2"],
  2101            		["130", "0", "1.3"],
  2102            		["100", "0", "NULL"],
  2103            		["110", "1", "1.1"],
  2104            		["120", "0", "1.2"],
  2105            		["0", "NULL", "NULL"],
  2106            		["10", "NULL", "1.1"],
  2107            		["20", "NULL", "1.2"]
  2108  			]
  2109  		  }`))
  2110  
  2111  		bc := qc.OOPK.currentBatch
  2112  		// Check whether pointers are properly cleaned up.
  2113  		Ω(len(qc.OOPK.foreignTables)).Should(BeZero())
  2114  		Ω(qc.cudaStreams[0]).Should(BeZero())
  2115  		Ω(qc.cudaStreams[1]).Should(BeZero())
  2116  
  2117  		Ω(bc.dimensionVectorD[0]).Should(BeZero())
  2118  		Ω(bc.dimensionVectorD[1]).Should(BeZero())
  2119  
  2120  		Ω(bc.dimIndexVectorD[0]).Should(BeZero())
  2121  		Ω(bc.dimIndexVectorD[1]).Should(BeZero())
  2122  
  2123  		Ω(bc.hashVectorD[0]).Should(BeZero())
  2124  		Ω(bc.hashVectorD[1]).Should(BeZero())
  2125  
  2126  		Ω(bc.measureVectorD[0]).Should(BeZero())
  2127  		Ω(bc.measureVectorD[1]).Should(BeZero())
  2128  
  2129  		Ω(bc.resultSize).Should(BeZero())
  2130  		Ω(bc.resultCapacity).Should(BeZero())
  2131  
  2132  		Ω(len(bc.columns)).Should(BeZero())
  2133  
  2134  		Ω(bc.indexVectorD).Should(BeZero())
  2135  		Ω(bc.predicateVectorD).Should(BeZero())
  2136  
  2137  		Ω(bc.size).Should(BeZero())
  2138  
  2139  		Ω(len(bc.foreignTableRecordIDsD)).Should(BeZero())
  2140  		Ω(len(bc.exprStackD)).Should(BeZero())
  2141  
  2142  		Ω(qc.OOPK.measureVectorH).Should(BeZero())
  2143  		Ω(qc.OOPK.dimensionVectorH).Should(BeZero())
  2144  
  2145  		Ω(qc.OOPK.hllVectorD).Should(BeZero())
  2146  		Ω(qc.OOPK.hllDimRegIDCountD).Should(BeZero())
  2147  	})
  2148  
  2149  	ginkgo.It("ProcessQuery should work for query without regular filters", func() {
  2150  		shard.ArchiveStore.CurrentVersion.Batches[0] = archiveBatch1
  2151  		qc := &AQLQueryContext{}
  2152  		q := &AQLQuery{
  2153  			Table: table,
  2154  			Dimensions: []Dimension{
  2155  				{Expr: "0"},
  2156  			},
  2157  			Measures: []Measure{
  2158  				{Expr: "count(*)"},
  2159  			},
  2160  			TimeFilter: TimeFilter{
  2161  				Column: "c0",
  2162  				From:   "1970-01-01",
  2163  				To:     "1970-01-02",
  2164  			},
  2165  		}
  2166  		qc.Query = q
  2167  		qc = q.Compile(memStore, false)
  2168  		Ω(qc.Error).Should(BeNil())
  2169  		qc.ProcessQuery(memStore)
  2170  		Ω(qc.Error).Should(BeNil())
  2171  
  2172  		qc.Results = qc.Postprocess()
  2173  		qc.ReleaseHostResultsBuffers()
  2174  		bs, err := json.Marshal(qc.Results)
  2175  		Ω(err).Should(BeNil())
  2176  
  2177  		Ω(bs).Should(MatchJSON(` {
  2178  			"0": 12
  2179  		  }`))
  2180  	})
  2181  })