This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 950fbb62ce GH-40733: [Go] Require Go 1.21 or later (#40848)
950fbb62ce is described below

commit 950fbb62ce7388aad926c5af5861bf07f7db6de1
Author: Matt Topol <[email protected]>
AuthorDate: Thu Mar 28 15:59:14 2024 -0400

    GH-40733: [Go] Require Go 1.21 or later (#40848)
    
    
    
    ### Rationale for this change
    Bumping to require Go 1.21 or later as 1.20 is EOL
    
    * GitHub Issue: #40733
    
    Authored-by: Matt Topol <[email protected]>
    Signed-off-by: Matt Topol <[email protected]>
---
 .env                                               |  4 +-
 .github/workflows/go.yml                           | 28 ++++++-----
 ci/docker/conda-integration.dockerfile             |  2 +-
 ci/docker/debian-12-go.dockerfile                  |  4 +-
 dev/release/verify-release-candidate.sh            |  6 +--
 dev/tasks/tasks.yml                                |  2 +-
 go/arrow/bitutil/bitutil.go                        | 35 +------------
 .../bitutil/bitutil_bytes.go}                      | 26 +++++-----
 go/arrow/cdata/cdata_allocate.go                   | 57 ++++++++++++++++++++++
 go/arrow/cdata/cdata_exports.go                    | 55 ---------------------
 go/arrow/compute/exec/span.go                      | 17 -------
 .../compute/exec/span_offsets.go}                  | 20 ++++++--
 go/arrow/compute/fieldref.go                       | 17 -------
 .../compute/fieldref_hash.go}                      | 23 +++++++--
 go/arrow/doc.go                                    |  2 -
 go/arrow/flight/flightsql/driver/driver_test.go    |  1 +
 go/arrow/memory/mallocator/mallocator.go           | 11 ++---
 go/arrow/memory/mallocator/mallocator_util.go      | 26 ++++++++++
 go/go.mod                                          |  2 +-
 go/internal/hashing/hash_string.go                 |  4 ++
 go/internal/hashing/xxh3_memo_table.go             |  9 +---
 go/parquet/types.go                                | 44 +++--------------
 22 files changed, 177 insertions(+), 218 deletions(-)

diff --git a/.env b/.env
index b5c66563f5..298c100c09 100644
--- a/.env
+++ b/.env
@@ -58,8 +58,8 @@ CUDA=11.2.2
 DASK=latest
 DOTNET=7.0
 GCC_VERSION=""
-GO=1.19.13
-STATICCHECK=v0.4.5
+GO=1.21.8
+STATICCHECK=v0.4.7
 HDFS=3.2.1
 JDK=8
 KARTOTHEK=latest
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 47148d9568..7ff781d35e 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -59,13 +59,13 @@ jobs:
           {
             "arch-label": "AMD64",
             "arch": "amd64",
-            "go": "1.19",
+            "go": "1.21",
             "runs-on": "ubuntu-latest"
           },
           {
             "arch-label": "AMD64",
             "arch": "amd64",
-            "go": "1.20",
+            "go": "1.22",
             "runs-on": "ubuntu-latest"
           }
           JSON
@@ -75,13 +75,13 @@ jobs:
           {
             "arch-label": "ARM64",
             "arch": "arm64v8",
-            "go": "1.19",
+            "go": "1.21",
             "runs-on": ["self-hosted", "arm", "linux"]
           },
           {
             "arch-label": "ARM64",
             "arch": "arm64v8",
-            "go": "1.20",
+            "go": "1.22",
             "runs-on": ["self-hosted", "arm", "linux"]
           }
           JSON
@@ -169,10 +169,13 @@ jobs:
         uses: actions/checkout@v4
         with:
           fetch-depth: 0
+      - name: Get required Go version
+        run: |
+          (. .env && echo "GO_VERSION=${GO}") >> $GITHUB_ENV
       - name: Install Go
         uses: actions/setup-go@v5
         with:
-          go-version: 1.19
+          go-version: "${{ env.GO_VERSION }}"
           cache: true
           cache-dependency-path: go/go.sum
       - name: Run build
@@ -188,7 +191,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        go: [1.19, '1.20']
+        go: ['1.21', '1.22']
     env:
       GO: ${{ matrix.go }}
     steps:
@@ -229,7 +232,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        go: [1.19, '1.20']
+        go: ['1.21', '1.22']
     env:
       GO: ${{ matrix.go }}
     steps:
