121 lines
3.3 KiB
Go
121 lines
3.3 KiB
Go
// Copyright 2025 Dolthub, Inc.
|
|
//
|
|
// Licensed 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.
|
|
|
|
package pg_extension
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
// Library is a fully-loaded extension library.
|
|
type Library struct {
|
|
Magic PgMagicStruct
|
|
Funcs map[string]Function
|
|
Version Version
|
|
internal InternalLoadedLibrary
|
|
}
|
|
|
|
// InternalLoadedLibrary is an interface that is implemented by the specific platform to handle library operations.
|
|
type InternalLoadedLibrary interface {
|
|
Lookup(sym string) (uintptr, error)
|
|
Close() error
|
|
}
|
|
|
|
// Function represents an internal library function.
|
|
type Function struct {
|
|
Name string
|
|
Ptr uintptr
|
|
Args []int
|
|
APIVersion int
|
|
// TODO: return type?
|
|
}
|
|
|
|
// PgFunctionInfo is a stand-in for the C struct that reports the function information.
|
|
type PgFunctionInfo struct {
|
|
APIVersion int32
|
|
}
|
|
|
|
// PgMagicStruct is a stand-in for the C struct that reports the information of the library.
|
|
type PgMagicStruct struct {
|
|
Len int32
|
|
Version int32
|
|
FuncMaxArgs int32
|
|
IndexMaxKeys int32
|
|
NameDataLen int32
|
|
Float4ByVal int32
|
|
Float8ByVal int32
|
|
}
|
|
|
|
var (
|
|
// loadedLibraries contains all of the loaded libraries.
|
|
// TODO: need to close all of these before the program ends
|
|
loadedLibraries = make(map[string]*Library)
|
|
// loadedLibrariesMutex gates access to the cached libraries.
|
|
loadedLibrariesMutex = &sync.Mutex{}
|
|
)
|
|
|
|
// LoadLibrary loads the library of the extension, along with preloading all of the functions given.
|
|
func LoadLibrary(path string, funcNames []string) (*Library, error) {
|
|
loadedLibrariesMutex.Lock()
|
|
defer loadedLibrariesMutex.Unlock()
|
|
|
|
if lib, ok := loadedLibraries[path]; ok {
|
|
return lib, nil
|
|
}
|
|
internalLib, err := loadLibraryInternal(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
magicPtr, err := internalLib.Lookup("Pg_magic_func")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// We don't free the magic struct since it's a pointer to static memory
|
|
magicStructDatum, isNotNull := CallFmgrFunction(magicPtr)
|
|
if !isNotNull {
|
|
return nil, fmt.Errorf("unable to find magic function for `%s`", path)
|
|
}
|
|
magicStruct := *(FromDatum[PgMagicStruct](magicStructDatum))
|
|
lib := &Library{
|
|
Magic: magicStruct,
|
|
Funcs: make(map[string]Function),
|
|
internal: internalLib,
|
|
}
|
|
for _, funcName := range funcNames {
|
|
finfoPtr, err := internalLib.Lookup(fmt.Sprintf("pg_finfo_%s", funcName))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// We don't free finfo since it's a pointer to static memory
|
|
finfoDatum, isNotNull := CallFmgrFunction(finfoPtr)
|
|
apiVersion := 0
|
|
if isNotNull {
|
|
apiVersion = int(FromDatum[PgFunctionInfo](finfoDatum).APIVersion)
|
|
}
|
|
funcPtr, err := internalLib.Lookup(funcName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lib.Funcs[funcName] = Function{
|
|
Name: funcName,
|
|
Ptr: funcPtr,
|
|
Args: nil,
|
|
APIVersion: apiVersion,
|
|
}
|
|
}
|
|
loadedLibraries[path] = lib
|
|
return lib, nil
|
|
}
|