@@ -268,7 +271,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        go: [1.19, '1.20']
+        go: ['1.21', '1.22']
     steps:
       - name: Checkout Arrow
         uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # 
v4.0.0
@@ -301,7 +304,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        go: [1.19, '1.20']
+        go: ['1.21', '1.22']
     steps:
       - name: Checkout Arrow
         uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # 
v4.0.0
@@ -359,7 +362,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        go: [1.19, '1.20']
+        go: ['1.21', '1.22']
     env:
       ARROW_GO_TESTCGO: "1"
     steps:
@@ -428,6 +431,9 @@ jobs:
         shell: msys2 {0}
         run: |
           ci/scripts/msys2_setup.sh cgo
+      - name: Get required Go version
+        run: |
+          (. .env && echo "GO_VERSION=${GO}") >> $GITHUB_ENV  
       - name: Update CGO Env vars
         shell: msys2 {0}
         run: |
@@ -437,7 +443,7 @@ jobs:
       - name: Install go
         uses: actions/setup-go@v5
         with:
-          go-version: '1.19'
+          go-version: "${{ env.GO_VERSION }}"
           cache: true
           cache-dependency-path: go/go.sum
       - name: Install staticcheck
diff --git a/ci/docker/conda-integration.dockerfile 
b/ci/docker/conda-integration.dockerfile
index 8406a419c0..a747ccbc72 100644
--- a/ci/docker/conda-integration.dockerfile
+++ b/ci/docker/conda-integration.dockerfile
@@ -24,7 +24,7 @@ ARG maven=3.8.7
 ARG node=16
 ARG yarn=1.22
 ARG jdk=8
-ARG go=1.19.13
+ARG go=1.21.8
 
 # Install Archery and integration dependencies
 COPY ci/conda_env_archery.txt /arrow/ci/
diff --git a/ci/docker/debian-12-go.dockerfile 
b/ci/docker/debian-12-go.dockerfile
index 7c077910a6..c958e6bdee 100644
--- a/ci/docker/debian-12-go.dockerfile
+++ b/ci/docker/debian-12-go.dockerfile
@@ -16,8 +16,8 @@
 # under the License.
 
 ARG arch=amd64
-ARG go=1.19
-ARG staticcheck=v0.4.5
+ARG go=1.21
+ARG staticcheck=v0.4.7
 FROM ${arch}/golang:${go}-bookworm
 
 # FROM collects all the args, get back the staticcheck version arg
diff --git a/dev/release/verify-release-candidate.sh 
b/dev/release/verify-release-candidate.sh
index d74ce1f670..e7d78328ed 100755
--- a/dev/release/verify-release-candidate.sh
+++ b/dev/release/verify-release-candidate.sh
@@ -24,7 +24,7 @@
 # - JDK >=8
 # - gcc >= 4.8
 # - Node.js >= 18
-# - Go >= 1.19
+# - Go >= 1.21
 # - Docker
 #
 # If using a non-system Boost, set BOOST_ROOT and add Boost libraries to
@@ -405,7 +405,7 @@ install_go() {
     return 0
   fi
 
-  local version=1.19.13
+  local version=1.21.8
   show_info "Installing go version ${version}..."
 
   local arch="$(uname -m)"
@@ -953,7 +953,7 @@ test_go() {
   show_header "Build and test Go libraries"
 
   maybe_setup_go
-  maybe_setup_conda compilers go=1.19
+  maybe_setup_conda compilers go=1.21
 
   pushd go
   go get -v ./...
diff --git a/dev/tasks/tasks.yml b/dev/tasks/tasks.yml
index 15b687b2d2..2abfbc1517 100644
--- a/dev/tasks/tasks.yml
+++ b/dev/tasks/tasks.yml
@@ -1415,7 +1415,7 @@ tasks:
         R_PRUNE_DEPS: TRUE
       image: fedora-r-clang-sanitizer
 
-  {% for go_version, staticcheck in [("1.19", "v0.4.5"), ("1.21", "latest")] %}
+  {% for go_version, staticcheck in [("1.21", "v0.4.7"), ("1.22", "latest")] %}
   test-debian-12-go-{{ go_version }}:
     ci: azure
     template: docker-tests/azure.linux.yml
diff --git a/go/arrow/bitutil/bitutil.go b/go/arrow/bitutil/bitutil.go
index 82747ee141..6a8f754103 100644
--- a/go/arrow/bitutil/bitutil.go
+++ b/go/arrow/bitutil/bitutil.go
@@ -19,7 +19,6 @@ package bitutil
 import (
        "math"
        "math/bits"
-       "reflect"
        "unsafe"
 
        "github.com/apache/arrow/go/v16/arrow/memory"
@@ -99,8 +98,6 @@ func countSetBitsWithOffset(buf []byte, offset, n int) int {
        count := 0
 
        beg := offset
-       end := offset + n
-
        begU8 := roundUp(beg, uint64SizeBits)
 
        init := min(n, begU8-beg)
@@ -110,27 +107,8 @@ func countSetBitsWithOffset(buf []byte, offset, n int) int 
{
                }
        }
 
-       nU64 := (n - init) / uint64SizeBits
-       begU64 := begU8 / uint64SizeBits
-       endU64 := begU64 + nU64
-       bufU64 := bytesToUint64(buf)
-       if begU64 < len(bufU64) {
-               for _, v := range bufU64[begU64:endU64] {
-                       count += bits.OnesCount64(v)
-               }
-       }
-
-       // FIXME: use a fallback to bits.OnesCount8
-       // before counting the tail bits.
-
-       tail := beg + init + nU64*uint64SizeBits
-       for i := tail; i < end; i++ {
-               if BitIsSet(buf, i) {
-                       count++
-               }
-       }
-
-       return count
+       begU64 := BytesForBits(int64(beg + init))
+       return count + CountSetBits(buf[begU64:], 0, n-init)
 }
 
 func roundUp(v, f int) int {
@@ -149,15 +127,6 @@ const (
        uint64SizeBits  = uint64SizeBytes * 8
 )
 
-func bytesToUint64(b []byte) []uint64 {
-       if cap(b) < uint64SizeBytes {
-               return nil
-       }
-
-       h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-       return unsafe.Slice((*uint64)(unsafe.Pointer(h.Data)), 
cap(b)/uint64SizeBytes)[:len(b)/uint64SizeBytes]
-}
-
 var (
        // PrecedingBitmask is a convenience set of values as bitmasks for 
checking
        // prefix bits of a byte
diff --git a/go/internal/hashing/hash_string_go1.19.go 
b/go/arrow/bitutil/bitutil_bytes.go
similarity index 58%
rename from go/internal/hashing/hash_string_go1.19.go
rename to go/arrow/bitutil/bitutil_bytes.go
index f38eb5c523..09dd5cbc67 100644
--- a/go/internal/hashing/hash_string_go1.19.go
+++ b/go/arrow/bitutil/bitutil_bytes.go
@@ -14,24 +14,24 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//go:build !go1.20 && !tinygo
+//go:build go1.20 || tinygo
 
-package hashing
+package bitutil
 
 import (
-       "reflect"
        "unsafe"
 )
 
-func hashString(val string, alg uint64) uint64 {
-       if val == "" {
-               return Hash([]byte{}, alg)
+func bytesToUint64(b []byte) []uint64 {
+       if len(b) < uint64SizeBytes {
+               return nil
        }
-       // highly efficient way to get byte slice without copy before
-       // the introduction of unsafe.StringData in go1.20
-       // 
(https://stackoverflow.com/questions/59209493/how-to-use-unsafe-get-a-byte-slice-from-a-string-without-memory-copy)
-       const MaxInt32 = 1<<31 - 1
-       buf := (*[MaxInt32]byte)(unsafe.Pointer((*reflect.StringHeader)(
-               unsafe.Pointer(&val)).Data))[: len(val)&MaxInt32 : 
len(val)&MaxInt32]
-       return Hash(buf, alg)
+
+       ptr := unsafe.SliceData(b)
+       if ptr == nil {
+               return nil
+       }
+
+       return unsafe.Slice((*uint64)(unsafe.Pointer(ptr)),
+               len(b)/uint64SizeBytes)
 }
diff --git a/go/arrow/cdata/cdata_allocate.go b/go/arrow/cdata/cdata_allocate.go
new file mode 100644
index 0000000000..da0bd957de
--- /dev/null
+++ b/go/arrow/cdata/cdata_allocate.go
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:build go1.20 || tinygo
+
+package cdata
+
+// #include <stdlib.h>
+// #include "arrow/c/abi.h"
+import "C"
+
+import (
+       "unsafe"
+)
+
+func allocateArrowSchemaArr(n int) (out []CArrowSchema) {
+       return unsafe.Slice((*CArrowSchema)(C.calloc(C.size_t(n),
+               C.sizeof_struct_ArrowSchema)), n)
+}
+
+func allocateArrowSchemaPtrArr(n int) (out []*CArrowSchema) {
+       return unsafe.Slice((**CArrowSchema)(C.calloc(C.size_t(n),
+               C.size_t(unsafe.Sizeof((*CArrowSchema)(nil))))), n)
+}
+
+func allocateArrowArrayArr(n int) (out []CArrowArray) {
+       return unsafe.Slice((*CArrowArray)(C.calloc(C.size_t(n),
+               C.sizeof_struct_ArrowArray)), n)
+}
+
+func allocateArrowArrayPtrArr(n int) (out []*CArrowArray) {
+       return unsafe.Slice((**CArrowArray)(C.calloc(C.size_t(n),
+               C.size_t(unsafe.Sizeof((*CArrowArray)(nil))))), n)
+}
+
+func allocateBufferPtrArr(n int) (out []*C.void) {
+       return unsafe.Slice((**C.void)(C.calloc(C.size_t(n),
+               C.size_t(unsafe.Sizeof((*C.void)(nil))))), n)
+}
+
+func allocateBufferSizeArr(n int) (out []C.int64_t) {
+       return unsafe.Slice((*C.int64_t)(C.calloc(C.size_t(n),
+               C.sizeof_int64_t)), n)
+}
diff --git a/go/arrow/cdata/cdata_exports.go b/go/arrow/cdata/cdata_exports.go
index d59c87712e..fecc8610bf 100644
--- a/go/arrow/cdata/cdata_exports.go
+++ b/go/arrow/cdata/cdata_exports.go
@@ -39,7 +39,6 @@ import (
        "bytes"
        "encoding/binary"
        "fmt"
-       "reflect"
        "runtime/cgo"
        "strconv"
        "strings"
@@ -291,60 +290,6 @@ func (exp *schemaExporter) export(field arrow.Field) {
        exp.exportMeta(&field.Metadata)
 }
 
-func allocateArrowSchemaArr(n int) (out []CArrowSchema) {
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&out))
-       s.Data = uintptr(C.calloc(C.size_t(n), C.sizeof_struct_ArrowSchema))
-       s.Len = n
-       s.Cap = n
-
-       return
-}
-
-func allocateArrowSchemaPtrArr(n int) (out []*CArrowSchema) {
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&out))
-       s.Data = uintptr(C.calloc(C.size_t(n), 
C.size_t(unsafe.Sizeof((*CArrowSchema)(nil)))))
-       s.Len = n
-       s.Cap = n
-
-       return
-}
-
-func allocateArrowArrayArr(n int) (out []CArrowArray) {
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&out))
-       s.Data = uintptr(C.calloc(C.size_t(n), C.sizeof_struct_ArrowArray))
-       s.Len = n
-       s.Cap = n
-
-       return
-}
-
-func allocateArrowArrayPtrArr(n int) (out []*CArrowArray) {
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&out))
-       s.Data = uintptr(C.calloc(C.size_t(n), 
C.size_t(unsafe.Sizeof((*CArrowArray)(nil)))))
-       s.Len = n
-       s.Cap = n
-
-       return
-}
-
-func allocateBufferPtrArr(n int) (out []*C.void) {
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&out))
-       s.Data = uintptr(C.calloc(C.size_t(n), 
C.size_t(unsafe.Sizeof((*C.void)(nil)))))
-       s.Len = n
-       s.Cap = n
-
-       return
-}
-
-func allocateBufferSizeArr(n int) (out []C.int64_t) {
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&out))
-       s.Data = uintptr(C.calloc(C.size_t(n), 
C.size_t(unsafe.Sizeof(int64(0)))))
-       s.Len = n
-       s.Cap = n
-
-       return
-}
-
 func (exp *schemaExporter) finish(out *CArrowSchema) {
        out.dictionary = nil
        if exp.dict != nil {
diff --git a/go/arrow/compute/exec/span.go b/go/arrow/compute/exec/span.go
index 6f9bb240e3..4425784f25 100644
--- a/go/arrow/compute/exec/span.go
+++ b/go/arrow/compute/exec/span.go
@@ -19,7 +19,6 @@
 package exec
 
 import (
-       "reflect"
        "sync/atomic"
        "unsafe"
 
@@ -250,22 +249,6 @@ func (a *ArraySpan) resizeChildren(i int) {
        }
 }
 
-// convenience function for populating the offsets buffer from a scalar
-// value's size.
-func setOffsetsForScalar[T int32 | int64](span *ArraySpan, buf []T, valueSize 
int64, bufidx int) {
-       buf[0] = 0
-       buf[1] = T(valueSize)
-
-       b := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&span.Buffers[bufidx].Buf))
-       s.Data = b.Data
-       s.Len = 2 * int(unsafe.Sizeof(T(0)))
-       s.Cap = s.Len
-
-       span.Buffers[bufidx].Owner = nil
-       span.Buffers[bufidx].SelfAlloc = false
-}
-
 // FillFromScalar populates this ArraySpan as if it were a 1 length array
 // with the single value equal to the passed in Scalar.
 func (a *ArraySpan) FillFromScalar(val scalar.Scalar) {
diff --git a/go/internal/hashing/hash_string.go 
b/go/arrow/compute/exec/span_offsets.go
similarity index 64%
copy from go/internal/hashing/hash_string.go
copy to go/arrow/compute/exec/span_offsets.go
index b772c7d7f8..d2d0398884 100644
--- a/go/internal/hashing/hash_string.go
+++ b/go/arrow/compute/exec/span_offsets.go
@@ -16,11 +16,21 @@
 
 //go:build go1.20 || tinygo
 
-package hashing
+package exec
 
-import "unsafe"
+import (
+       "unsafe"
+)
 
-func hashString(val string, alg uint64) uint64 {
-       buf := unsafe.Slice(unsafe.StringData(val), len(val))
-       return Hash(buf, alg)
+// convenience function for populating the offsets buffer from a scalar
+// value's size.
+func setOffsetsForScalar[T int32 | int64](span *ArraySpan, buf []T, valueSize 
int64, bufidx int) {
+       buf[0] = 0
+       buf[1] = T(valueSize)
+
+       span.Buffers[bufidx].Buf = 
unsafe.Slice((*byte)(unsafe.Pointer(unsafe.SliceData(buf))),
+               2*int(unsafe.Sizeof(T(0))))
+
+       span.Buffers[bufidx].Owner = nil
+       span.Buffers[bufidx].SelfAlloc = false
 }
diff --git a/go/arrow/compute/fieldref.go b/go/arrow/compute/fieldref.go
index ab6d856f85..0c55c36dab 100644
--- a/go/arrow/compute/fieldref.go
+++ b/go/arrow/compute/fieldref.go
@@ -20,12 +20,10 @@ import (
        "errors"
        "fmt"
        "hash/maphash"
-       "math/bits"
        "reflect"
        "strconv"
        "strings"
        "unicode"
-       "unsafe"
 
        "github.com/apache/arrow/go/v16/arrow"
        "github.com/apache/arrow/go/v16/arrow/array"
@@ -168,21 +166,6 @@ func (f FieldPath) GetColumn(batch arrow.Record) 
(arrow.Array, error) {
        return f.getArray(batch.Columns())
 }
 
-func (f FieldPath) hash(h *maphash.Hash) {
-       raw := (*reflect.SliceHeader)(unsafe.Pointer(&f)).Data
-
-       var b []byte
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-       s.Data = raw
-       if bits.UintSize == 32 {
-               s.Len = arrow.Int32Traits.BytesRequired(len(f))
-       } else {
-               s.Len = arrow.Int64Traits.BytesRequired(len(f))
-       }
-       s.Cap = s.Len
-       h.Write(b)
-}
-
 func (f FieldPath) findAll(fields []arrow.Field) []FieldPath {
        _, err := f.GetFieldFromSlice(fields)
        if err == nil {
diff --git a/go/internal/hashing/hash_string.go 
b/go/arrow/compute/fieldref_hash.go
similarity index 67%
copy from go/internal/hashing/hash_string.go
copy to go/arrow/compute/fieldref_hash.go
index b772c7d7f8..dace05788b 100644
--- a/go/internal/hashing/hash_string.go
+++ b/go/arrow/compute/fieldref_hash.go
@@ -16,11 +16,24 @@
 
 //go:build go1.20 || tinygo
 
-package hashing
+package compute
 
-import "unsafe"
+import (
+       "hash/maphash"
+       "math/bits"
+       "unsafe"
 
-func hashString(val string, alg uint64) uint64 {
-       buf := unsafe.Slice(unsafe.StringData(val), len(val))
-       return Hash(buf, alg)
+       "github.com/apache/arrow/go/v16/arrow"
+)
+
+func (f FieldPath) hash(h *maphash.Hash) {
+       raw := unsafe.Pointer(unsafe.SliceData(f))
+       var byteLen int
+       if bits.UintSize == 32 {
+               byteLen = arrow.Int32Traits.BytesRequired(len(f))
+       } else {
+               byteLen = arrow.Int64Traits.BytesRequired(len(f))
+       }
+
+       h.Write(unsafe.Slice((*byte)(raw), byteLen))
 }
diff --git a/go/arrow/doc.go b/go/arrow/doc.go
index 2f7c8c2acf..19f24c5d0b 100644
--- a/go/arrow/doc.go
+++ b/go/arrow/doc.go
@@ -30,8 +30,6 @@ array is valid (not null). If the array has no null entries, 
it is possible to o
 
 # Requirements
 
-Despite the go.mod stating go1.20, everything is able to be built with go1.19 
or higher.
-
 To build with tinygo include the noasm build tag.
 */
 package arrow
diff --git a/go/arrow/flight/flightsql/driver/driver_test.go 
b/go/arrow/flight/flightsql/driver/driver_test.go
index 79955f6099..11b9036519 100644
--- a/go/arrow/flight/flightsql/driver/driver_test.go
+++ b/go/arrow/flight/flightsql/driver/driver_test.go
@@ -619,6 +619,7 @@ func (s *SqlTestSuite) 
TestRowsPrematureCloseDuringNextLoop() {
        require.NoError(t, err)
        require.Equal(t, int64(rowCount), insertedRows)
 
+       time.Sleep(200 * time.Millisecond)
        // Do query
        const sqlSelectAll = `SELECT id, name, value FROM ` + tableName
 
diff --git a/go/arrow/memory/mallocator/mallocator.go 
b/go/arrow/memory/mallocator/mallocator.go
index a111f009ec..59d240a106 100644
--- a/go/arrow/memory/mallocator/mallocator.go
+++ b/go/arrow/memory/mallocator/mallocator.go
@@ -30,7 +30,6 @@ package mallocator
 import "C"
 
 import (
-       "reflect"
        "sync/atomic"
        "unsafe"
 )
@@ -70,18 +69,18 @@ func (alloc *Mallocator) Allocate(size int) []byte {
 }
 
 func (alloc *Mallocator) Free(b []byte) {
-       sh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-       C.free(unsafe.Pointer(sh.Data))
+       sz := len(b)
+       C.free(getPtr(b))
        // Subtract sh.Len via two's complement (since atomic doesn't offer 
subtract)
-       atomic.AddUint64(&alloc.allocatedBytes, ^(uint64(sh.Len) - 1))
+       atomic.AddUint64(&alloc.allocatedBytes, ^(uint64(sz) - 1))
 }
 
 func (alloc *Mallocator) Reallocate(size int, b []byte) []byte {
        if size < 0 {
                panic("mallocator: negative size")
        }
-       sh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-       ptr, err := C.realloc_and_initialize(unsafe.Pointer(sh.Data), 
C.size_t(sh.Cap), C.size_t(size))
+       cp := cap(b)
+       ptr, err := C.realloc_and_initialize(getPtr(b), C.size_t(cp), 
C.size_t(size))
        if err != nil {
                panic(err)
        } else if ptr == nil && size != 0 {
diff --git a/go/arrow/memory/mallocator/mallocator_util.go 
b/go/arrow/memory/mallocator/mallocator_util.go
new file mode 100644
index 0000000000..0ab5f8f515
--- /dev/null
+++ b/go/arrow/memory/mallocator/mallocator_util.go
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//go:build go1.20 || tinygo
+
+package mallocator
+
+import "unsafe"
+
+func getPtr(b []byte) unsafe.Pointer {
+       return unsafe.Pointer(unsafe.SliceData(b))
+}
diff --git a/go/go.mod b/go/go.mod
index 5c297c74d6..2f788c5c26 100644
--- a/go/go.mod
+++ b/go/go.mod
@@ -16,7 +16,7 @@
 
 module github.com/apache/arrow/go/v16
 
-go 1.20
+go 1.21
 
 require (
        github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c
diff --git a/go/internal/hashing/hash_string.go 
b/go/internal/hashing/hash_string.go
index b772c7d7f8..c8579c1ec5 100644
--- a/go/internal/hashing/hash_string.go
+++ b/go/internal/hashing/hash_string.go
@@ -24,3 +24,7 @@ func hashString(val string, alg uint64) uint64 {
        buf := unsafe.Slice(unsafe.StringData(val), len(val))
        return Hash(buf, alg)
 }
+
+func strToBytes(v string) []byte {
+       return unsafe.Slice(unsafe.StringData(v), len(v))
+}
diff --git a/go/internal/hashing/xxh3_memo_table.go 
b/go/internal/hashing/xxh3_memo_table.go
index 283bc1a953..fbb8b33531 100644
--- a/go/internal/hashing/xxh3_memo_table.go
+++ b/go/internal/hashing/xxh3_memo_table.go
@@ -22,7 +22,6 @@ package hashing
 import (
        "bytes"
        "math"
-       "reflect"
        "unsafe"
 )
 
@@ -183,13 +182,7 @@ func (BinaryMemoTable) valAsByteSlice(val interface{}) 
[]byte {
        case ByteSlice:
                return v.Bytes()
        case string:
-               var out []byte
-               h := (*reflect.StringHeader)(unsafe.Pointer(&v))
-               s := (*reflect.SliceHeader)(unsafe.Pointer(&out))
-               s.Data = h.Data
-               s.Len = h.Len
-               s.Cap = h.Len
-               return out
+               return strToBytes(v)
        default:
                panic("invalid type for binarymemotable")
        }
diff --git a/go/parquet/types.go b/go/parquet/types.go
index 8742c3ba8b..5447e793b4 100644
--- a/go/parquet/types.go
+++ b/go/parquet/types.go
@@ -95,27 +95,13 @@ type int96Traits struct{}
 func (int96Traits) BytesRequired(n int) int { return Int96SizeBytes * n }
 
 func (int96Traits) CastFromBytes(b []byte) []Int96 {
-       h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-
-       var res []Int96
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
-       s.Data = h.Data
-       s.Len = h.Len / Int96SizeBytes
-       s.Cap = h.Cap / Int96SizeBytes
-
-       return res
+       return unsafe.Slice((*Int96)(unsafe.Pointer(unsafe.SliceData(b))),
+               len(b)/Int96SizeBytes)
 }
 
 func (int96Traits) CastToBytes(b []Int96) []byte {
-       h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-
-       var res []byte
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
-       s.Data = h.Data
-       s.Len = h.Len * Int96SizeBytes
-       s.Cap = h.Cap * Int96SizeBytes
-
-       return res
+       return unsafe.Slice((*byte)(unsafe.Pointer(unsafe.SliceData(b))),
+               len(b)*Int96SizeBytes)
 }
 
 // ByteArray is a type to be utilized for representing the Parquet ByteArray 
physical type, represented as a byte slice
@@ -142,15 +128,8 @@ func (byteArrayTraits) BytesRequired(n int) int {
 }
 
 func (byteArrayTraits) CastFromBytes(b []byte) []ByteArray {
-       h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-
-       var res []ByteArray
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
-       s.Data = h.Data
-       s.Len = h.Len / ByteArraySizeBytes
-       s.Cap = h.Cap / ByteArraySizeBytes
-
-       return res
+       return unsafe.Slice((*ByteArray)(unsafe.Pointer(unsafe.SliceData(b))),
+               len(b)/ByteArraySizeBytes)
 }
 
 // FixedLenByteArray is a go type to represent a FixedLengthByteArray as a 
byte slice
@@ -177,15 +156,8 @@ func (fixedLenByteArrayTraits) BytesRequired(n int) int {
 }
 
 func (fixedLenByteArrayTraits) CastFromBytes(b []byte) []FixedLenByteArray {
-       h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-
-       var res []FixedLenByteArray
-       s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
-       s.Data = h.Data
-       s.Len = h.Len / FixedLenByteArraySizeBytes
-       s.Cap = h.Cap / FixedLenByteArraySizeBytes
-
-       return res
+       return 
unsafe.Slice((*FixedLenByteArray)(unsafe.Pointer(unsafe.SliceData(b))),
+               len(b)/FixedLenByteArraySizeBytes)
 }
 
 // Creating our own enums allows avoiding the transitive dependency on the

Reply via email to